using Amazon.Lambda.Core;
using BackEnd;
using BackEnd.Game;
using LitJson;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text;
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]
namespace BackendFunction {
public class BFunc {
public class MissionData {
public int KEY; //미션 index
public int MI; //미션 종류
public BigInteger GV; //미션 목표값
public bool WR; //보상 수령 여부
}
public class MissionRewardGetAns {
public GetRewardResult state;
public List<string> rewards = new List<string>();
public string message;
}
public class ServerInventoryData {
public int Key;
public int Count;
public int CurrentStar;
}
public enum GetRewardResult {
Error = -1,
Nothing = 0,
RewardGet = 1,
}
public enum MissionType {
None = 0,
Daily = 1,
Weekly = 2,
Achievement = 3,
DailyPoint = 4,
WeeklyPoint = 5,
NewUser7Days = 6,
StageWaveCompetition = 7,
HeroGrowth = 8,
}
private const string MISSIONDATA = "MissionData";
private const string MISSION_DAY = "Mission_Day";
private const string MISSION_WEEK = "Mission_Week";
private const string MISSIONTYPE = "MissionType";
private const string MISSIONKEY = "MissionKey";
private const string MISSIONPROGRESS = "MissionProgress";
private const string POINTREWARDINDEX = "PointRewardIndex";
private const string REWARDBANK = "RewardBank";
private const string RESERVEDREWARDS = "ReservedRewards";
//private const string REWARDDIA = "RewardDia";
private const string ITEMKEY = "itemKey";
private const string ITEMAMOUNT = "itemAmount";
private const string KEY = "Key";
private const string ACHIEVEMENT_STACK = "Achievement_Stack";
private const string MISSIONPOINTREWARDDAILY = "MissionPointReward_Daily";
private const string MISSIONPOINTREWARDWEEKLY = "MissionPointReward_Weekly";
private const string CLEARMISSIONNUMBER = "ClearMissionNumber";
private const string MISSIONOBJECTIVE = "MissionObjective";
private const string GOALVALUE = "GoalValue";
private const string MISSION_EVENT_NEWUSER7DAYS = "Mission_Event_NewUser7Days";
private const string MISSION_EVENT_STAGEWAVECOMPETITION = "Mission_Event_StageWaveCompetetion";
private const string MISSION_EVENT_HEROGROWTH = "Mission_Event_HeroGrowth";
private StringBuilder _sb = new StringBuilder();
public Stream Function(Stream stream, ILambdaContext context) {
try {
// Initialize BackendFunction API
Backend.Initialize(ref stream);
} catch (Exception e) {
//Return the reason if Initializing BackendFunction API was failed
return ReturnErrorObject("initialize " + e.ToString());
}
// TODO
if (Backend.HasKey(MISSIONTYPE) == false) return ReturnErrorObject("MissionType parameter required");
MissionType missonType = MissionType.None;
int[] missionKey = new int[0];
int[] pointRewardIndexs = new int[0];
string[] missionKey_String = new string[0];
BigInteger[] missionProgress = new BigInteger[0];
try {
missonType = (MissionType)int.Parse(Backend.Content[MISSIONTYPE].ToString());
bool isPointType = false;
switch (missonType) {
case MissionType.Daily: break;
case MissionType.Weekly: break;
case MissionType.Achievement: break;
case MissionType.DailyPoint: isPointType = true; break;
case MissionType.WeeklyPoint: isPointType = true; break;
case MissionType.NewUser7Days: break;
case MissionType.StageWaveCompetition: break;
case MissionType.HeroGrowth: break;
default: return ReturnErrorObject("MissionType parse result not valid " + missonType);
}
if (isPointType) {
//일일미션, 주간미션 포인트 모아서 추가 보상 버전
if (Backend.HasKey(POINTREWARDINDEX) == false) return ReturnErrorObject("PointRewardIndex parameter required");
JsonData priJson = Backend.Content[POINTREWARDINDEX];
pointRewardIndexs = new int[priJson.Count];
for (int i = 0; i < priJson.Count; i++) {
pointRewardIndexs[i] = int.Parse(priJson[i].ToString());
}
} else {
//일일미션,주간미션,업적 슬롯 보상 버전
if (Backend.HasKey(MISSIONKEY) == false) return ReturnErrorObject("MissionKey parameter required");
if (Backend.HasKey(MISSIONPROGRESS) == false) return ReturnErrorObject("MissionProgress parameter required");
JsonData keyJson = Backend.Content[MISSIONKEY];
missionKey_String = new string[keyJson.Count];
missionKey = new int[keyJson.Count];
for (int i = 0; i < keyJson.Count; i++) {
missionKey_String[i] = keyJson[i].ToString();
missionKey[i] = int.Parse(missionKey_String[i]);
}
JsonData progJson = Backend.Content[MISSIONPROGRESS];
missionProgress = new BigInteger[progJson.Count];
for (int i = 0; i < progJson.Count; i++) {
missionProgress[i] = BigInteger.Parse(progJson[i].ToString());
}
}
} catch (Exception e){
return ReturnErrorObject($"Mission Parameter parsing fail: {Backend.Content[MISSIONTYPE]}\n" + e.Message);
}
if (missonType == MissionType.None) return ReturnErrorObject("MissionType None is not valid ");
//RewardBank 테이블
BackendReturnObject rewardBankBro = Backend.GameData.GetMyData(REWARDBANK, new Where());
if (rewardBankBro.IsSuccess() == false) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("RewardBank get failed")));
JsonData rewardBankJson = rewardBankBro.FlattenRows();
if (rewardBankJson.Count <= 0) {
Param newParam = new Param();
newParam.Add(RESERVEDREWARDS, new Dictionary<int, string>());
BackendReturnObject insertBro = Backend.GameData.Insert(REWARDBANK, newParam);
if (insertBro.IsSuccess()) {
rewardBankBro = Backend.GameData.GetMyData(REWARDBANK, new Where());
if (rewardBankBro.IsSuccess() == false) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("RewardBank DB row not created")));
rewardBankJson = rewardBankBro.FlattenRows();
} else {
return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("RewardBank DB row insert failed: " + insertBro.GetMessage())));
}
}
JsonData rewardBankRow = rewardBankJson[0];
SortedDictionary<int, string> rewardStringDic;
Dictionary<int, BigInteger> rewardSumDic = new Dictionary<int, BigInteger>();
if (rewardBankRow[RESERVEDREWARDS].Count > 0) {
rewardStringDic = JsonConvert.DeserializeObject<SortedDictionary<int, string>>(rewardBankRow[RESERVEDREWARDS].ToJson());
foreach (var item in rewardStringDic) {
rewardSumDic.Add(item.Key, BigInteger.Parse(item.Value));
}
} else {
rewardStringDic = new SortedDictionary<int, string>();
}
//미션과 업적 정보 차트
BackendReturnObject chartBro = Backend.Chart.GetChartListV2();
if (chartBro.IsSuccess() == false) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("Error during chart parsing (0)")));
JsonData chartFlatRows = chartBro.FlattenRows();
Dictionary<string, string> chartDic = new Dictionary<string, string>();
for (int i = 0; i < chartFlatRows.Count; i++) {
chartDic[chartFlatRows[i]["chartName"].ToString()] = chartFlatRows[i]["selectedChartFileId"].ToString();
}
//본격적으로 보상 수령 처리 시작
BackendReturnObject tableBro = Backend.GameData.GetMyData(MISSIONDATA, new Where());
JsonData tableFlatRows = tableBro.FlattenRows();
if (tableFlatRows.Count <= 0) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("No mission DB row found (A)")));
JsonData tableRow = tableFlatRows[0];
MissionRewardGetAns newResponse = new MissionRewardGetAns();
newResponse.state = GetRewardResult.RewardGet;
List<TransactionValue> transactionList = new List<TransactionValue>();
Param param_RewardBank = new Param();
transactionList.Add(TransactionValue.SetUpdate(REWARDBANK, new Where(), param_RewardBank));
if ((missonType == MissionType.Daily) || (missonType == MissionType.Weekly) || (missonType == MissionType.NewUser7Days) || (missonType == MissionType.StageWaveCompetition) || (missonType == MissionType.HeroGrowth)) {
string columnString = null;
if (missonType == MissionType.Daily) columnString = MISSION_DAY;
else if (missonType == MissionType.Weekly) columnString = MISSION_WEEK;
else if (missonType == MissionType.NewUser7Days) columnString = MISSION_EVENT_NEWUSER7DAYS;
else if (missonType == MissionType.StageWaveCompetition) columnString = MISSION_EVENT_STAGEWAVECOMPETITION;
else if (missonType == MissionType.HeroGrowth) columnString = MISSION_EVENT_HEROGROWTH;
if (columnString == null) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("Wrong mission column: " + missonType)));
//차트 뒤져서 보상값 얼마인지 확인해야됨
BackendReturnObject missionChart = null;
if (missonType == MissionType.Daily) missionChart = Backend.Chart.GetChartContents(chartDic["DailyMission"]);
else if (missonType == MissionType.Weekly) missionChart = Backend.Chart.GetChartContents(chartDic["WeeklyMission"]);
else if (missonType == MissionType.NewUser7Days) missionChart = Backend.Chart.GetChartContents(chartDic["Event_NewUser7DaysMission"]);
else if (missonType == MissionType.StageWaveCompetition) missionChart = Backend.Chart.GetChartContents(chartDic["Event_StageClearCompetition"]);
else if (missonType == MissionType.HeroGrowth) missionChart = Backend.Chart.GetChartContents(chartDic["Event_HeroGrowth"]);
if (missionChart == null) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("Reward chart is null for " + missonType)));
JsonData missionChartJson = missionChart.FlattenRows();
List<MissionData> missionsOnDb = null;
if (tableRow.ContainsKey(columnString) == false) {
if ((missonType == MissionType.NewUser7Days) || (missonType == MissionType.StageWaveCompetition) || (missonType == MissionType.HeroGrowth)) {
//이 미션들은 MissionDateCheck에서 컬럼을 만들어 주지 않음.
missionsOnDb = new List<MissionData>();
for (int i = 0; i < missionChartJson.Count; i++) {
JsonData data = missionChartJson[i];
MissionData newMission = new MissionData();
newMission.KEY = int.Parse(data[KEY].ToString());
newMission.MI = int.Parse(data[MISSIONOBJECTIVE].ToString());
newMission.GV = BigInteger.Parse(data[GOALVALUE].ToString());
newMission.WR = false;
missionsOnDb.Add(newMission);
}
} else {
return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("No mission data found (B)")));
}
}
if (missionsOnDb == null) missionsOnDb = JsonConvert.DeserializeObject<List<MissionData>>(tableRow[columnString].ToJson());
List<MissionData> foundMission = new List<MissionData>();
for (int j = 0; j < missionKey.Length; j++) {
for (int i = 0; i < missionsOnDb.Count; i++) {
if (missionsOnDb[i].KEY == missionKey[j]) {
foundMission.Add(missionsOnDb[i]);
break;
}
}
}
if (foundMission.Count != missionKey.Length) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError($"Found mission count and Requested mission number doesn't match {foundMission.Count} / {missionKey.Length}")));
for (int i = 0; i < foundMission.Count; i++) {
if (foundMission[i] == null) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("MissionId not found from DB: " + missionKey[i])));
if (foundMission[i].WR) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("Already rewarded mission: " + missionKey[i])));
if (foundMission[i].GV > missionProgress[i]) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError($"Mission{missionKey[i]} goal not fuifilled: ({missionProgress[i]} / {foundMission[i].GV})")));
foundMission[i].WR = true; //어차피 class라서 ref이므로 여기다 수정해도 됨.
}
for (int j = 0; j < foundMission.Count; j++) {
JsonData missionRow = null;
for (int i = 0; i < missionChartJson.Count; i++) {
if (missionChartJson[i][KEY].ToString() == missionKey_String[j]) {
missionRow = missionChartJson[i];
break;
}
}
if (missionRow == null) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("MissionKey not found from Chart" + missionKey_String[j])));
//if (int.TryParse(missionRow[REWARDDIA].ToString(), out int reward)) {
// rewardDia += reward;
//} else {
// return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("Error during chart parsing (B)")));
//}
int itemKey;
if (int.TryParse(missionRow[ITEMKEY].ToString(), out itemKey) == false) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("itemKey invalid")));
if (itemKey == 0) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("itemKey is 0")));
BigInteger itemAmount = BigInteger.Parse(missionRow[ITEMAMOUNT].ToString());
_sb.Clear();
_sb.Append(itemKey);
_sb.Append('/');
_sb.Append(itemAmount.ToString());
newResponse.rewards.Add(_sb.ToString());
if (rewardSumDic.TryAdd(itemKey, itemAmount)) {
rewardStringDic.Add(itemKey, itemAmount.ToString());
} else {
rewardSumDic[itemKey] += itemAmount;
rewardStringDic[itemKey] = rewardSumDic[itemKey].ToString();
}
}
//트랜잭션으로 미션 보상 수령 + 보상 실제 지급
Param param_Mission = new Param {
{ columnString, missionsOnDb }
};
transactionList.Add(TransactionValue.SetUpdate(MISSIONDATA, new Where(), param_Mission));
} else if (missonType == MissionType.Achievement) {
BackendReturnObject achChart = Backend.Chart.GetChartContents(chartDic["AchievementMission"]);
JsonData achChartJson = achChart.FlattenRows();
Dictionary<int, int> achStackDic = new Dictionary<int, int>();
if (tableRow.ContainsKey(ACHIEVEMENT_STACK)) {
try {
achStackDic = JsonConvert.DeserializeObject<Dictionary<int, int>>(tableRow[ACHIEVEMENT_STACK].ToJson());
} catch (Exception e) {
return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("Achievement_Stack Json read failed: " + e.Message)));
}
} else achStackDic = new Dictionary<int, int>();
for (int i = 0; i < missionKey.Length; i++) {
JsonData achRow = null;
for (int j = 0; j < achChartJson.Count; j++) {
if (int.Parse(achChartJson[j][KEY].ToString()) == missionKey[i]) {
achRow = achChartJson[j];
break;
}
}
if (achRow == null) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("achievement key invalid: " + missionKey[i])));
BigInteger goalValue_Min = BigInteger.Parse(achRow["GoalValue_Min"].ToString());
BigInteger goalValue_Max = BigInteger.Parse(achRow["GoalValue_Max"].ToString());
BigInteger goalValue_Incre = BigInteger.Parse(achRow["ValueIncrease"].ToString());
//rewardDia += int.Parse(achRow[REWARDDIA].ToString());
int itemKey;
if (int.TryParse(achRow[ITEMKEY].ToString(), out itemKey) == false) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("itemKey invalid")));
if (itemKey == 0) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("itemKey is 0")));
BigInteger itemAmount = BigInteger.Parse(achRow[ITEMAMOUNT].ToString());
_sb.Clear();
_sb.Append(itemKey);
_sb.Append('/');
_sb.Append(itemAmount.ToString());
newResponse.rewards.Add(_sb.ToString());
if (rewardSumDic.TryAdd(itemKey, itemAmount)) {
rewardStringDic.Add(itemKey, itemAmount.ToString());
} else {
rewardSumDic[itemKey] += itemAmount;
rewardStringDic[itemKey] = rewardSumDic[itemKey].ToString();
}
int currentAchStack = 0;
if (achStackDic.ContainsKey(missionKey[i])) currentAchStack = achStackDic[missionKey[i]];
else achStackDic.Add(missionKey[i], 0);
BigInteger goalValue_Calc = goalValue_Min + goalValue_Incre * currentAchStack;
if (goalValue_Calc > goalValue_Max) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError($"Achievement{missionKey[i]} goal overflow: ({goalValue_Calc} / {goalValue_Max})")));
if (goalValue_Calc > missionProgress[i]) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError($"Achievement{missionKey[i]} goal not fuifilled: ({missionProgress[i]} / {goalValue_Calc})")));
achStackDic[missionKey[i]] = (currentAchStack + 1);
}
//트랜잭션으로 업적 보상 수령 + 보상 실제 지급
Param param_Mission = new Param {
{ ACHIEVEMENT_STACK, achStackDic },
};
transactionList.Add(TransactionValue.SetUpdate(MISSIONDATA, new Where(), param_Mission));
} else if ((missonType == MissionType.DailyPoint) || (missonType == MissionType.WeeklyPoint)) {
string columnString;
if (missonType == MissionType.DailyPoint) {
columnString = MISSIONPOINTREWARDDAILY;
} else {
columnString = MISSIONPOINTREWARDWEEKLY;
}
int maxLength = 0;
for (int i = 0; i < pointRewardIndexs.Length; i++) {
if (maxLength <= pointRewardIndexs[i]) maxLength = pointRewardIndexs[i] + 1;
}
int[] pointRewardArray; //해당 보상 이미 받았는지 체크
if (tableRow.ContainsKey(columnString)) {
try {
pointRewardArray = JsonConvert.DeserializeObject<int[]>(tableRow[columnString].ToJson());
if (pointRewardArray.Length < maxLength) {
int[] backup = new int[pointRewardArray.Length];
for (int i = 0; i < pointRewardArray.Length; i++) backup[i] = pointRewardArray[i];
pointRewardArray = new int[maxLength];
for (int i = 0; i < backup.Length; i++) pointRewardArray[i] = backup[i];
}
} catch {
pointRewardArray = new int[maxLength];
}
} else {
//db 없으면 새로 만들고 (미션 1개 깨고 해금되는 보상이면 index 값이 1임)
pointRewardArray = new int[maxLength];
}
for (int i = 0; i < pointRewardIndexs.Length; i++) {
int rewardIndex = pointRewardIndexs[i];
if (pointRewardArray[rewardIndex] != 0) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("Already rewarded MissionPointReward exist: " + rewardIndex)));
pointRewardArray[rewardIndex] = 1;
} //하나라도 이미 보상을 수령했으면 오류 처리
//차트 뒤져서 보상값 얼마인지 확인해야됨
BackendReturnObject missionChart = Backend.Chart.GetChartContents(chartDic["MissionPointReward"]);
JsonData missionChartJson = missionChart.GetFlattenJSON()["rows"];
//int rewardDia = -1;
for (int pri = 0; pri < pointRewardIndexs.Length; pri++) {
for (int i = 0; i < missionChartJson.Count; i++) {
if (int.Parse(missionChartJson[i][CLEARMISSIONNUMBER].ToString()) == pointRewardIndexs[pri]) {
if (((missonType == MissionType.DailyPoint) && (missionChartJson[i][MISSIONTYPE].ToString()[0] == 'D'))
|| ((missonType == MissionType.WeeklyPoint) && ((missionChartJson[i][MISSIONTYPE].ToString()[0] == 'W')))) {
if (missionChartJson[i][MISSIONTYPE].ToString()[0] == 'D') { //기획에서 이 차트 구성을 요구함
//rewardDia += int.Parse(missionChartJson[i][REWARDDIA].ToString());
int itemKey;
if (int.TryParse(missionChartJson[i][ITEMKEY].ToString(), out itemKey) == false) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("itemKey invalid")));
if (itemKey == 0) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("itemKey is 0")));
BigInteger itemAmount = BigInteger.Parse(missionChartJson[i][ITEMAMOUNT].ToString());
_sb.Clear();
_sb.Append(itemKey);
_sb.Append('/');
_sb.Append(itemAmount.ToString());
newResponse.rewards.Add(_sb.ToString());
if (rewardSumDic.TryAdd(itemKey, itemAmount)) {
rewardStringDic.Add(itemKey, itemAmount.ToString());
} else {
rewardSumDic[itemKey] += itemAmount;
rewardStringDic[itemKey] = rewardSumDic[itemKey].ToString();
}
}
}
}
}
}
//트랜잭션으로 미션 보상 수령 + 보상 실제 지급
Param param_MissionPointReward = new Param {
{ columnString, pointRewardArray }
};
transactionList.Add(TransactionValue.SetUpdate(MISSIONDATA, new Where(), param_MissionPointReward));
} else {
return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("Not implemented mission type " + missonType)));
}
//_sb.Clear();
//foreach (var item in rewardStringDic) {
// _sb.Append($"[{item.Key}: {item.Value}]\n");
//}
//return Backend.StringToStream(_sb.ToString());
Dictionary<int, string> tempDic = new Dictionary<int, string>();
tempDic.Add(201, "5");
tempDic.Add(103, "500");
param_RewardBank.Add(RESERVEDREWARDS, tempDic);
BackendReturnObject transactionBro = Backend.GameData.TransactionWriteV2(transactionList);
if (transactionBro.IsSuccess() == false) return Backend.StringToStream(JsonMapper.ToJson(MakeResponseError("Error during update user DB\n" + transactionBro.GetMessage())));
return Backend.StringToStream(JsonMapper.ToJson(newResponse));
}
private int KeySort((int, string) x, (int,string) y) {
if (x.Item1 > y.Item1) return 1;
else if (x.Item1 < y.Item1) return -1;
return 0;
}
static Stream ReturnErrorObject(string err) {
JObject error = new JObject();
error.Add("error", err);
return Backend.JsonToStream(error.ToString());
}
public MissionRewardGetAns MakeResponseError(string _message) {
MissionRewardGetAns newResponse = new MissionRewardGetAns();
newResponse.state = GetRewardResult.Error;
newResponse.message = _message;
return newResponse;
}
}
}
코드 전체 공유드립니다.
지금은 SortedDictionary를 써서 문제는 안 겪는 중입니다.
오류가 나도록 마지막 부분에 tempDic 부분을 넣어두었습니다.