basic account auth handlers, bug fixes

This commit is contained in:
raphaeIl 2024-04-25 21:32:21 -04:00
parent 9b0a4075f6
commit 14e13bc9d7
15 changed files with 2406 additions and 2061 deletions

View File

@ -1,13 +1,39 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using SCHALE.Common.FlatData;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver.Core.Servers;
namespace SCHALE.Common.Database.Models.Game
{
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public class Account : AccountDB
public class Account
{
[Key]
[Column("_id")]
public new uint ServerId { get; set; }
public uint ServerId { get; set; }
public AccountDB AccountDB { get; set; }
public static Account Create(uint guest_account_uid) // make sure ServerId matches GuestAccount UID
{
Account account = new()
{
ServerId = guest_account_uid,
AccountDB = new AccountDB()
{
ServerId = guest_account_uid,
State = AccountState.Normal,
Level = 0,
Exp = 0,
RepresentCharacterServerId = 1037810385, // i think this is the default
LastConnectTime = DateTime.Now,
CreateDate = DateTime.Now,
}
};
return account;
}
}
}

View File

@ -6,10 +6,12 @@ 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 GuestAccount
{
public uint Uid { get; set; }
public string DeviceId { get; set; }
[Key]
[Column("_id")]
public uint Uid { get; set; }
public string DeviceId { get; set; }
public string Token { get; set; }
}
}

View File

@ -19,23 +19,16 @@ namespace SCHALE.Common.Database
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<GuestAccount>().Property(x => x.Uid).HasValueGenerator<GuestAccountAutoIncrementValueGenerator>();
modelBuilder.Entity<GuestAccount>().ToCollection("guest_accounts");
modelBuilder.Entity<Account>().Property(x => x.ServerId).HasValueGenerator<AccountAutoIncrementValueGenerator>();
modelBuilder.Entity<Account>().ToCollection("accounts");
modelBuilder.Entity<Counter>().ToCollection("counters");
}
private class AccountAutoIncrementValueGenerator : AutoIncrementValueGenerator
{
protected override string Collection => "account";
}
private class GuestAccountAutoIncrementValueGenerator : AutoIncrementValueGenerator
{
protected override string Collection => "guest_account";
@ -68,19 +61,5 @@ namespace SCHALE.Common.Database
return counter.Seq;
}
}
public override void Dispose()
{
GC.SuppressFinalize(this);
SaveChanges();
base.Dispose();
}
public override ValueTask DisposeAsync()
{
GC.SuppressFinalize(this);
SaveChanges();
return base.DisposeAsync();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,9 @@
using SCHALE.Common.Database;
using System.Text.Json.Serialization;
using SCHALE.Common.Parcel;
using SCHALE.Common.FlatData;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SCHALE.Common.NetworkProtocol
{
@ -137,16 +140,16 @@ namespace SCHALE.Common.NetworkProtocol
}
//public class AccountAuth2Request : AccountAuthRequest
//{
// public override Protocol Protocol
// {
// get
// {
// return NetworkProtocol.Protocol.Account_Auth2;
// }
// }
//}
public class AccountAuth2Request : AccountAuthRequest
{
public override Protocol Protocol
{
get
{
return NetworkProtocol.Protocol.Account_Auth2;
}
}
}
public class AccountAuth2Response : AccountAuthResponse
@ -6579,7 +6582,7 @@ namespace SCHALE.Common.NetworkProtocol
public long CharacterCount { get; set; }
public long? LastNormalCampaignClearStageId { get; set; }
public long? LastHardCampaignClearStageId { get; set; }
public long? ArenaRanking{ get; set; }
public long? ArenaRanking { get; set; }
public long? RaidRanking { get; set; }
public int? RaidTier { get; set; }
public DetailedAccountInfoDB DetailedAccountInfoDB { get; set; }
@ -7980,8 +7983,8 @@ namespace SCHALE.Common.NetworkProtocol
return NetworkProtocol.Protocol.ProofToken_RequestQuestion;
}
}
public long Hint;
public string Question;
public long Hint { get; set; }
public string Question { get; set; }
}
@ -8855,7 +8858,80 @@ namespace SCHALE.Common.NetworkProtocol
public long StageUniqueId { get; set; }
}
public interface IMissionConstraint
{
bool CanComplete(DateTime serverTime);
bool CanReceiveReward(DateTime serverTime);
}
public class MissionInfo : IMissionConstraint
{
public long Id { get; set; }
public MissionCategory Category { get; set; }
public MissionResetType ResetType { get; set; }
public MissionToastDisplayConditionType ToastDisplayType { get; set; }
public string Description { get; set; }
public bool IsVisible { get; set; }
public bool IsLimited { get; set; }
public DateTime StartDate { get; set; }
public DateTime StartableEndDate { get; set; }
public DateTime EndDate { get; set; }
public long EndDday { get; set; }
public AccountState AccountState { get; set; }
public long AccountLevel { get; set; }
public List<long> PreMissionIds { get; set; }
public long NextMissionId { get; set; }
public SuddenMissionContentType[] SuddenMissionContentTypes { get; set; }
public MissionCompleteConditionType CompleteConditionType { get; set; }
public long CompleteConditionCount { get; set; }
public List<long> CompleteConditionParameters { get; set; }
public string RewardIcon { get; set; }
public List<ParcelInfo> Rewards { get; set; }
public ContentType DateAutoRefer { get; set; }
public string ToastImagePath { get; set; }
public long DisplayOrder { get; set; }
public bool HasFollowingMission { get; set; }
public string[] Shortcuts { get; set; }
public long ChallengeStageId { get; set; }
public virtual bool CanComplete(DateTime serverTime)
{
return true;
}
public virtual bool CanReceiveReward(DateTime serverTime)
{
return false;
}
}
public class MissionListResponse : ResponsePacket
{
public override Protocol Protocol
@ -8867,7 +8943,7 @@ namespace SCHALE.Common.NetworkProtocol
}
public List<long> MissionHistoryUniqueIds { get; set; }
public List<MissionProgressDB> ProgressDBs { get; set; }
//public MissionInfo DailySuddenMissionInfo { get; set; }
public MissionInfo DailySuddenMissionInfo { get; set; }
public List<long> ClearedOrignalMissionIds { get; set; }
}
@ -10319,7 +10395,7 @@ namespace SCHALE.Common.NetworkProtocol
}
}
[JsonIgnore]
public AccountCurrencyDB AccountCurrencyDB{ get; set; }
public AccountCurrencyDB AccountCurrencyDB { get; set; }
public ConsumeResultDB ConsumeResultDB { get; set; }
public ParcelResultDB ParcelResultDB { get; set; }
}

