/////////////////////////////////////////////////////////////////////////////////////////////////////// // // Welcome to your first Cloud Script revision! // // Cloud Script runs in the PlayFab cloud and has full access to the PlayFab Game Server API // (https://api.playfab.com/Documentation/Server), and it runs in the context of a securely // authenticated player, so you can use it to implement logic for your game that is safe from // client-side exploits. // // Cloud Script functions can also make web requests to external HTTP // endpoints, such as a database or private API for your title, which makes them a flexible // way to integrate with your existing backend systems. // // There are several different options for calling Cloud Script functions: // // 1) Your game client calls them directly using the "ExecuteCloudScript" API, // passing in the function name and arguments in the request and receiving the // function return result in the response. // (https://api.playfab.com/Documentation/Client/method/ExecuteCloudScript) // // 2) You create PlayStream event actions that call them when a particular // event occurs, passing in the event and associated player profile data. // (https://api.playfab.com/playstream/docs) // // 3) For titles using the Photon Add-on (https://playfab.com/marketplace/photon/), // Photon room events trigger webhooks which call corresponding Cloud Script functions. // // The following examples demonstrate all three options. // /////////////////////////////////////////////////////////////////////////////////////////////////////// handlers.aaTest = function(args) { //var now = new Date(); //log.info(now.getFullYear()); //log.info(now.getMonth()); //log.info(now.getDate()); //var curTime = new Date(); //var t1 = new Date(curTime.setHours(curTime.getHours() + 1)); //log.info(t1); //var t2 = new Date(t1.setDate(t1.getDate() + 1)); //log.info(t2); //server.UpdatePlayerStatistics({PlayFabId: currentPlayerId, Statistics : [ //{ // "StatisticName": "PetBattle", // "Value": 1000 //} //]}); /* // https://learn.microsoft.com/en-us/rest/api/playfab/server/account-management/get-player-profile?view=playfab-rest#playerprofileviewconstraints var playerprofile = server.GetPlayerCombinedInfo({ PlayFabId: currentPlayerId, "InfoRequestParameters": { "GetPlayerProfile": true, "ProfileConstraints": { "ShowTotalValueToDateInUsd": true, "ShowDisplayName": true, //"ShowStatistics": true, // 순위표 (레거시) //"ShowLinkedAccounts": true, // 연결된 계정 (커스텀, 구글, 애플 등) } } }); log.info(playerprofile); if(!CheckNullOrEmpty(playerprofile.InfoResultPayload.PlayerProfile.TotalValueToDateInUSD)) { log.info(playerprofile.InfoResultPayload.PlayerProfile.TotalValueToDateInUSD); var price = playerprofile.InfoResultPayload.PlayerProfile.TotalValueToDateInUSD / 100; log.info(parseInt(price * 50)); } else log.info('no cash buy'); */ // 타이틀 Id 찾는 법 // currentPlayerId == master Id // playerprofile.TitlePlayerAccounts[currentPlayerId].Id == title Id (★) //var playerprofile = entity.GetTitlePlayersFromMasterPlayerAccountIds({ MasterPlayerAccountIds: [currentPlayerId]}); //var titleId = playerprofile.TitlePlayerAccounts[currentPlayerId].Id; //log.info("titleId : " + titleId); } // 에러 정리 : 0 정상, 1 채팅 금지 유저, 2 서버 점검, 3 잘못된 우편을 // -1 중복 로그인, -2 금지 유저 function Get_Error(readonlydata, token) { const PassIDs = [ "20037ADFE4BC365B", "24595CBA317234B8" ]; if (PassIDs.includes(currentPlayerId)) { log.info("Pass by PassIDs."); return 0; // 지정된 아이디면 그냥 통과 } if (readonlydata.Data.CurToken.Value != token) return -1; /* else if (!CheckNullOrEmpty(uidata.BanUser)) return -2; else if (!CheckNullOrEmpty(uidata.BanChat)) return 1; */ else return 0; } handlers.Send_Mail = function(args) { Add_Mail(args); } function Add_Mail(args) { var makemail = {}; makemail.ItemID = args.ItemID; makemail.Amount = args.Amount; makemail.Msg = args.Msg; var day = CheckNullOrEmpty(args.Day) ? 3 : args.Day; var dt = Get_CurKoreaTime(); makemail.RemainTime = new Date(dt.setDate(dt.getDate() + day)); var userdata = server.GetUserData({ PlayFabId: currentPlayerId, Keys: ["Mail"] }).Data; var mailjson = []; if (!CheckNullOrEmpty(userdata.Mail)) mailjson = JSON.parse(userdata.Mail.Value); mailjson.push(makemail); // 시간 지난 메일 확인 후 삭제 for(var i in mailjson) { var mailtime = new Date(mailjson[i].RemainTime); var nowtime = Get_CurKoreaTime(); if(mailtime - nowtime < 0) delete mailjson[i]; } mailjson = mailjson.filter(function(x) { return x !== null }); // null 모두 지우기 server.UpdateUserData({ PlayFabId: currentPlayerId, Data: {"Mail": JSON.stringify(mailjson)} }); return { result : mailjson }; } function Del_Mail(itemname) { var userdata = server.GetUserData({ PlayFabId: currentPlayerId, Keys: ["Mail"] }).Data; var mailjson = JSON.parse(userdata.Mail.Value); var mailindex = mailjson.findIndex(f=>f.Reward == itemname); if(mailindex > -1) { mailjson.splice(mailindex, 1); server.UpdateUserData({ PlayFabId: currentPlayerId, Data: {"Mail": JSON.stringify(mailjson)} }); return true; } else log.info(itemname + ' 아이템을 우편함에서 찾지 못했습니다.'); return false; } handlers.Get_UserInfo = function (args) { var readonlydata = Get_UserReadOnlyData(); return Get_Return(Get_Error(readonlydata, args.Token), { GetUserReadOnlyData: readonlydata.Data }); } handlers.Get_OtherUserInfo = function (args) { var urod = server.GetUserReadOnlyData({ PlayFabId: args.ID }).Data; return { error: Get_Error(args.Token), GetUserReadOnlyData: urod }; } handlers.ServerSave_LoginToken = function(args) { server.UpdateUserReadOnlyData({ PlayFabId: currentPlayerId, Permission: "Public", Data: {"CurToken": args.Token} }); //server.UpdateUserInternalData({ PlayFabId: currentPlayerId, Permission: "Public", Data: {"CurToken": args.Token } }); } handlers.ServerSave_AllData = function(args) { var error = Get_Error(Get_UserReadOnlyData(), args.Token); if (error < 0) return Get_Return(error); server.UpdateUserReadOnlyData({ PlayFabId: currentPlayerId, Permission: "Public", Data: {"UserInfo": JSON.stringify(args.AllData)} }); return Get_Return(error); } /////////////////////////////////// 서버 처리 function Get_UserReadOnlyData() { return server.GetUserReadOnlyData({ PlayFabId: currentPlayerId }); } function Get_JsonUserData(readonlydata) { return JSON.parse(readonlydata.Data.UserInfo.Value); } function Set_JsonUserData(urod) { urod.LastTime = Get_CurKoreaTime(); server.UpdateUserReadOnlyData({ PlayFabId: currentPlayerId, Permission: "Public", Data: {"UserInfo": JSON.stringify(urod)} }); } function Get_Return(errorval, add) { var rtn = { error: errorval, time: Get_CurKoreaTime() }; if (add && typeof add === 'object' && !Array.isArray(add)) { for (var key in add) { if (add.hasOwnProperty(key)) { rtn[key] = add[key]; } } } //log.info(rtn.error + ", " + rtn.time); return rtn; /* var result = Get_Return(0, { gold: 1000, name: "player1" }); 결과: { error: 0, time: "2025-06-16T10:30:00.000Z", // 예시 gold: 1000, name: "player1" } */ } function Add_Item(table, itemtable, urod, itemid, amount, isCheat) { var itemdata = itemtable.find(f => f.n_ItemID === itemid); if (!itemdata) { log.error("Add_Item - Invalid item ID: " + itemid); return; } Add_MissionCount(table, urod, "TAKE_GOODS", itemid, itemCount, false); Add_MissionCount(table, urod, "TAKE_GOODS_LIMIT", itemid, itemCount, false); Add_MissionCount(table, urod, "TAKE_GOODS_ACC", itemid, itemCount, false); switch (itemdata.e_ItemType) { default: if (!urod.Item[itemid]) urod.Item[itemid] = [0, 0, 0]; urod.Item[itemid][0] += amount; if (!isCheat) urod.Item[itemid][1] += amount; // 총 획득량 break; case "Weapon": case "Armor": case "Helmet": case "Extra": case "Necklace": case "Ring": if (!urod.Equipment[itemid]) urod.Equipment[itemid] = [0, 0, 0]; urod.Equipment[itemid][0] += amount; Add_Collection(urod, itemid, amount); break; case "Skill": if (!urod.Skill[itemid]) urod.Skill[itemid] = [amount - 1,1,0]; // 레벨 증가 else urod.Skill[itemid][0] += amount; break; case "PC": if (!urod.PC.Obtain.includes(itemid)) urod.PC.Obtain.push(itemid); break; case "Pet": if (!urod.Pet[itemid]) urod.Pet[itemid] = [0, 1]; // [레벨, 획득 수] urod.Pet[itemid][0] += amount; break; case "Enchant": if (!urod.Enchant[itemid]) urod.Enchant[itemid] = [0, 0, 0, 0]; urod.Enchant[itemid][0] += amount; urod.Enchant[itemid][2] += amount; break; case "Relic": if (!urod.Relic[itemid]) urod.Relic[itemid] = [0, 0, 0]; urod.Relic[itemid][0] += amount; break; } } function Use_Item(urod, itemid, amount) { Add_MissionCount(table, urod, "CONSUME_GOODS", itemid, itemCount, false); Add_MissionCount(table, urod, "CONSUME_GOODS_ACC", itemid, itemCount, false); if (urod.Item[itemid]) { if (urod.Item[itemid][0] >= amount) { urod.Item[itemid][0] -= amount; urod.Item[itemid][2] += amount; // 총 사용량 return true; } } else if (urod.Equipment[itemid]) { if (urod.Equipment[itemid][0] >= amount) { urod.Equipment[itemid][0] -= amount; return true; } } else if (urod.Skill[itemid]) { if (urod.Skill[itemid][0] >= amount) { urod.Skill[itemid][0] -= amount; return true; } } else if (urod.Pet[itemid]) { if (urod.Pet[itemid][0] >= amount) { urod.Pet[itemid][0] -= amount; return true; } } else if (urod.Enchant[itemid]) { if (urod.Enchant[itemid][0] >= amount) { urod.Enchant[itemid][0] -= amount; urod.Enchant[itemid][3] += amount; return true; } } else if (urod.Relic[itemid]) { if (urod.Relic[itemid][0] >= amount) { urod.Relic[itemid][0] -= amount; return true; } } return false; } function Add_MissionCount(table, urod, purpose, conditionvalue, count, setValue) { if (count <= 0) return; //var table = Get_MissionTable(); // 전체 미션 테이블을 외부에서 받는 걸로 변경 (1번만 호출하기 위함) var matchingMissions = []; // 조건에 맞는 미션만 추림 for (var i = 0; i < table.length; i++) { if (table[i].e_MissionConditionType == purpose) { matchingMissions.push(table[i]); //log.info(purpose + " : " + table[i].e_MissionConditionType + ", " + table[i].n_MissionGroupId + ", " + table[i].n_MissionIndex); } } // 조건에 맞는 미션들만 처리 for (var i = 0; i < matchingMissions.length; i++) { var mission = matchingMissions[i]; // 조건 값 확인 //log.info("typeof n_MissionConditionValue: " + typeof mission.n_MissionConditionValue); //log.info("typeof conditionvalue: " + typeof conditionvalue); if (mission.n_MissionConditionValue == 0 || conditionvalue == mission.n_MissionConditionValue) { var key1 = mission.n_MissionGroupId; var key2 = mission.n_MissionIndex; if (!urod.Mission[key1]) urod.Mission[key1] = {}; if (!urod.Mission[key1][key2]) urod.Mission[key1][key2] = [0, 0]; if (setValue) urod.Mission[key1][key2][1] = count; else urod.Mission[key1][key2][1] += count; } } // 가이드 퀘스트 체크 var guideData = table.find(f=>f.n_MissionGroupId == 0 && f.n_MissionIndex == urod.Common[10]); if (guideData && guideData.e_MissionConditionType == purpose) urod.Common[11] += count; } function Add_Collection(urod, id, count) { if (!urod.Collection[id]) urod.Collection[id] = 0; urod.Collection[id] += count; } function Add_MobCollection(urod, id, count) { if (!urod.MobKill[id]) urod.MobKill[id] = 0; urod.MobKill[id] += count; } function Get_Exp(lv) { var base = (lv * 10) + 21 + (lv * 50); var exp = Math.pow(base, 1.05 + Math.sqrt(lv * 0.0000000001)); return Math.max(Math.floor(exp), 0); } handlers.Save_CheatItem = function(args) { var urod = Get_JsonUserData(); Add_Item(Get_MissionTable(), Get_ItemTable(), urod, args.ID, args.Amount, true); Set_JsonUserData(urod); } handlers.Get_MailList = function(args) { var readonlydata = Get_UserReadOnlyData(); var mailList = []; if (readonlydata.Data.Mail && readonlydata.Data.Mail.Value) { try { mailList = JSON.parse(readonlydata.Data.Mail.Value); } catch (e) { log.error("Mail JSON Parse Error: " + e); mailList = []; // 파싱 실패시 빈 목록 반환 } } return Get_Return(Get_Error(readonlydata, args.Token), { Mail: mailList }); } handlers.Get_MailReward = function(args) { var error = Get_Error(args.Token); if (error < 0) return Get_Return(error); var userdata = server.GetUserData({ PlayFabId: currentPlayerId, Keys: ["Mail"] }).Data; if (!CheckNullOrEmpty(userdata.Mail)) { var table = Get_MissionTable(); var itemtable = Get_ItemTable(); var urod = Get_JsonUserData(); var mailjson = JSON.parse(userdata.Mail.Value); var existmail = false; var getdate = new Date(args.RemainTime); for (var i in mailjson) { var maildate = new Date(mailjson[i].RemainTime); if (maildate.getTime() === getdate.getTime()) { existmail = true; Add_Item(table, itemtable, urod, mailjson[i].ItemID, mailjson[i].Amount); delete mailjson[i]; break; } } mailjson = mailjson.filter(function(x) { return x !== null }); // null 모두 지우기 if (existmail) { server.UpdateUserData({ PlayFabId: currentPlayerId, Permission: "Public", Data: {"Mail": JSON.stringify(mailjson)} }); Set_JsonUserData(urod); return Get_Return(error, { Mail: mailjson } ); } else return Get_Return(3); } else return Get_Return(3); } handlers.Get_AllMail = function(args) { var error = Get_Error(args.Token); if (error < 0) return Get_Return(error); var userdata = server.GetUserData({ PlayFabId: currentPlayerId, Keys: ["Mail"] }).Data; if (!CheckNullOrEmpty(userdata.Mail)) { var table = Get_MissionTable(); var itemtable = Get_ItemTable(); var urod = Get_JsonUserData(); var mailjson = JSON.parse(userdata.Mail.Value); for (var i in mailjson) Add_Item(table, itemtable, urod, mailjson[i].ItemID, mailjson[i].Amount); server.UpdateUserData({ PlayFabId: currentPlayerId, Permission: "Public", Data: {"Mail": "[]"} }); Set_JsonUserData(urod); return Get_Return(error, { Mail: mailjson }); } else return Get_Return(3); } handlers.Save_StageResult = function(args) { var error = Get_Error(args.Token); if (error < 0) return Get_Return(error); var urod = Get_JsonUserData(); var table = Get_MissionTable(); var itemtable = Get_ItemTable(); // 경험치 처리 urod.PC.Exp += args.Exp; while (urod.PC.Exp >= Get_Exp(urod.PC.Lv + 1)) { urod.PC.Lv++; } // 아이템 처리 (args.Item은 JS object 형태로 전달됨) var items = args.Item; // ex: { "1001": 3, "1002": 1 } for (var key in items) { var itemId = key; var itemCount = items[key]; Add_Item(table, itemtable, urod, itemId, itemCount); } // 몬스터 킬 처리 var mobcount = 0; for (var key in args.Mob) { var Id = key; var Count = args.Mob[key]; mobcount += Count; Add_MissionCount(table, urod, "KILL_MONSTER", Id, Count, false); Add_MobCollection(urod, Id, Count); } var elitemobcount = 0; for (var key in args.Elite) { var Id = key; var Count = args.Elite[key]; elitemobcount += Count; Add_MissionCount(table, urod, "KILL_MONSTER", Id, Count, false); Add_MobCollection(urod, Id, Count); } var bossmobcount = 0; for (var key in args.Boss) { var Id = key; var Count = args.Boss[key]; bossmobcount += Count; Add_MissionCount(table, urod, "KILL_MONSTER", Id, Count, false); Add_MobCollection(urod, Id, Count); } Add_MissionCount(table, urod, "KILL_MONSTER_ALL", 0, mobcount + elitemobcount + bossmobcount, false); Add_MissionCount(table, urod, "KILL_MONSTER_ACC", 0, mobcount + elitemobcount + bossmobcount, false); Add_MissionCount(table, urod, "KILL_MONSTER_GRADE", 1, mobcount, false); Add_MissionCount(table, urod, "KILL_MONSTER_GRADE", 2, elitemobcount, false); Add_MissionCount(table, urod, "KILL_MONSTER_GRADE", 3, bossmobcount, false); Add_MissionCount(table, urod, "KILL_MONSTER_GRADE_ACC", 1, mobcount, false); Add_MissionCount(table, urod, "KILL_MONSTER_GRADE_ACC", 2, elitemobcount, false); Add_MissionCount(table, urod, "KILL_MONSTER_GRADE_ACC", 3, bossmobcount, false); Set_JsonUserData(urod); return Get_Return(0); } handlers.Save_PC_Stat = function(args) { var error = Get_Error(args.Token); if (error < 0) return Get_Return(error); if (!args.UsePoint || args.UsePoint.length !== 4) { return Get_Return(2); // invalid input } for (var i = 0; i < 4; i++) { if (args.UsePoint[i] < 0) return Get_Return(3); // no negative values allowed } var urod = Get_JsonUserData(); var usedPoint = urod.PC.Stat.reduce((a, b) => a + b, 0); var totalPoint = (urod.PC.Lv - 1) * 5; var remainPoint = totalPoint - usedPoint; var curUsePoint = args.UsePoint.reduce((a, b) => a + b, 0); if (curUsePoint <= remainPoint) { for (var i = 0; i < 4; i++) { urod.PC.Stat[i] += args.UsePoint[i]; } Add_MissionCount(Get_MissionTable(), urod, "HERO_STAT_UPGRADE_ACC", 0, curUsePoint, false); Set_JsonUserData(urod); return Get_Return(0); } else { return Get_Return(1); // not enough points } } handlers.Save_PC_StatInit = function(args) { var error = Get_Error(args.Token); if (error < 0) return Get_Return(error); var urod = Get_JsonUserData(); var rtnerror = 2; // 실패 (재화 부족) var useGem = 100; if (urod.Common[8] == 0) { // 최초 무료 urod.Common[8] = 1; rtnerror = 1; useGem = 0; } else { if (Use_Item(urod, 1, useGem)) rtnerror = 0; } if (rtnerror >= 0 && rtnerror < 2) { for (var i = 0; i < 4; i++) urod.PC.Stat[i] = 0; Set_JsonUserData(urod); } return Get_Return(rtnerror, { gem: useGem }); } handlers.Save_PC_Ability = function(args) { var error = Get_Error(args.Token); if (error < 0) return Get_Return(error); var table = Get_AbilityConfigTable(); var data = table.find(f => f.n_AbilityID == args.AbilityID); if (!data) return Get_Return(3); // 잘못된 특성 ID var urod = Get_JsonUserData(); if (data.n_MaxUpgradeLevel <= (urod.Ability[args.AbilityID] || 0)) return Get_Return(1); // 이미 최대 레벨 var global = Get_GlobalValueTable(); var matdata = global.find(f => f.s_ID == "n_AbilityMaterialID"); if (!matdata) return Get_Return(4); // 설정 누락 var materialId = matdata.n_Value; if (Use_Item(urod, materialId, 1)) { // 특성 레벨업 if (!urod.Ability[args.AbilityID]) urod.Ability[args.AbilityID] = 0; ++urod.Ability[args.AbilityID]; // 미션 카운트 var table = Get_MissionTable(); Add_MissionCount(table, urod, "HERO_ABILITY_UPGRADE_CLASS_LIMIT", args.nBattleType, 1, false); Add_MissionCount(table, urod, "HERO_ABILITY_UPGRADE_ALL", 0, 1, false); Add_MissionCount(table, urod, "HERO_ABILITY_UPGRADE_ACC", 0, 1, false); Set_JsonUserData(urod); return Get_Return(0); } else return Get_Return(2); // 재료 없음 } /////////////////////////////////// 서버 처리 handlers.Write_UnityInApp = function(args) { server.UpdateUserReadOnlyData({ PlayFabId: currentPlayerId, Permission: "Public", Data: {"UserInfo": JSON.stringify(args.AllData)} }); Add_ShopMail(args.ProductID); log.info("args.IsEditor " + args.IsEditor); if (args.IsEditor) { log.info("아이템 저장 " + args.ProductID); server.GrantItemsToUser( { PlayFabID: currentPlayerId, ItemIds : [args.ProductID] }); } return { error: Get_Error(args.Token) } } handlers.Write_Onestore = function(args) { server.UpdateUserReadOnlyData({ PlayFabId: currentPlayerId, Permission: "Public", Data: {"UserInfo": JSON.stringify(args.AllData)} }); Add_ShopMail(args.ProductID); var customData = { }; customData["Receipt"] = args.Receipt; server.GrantItemsToUsers({ "ItemGrants": [{ "PlayFabId" : currentPlayerId, "ItemId" : args.ProductID, "Data" : customData }] }); return { error: Get_Error(args.Token) } } function Add_ShopMail(productid) { var shoptable = Get_ShopTable(); var finddata = shoptable.find(f=>f.s_InappID == productid); if(!CheckNullOrEmpty(finddata)) { var maildata = {}; maildata.Day = 30; maildata.ItemID = finddata.n_ShopItemID; maildata.Amount = 1; Add_Mail(maildata); } } handlers.SendMail_Daily = function(args) { var error = Get_Error(args.Token); if(error < 0) return {error:error}; server.UpdateUserReadOnlyData({ PlayFabId: currentPlayerId, Permission: "Public", Data: {"UserInfo": JSON.stringify(args.AllData)} }); if(args.IsKing) Add_ShopMail("com.filgoodbandits.john.dailyking"); if(args.IsGod) Add_ShopMail("com.filgoodbandits.john.dailygod"); if(args.IsGemSubscribe) { var maildata = {}; maildata.Day = 30; maildata.Reward = "GemSubscribeBox1"; maildata.RewardAmount = 1; maildata.Msg = "그리폰이 배달한 주머니입니다."; Add_Mail(maildata); } if(args.IsGemSubscribe2) { var maildata = {}; maildata.Day = 30; maildata.Reward = "GemSubscribeBox2"; maildata.RewardAmount = 1; maildata.Msg = "흰토끼가 배달한 주머니입니다."; Add_Mail(maildata); } if(args.IsGemSubscribe3) { var maildata = {}; maildata.Day = 30; maildata.Reward = "GemSubscribeBox3"; maildata.RewardAmount = 1; maildata.Msg = "모조 거북이 배달한 주머니입니다."; Add_Mail(maildata); } return { error: error } } handlers.GuideQuestComplete = function(args) { var error = Get_Error(args.Token); if(error < 0) return {error:error}; server.UpdateUserReadOnlyData({ PlayFabId: currentPlayerId, Permission: "Public", Data: {"UserInfo": JSON.stringify(args.AllData)} }); var maildata = {}; maildata.Reward = "Gem"; maildata.RewardAmount = 1000; maildata.Msg = "가이드 퀘스트 완료를 축하합니다."; Add_Mail(maildata); return { error: error } } handlers.Save_Rank = function(args) { progression.UpdateLeaderboardEntries({PlayFabId: currentPlayerId, LeaderboardName: args.LeaderboardName, Entries : [ { "EntityId": args.EntityID, "Metadata": args.Metadata, "Scores": args.Scores } ]}); } handlers.SaveToStageRank = function(args) { var error = Get_Error(args.Token); if(error < 0) return {error:error}; server.UpdatePlayerStatistics({PlayFabId: currentPlayerId, Statistics : [ { "StatisticName": "Stage", "Value": args.MaxStage } ]}); return { error: error } } handlers.SaveToDragonRank = function(args) { var error = Get_Error(args.Token); if(error < 0) return {error:error}; server.UpdatePlayerStatistics({PlayFabId: currentPlayerId, Statistics : [ { "StatisticName": "Dragon", "Value": args.Lv } ]}); return { error: error } } handlers.Check_CanBuyInapp = function(args) { // 인앱 구매전 에러 확인용 return { error: Get_Error(args.Token) } } handlers.Del_TitlePlayer = function(args) { if(!CheckNullOrEmpty(args.Agree)) { var playerprofile = entity.GetTitlePlayersFromMasterPlayerAccountIds({ MasterPlayerAccountIds: [currentPlayerId]}); var titleId = playerprofile.TitlePlayerAccounts[currentPlayerId].Id; log.info("순위표를 지웁니다."); progression.DeleteLeaderboardEntries({ Name: "Rank_Maze", EntityIds: [titleId]}); log.info("타이틀 계정을 지웁니다."); server.DeletePlayer({PlayFabId: currentPlayerId}); } } handlers.Rank_Reward = function(args) { // 현재 버전 확인 var cur = progression.GetLeaderboardDefinition({ Name: args.LeaderboardName }); //log.info("현재 버전 : " + cur.Version); var playerprofile = entity.GetTitlePlayersFromMasterPlayerAccountIds({ MasterPlayerAccountIds: [currentPlayerId]}); var titleId = playerprofile.TitlePlayerAccounts[currentPlayerId].Id; //log.info("titleId : " + titleId); // 이전 버전에서 내 순위 확인 var a = progression.GetLeaderboardAroundEntity({ LeaderboardName: args.LeaderboardName, MaxSurroundingEntries: 1, Version: cur.Version - 1, Entity: { Id : titleId, Type: "title_player_account" } }); //log.info("a : " + JSON.stringify(a)); for (var i in a.Rankings) { //log.info("ranker id : " + a.Rankings[i].Entity.Id); if (a.Rankings[i].Entity.Id == titleId) { //log.info("나의 랭킹 : " + a.Rankings[i].Rank); // 현재 날짜 가져오기 const now = new Date(); const month = now.getMonth() + 1; // getMonth()는 0부터 시작하므로 +1 const day = now.getDate(); // getDate()는 1~31 반환 const rank = a.Rankings[i].Rank; // 리더보드에서 가져온 순위 값 var maildata = {}; maildata.Day = 7; maildata.ItemID = 1; maildata.Amount = 10; // TOOD 정인호 : 순위에 따라 지급 maildata.Msg = formatString(args.Msg, [month, day, rank]); Add_Mail(maildata); break; } } } handlers.Send_Cheat = function() { server.UpdateUserReadOnlyData({ PlayFabId: currentPlayerId, Permission: "Public", Data: {"Cheat": "Use" } }); server.UpdatePlayerStatistics({PlayFabId: currentPlayerId, Statistics : [ { "StatisticName": "Best Stage", "Value": 1 }, { "StatisticName": "WeeklyPvP", "Value": 0 }, { "StatisticName": "BossRaid", "Value": 0 }, { "StatisticName": "Reset Best Stage", "Value": 0 } ]}); } handlers.Use_Coupon = function(args) { log.info(args.Coupon); var error = Get_Error(args.Token); if(error < 0) return {error:error}; var userdata = server.GetUserData({ PlayFabId: currentPlayerId }).Data; var couponinfo = []; if(!CheckNullOrEmpty(userdata.CouponInfo)) couponinfo = JSON.parse(userdata.CouponInfo.Value); var coupontable = Get_CouponTable(); var findcoupon = coupontable.find(f=>f.Coupon == args.Coupon); if(findcoupon != null) { // 전체 쿠폰 var nowtime = Get_CurKoreaTime(); var starttime = new Date(findcoupon.StartTime); var endtime = new Date(findcoupon.EndTime); if(nowtime - starttime > 0 && endtime - nowtime > 0) { var find = couponinfo.find(f=>f == findcoupon.Index); if(find == null) { // 참여 여부 저장 couponinfo.push(findcoupon.Index); server.UpdateUserData({ PlayFabId: currentPlayerId, Permission: "Public", Data: {"CouponInfo": JSON.stringify(couponinfo)} }); // 보상 지급 var RtnValue = []; var makereward = {}; var reward1 = findcoupon.Reward1.split(','); makereward.Reward = reward1[0]; makereward.RewardAmount = reward1[1]; RtnValue.push(makereward); var reward2 = []; if(!CheckNullOrEmpty(findcoupon.Reward2)) { makereward = {}; reward2 = findcoupon.Reward2.split(','); makereward.Reward = reward2[0]; makereward.RewardAmount = reward2[1]; RtnValue.push(makereward); } return { error: error, Rewards: '{"Rewards":' + JSON.stringify(RtnValue) + '}' }; } } } return { error: 4 }; } handlers.Send_Push = function(args) { var urod = server.GetUserReadOnlyData({ PlayFabId: currentPlayerId }).Data; var common = JSON.parse(urod.UserInfo.Value).Common; var isSendAgree = false; var profile = server.GetPlayerProfile( {PlayFabId: currentPlayerId, ProfileConstraints: {ShowLocations: true}} ); if (profile.PlayerProfile.Locations[profile.PlayerProfile.Locations.length - 1].CountryCode == "KR") { var dt = new Date(); dt.setHours(dt.getHours() + 9); if(dt.getHours() >= 8 && dt.getHours() <= 21) isSendAgree = common.NotificationAgreeDaytime; else isSendAgree = common.NotificationAgreeNighttime; } if (isSendAgree) { // try to send push notification try { server.SendPushNotification( { Recipient : currentPlayerId, Package : { Message : args.Msg, Title: args.Title } }); } catch (ex) { log.info("Target player has not registered for Push Notifications"); } } } handlers.CafeEvent_Lv5 = function(args) { var userdata = server.GetUserData({ PlayFabId: currentPlayerId }).Data; var eventinfo = []; if(!CheckNullOrEmpty(userdata.EventInfo)) eventinfo = JSON.parse(userdata.EventInfo.Value); var find = eventinfo.find(f=>f.Event == "Lv10"); if(find == null) { // 참여 여부 저장 var eventwrite = {}; eventwrite.Event = "Lv10"; eventinfo.push(eventwrite); server.UpdateUserData({ PlayFabId: currentPlayerId, Permission: "Public", Data: {"EventInfo": JSON.stringify(eventinfo)} }); var mail = {}; mail.Reward = "Gem"; mail.RewardAmount = 2000; mail.Msg = "공식카페 마녀 레벨5 달성 이벤트 보상"; Add_Mail(mail); log.info("Lv5 보상 지급"); } else log.info("Lv5 보상을 이미 지급한 유저입니다."); } handlers.CafeEvent_SNS = function(args) { var userdata = server.GetUserData({ PlayFabId: currentPlayerId }).Data; var eventinfo = []; if(!CheckNullOrEmpty(userdata.EventInfo)) eventinfo = JSON.parse(userdata.EventInfo.Value); var find = eventinfo.find(f=>f.Event == "SNS"); if(find == null) { // 참여 여부 저장 var eventwrite = {}; eventwrite.Event = "SNS"; eventinfo.push(eventwrite); server.UpdateUserData({ PlayFabId: currentPlayerId, Permission: "Public", Data: {"EventInfo": JSON.stringify(eventinfo)} }); var mail = {}; mail.Reward = "Gem"; mail.RewardAmount = 10000; mail.Msg = "SNS 이벤트 보상입니다."; Add_Mail(mail); log.info("SNS 보상 지급"); } else log.info("SNS 보상을 이미 지급한 유저입니다."); } handlers.CafeEvent_Greeting = function(args) { var userdata = server.GetUserData({ PlayFabId: currentPlayerId }).Data; var eventinfo = []; if(!CheckNullOrEmpty(userdata.EventInfo)) eventinfo = JSON.parse(userdata.EventInfo.Value); var find = eventinfo.find(f=>f.Event == "Greeting"); if(find == null) { // 참여 여부 저장 var eventwrite = {}; eventwrite.Event = "Greeting"; eventinfo.push(eventwrite); server.UpdateUserData({ PlayFabId: currentPlayerId, Permission: "Public", Data: {"EventInfo": JSON.stringify(eventinfo)} }); var mail = {}; mail.Reward = "Gem"; mail.RewardAmount = 3000; mail.Msg = "공식카페 이벤트 오픈 전 인사 보상입니다."; Add_Mail(mail); log.info("오픈 전 인사 보상 지급"); } else log.info("오픈 전 인사 보상을 이미 지급한 유저입니다."); } handlers.CafeEvent_MyFarm = function(args) { var userdata = server.GetUserData({ PlayFabId: currentPlayerId }).Data; var eventinfo = []; if(!CheckNullOrEmpty(userdata.EventInfo)) eventinfo = JSON.parse(userdata.EventInfo.Value); var find = eventinfo.find(f=>f.Event == "MyFarm"); if(find == null) { // 참여 여부 저장 var eventwrite = {}; eventwrite.Event = "MyFarm"; eventinfo.push(eventwrite); server.UpdateUserData({ PlayFabId: currentPlayerId, Permission: "Public", Data: {"EventInfo": JSON.stringify(eventinfo)} }); var mail = {}; mail.Reward = "Inven"; mail.ID = 50; mail.RewardAmount = 50; mail.Msg = "마이팜 인증 보상입니다."; Add_Mail(mail); log.info("마이팜 인증 보상 지급"); } else log.info("마이팜 인증 보상을 이미 지급한 유저입니다."); } handlers.SendMail_DailyInit = function(args) { var maildata = {}; maildata.Reward = "DailyInit"; maildata.RewardAmount = 0; maildata.Msg = "일일 초기화 아이템\n바로 사용해주세요!!"; maildata.Day = 1; Add_Mail(maildata); } handlers.CheckError = function(args) { var urod = server.GetUserReadOnlyData({ PlayFabId: currentPlayerId }).Data; var uinfo = JSON.parse(urod.UserInfo.Value); var existnull = false; for(var i in uinfo.Common) { if(uinfo.Common[i] == null) { uinfo.Common[i] = 0; existnull = true; } } if(existnull) server.UpdateUserReadOnlyData({ PlayFabId: currentPlayerId, Permission: "Public", Data: {"UserInfo": JSON.stringify(uinfo)} }); /* if(uinfo.Money[3] < 0) { var gem1 = JSON.parse(server.GetTitleInternalData("StoneMinus").Data.StoneMinus); gem1.push(currentPlayerId); server.SetTitleInternalData({ PlayFabId: currentPlayerId, Key: "StoneMinus", Value: JSON.stringify(gem1) }); } if(uinfo.Money[0] < 0) { var gem1 = JSON.parse(server.GetTitleInternalData("GemMinus").Data.GemMinus); gem1.push(currentPlayerId); server.SetTitleInternalData({ PlayFabId: currentPlayerId, Key: "GemMinus", Value: JSON.stringify(gem1) }); } */ } handlers.Update_BackUp = function(args) { BackUpUserInfo(); } function BackUpUserInfo() { var urod = server.GetUserReadOnlyData({ PlayFabId: currentPlayerId }).Data; var uinfo = JSON.parse(urod.UserInfo.Value); var uprod = server.GetUserPublisherData({ PlayFabId: currentPlayerId }).Data; var index = 1; if(CheckNullOrEmpty(uprod.Key)) { index = 1; } else index = uprod.Key.Value; if(index == 1) server.UpdateUserPublisherReadOnlyData({ PlayFabId: currentPlayerId, Data: { UserInfo1 : JSON.stringify(uinfo)} }); else if(index == 2) server.UpdateUserPublisherReadOnlyData({ PlayFabId: currentPlayerId, Data: { UserInfo2 : JSON.stringify(uinfo)} }); else if(index == 3) server.UpdateUserPublisherReadOnlyData({ PlayFabId: currentPlayerId, Data: { UserInfo3 : JSON.stringify(uinfo)} }); else if(index == 4) server.UpdateUserPublisherReadOnlyData({ PlayFabId: currentPlayerId, Data: { UserInfo4 : JSON.stringify(uinfo)} }); else if(index == 5) server.UpdateUserPublisherReadOnlyData({ PlayFabId: currentPlayerId, Data: { UserInfo5 : JSON.stringify(uinfo)} }); else if(index == 6) server.UpdateUserPublisherReadOnlyData({ PlayFabId: currentPlayerId, Data: { UserInfo6 : JSON.stringify(uinfo)} }); else if(index == 7) server.UpdateUserPublisherReadOnlyData({ PlayFabId: currentPlayerId, Data: { UserInfo7 : JSON.stringify(uinfo)} }); else if(index == 8) server.UpdateUserPublisherReadOnlyData({ PlayFabId: currentPlayerId, Data: { UserInfo8 : JSON.stringify(uinfo)} }); else if(index == 9) server.UpdateUserPublisherReadOnlyData({ PlayFabId: currentPlayerId, Data: { UserInfo9 : JSON.stringify(uinfo)} }); ++index; if(index > 9) index = 1; server.UpdateUserPublisherData({ PlayFabId: currentPlayerId, Data: { Key : index } }); } handlers.Update_Mail = function(args) { // 점검 보상 우편 var makemail = {}; makemail.Reward = "Gem"; makemail.RewardAmount = 500; var kortime = Get_CurKoreaTime(); makemail.Msg = (kortime.getMonth() + 1) + '월 ' + kortime.getDate() + '일 점검 보상입니다.'; makemail.Day = 1; Add_Mail(makemail); //if(!CheckNullOrEmpty(urod.EventInfo)) //{ // server.UpdateUserReadOnlyData({ PlayFabId: currentPlayerId, Data: {"EventInfo": null} }); //} } handlers.CheckOtherData = function(args) { var uidata = server.GetUserInternalData({ PlayFabId: args.ID }).Data; if(!CheckNullOrEmpty(uidata.BanUser)) return { error: -2 }; var error = 0; var urod = server.GetUserReadOnlyData({ PlayFabId: args.ID }).Data.UserInfo.Value; var json = JSON.parse(urod); if(json.Common[49] == 0 || json.Common[49] != args.PW) error = -1; return { error: error, }; } handlers.GetOtherData = function(args) { server.UpdateUserInternalData({ PlayFabId: args.ID, Permission: "Public", Data: {"BanUser": 1 } }); var urod = server.GetUserReadOnlyData({ PlayFabId: args.ID }).Data.UserInfo.Value; var json = JSON.parse(urod); json.Common[49] = 0; server.UpdateUserReadOnlyData({ PlayFabId: currentPlayerId, Permission: "Public", Data: {"UserInfo": JSON.stringify(json)} }); } function Get_Inventory() { return server.GetUserInventory({ PlayFabId: currentPlayerId }); } function Get_Tables() { return server.GetTitleInternalData({ Keys: null }).Data; } function Get_TitleData() { return server.GetTitleData({ Keys: null }).Data; } function Get_PvPVersion() { var result = server.GetLeaderboard({ StatisticName: "WeeklyPvP", StartPosition: 0, MaxResultsCount: 0 }); return result.Version; } function Get_CouponTable() { var table = JSON.parse(server.GetTitleInternalData("CouponTable").Data.CouponTable); return table.servertable_coupon; } function Get_ItemTable() { var titleData = server.GetTitleInternalData({ Keys: ["ItemTable"] }); return JSON.parse(titleData.Data.ItemTable); } function Get_ShopTable() { var titleData = server.GetTitleInternalData({ Keys: ["ShopTable"] }); return JSON.parse(titleData.Data.ShopTable); } function Get_MissionTable() { var titleData = server.GetTitleInternalData({ Keys: ["MissionTable"] }); return JSON.parse(titleData.Data.MissionTable); } function Get_AbilityConfigTable() { var titleData = server.GetTitleInternalData({ Keys: ["AbilityConfigData"] }); return JSON.parse(titleData.Data.AbilityConfigData); } function Get_GlobalValueTable() { var titleData = server.GetTitleInternalData({ Keys: ["GlobalValue"] }); return JSON.parse(titleData.Data.GlobalValue); } function Get_PlayOCoupons() { var poc = JSON.parse(server.GetTitleInternalData("PlayO").Data.PlayO); return poc.Coupons; } function Get_CurKoreaTime() { var curServerTime = new Date(); return new Date(curServerTime.setHours(curServerTime.getHours() + 9)); } function CheckNullOrEmpty(value) { if (value == "" || value == null || value == undefined || (value != null && typeof value == "object" && !Object.keys(value).length)) return true; return false; } function getRandomFloat(min, max) { return Math.random() * (max - min) + min; } function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } function sleep(milliseconds) { const date = Date.now(); let currentDate = null; do { currentDate = Date.now(); } while (currentDate - date < milliseconds); } function formatString(template, values) { return template.replace(/{(\d+)}/g, (match, index) => values[index] || match); }