diff --git a/SCHALE.Common/Crypto/XOR.cs b/SCHALE.Common/Crypto/XOR.cs new file mode 100644 index 0000000..f5e3d73 --- /dev/null +++ b/SCHALE.Common/Crypto/XOR.cs @@ -0,0 +1,13 @@ +namespace SCHALE.Common.Crypto +{ + public static class XOR + { + public static void Crypt(byte[] bytes, byte key, uint offset = 0) + { + while (offset < bytes.Length) + { + bytes[offset++] ^= key; + } + } + } +} diff --git a/SCHALE.Common/Database/Models/Account.cs b/SCHALE.Common/Database/Models/Account.cs new file mode 100644 index 0000000..5a1eda7 --- /dev/null +++ b/SCHALE.Common/Database/Models/Account.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace SCHALE.Common.Database.Models +{ +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + public class Account + { + [Key] + [Column("_id")] + public uint Uid { get; set; } + public string DeviceId { get; set; } + public string Token { get; set; } + } +} diff --git a/SCHALE.Common/Database/Models/Counter.cs b/SCHALE.Common/Database/Models/Counter.cs new file mode 100644 index 0000000..80bd046 --- /dev/null +++ b/SCHALE.Common/Database/Models/Counter.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; + +namespace SCHALE.Common.Database.Models +{ +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + public class Counter + { + [Key] + [Column("_id")] + public string Id { get; set; } + public uint Seq { get; set; } + } +} diff --git a/SCHALE.Common/Database/SCHALEContext.cs b/SCHALE.Common/Database/SCHALEContext.cs new file mode 100644 index 0000000..73d67f5 --- /dev/null +++ b/SCHALE.Common/Database/SCHALEContext.cs @@ -0,0 +1,60 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using Microsoft.EntityFrameworkCore.ValueGeneration; +using MongoDB.EntityFrameworkCore.Extensions; +using SCHALE.Common.Database.Models; + +namespace SCHALE.Common.Database +{ + public class SCHALEContext : DbContext + { + public DbSet Accounts { get; set; } + public DbSet Counters { get; set; } + + public SCHALEContext(DbContextOptions options) : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + + base.OnModelCreating(modelBuilder); + modelBuilder.Entity().Property(x => x.Uid).HasValueGenerator(); + modelBuilder.Entity().ToCollection("accounts"); + modelBuilder.Entity().ToCollection("counters"); + } + } + + class AccountAutoIncrementValueGenerator : AutoIncrementValueGenerator + { + protected override string Collection => "account"; + } + + abstract class AutoIncrementValueGenerator : ValueGenerator + { + protected abstract string Collection { get; } + public override bool GeneratesTemporaryValues => false; + + public override uint Next(EntityEntry entry) + { + if (entry.Context is not SCHALEContext) + { + throw new ArgumentNullException($"{nameof(AutoIncrementValueGenerator)} is only implemented for {nameof(SCHALEContext)}"); + } + + var context = ((SCHALEContext)entry.Context); + var counter = context.Counters.SingleOrDefault(x => x.Id == Collection); + + if (counter is null) + { + counter = new Counter() { Id = Collection, Seq = 0 }; + context.Counters.Add(counter); + } + + counter.Seq++; + context.Update(counter); + + return counter.Seq; + } + } +} diff --git a/SCHALE.Common/Database/ServicesExtesions.cs b/SCHALE.Common/Database/ServicesExtesions.cs new file mode 100644 index 0000000..8ec6137 --- /dev/null +++ b/SCHALE.Common/Database/ServicesExtesions.cs @@ -0,0 +1,16 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; + +namespace SCHALE.Common.Database +{ + public static class ServicesExtesions + { + public static void AddMongoDBProvider(this IServiceCollection services, string connectionString) + { + services.AddDbContext(opt => + { + opt.UseMongoDB(connectionString, "SCHALE"); + }); + } + } +} diff --git a/SCHALE.Common/NetworkProtocol/Packet.cs b/SCHALE.Common/NetworkProtocol/Packet.cs new file mode 100644 index 0000000..544a401 --- /dev/null +++ b/SCHALE.Common/NetworkProtocol/Packet.cs @@ -0,0 +1,87 @@ +namespace SCHALE.Common.NetworkProtocol +{ + public class SessionKey + { + public long AccountServerId { get; set; } + + public required string MxToken { get; set; } + } + + public abstract class BasePacket + { + public SessionKey? SessionKey { get; set; } + + public abstract Protocol Protocol { get; } + + public long AccountId => SessionKey?.AccountServerId ?? 0; + } + + public abstract class RequestPacket : BasePacket + { + private static int _counter; + + public int ClientUpTime { get; set; } + + public bool Resendable { get; set; } = true; + + + public long Hash { get; set; } + + public bool IsTest { get; set; } + + public DateTime? ModifiedServerTime__DebugOnly { get; set; } + + public static long CreateHash(Protocol protocol) + { + return _counter++ | ((int)protocol << 32); + } + } + + public abstract class ResponsePacket : BasePacket + { + public long ServerTimeTicks { get; set; } + + public ServerNotificationFlag ServerNotification { get; set; } + + // public List MissionProgressDBs { get; set; } + + // public Dictionary> EventMissionProgressDBDict { get; set; } + + // public Dictionary StaticOpenConditions { get; set; } + } + + [Flags] + public enum ServerNotificationFlag + { + // Token: 0x04009560 RID: 38240 + None = 0, + // Token: 0x04009561 RID: 38241 + NewMailArrived = 4, + // Token: 0x04009562 RID: 38242 + HasUnreadMail = 8, + // Token: 0x04009563 RID: 38243 + NewToastDetected = 16, + // Token: 0x04009564 RID: 38244 + CanReceiveArenaDailyReward = 32, + // Token: 0x04009565 RID: 38245 + CanReceiveRaidReward = 64, + // Token: 0x04009566 RID: 38246 + ServerMaintenance = 256, + // Token: 0x04009567 RID: 38247 + CannotReceiveMail = 512, + // Token: 0x04009568 RID: 38248 + InventoryFullRewardMail = 1024, + // Token: 0x04009569 RID: 38249 + CanReceiveClanAttendanceReward = 2048, + // Token: 0x0400956A RID: 38250 + HasClanApplicant = 4096, + // Token: 0x0400956B RID: 38251 + HasFriendRequest = 8192, + // Token: 0x0400956C RID: 38252 + CheckConquest = 16384, + // Token: 0x0400956D RID: 38253 + CanReceiveEliminateRaidReward = 32768, + // Token: 0x0400956E RID: 38254 + CanReceiveMultiFloorRaidReward = 65536 + } +} diff --git a/SCHALE.Common/NetworkProtocol/Protocol.cs b/SCHALE.Common/NetworkProtocol/Protocol.cs new file mode 100644 index 0000000..7baf01e --- /dev/null +++ b/SCHALE.Common/NetworkProtocol/Protocol.cs @@ -0,0 +1,431 @@ +namespace SCHALE.Common.NetworkProtocol +{ + public enum Protocol + { + Common_Cheat = -9999, + Error = -1, + None = 0, + System_Version = 1, + [Obsolete] + Session_Info = 2, + NetworkTime_Sync = 3, + [Obsolete] + NetworkTime_SyncReply = 4, + Audit_GachaStatistics = 5, + Account_Create = 1000, + Account_Nickname = 1001, + Account_Auth = 1002, + Account_CurrencySync = 1003, + Account_SetRepresentCharacterAndComment = 1004, + Account_GetTutorial = 1005, + Account_SetTutorial = 1006, + Account_PassCheck = 1007, + Account_VerifyForYostar = 1008, + Account_CheckYostar = 1009, + Account_CallName = 1010, + Account_BirthDay = 1011, + Account_Auth2 = 1012, + Account_LinkReward = 1013, + Account_ReportXignCodeCheater = 1014, + Account_DismissRepurchasablePopup = 1015, + Account_InvalidateToken = 1016, + Account_LoginSync = 1017, + Account_Reset = 1018, + Account_RequestBirthdayMail = 1019, + Character_List = 2000, + Character_Transcendence = 2001, + Character_ExpGrowth = 2002, + Character_FavorGrowth = 2003, + Character_UpdateSkillLevel = 2004, + Character_UnlockWeapon = 2005, + Character_WeaponExpGrowth = 2006, + Character_WeaponTranscendence = 2007, + Character_SetFavorites = 2008, + Character_SetCostume = 2009, + Character_BatchSkillLevelUpdate = 2010, + Character_PotentialGrowth = 2011, + Equipment_List = 3000, + Equipment_Sell = 3001, + Equipment_Equip = 3002, + Equipment_LevelUp = 3003, + Equipment_TierUp = 3004, + Equipment_Lock = 3005, + Equipment_BatchGrowth = 3006, + Item_List = 4000, + Item_Sell = 4001, + Item_Consume = 4002, + Item_Lock = 4003, + Item_BulkConsume = 4004, + Item_SelectTicket = 4005, + Item_AutoSynth = 4006, + Echelon_List = 5000, + Echelon_Save = 5001, + Echelon_PresetList = 5002, + Echelon_PresetSave = 5003, + Echelon_PresetGroupRename = 5004, + Campaign_List = 6000, + Campaign_EnterMainStage = 6001, + Campaign_ConfirmMainStage = 6002, + Campaign_DeployEchelon = 6003, + Campaign_WithdrawEchelon = 6004, + Campaign_MapMove = 6005, + Campaign_EndTurn = 6006, + Campaign_EnterTactic = 6007, + Campaign_TacticResult = 6008, + Campaign_Retreat = 6009, + Campaign_ChapterClearReward = 6010, + Campaign_Heal = 6011, + Campaign_EnterSubStage = 6012, + Campaign_SubStageResult = 6013, + Campaign_Portal = 6014, + Campaign_ConfirmTutorialStage = 6015, + Campaign_PurchasePlayCountHardStage = 6016, + Campaign_EnterTutorialStage = 6017, + Campaign_TutorialStageResult = 6018, + Campaign_RestartMainStage = 6019, + Campaign_EnterMainStageStrategySkip = 6020, + Campaign_MainStageStrategySkipResult = 6021, + Mail_List = 7000, + Mail_Check = 7001, + Mail_Receive = 7002, + Mission_List = 8000, + Mission_Reward = 8001, + Mission_MultipleReward = 8002, + Mission_GuideReward = 8003, + Mission_MultipleGuideReward = 8004, + Mission_Sync = 8005, + Mission_GuideMissionSeasonList = 8006, + Attendance_List = 9000, + Attendance_Check = 9001, + Attendance_Reward = 9002, + Shop_BuyMerchandise = 10000, + Shop_BuyGacha = 10001, + Shop_List = 10002, + Shop_Refresh = 10003, + Shop_BuyEligma = 10004, + Shop_BuyGacha2 = 10005, + Shop_GachaRecruitList = 10006, + Shop_BuyRefreshMerchandise = 10007, + Shop_BuyGacha3 = 10008, + Shop_BuyAP = 10009, + Shop_BeforehandGachaGet = 10010, + Shop_BeforehandGachaRun = 10011, + Shop_BeforehandGachaSave = 10012, + Shop_BeforehandGachaPick = 10013, + Recipe_Craft = 11000, + MemoryLobby_List = 12000, + MemoryLobby_SetMain = 12001, + MemoryLobby_UpdateLobbyMode = 12002, + MemoryLobby_Interact = 12003, + [Obsolete] + CumulativeTimeReward_List = 13000, + [Obsolete] + CumulativeTimeReward_Reward = 13001, + OpenCondition_List = 15000, + OpenCondition_Set = 15001, + OpenCondition_EventList = 15002, + Toast_List = 16000, + Raid_List = 17000, + Raid_CompleteList = 17001, + Raid_Detail = 17002, + Raid_Search = 17003, + Raid_CreateBattle = 17004, + Raid_EnterBattle = 17005, + Raid_BattleUpdate = 17006, + Raid_EndBattle = 17007, + Raid_Reward = 17008, + Raid_RewardAll = 17009, + Raid_Revive = 17010, + Raid_Share = 17011, + Raid_SeasonInfo = 17012, + Raid_SeasonReward = 17013, + Raid_Lobby = 17014, + Raid_GiveUp = 17015, + Raid_OpponentList = 17016, + Raid_RankingReward = 17017, + Raid_Login = 17018, + Raid_Sweep = 17019, + Raid_GetBestTeam = 17020, + SkipHistory_List = 18000, + SkipHistory_Save = 18001, + Scenario_List = 19000, + Scenario_Clear = 19001, + Scenario_GroupHistoryUpdate = 19002, + Scenario_Skip = 19003, + Scenario_Select = 19004, + Scenario_AccountStudentChange = 19005, + Scenario_LobbyStudentChange = 19006, + Scenario_SpecialLobbyChange = 19007, + Scenario_Enter = 19008, + Scenario_EnterMainStage = 19009, + Scenario_ConfirmMainStage = 19010, + Scenario_DeployEchelon = 19011, + Scenario_WithdrawEchelon = 19012, + Scenario_MapMove = 19013, + Scenario_EndTurn = 19014, + Scenario_EnterTactic = 19015, + Scenario_TacticResult = 19016, + Scenario_Retreat = 19017, + Scenario_Portal = 19018, + Scenario_RestartMainStage = 19019, + Scenario_SkipMainStage = 19020, + Cafe_Get = 20000, + Cafe_Ack = 20001, + Cafe_Deploy = 20002, + Cafe_Relocate = 20003, + Cafe_Remove = 20004, + Cafe_RemoveAll = 20005, + Cafe_Interact = 20006, + Cafe_ListPreset = 20007, + Cafe_RenamePreset = 20008, + Cafe_ClearPreset = 20009, + Cafe_UpdatePresetFurniture = 20010, + Cafe_ApplyPreset = 20011, + Cafe_RankUp = 20012, + Cafe_ReceiveCurrency = 20013, + Cafe_GiveGift = 20014, + Cafe_SummonCharacter = 20015, + Cafe_TrophyHistory = 20016, + Cafe_ApplyTemplate = 20017, + Cafe_Open = 20018, + Craft_List = 21000, + Craft_SelectNode = 21001, + Craft_UpdateNodeLevel = 21002, + Craft_BeginProcess = 21003, + Craft_CompleteProcess = 21004, + Craft_Reward = 21005, + Craft_HistoryList = 21006, + Craft_ShiftingBeginProcess = 21007, + Craft_ShiftingCompleteProcess = 21008, + Craft_ShiftingReward = 21009, + Craft_AutoBeginProcess = 21010, + Craft_CompleteProcessAll = 21011, + Craft_RewardAll = 21012, + Craft_ShiftingCompleteProcessAll = 21013, + Craft_ShiftingRewardAll = 21014, + Arena_EnterLobby = 22000, + Arena_Login = 22001, + Arena_SettingChange = 22002, + Arena_OpponentList = 22003, + Arena_EnterBattle = 22004, + Arena_EnterBattlePart1 = 22005, + Arena_EnterBattlePart2 = 22006, + Arena_BattleResult = 22007, + Arena_CumulativeTimeReward = 22008, + Arena_DailyReward = 22009, + Arena_RankList = 22010, + Arena_History = 22011, + Arena_RecordSync = 22012, + Arena_TicketPurchase = 22013, + Arena_DamageReport = 22014, + Arena_CheckSeasonCloseReward = 22015, + Arena_SyncEchelonSettingTime = 22016, + WeekDungeon_List = 23000, + WeekDungeon_EnterBattle = 23001, + WeekDungeon_BattleResult = 23002, + WeekDungeon_Retreat = 23003, + Academy_GetInfo = 24000, + Academy_AttendSchedule = 24001, + Academy_AttendFavorSchedule = 24002, + Event_GetList = 25000, + Event_GetImage = 25001, + Event_UseCoupon = 25002, + Event_RewardIncrease = 25003, + ContentSave_Get = 26000, + ContentSave_Discard = 26001, + ContentSweep_Request = 27000, + ContentSweep_MultiSweep = 27001, + ContentSweep_MultiSweepPresetList = 27002, + ContentSweep_SetMultiSweepPreset = 27003, + Clan_Lobby = 28000, + Clan_Login = 28001, + Clan_Search = 28002, + Clan_Create = 28003, + Clan_Member = 28004, + Clan_Applicant = 28005, + Clan_Join = 28006, + Clan_Quit = 28007, + Clan_Permit = 28008, + Clan_Kick = 28009, + Clan_Setting = 28010, + Clan_Confer = 28011, + Clan_Dismiss = 28012, + Clan_AutoJoin = 28013, + Clan_MemberList = 28014, + Clan_CancelApply = 28015, + Clan_MyAssistList = 28016, + Clan_SetAssist = 28017, + Clan_ChatLog = 28018, + Clan_Check = 28019, + Clan_AllAssistList = 28020, + Billing_TransactionStartByYostar = 29000, + Billing_TransactionEndByYostar = 29001, + Billing_PurchaseListByYostar = 29002, + EventContent_AdventureList = 30000, + EventContent_EnterMainStage = 30001, + EventContent_ConfirmMainStage = 30002, + EventContent_EnterTactic = 30003, + EventContent_TacticResult = 30004, + EventContent_EnterSubStage = 30005, + EventContent_SubStageResult = 30006, + EventContent_DeployEchelon = 30007, + EventContent_WithdrawEchelon = 30008, + EventContent_MapMove = 30009, + EventContent_EndTurn = 30010, + EventContent_Retreat = 30011, + EventContent_Portal = 30012, + EventContent_PurchasePlayCountHardStage = 30013, + EventContent_ShopList = 30014, + EventContent_ShopRefresh = 30015, + EventContent_ReceiveStageTotalReward = 30016, + EventContent_EnterMainGroundStage = 30017, + EventContent_MainGroundStageResult = 30018, + EventContent_ShopBuyMerchandise = 30019, + EventContent_ShopBuyRefreshMerchandise = 30020, + EventContent_SelectBuff = 30021, + EventContent_BoxGachaShopList = 30022, + EventContent_BoxGachaShopPurchase = 30023, + EventContent_BoxGachaShopRefresh = 30024, + EventContent_CollectionList = 30025, + EventContent_CollectionForMission = 30026, + EventContent_ScenarioGroupHistoryUpdate = 30027, + EventContent_CardShopList = 30028, + EventContent_CardShopShuffle = 30029, + EventContent_CardShopPurchase = 30030, + EventContent_RestartMainStage = 30031, + EventContent_LocationGetInfo = 30032, + EventContent_LocationAttendSchedule = 30033, + EventContent_FortuneGachaPurchase = 30034, + EventContent_SubEventLobby = 30035, + EventContent_EnterStoryStage = 30036, + EventContent_StoryStageResult = 30037, + EventContent_DiceRaceLobby = 30038, + EventContent_DiceRaceRoll = 30039, + EventContent_DiceRaceLapReward = 30040, + EventContent_PermanentList = 30041, + EventContent_DiceRaceUseItem = 30042, + EventContent_CardShopPurchaseAll = 30043, + EventContent_TreasureLobby = 30044, + EventContent_TreasureFlip = 30045, + EventContent_TreasureNextRound = 30046, + TTS_GetFile = 31000, + ContentLog_UIOpenStatistics = 32000, + MomoTalk_OutLine = 33000, + MomoTalk_MessageList = 33001, + MomoTalk_Read = 33002, + MomoTalk_Reply = 33003, + MomoTalk_FavorSchedule = 33004, + ClearDeck_List = 34000, + MiniGame_StageList = 35000, + MiniGame_EnterStage = 35001, + MiniGame_Result = 35002, + MiniGame_MissionList = 35003, + MiniGame_MissionReward = 35004, + MiniGame_MissionMultipleReward = 35005, + MiniGame_ShootingLobby = 35006, + MiniGame_ShootingBattleEnter = 35007, + MiniGame_ShootingBattleResult = 35008, + MiniGame_ShootingSweep = 35009, + MiniGame_TableBoardSync = 35010, + MiniGame_TableBoardMove = 35011, + MiniGame_TableBoardEncounterInput = 35012, + MiniGame_TableBoardBattleEncounter = 35013, + MiniGame_TableBoardBattleRunAway = 35014, + MiniGame_TableBoardClearThema = 35015, + MiniGame_TableBoardUseItem = 35016, + MiniGame_TableBoardResurrect = 35017, + MiniGame_TableBoardSweep = 35018, + MiniGame_TableBoardMoveThema = 35019, + MiniGame_DreamMakerGetInfo = 35020, + MiniGame_DreamMakerNewGame = 35021, + MiniGame_DreamMakerRestart = 35022, + MiniGame_DreamMakerAttendSchedule = 35023, + MiniGame_DreamMakerDailyClosing = 35024, + Notification_LobbyCheck = 36000, + Notification_EventContentReddotCheck = 36001, + ProofToken_RequestQuestion = 37000, + ProofToken_Submit = 37001, + SchoolDungeon_List = 38000, + SchoolDungeon_EnterBattle = 38001, + SchoolDungeon_BattleResult = 38002, + SchoolDungeon_Retreat = 38003, + TimeAttackDungeon_Lobby = 39000, + TimeAttackDungeon_CreateBattle = 39001, + TimeAttackDungeon_EnterBattle = 39002, + TimeAttackDungeon_EndBattle = 39003, + TimeAttackDungeon_Sweep = 39004, + TimeAttackDungeon_GiveUp = 39005, + TimeAttackDungeon_Login = 39006, + WorldRaid_Lobby = 40000, + WorldRaid_BossList = 40001, + WorldRaid_EnterBattle = 40002, + WorldRaid_BattleResult = 40003, + WorldRaid_ReceiveReward = 40004, + ResetableContent_Get = 41000, + Conquest_GetInfo = 42000, + Conquest_Conquer = 42001, + Conquest_ConquerWithBattleStart = 42002, + Conquest_ConquerWithBattleResult = 42003, + Conquest_DeployEchelon = 42004, + Conquest_ManageBase = 42005, + Conquest_UpgradeBase = 42006, + Conquest_TakeEventObject = 42007, + Conquest_EventObjectBattleStart = 42008, + Conquest_EventObjectBattleResult = 42009, + Conquest_ReceiveCalculateRewards = 42010, + Conquest_NormalizeEchelon = 42011, + Conquest_Check = 42012, + Conquest_ErosionBattleStart = 42013, + Conquest_ErosionBattleResult = 42014, + Conquest_MainStoryGetInfo = 42015, + Conquest_MainStoryConquer = 42016, + Conquest_MainStoryConquerWithBattleStart = 42017, + Conquest_MainStoryConquerWithBattleResult = 42018, + Conquest_MainStoryCheck = 42019, + Friend_List = 43000, + Friend_Remove = 43001, + Friend_GetFriendDetailedInfo = 43002, + Friend_GetIdCard = 43003, + Friend_SetIdCard = 43004, + Friend_Search = 43005, + Friend_SendFriendRequest = 43006, + Friend_AcceptFriendRequest = 43007, + Friend_DeclineFriendRequest = 43008, + Friend_CancelFriendRequest = 43009, + Friend_Check = 43010, + CharacterGear_List = 44000, + CharacterGear_Unlock = 44001, + CharacterGear_TierUp = 44002, + EliminateRaid_Login = 45000, + EliminateRaid_Lobby = 45001, + EliminateRaid_OpponentList = 45002, + EliminateRaid_GetBestTeam = 45003, + EliminateRaid_CreateBattle = 45004, + EliminateRaid_EnterBattle = 45005, + EliminateRaid_EndBattle = 45006, + EliminateRaid_GiveUp = 45007, + EliminateRaid_Sweep = 45008, + EliminateRaid_SeasonReward = 45009, + EliminateRaid_RankingReward = 45010, + EliminateRaid_LimitedReward = 45011, + Attachment_Get = 46000, + Attachment_EmblemList = 46001, + Attachment_EmblemAcquire = 46002, + Attachment_EmblemAttach = 46003, + Sticker_Login = 47000, + Sticker_Lobby = 47001, + Sticker_UseSticker = 47002, + Field_Sync = 48000, + Field_Interaction = 48001, + Field_QuestClear = 48002, + Field_SceneChanged = 48003, + Field_EndDate = 48004, + Field_EnterStage = 48005, + Field_StageResult = 48006, + MultiFloorRaid_Sync = 49000, + MultiFloorRaid_EnterBattle = 49001, + MultiFloorRaid_EndBattle = 49002, + MultiFloorRaid_ReceiveReward = 49003, + Queuing_GetTicket = 50000 + } +} diff --git a/SCHALE.Common/SCHALE.Common.csproj b/SCHALE.Common/SCHALE.Common.csproj new file mode 100644 index 0000000..5286339 --- /dev/null +++ b/SCHALE.Common/SCHALE.Common.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/SCHALE.GameServer.sln b/SCHALE.GameServer.sln new file mode 100644 index 0000000..f973c9e --- /dev/null +++ b/SCHALE.GameServer.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34309.116 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SCHALE.GameServer", "SCHALE.GameServer\SCHALE.GameServer.csproj", "{FA808FE1-3F81-4AFC-9FBE-8662B9781EF8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SCHALE.Common", "SCHALE.Common\SCHALE.Common.csproj", "{D8ED8CB5-EA39-46BE-9236-7FC1F46FE15B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FA808FE1-3F81-4AFC-9FBE-8662B9781EF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FA808FE1-3F81-4AFC-9FBE-8662B9781EF8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FA808FE1-3F81-4AFC-9FBE-8662B9781EF8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FA808FE1-3F81-4AFC-9FBE-8662B9781EF8}.Release|Any CPU.Build.0 = Release|Any CPU + {D8ED8CB5-EA39-46BE-9236-7FC1F46FE15B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D8ED8CB5-EA39-46BE-9236-7FC1F46FE15B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D8ED8CB5-EA39-46BE-9236-7FC1F46FE15B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D8ED8CB5-EA39-46BE-9236-7FC1F46FE15B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {7F07F015-7AB5-4319-B54F-A088AF2F7CB4} + EndGlobalSection +EndGlobal diff --git a/SCHALE.GameServer/Controllers/Api/GatewayController.cs b/SCHALE.GameServer/Controllers/Api/GatewayController.cs new file mode 100644 index 0000000..050ec51 --- /dev/null +++ b/SCHALE.GameServer/Controllers/Api/GatewayController.cs @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.Mvc; +using SCHALE.Common.Crypto; +using System.IO.Compression; +using System.Text; + +namespace SCHALE.GameServer.Controllers.Api +{ + [Route("/api/[controller]")] + public class GatewayController : ControllerBase + { + [HttpPost] + public IResult GatewayRequest() + { + var formFile = Request.Form.Files.GetFile("mx"); + if (formFile is null) + return Results.BadRequest("Expecting an mx file"); + + using var reader = new BinaryReader(formFile.OpenReadStream()); + + // CRC + Protocol type conversion (?) + reader.BaseStream.Position = 12; + + byte[] compressedPayload = reader.ReadBytes((int)reader.BaseStream.Length - 12); + XOR.Crypt(compressedPayload, 0xD9); + using var gzStream = new GZipStream(new MemoryStream(compressedPayload), CompressionMode.Decompress); + using var payloadMs = new MemoryStream(); + gzStream.CopyTo(payloadMs); + + return Results.Text(Encoding.UTF8.GetString(payloadMs.ToArray()), "application/json"); + } + } +} diff --git a/SCHALE.GameServer/Controllers/AppConfigController.cs b/SCHALE.GameServer/Controllers/AppConfigController.cs new file mode 100644 index 0000000..d420514 --- /dev/null +++ b/SCHALE.GameServer/Controllers/AppConfigController.cs @@ -0,0 +1,464 @@ +using Microsoft.AspNetCore.Mvc; + +namespace SCHALE.GameServer.Controllers +{ + [ApiController] + [Route("/app")] + public class AppConfigController : ControllerBase + { + [Route("client_info")] + public IResult ClientInfo() + { + return Results.Json(new + { + result = 0 + }); + } + + [Route("getSettings")] + public IResult GetSettings() + { + Response.ContentType = "application/json"; + + return Results.Text(@"{ + ""settings"": { + ""APP_ANDROIDKEY"": ""MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhV/4Nvy/YuMRlBncn7Qac70zomF74qWAKIDiTKGiuMrNjIAkD3ijNuhNVYhklV8gVEP5XkAZIGF8SXlIS0SYDwFhE7LwsHtKr42rDj1m9XG9y3CEnOilmfJZ4bFKIBI46a+2EsjDB1fxDdh2PqNvq5oRVU9/KDJKTmBXDSjeHob3UKbQRgSiKdwv4/QQLv1bm3qbQJhPhgGjWZm8/aQIw0hy561dcY82u/ioESeDZjRgnOtL62ufmt9Xq2hecXMmSasqX2dojxdJrL19YXFuCXV+YSe6ElovwCo+Qy9a4bPstjS4BG0VEcL7iw72kJGsQZq48drgz/vZGeH9DbhXmQIDAQAB"", + ""ADJUST_ENABLED"": 0, + ""ADJUST_ISDEBUG"": 0, + ""ADJUST_APPID"": ""lkm6uvfjb75s"", + ""ADJUST_CHARGEEVENTTOKEN"": ""k6igj0"", + ""app_gl"": ""ja"", + ""USER_AGREEMENT"": { + ""LATEST"": { + ""version"": ""1.0.0"" + } + }, + ""app_fire"": 0, + ""app_debug"": 1, + ""UserDestroyDays"": 0, + ""LOG_ENABLE"": 1, + ""MERGE_TO_4X"": { + ""WEB_URL"": ""https://sdk-association.yostarplat.com/#/index"", + ""ONE_KEY_ENABLE"": 1 + }, + ""ADJUST_EVENTTOKENS"": { }, + ""TWITTER_CLIENT_ID"": ""dnlSQzBBZGdQbDZ0czNabF9WQms6MTpjaQ"", + ""GOOGLE_CLIENT_ID"": ""411167048846-ri57ab445m2gl5nrpoabqvkjirhn6ehg.apps.googleusercontent.com"", + ""TWITTER_KEY"": ""iywFqxZVJUnHeQe9VuX6LvCii"", + ""TWITTER_SECRET"": ""iQi4fg2S74iMDlB1LpXebT8Cv7Dn9xrZsKZoaYitx1d7yJSPsa"", + ""FACEBOOK_APPID"": ""FACEBOOK_APPID.todo"", + ""FACEBOOK_CLIENTTOKEN"": ""null"", + ""APP_BIRTHSET_ENABLED"": 0, + ""GEETEST_ENABLE"": 0, + ""GEETEST_ID"": ""00b06e0a4ed58bd1c2ad59f1b054ade0"", + ""GEETEST_FORCECHECK"": 0 + }, + ""EuropeUnion"": false +}"); + } + + [Route("getCode")] + public IResult GetCode() + { + Response.ContentType = "application/json"; + + return Results.Text(@"{ + ""result"": 0, + ""data"": [ + { + ""codestr"": ""-1"", + ""codemessage"": ""Unknown Error"" + }, + { + ""codestr"": ""0"", + ""codemessage"": ""Success"" + }, + { + ""codestr"": ""100100"", + ""codemessage"": ""Device ID is banned"" + }, + { + ""codestr"": ""100110"", + ""codemessage"": ""Verification failed"" + }, + { + ""codestr"": ""100111"", + ""codemessage"": ""Account creation failed"" + }, + { + ""codestr"": ""100112"", + ""codemessage"": ""Account creation success; Account binding failed"" + }, + { + ""codestr"": ""100113"", + ""codemessage"": ""Account binding success; Verification failed"" + }, + { + ""codestr"": ""100114"", + ""codemessage"": ""IP is restricted during login creation"" + }, + { + ""codestr"": ""100115"", + ""codemessage"": ""Device ID is banned during login creation"" + }, + { + ""codestr"": ""100116"", + ""codemessage"": ""UID is banned during login creation"" + }, + { + ""codestr"": ""100117"", + ""codemessage"": ""Missing parameters"" + }, + { + ""codestr"": ""100120"", + ""codemessage"": ""Login failed, IP is restricted"" + }, + { + ""codestr"": ""100130"", + ""codemessage"": ""Login failed, UID is banned"" + }, + { + ""codestr"": ""100140"", + ""codemessage"": ""Access Token verification failed"" + }, + { + ""codestr"": ""100150"", + ""codemessage"": ""UID does not match with Transcode"" + }, + { + ""codestr"": ""100160"", + ""codemessage"": ""User birthday has already been added"" + }, + { + ""codestr"": ""100170"", + ""codemessage"": ""Invalid birthday format"" + }, + { + ""codestr"": ""100180"", + ""codemessage"": ""The third party account is not bound with any game account"" + }, + { + ""codestr"": ""100190"", + ""codemessage"": ""Failed to verify the third party parameter"" + }, + { + ""codestr"": ""100200"", + ""codemessage"": ""The third party account is already bound with another UID"" + }, + { + ""codestr"": ""100210"", + ""codemessage"": ""The third party account does not match with the one bound to this account"" + }, + { + ""codestr"": ""100211"", + ""codemessage"": ""Platform binding error"" + }, + { + ""codestr"": ""100212"", + ""codemessage"": ""Platform unbinding error"" + }, + { + ""codestr"": ""100213"", + ""codemessage"": ""Unable to unbind the account"" + }, + { + ""codestr"": ""100220"", + ""codemessage"": ""Authorization canceled"" + }, + { + ""codestr"": ""100221"", + ""codemessage"": ""Authorization failed"" + }, + { + ""codestr"": ""100222"", + ""codemessage"": ""Authorization failed"" + }, + { + ""codestr"": ""100223"", + ""codemessage"": ""Authorization failed"" + }, + { + ""codestr"": ""100224"", + ""codemessage"": ""Unable to use Google service"" + }, + { + ""codestr"": ""100225"", + ""codemessage"": ""Google authorization was canceled by user"" + }, + { + ""codestr"": ""100226"", + ""codemessage"": ""Unable to login during another login request"" + }, + { + ""codestr"": ""100227"", + ""codemessage"": ""Failed to login with the current account"" + }, + { + ""codestr"": ""100228"", + ""codemessage"": ""The account has been deleted. Log in failed."" + }, + { + ""codestr"": ""100229"", + ""codemessage"": ""Account deletion cannot be performed repeatedly"" + }, + { + ""codestr"": ""100231"", + ""codemessage"": ""Failed to restore, the account was deleted completely"" + }, + { + ""codestr"": ""100232"", + ""codemessage"": ""Unable to restore, no deletion history of the account"" + }, + { + ""codestr"": ""100233"", + ""codemessage"": ""The account has been in the cooling-off period for account deletion now."" + }, + { + ""codestr"": ""100234"", + ""codemessage"": ""The account is not authorized to login"" + }, + { + ""codestr"": ""100230"", + ""codemessage"": ""Initialization failed"" + }, + { + ""codestr"": ""100240"", + ""codemessage"": ""Apple authorization information does not match"" + }, + { + ""codestr"": ""100241"", + ""codemessage"": ""User cancelled Apple authorization request"" + }, + { + ""codestr"": ""100242"", + ""codemessage"": ""Apple authorization request failed"" + }, + { + ""codestr"": ""100243"", + ""codemessage"": ""Invalid response from Apple authorization request"" + }, + { + ""codestr"": ""100244"", + ""codemessage"": ""Failed to process Apple authorization request"" + }, + { + ""codestr"": ""100245"", + ""codemessage"": ""Apple authorization request failed for unknown reason"" + }, + { + ""codestr"": ""100246"", + ""codemessage"": ""System version does not support Apple authorization"" + }, + { + ""codestr"": ""100300"", + ""codemessage"": ""Invalid email address format"" + }, + { + ""codestr"": ""100301"", + ""codemessage"": ""Email addresses do not match"" + }, + { + ""codestr"": ""100302"", + ""codemessage"": ""Verification code request is too frequent"" + }, + { + ""codestr"": ""100303"", + ""codemessage"": ""Verification failed"" + }, + { + ""codestr"": ""100304"", + ""codemessage"": ""Verification failed too many times"" + }, + { + ""codestr"": ""100305"", + ""codemessage"": ""The account is banned"" + }, + { + ""codestr"": ""100306"", + ""codemessage"": ""Verification code cannot be empty"" + }, + { + ""codestr"": ""100404"", + ""codemessage"": ""Network error"" + }, + { + ""codestr"": ""200100"", + ""codemessage"": ""User birthday is required"" + }, + { + ""codestr"": ""200110"", + ""codemessage"": ""Monthly purchase limit exceeded"" + }, + { + ""codestr"": ""200120"", + ""codemessage"": ""Order creation failed: Item is not configured in SDK management platform"" + }, + { + ""codestr"": ""200130"", + ""codemessage"": ""Payment method does not exist"" + }, + { + ""codestr"": ""200140"", + ""codemessage"": ""serverTag does not exist"" + }, + { + ""codestr"": ""200150"", + ""codemessage"": ""Payment receipt verification failed"" + }, + { + ""codestr"": ""200160"", + ""codemessage"": ""Invalid purchase request"" + }, + { + ""codestr"": ""200170"", + ""codemessage"": ""Purchase request failed on game server"" + }, + { + ""codestr"": ""200180"", + ""codemessage"": ""It takes a long time for searching the purchase result"" + }, + { + ""codestr"": ""200190"", + ""codemessage"": ""Order ID does not exist"" + }, + { + ""codestr"": ""200200"", + ""codemessage"": ""Order status tracking timed out"" + }, + { + ""codestr"": ""200210"", + ""codemessage"": ""productid does not exist on payment backend"" + }, + { + ""codestr"": ""200220"", + ""codemessage"": ""Payment backend response - payment failed"" + }, + { + ""codestr"": ""200230"", + ""codemessage"": ""Payment backend response - payment canceled"" + }, + { + ""codestr"": ""200240"", + ""codemessage"": ""Current API version does not support the request"" + }, + { + ""codestr"": ""200250"", + ""codemessage"": ""Invalid parameters provided to API"" + }, + { + ""codestr"": ""200260"", + ""codemessage"": ""Fatal error during API operation"" + }, + { + ""codestr"": ""200270"", + ""codemessage"": ""The request is not supported by the Play store on current device"" + }, + { + ""codestr"": ""200280"", + ""codemessage"": ""Item has already been purchased, not consumed yet"" + }, + { + ""codestr"": ""200290"", + ""codemessage"": ""Item has already been purchased, failed to consume"" + }, + { + ""codestr"": ""200300"", + ""codemessage"": ""Unable to purchase the requested item"" + }, + { + ""codestr"": ""200310"", + ""codemessage"": ""Unable to connect to Google Play service"" + }, + { + ""codestr"": ""200320"", + ""codemessage"": ""Request reached maximum timeout before receiving any response from Google Play"" + }, + { + ""codestr"": ""200330"", + ""codemessage"": ""Network connection is turned off"" + }, + { + ""codestr"": ""200340"", + ""codemessage"": ""Payment canceled by user"" + }, + { + ""codestr"": ""200350"", + ""codemessage"": ""Order creation failed: Item doesn't exist at store"" + }, + { + ""codestr"": ""200360"", + ""codemessage"": ""Connection to play services failed"" + }, + { + ""codestr"": ""300100"", + ""codemessage"": ""System sharing failed"" + }, + { + ""codestr"": ""200390"", + ""codemessage"": ""Payment backend response - payment failed"" + }, + { + ""codestr"": ""100205"", + ""codemessage"": ""Unbind failed. Your game account hasn't been linked to a Google Play Games account."" + }, + { + ""codestr"": ""100214"", + ""codemessage"": ""The game account now is linked to a Google Play Games account. If you unlink it from other accounts (except the Google Play Games account), it will also unlink from the Google Play Games account automatically."" + }, + { + ""codestr"": ""100206"", + ""codemessage"": ""The non-guest account has been linked to a Google Play Games account automatically. You can log on another device with the Google Play Games account."" + }, + { + ""codestr"": ""100201"", + ""codemessage"": ""The Google Play Games account has been linked to another game account. Confirm to unlink it from the old game account and re-link to the current one?"" + }, + { + ""codestr"": ""100202"", + ""codemessage"": ""The game account has been linked to another Google Play Games account. Confirm to unlink it from the old Google Play Games account and re-link to the current one?"" + }, + { + ""codestr"": ""100203"", + ""codemessage"": ""The current game account and Google Play Games account have each been linked to other accounts. Confirm to unlink the both from the old accounts and re-link them together?"" + }, + { + ""codestr"": ""100204"", + ""codemessage"": ""The guest account can't be linked to a Google Play Games account so you can't log on another device with the guest account. If you want to link the guest account to a Google Play Games account, please link it to a Yostar account/third-party account first."" + }, + { + ""codestr"": ""100803"", + ""codemessage"": ""Callback URL exceeds its maximum characters"" + }, + { + ""codestr"": ""200232"", + ""codemessage"": ""Apple Pay is not available on this device"" + }, + { + ""codestr"": ""200141"", + ""codemessage"": ""Order creation failed: Purchase currency is not supported"" + }, + { + ""codestr"": ""100215"", + ""codemessage"": ""Unable to bound Twitter account in current App"" + }, + { + ""codestr"": ""100216"", + ""codemessage"": ""Unable to switch Twitter account in current App"" + }, + { + ""codestr"": ""100217"", + ""codemessage"": ""Unable to register Twitter account in current App"" + }, + { + ""codestr"": ""100218"", + ""codemessage"": ""Unable to login with Twitter account in current App"" + }, + { + ""codestr"": ""100600"", + ""codemessage"": ""Interface parameter error. Invoke failed"" + } + ] +}"); + } + } +} diff --git a/SCHALE.GameServer/Controllers/UserController.cs b/SCHALE.GameServer/Controllers/UserController.cs new file mode 100644 index 0000000..525734c --- /dev/null +++ b/SCHALE.GameServer/Controllers/UserController.cs @@ -0,0 +1,75 @@ +using Microsoft.AspNetCore.Mvc; +using SCHALE.Common.Database; +using SCHALE.GameServer.Models; + +namespace SCHALE.GameServer.Controllers +{ + [ApiController] + [Route("/user")] + public class UserController : ControllerBase + { + private readonly SCHALEContext context; + + public UserController(SCHALEContext _context) + { + context = _context; + } + + [HttpGet("agreement")] + public IResult Agreement([FromQuery] string version = "v0.0") + { + return Results.Json(new UserAgreementResponse() + { + Version = version, + Data = [] + }); + } + + [HttpPost("create")] + public IResult Create([FromForm] string deviceId) + { + UserCreateResponse rsp = new() { Result = 0, IsNew = 0 }; + var account = context.Accounts.SingleOrDefault(x => x.DeviceId == deviceId); + + if (account is null) + { + account = new() { DeviceId = deviceId, Token = Guid.NewGuid().ToString() }; + context.Add(account); + context.SaveChanges(); + rsp.IsNew = 1; + } + + rsp.Uid = account.Uid; + rsp.Token = account.Token; + + return Results.Json(rsp); + } + + [HttpPost("login")] + public IResult Login([FromForm] uint uid, [FromForm] string token, [FromForm] string storeId) + { + var account = context.Accounts.SingleOrDefault(x => x.Uid == uid && x.Token == token); + if (account is not null) + { + return Results.Json(new UserLoginResponse() + { + AccessToken = account.Token, + Birth = null, + ChannelId = storeId, + CurrentTimestampMs = DateTimeOffset.Now.ToUnixTimeMilliseconds(), + KrKmcStatus = 2, + Result = 0, + Transcode = "NULL", + Check7Until = 0, + Migrated = false, + ShowMigratePage = false + }); + } + + return Results.Json(new + { + result = 1 + }); + } + } +} diff --git a/SCHALE.GameServer/GameServer.cs b/SCHALE.GameServer/GameServer.cs new file mode 100644 index 0000000..0999810 --- /dev/null +++ b/SCHALE.GameServer/GameServer.cs @@ -0,0 +1,68 @@ +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Serilog.Events; +using Serilog; +using System.Reflection; +using SCHALE.Common.Database; + +namespace SCHALE.GameServer +{ + public class GameServer + { + public static void Main(string[] args) + { + var config = new ConfigurationBuilder() + .SetBasePath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!) + .AddJsonFile("appsettings.json") + .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", true) + .Build(); + + { + var logFilePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "logs", "log.txt"); + if (File.Exists(logFilePath)) + { + var prevLogFilePath = Path.Combine(Path.GetDirectoryName(logFilePath)!, "log-prev.txt"); + if (File.Exists(prevLogFilePath)) + File.Delete(prevLogFilePath); + + File.Move(logFilePath, prevLogFilePath); + } + Log.Logger = new LoggerConfiguration() + .WriteTo.Console() + .WriteTo.File(logFilePath, restrictedToMinimumLevel: LogEventLevel.Verbose, shared: true) + .ReadFrom.Configuration(config) + .CreateBootstrapLogger(); + } + + Log.Information("Starting..."); + try + { + var builder = WebApplication.CreateBuilder(args); + + builder.Services.Configure(op => op.AllowSynchronousIO = true); + builder.Host.UseSerilog(); + + // Add services to the container. + builder.Services.AddControllers(); + builder.Services.AddMongoDBProvider(config.GetConnectionString("MongoDB") ?? throw new ArgumentNullException("ConnectionStrings/MongoDB in appsettings is missing")); + + var app = builder.Build(); + + // Configure the HTTP request pipeline. + app.UseAuthorization(); + app.UseSerilogRequestLogging(); + + app.MapControllers(); + + app.Run(); + } + catch (Exception ex) + { + Log.Fatal(ex, "An unhandled exception occurred during runtime"); + } + finally + { + Log.CloseAndFlush(); + } + } + } +} diff --git a/SCHALE.GameServer/Models/Base.cs b/SCHALE.GameServer/Models/Base.cs new file mode 100644 index 0000000..1bf475f --- /dev/null +++ b/SCHALE.GameServer/Models/Base.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; + +namespace SCHALE.GameServer.Models +{ + class BaseResponse + { + [JsonPropertyName("result")] + public int Result { get; set; } + } +} diff --git a/SCHALE.GameServer/Models/User.cs b/SCHALE.GameServer/Models/User.cs new file mode 100644 index 0000000..4d8694b --- /dev/null +++ b/SCHALE.GameServer/Models/User.cs @@ -0,0 +1,56 @@ +using System.Text.Json.Serialization; + +namespace SCHALE.GameServer.Models +{ +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + class UserAgreementResponse + { + [JsonPropertyName("version")] + public string Version { get; set; } + + [JsonPropertyName("data")] + public List Data { get; set; } + } + + class UserLoginResponse : BaseResponse + { + [JsonPropertyName("accessToken")] + public string AccessToken { get; set; } + + [JsonPropertyName("birth")] + public dynamic? Birth { get; set; } + + [JsonPropertyName("transcode")] + public string Transcode { get; set; } + + [JsonPropertyName("current_timestamp_ms")] + public long CurrentTimestampMs { get; set; } + + [JsonPropertyName("check7until")] + public int Check7Until { get; set; } + + [JsonPropertyName("migrated")] + public bool Migrated { get; set; } + + [JsonPropertyName("show_migrate_page")] + public bool ShowMigratePage { get; set; } + + [JsonPropertyName("channelId")] + public string ChannelId { get; set; } + + [JsonPropertyName("kr_kmc_status")] + public int KrKmcStatus { get; set; } + } + + class UserCreateResponse : BaseResponse + { + [JsonPropertyName("uid")] + public uint Uid { get; set; } + + [JsonPropertyName("token")] + public string Token { get; set; } + + [JsonPropertyName("isNew")] + public int IsNew { get; set; } + } +} diff --git a/SCHALE.GameServer/Properties/launchSettings.json b/SCHALE.GameServer/Properties/launchSettings.json new file mode 100644 index 0000000..ec45758 --- /dev/null +++ b/SCHALE.GameServer/Properties/launchSettings.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "https://0.0.0.0:443;http://0.0.0.0:80", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/SCHALE.GameServer/SCHALE.GameServer.csproj b/SCHALE.GameServer/SCHALE.GameServer.csproj new file mode 100644 index 0000000..275a908 --- /dev/null +++ b/SCHALE.GameServer/SCHALE.GameServer.csproj @@ -0,0 +1,17 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + diff --git a/SCHALE.GameServer/appsettings.Development.json b/SCHALE.GameServer/appsettings.Development.json new file mode 100644 index 0000000..2c63c08 --- /dev/null +++ b/SCHALE.GameServer/appsettings.Development.json @@ -0,0 +1,2 @@ +{ +} diff --git a/SCHALE.GameServer/appsettings.json b/SCHALE.GameServer/appsettings.json new file mode 100644 index 0000000..d889eb5 --- /dev/null +++ b/SCHALE.GameServer/appsettings.json @@ -0,0 +1,15 @@ +{ + "Serilog": { + "MinimumLevel": { + "Default": "Information", + "Override": { + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } + }, + "ConnectionStrings": { + "MongoDB": "mongodb://localhost:27017/SCHALE" + }, + "AllowedHosts": "*" +}