View File

@ -1,5 +1,6 @@

using SCHALE.Common.Database;
using SCHALE.Common.FlatData;
namespace SCHALE.Common.Parcel
{
@ -96,16 +97,53 @@ namespace SCHALE.Common.Parcel
public ParcelChangeType ParcelChangeType { get; set; }
}
public class ParcelInfo
public struct BasisPoint : IEquatable<BasisPoint>, IComparable<BasisPoint>
{
public ParcelKeyPair Key { get; set; }
public long Amount { get; set; }
//public BasisPoint Multiplier { get; set; }
public long MultipliedAmount { get; set; }
//public BasisPoint Probability { get; set; }
public long RawValue { get; set; }
public static readonly double DoubleEpsilon;
public static readonly BasisPoint Epsilon;
private static readonly long Multiplier;
public static readonly BasisPoint One;
private static readonly double OneOver10_4;
private long rawValue;
public static readonly BasisPoint Zero;
public bool Equals(BasisPoint other)
{
throw new NotImplementedException();
}
public int CompareTo(BasisPoint other)
{
throw new NotImplementedException();
}
}
public class ParcelInfo : IEquatable<ParcelInfo>
{
public ParcelKeyPair Key { get; set; }
public long Amount { get; set; }
public BasisPoint Multiplier { get; set; }
public long MultipliedAmount { get; set; }
public BasisPoint Probability { get; set; }
public bool Equals(ParcelInfo? other)
{
return this.Key.Id.Equals(other.Key.Id);
}
}
public class ParcelKeyPair
{

View File

@ -44,6 +44,7 @@ namespace SCHALE.GameServer.Controllers.Api
var payloadStr = Encoding.UTF8.GetString(payloadMs.ToArray());
var jsonNode = JsonSerializer.Deserialize<JsonNode>(payloadStr);
var protocol = (Protocol?)jsonNode?["Protocol"]?.GetValue<int?>() ?? Protocol.None;
if (protocol == Protocol.None)
{
logger.LogWarning("Failed to read protocol from JsonNode, {Payload:j}", payloadStr);
@ -60,6 +61,8 @@ namespace SCHALE.GameServer.Controllers.Api
var payload = (JsonSerializer.Deserialize(payloadStr, requestType) as RequestPacket)!;
var rsp = protocolHandlerFactory.Invoke(protocol, payload);
if (rsp is null)
{
logger.LogDebug("{Protocol} {Payload:j}", payload.Protocol, payloadStr);
@ -71,7 +74,7 @@ namespace SCHALE.GameServer.Controllers.Api
return Results.Json(new
{
packet = JsonSerializer.Serialize(rsp),
protocol = payload.Protocol.ToString()
protocol = ((BasePacket)rsp).Protocol.ToString()
});
protocolErrorRet:

View File

@ -0,0 +1,22 @@
using SCHALE.Common.NetworkProtocol;
namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers
{
public class Academy : ProtocolHandlerBase
{
public Academy(IServiceScopeFactory scopeFactory, IProtocolHandlerFactory protocolHandlerFactory) : base(scopeFactory, protocolHandlerFactory) { }
[ProtocolHandler(Protocol.Academy_GetInfo)]
public ResponsePacket GetInfoHandler(AcademyGetInfoRequest req)
{
return new AcademyGetInfoResponse()
{
AcademyDB = new()
{
AccountId = 1
},
AcademyLocationDBs = [],
};
}
}
}

View File

@ -1,4 +1,8 @@
using SCHALE.Common.NetworkProtocol;
using SCHALE.Common.Database;
using SCHALE.Common.FlatData;
using SCHALE.Common.NetworkProtocol;
using SCHALE.Common.Parcel;
using Serilog;
namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers
{
@ -6,10 +10,14 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers
{
public Account(IServiceScopeFactory scopeFactory, IProtocolHandlerFactory protocolHandlerFactory) : base(scopeFactory, protocolHandlerFactory) { }
// most handlers empty
[ProtocolHandler(Protocol.Account_CheckYostar)]
public ResponsePacket CheckYostarHandler(AccountCheckYostarRequest req)
{
var account = Context.GuestAccounts.SingleOrDefault(x => x.Uid == uint.Parse(req.EnterTicket.Split(":", StringSplitOptions.None).First()) && x.Token == req.EnterTicket.Split(":", StringSplitOptions.None).Last());
string[] uid_token = req.EnterTicket.Split(':');
var account = Context.GuestAccounts.SingleOrDefault(x => x.Uid == uint.Parse(uid_token[0]) && x.Token == uid_token[1]);
if (account is null)
{
return new AccountCheckYostarResponse()
@ -24,19 +32,160 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers
ResultState = 1,
SessionKey = new()
{
AccountServerId = account.Uid,
MxToken = req.EnterTicket,
AccountServerId = account.Uid
}
};
}
[ProtocolHandler(Protocol.Account_Auth)]
public ResponsePacket AuthHandler(AccountAuthRequest req)
{
var account = Context.Accounts.SingleOrDefault(x => x.ServerId == req.AccountId);
if (account == null)
{
return new ErrorPacket()
{
ErrorCode = WebAPIErrorCode.AccountAuthNotCreated
};
}
else
{
return new AccountAuthResponse()
{
CurrentVersion = req.Version,
AccountDB = account.AccountDB,
SessionKey = new()
{
AccountServerId = account.ServerId,
MxToken = req.SessionKey.MxToken,
}
};
}
}
[ProtocolHandler(Protocol.Account_Create)]
public ResponsePacket CreateHandler(AccountCreateRequest req)
{
var account = Common.Database.Models.Game.Account.Create((uint)req.AccountId);
Context.Accounts.Add(account);
Context.SaveChanges();
Log.Information("Account Created " + Context.Accounts.Count());
return new AccountCreateResponse()
{
SessionKey = new()
{
AccountServerId = account.ServerId,
MxToken = req.SessionKey.MxToken,
},
};
}
[ProtocolHandler(Protocol.Account_Nickname)]
public ResponsePacket NicknameHandler(AccountNicknameRequest req)
{
var account = Context.Accounts.SingleOrDefault(x => x.ServerId == req.AccountId);
account.AccountDB.Nickname = req.Nickname;
Context.SaveChanges();
return new AccountNicknameResponse()
{
AccountDB = account.AccountDB
};
}
[ProtocolHandler(Protocol.Account_LoginSync)]
public ResponsePacket LoginSyncHandler(AccountLoginSyncRequest req)
{
return new AccountLoginSyncResponse()
{
};
}
[ProtocolHandler(Protocol.Account_GetTutorial)]
public ResponsePacket GetTutorialHandler(AccountGetTutorialRequest req)
{
return new AccountGetTutorialResponse()
{
};
}
[ProtocolHandler(Protocol.Account_SetTutorial)]
public ResponsePacket SetTutorialHandler(AccountSetTutorialRequest req)
{
return new AccountSetTutorialResponse()
{
};
}
// others handlers, move to different handler group later
[ProtocolHandler(Protocol.Item_List)]
public ResponsePacket Item_ListRequestHandler(ItemListRequest req)
{
return new ItemListResponse()
{
ItemDBs = [],
ExpiryItemDBs = [],
ServerNotification = ServerNotificationFlag.HasUnreadMail,
};
}
[ProtocolHandler(Protocol.NetworkTime_Sync)]
public ResponsePacket NetworkTime_Sync(NetworkTimeSyncRequest req)
{
long received_tick = DateTimeOffset.Now.Ticks;
return new NetworkTimeSyncResponse()
{
ReceiveTick = received_tick,
EchoSendTick = DateTimeOffset.Now.Ticks,
ServerTimeTicks = received_tick,
};
}
[ProtocolHandler(Protocol.ContentSave_Get)]
public ResponsePacket ContentSave_Get(ContentSaveGetRequest req)
{
return new ContentSaveGetResponse()
{
ServerNotification = ServerNotificationFlag.HasUnreadMail,
};
}
[ProtocolHandler(Protocol.Shop_BeforehandGachaGet)]
public ResponsePacket Shop_BeforehandGachaGet(ShopBeforehandGachaGetRequest req)
{
return new ShopBeforehandGachaGetResponse()
{
SessionKey = new ()
{
MxToken = req.SessionKey.MxToken,
AccountServerId = req.SessionKey.AccountServerId,
},
};
}
[ProtocolHandler(Protocol.Toast_List)]
public ResponsePacket ToastListHandler(ToastListRequest req)
{
return new ToastListResponse()
{
};
}
}
}

View File

@ -0,0 +1,27 @@
using SCHALE.Common.NetworkProtocol;
namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers
{
public class Mission : ProtocolHandlerBase
{
public Mission(IServiceScopeFactory scopeFactory, IProtocolHandlerFactory protocolHandlerFactory) : base(scopeFactory, protocolHandlerFactory) { }
[ProtocolHandler(Protocol.Mission_List)]
public ResponsePacket ListHandler(MissionListRequest req)
{
return new MissionListResponse()
{
};
}
[ProtocolHandler(Protocol.Mission_GuideMissionSeasonList)]
public ResponsePacket GuideMissionSeasonListHandler(GuideMissionSeasonListRequest req)
{
return new GuideMissionSeasonListResponse()
{
};
}
}
}

View File

@ -0,0 +1,37 @@
using SCHALE.Common.NetworkProtocol;
namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers
{
public class ProofToken : ProtocolHandlerBase
{
public ProofToken(IServiceScopeFactory scopeFactory, IProtocolHandlerFactory protocolHandlerFactory) : base(scopeFactory, protocolHandlerFactory) { }
[ProtocolHandler(Protocol.ProofToken_RequestQuestion)]
public ResponsePacket RequestQuestionHandler(ProofTokenRequestQuestionRequest req)
{
return new ProofTokenRequestQuestionResponse()
{
Hint = 69,
Question = "seggs",
SessionKey = new()
{
MxToken = req.SessionKey.MxToken,
AccountServerId = req.SessionKey.AccountServerId,
},
};
}
[ProtocolHandler(Protocol.ProofToken_Submit)]
public ResponsePacket SubmitHandler(ProofTokenSubmitRequest req)
{
return new ProofTokenSubmitResponse()
{
SessionKey = new()
{
MxToken = req.SessionKey.MxToken,
AccountServerId = req.SessionKey.AccountServerId,
},
};
}
}
}

View File

@ -18,7 +18,7 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers
public interface IProtocolHandlerFactory
{
public ResponsePacket? Invoke(Protocol protocol, RequestPacket? req);
public object? Invoke(Protocol protocol, RequestPacket? req);
public MethodInfo? GetProtocolHandler(Protocol protocol);
public Type? GetRequestPacketTypeByProtocol(Protocol protocol);
public void RegisterInstance(Type t, object? inst);
@ -62,7 +62,7 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers
}
}
public ResponsePacket? Invoke(Protocol protocol, RequestPacket? req)
public object? Invoke(Protocol protocol, RequestPacket? req)
{
var handler = GetProtocolHandler(protocol);
if (handler is null)
@ -91,6 +91,8 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers
{
private readonly IServiceScopeFactory scopeFactory;
private IServiceScope scope;
public ProtocolHandlerBase(IServiceScopeFactory _scopeFactory, IProtocolHandlerFactory protocolHandlerFactory)
{
scopeFactory = _scopeFactory;
@ -100,23 +102,23 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers
public SCHALEContext Context
{
get
{
using (var scope = scopeFactory.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<SCHALEContext>();
return db;
}
}
}
public Task StartAsync(CancellationToken cancellationToken)
{
scope = scopeFactory.CreateScope();
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
scope.Dispose();
Context.Dispose();
return Task.CompletedTask;
}
}

View File

@ -0,0 +1,31 @@
using SCHALE.Common.NetworkProtocol;
namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers
{
public class Scenario : ProtocolHandlerBase
{
public Scenario(IServiceScopeFactory scopeFactory, IProtocolHandlerFactory protocolHandlerFactory) : base(scopeFactory, protocolHandlerFactory) { }
[ProtocolHandler(Protocol.Scenario_Skip)]
public ResponsePacket SkipHandler(ScenarioSkipRequest req)
{
// skip story doesn't work yet, probably need to implement missiondb
return new ScenarioSkipResponse()
{
};
}
[ProtocolHandler(Protocol.Scenario_Select)]
public ResponsePacket SelectHandler(ScenarioSelectRequest req)
{
return new ScenarioSelectResponse()
{
};
}
}
}

View File

@ -48,6 +48,10 @@ namespace SCHALE.GameServer
builder.Services.AddProtocolHandlerFactory();
builder.Services.AddProtocolHandlerGroup<Account>();
builder.Services.AddProtocolHandlerGroup<Queuing>();
builder.Services.AddProtocolHandlerGroup<Academy>();
builder.Services.AddProtocolHandlerGroup<Mission>();
builder.Services.AddProtocolHandlerGroup<ProofToken>();
builder.Services.AddProtocolHandlerGroup<Scenario>();
var app = builder.Build();

View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.002.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SCHALE.GameServer", "SCHALE.GameServer.csproj", "{73DF585D-E422-4642-8026-C55F031B3D07}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{73DF585D-E422-4642-8026-C55F031B3D07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{73DF585D-E422-4642-8026-C55F031B3D07}.Debug|Any CPU.Build.0 = Debug|Any CPU
{73DF585D-E422-4642-8026-C55F031B3D07}.Release|Any CPU.ActiveCfg = Release|Any CPU
{73DF585D-E422-4642-8026-C55F031B3D07}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CC05112F-B591-4DB5-8D12-F56FBF1FA838}
EndGlobalSection
EndGlobal