Add project files.

This commit is contained in:
rfi 2024-04-18 14:12:10 +07:00
parent 84116e7cda
commit 477b05df2f
19 changed files with 1433 additions and 0 deletions

View File

@ -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;
}
}
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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<Account> Accounts { get; set; }
public DbSet<Counter> Counters { get; set; }
public SCHALEContext(DbContextOptions<SCHALEContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Account>().Property(x => x.Uid).HasValueGenerator<AccountAutoIncrementValueGenerator>();
modelBuilder.Entity<Account>().ToCollection("accounts");
modelBuilder.Entity<Counter>().ToCollection("counters");
}
}
class AccountAutoIncrementValueGenerator : AutoIncrementValueGenerator
{
protected override string Collection => "account";
}
abstract class AutoIncrementValueGenerator : ValueGenerator<uint>
{
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;
}
}
}

View File

@ -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<SCHALEContext>(opt =>
{
opt.UseMongoDB(connectionString, "SCHALE");
});
}
}
}

View File

@ -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<MissionProgressDB> MissionProgressDBs { get; set; }
// public Dictionary<long, List<MissionProgressDB>> EventMissionProgressDBDict { get; set; }
// public Dictionary<OpenConditionContent, OpenConditionLockReason> 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
}
}

View File

@ -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
}
}

View File

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MongoDB.EntityFrameworkCore" Version="7.0.0-preview.1" />
</ItemGroup>
</Project>

31
SCHALE.GameServer.sln Normal file
View File

@ -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

View File

@ -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");
}
}
}

View File

@ -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""
}
]
}");
}
}
}

View File

@ -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
});
}
}
}

View File

@ -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<KestrelServerOptions>(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();
}
}
}
}

View File

@ -0,0 +1,10 @@
using System.Text.Json.Serialization;
namespace SCHALE.GameServer.Models
{
class BaseResponse
{
[JsonPropertyName("result")]
public int Result { get; set; }
}
}

View File

@ -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<string> 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; }
}
}

View File

@ -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"
}
}
}
}

View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SCHALE.Common\SCHALE.Common.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,2 @@
{
}

View File

@ -0,0 +1,15 @@
{
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
},
"ConnectionStrings": {
"MongoDB": "mongodb://localhost:27017/SCHALE"
},
"AllowedHosts": "*"
}