mirror of
https://github.com/thebreaddev/Supercell.GUT.git
synced 2024-11-24 21:34:38 +00:00
[v0.1.0] database implementation
not finished. early wip state
This commit is contained in:
parent
8c6a533918
commit
281d2789ea
24 changed files with 637 additions and 29 deletions
|
@ -72,4 +72,9 @@ public class LogicClientAvatar : LogicBase
|
||||||
|
|
||||||
checksumEncoder.WriteInt(this.TutorialFlags);
|
checksumEncoder.WriteInt(this.TutorialFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetTutorialFlags(int tutorialFlags)
|
||||||
|
{
|
||||||
|
this.TutorialFlags |= tutorialFlags;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
46
Supercell.GUT.Logic/Message/Account/CreateAvatarMessage.cs
Normal file
46
Supercell.GUT.Logic/Message/Account/CreateAvatarMessage.cs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
using Supercell.GUT.Logic.Message.Attributes;
|
||||||
|
using Supercell.GUT.Titan.Logic.Message;
|
||||||
|
|
||||||
|
namespace Supercell.GUT.Logic.Message.Account;
|
||||||
|
|
||||||
|
[VersionedMessage(10200)]
|
||||||
|
public class CreateAvatarMessage : VersionedMessage
|
||||||
|
{
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
public CreateAvatarMessage() : base(0)
|
||||||
|
{
|
||||||
|
Name = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Encode()
|
||||||
|
{
|
||||||
|
base.Encode();
|
||||||
|
|
||||||
|
ByteStream.WriteString(Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Decode()
|
||||||
|
{
|
||||||
|
base.Decode();
|
||||||
|
|
||||||
|
Name = ByteStream.ReadString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetMessageType()
|
||||||
|
{
|
||||||
|
return 10200;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetServiceNodeType()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Destruct()
|
||||||
|
{
|
||||||
|
base.Destruct();
|
||||||
|
|
||||||
|
Name = null;
|
||||||
|
}
|
||||||
|
}
|
33
Supercell.GUT.Logic/Message/Account/KeepAliveMessage.cs
Normal file
33
Supercell.GUT.Logic/Message/Account/KeepAliveMessage.cs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
using Supercell.GUT.Logic.Message.Attributes;
|
||||||
|
using Supercell.GUT.Titan.Logic.Message;
|
||||||
|
|
||||||
|
namespace Supercell.GUT.Logic.Message.Account;
|
||||||
|
|
||||||
|
[VersionedMessage(10108)]
|
||||||
|
public class KeepAliveMessage : VersionedMessage
|
||||||
|
{
|
||||||
|
public KeepAliveMessage() : base(0)
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Encode()
|
||||||
|
{
|
||||||
|
base.Encode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Decode()
|
||||||
|
{
|
||||||
|
base.Decode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetMessageType()
|
||||||
|
{
|
||||||
|
return 10108;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetServiceNodeType()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
42
Supercell.GUT.Logic/Message/Avatar/AddableFriendsMessage.cs
Normal file
42
Supercell.GUT.Logic/Message/Avatar/AddableFriendsMessage.cs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
using Supercell.GUT.Logic.Message.Attributes;
|
||||||
|
using Supercell.GUT.Titan.Logic.Message;
|
||||||
|
|
||||||
|
namespace Supercell.GUT.Logic.Message.Avatar;
|
||||||
|
|
||||||
|
[VersionedMessage(20107)]
|
||||||
|
public class AddableFriendsMessage : VersionedMessage
|
||||||
|
{
|
||||||
|
public AddableFriendsMessage() : base(0)
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Encode()
|
||||||
|
{
|
||||||
|
base.Encode();
|
||||||
|
|
||||||
|
this.ByteStream.WriteInt(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Decode()
|
||||||
|
{
|
||||||
|
base.Decode();
|
||||||
|
|
||||||
|
this.ByteStream.ReadInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetMessageType()
|
||||||
|
{
|
||||||
|
return 20107;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetServiceNodeType()
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Destruct()
|
||||||
|
{
|
||||||
|
base.Destruct();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
using Supercell.GUT.Logic.Message.Attributes;
|
||||||
|
using Supercell.GUT.Titan.Logic.Message;
|
||||||
|
using Supercell.GUT.Titan.Logic.Util;
|
||||||
|
|
||||||
|
namespace Supercell.GUT.Logic.Message.Avatar;
|
||||||
|
|
||||||
|
[VersionedMessage(10503)]
|
||||||
|
public class AskForAddableFriendsMessage : VersionedMessage
|
||||||
|
{
|
||||||
|
public LogicArrayList<string> FacebookIds { get; set; }
|
||||||
|
public LogicArrayList<string> GamecenterIds { get; set; }
|
||||||
|
|
||||||
|
public AskForAddableFriendsMessage() : base(0)
|
||||||
|
{
|
||||||
|
this.FacebookIds = new LogicArrayList<string>();
|
||||||
|
this.GamecenterIds = new LogicArrayList<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Destruct()
|
||||||
|
{
|
||||||
|
base.Destruct();
|
||||||
|
|
||||||
|
this.FacebookIds.Clear();
|
||||||
|
this.GamecenterIds.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Encode()
|
||||||
|
{
|
||||||
|
base.Encode();
|
||||||
|
|
||||||
|
int size = this.FacebookIds.Size();
|
||||||
|
|
||||||
|
this.ByteStream.WriteInt(size);
|
||||||
|
for (int i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
this.ByteStream.WriteString(this.FacebookIds[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
size = this.GamecenterIds.Size();
|
||||||
|
|
||||||
|
this.ByteStream.WriteInt(size);
|
||||||
|
for (int i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
this.ByteStream.WriteString(this.GamecenterIds[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Decode()
|
||||||
|
{
|
||||||
|
base.Decode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetMessageType()
|
||||||
|
{
|
||||||
|
return 10503;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetServiceNodeType()
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
using Supercell.GUT.Logic.Message.Attributes;
|
||||||
|
using Supercell.GUT.Titan.Logic.Message;
|
||||||
|
|
||||||
|
namespace Supercell.GUT.Logic.Message.Avatar;
|
||||||
|
|
||||||
|
[VersionedMessage(10504)]
|
||||||
|
public class AskForFriendListMessage : VersionedMessage
|
||||||
|
{
|
||||||
|
public AskForFriendListMessage() : base(0)
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetMessageType()
|
||||||
|
{
|
||||||
|
return 10504;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetServiceNodeType()
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
}
|
37
Supercell.GUT.Logic/Message/Avatar/FriendListMessage.cs
Normal file
37
Supercell.GUT.Logic/Message/Avatar/FriendListMessage.cs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
using Supercell.GUT.Logic.Message.Attributes;
|
||||||
|
using Supercell.GUT.Titan.Logic.Message;
|
||||||
|
|
||||||
|
namespace Supercell.GUT.Logic.Message.Avatar;
|
||||||
|
|
||||||
|
[VersionedMessage(20105)]
|
||||||
|
public class FriendListMessage : VersionedMessage
|
||||||
|
{
|
||||||
|
public FriendListMessage() : base(0)
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Encode()
|
||||||
|
{
|
||||||
|
base.Encode();
|
||||||
|
|
||||||
|
this.ByteStream.WriteInt(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Decode()
|
||||||
|
{
|
||||||
|
base.Decode();
|
||||||
|
|
||||||
|
this.ByteStream.ReadInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetMessageType()
|
||||||
|
{
|
||||||
|
return 20105;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetServiceNodeType()
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
using Supercell.GUT.Logic.Message.Attributes;
|
||||||
|
using Supercell.GUT.Titan.Logic.Message;
|
||||||
|
|
||||||
|
namespace Supercell.GUT.Logic.Message.Avatar;
|
||||||
|
|
||||||
|
[VersionedMessage(10210)]
|
||||||
|
public class TutorialProgressUpdateMessage : VersionedMessage
|
||||||
|
{
|
||||||
|
public int TutorialFlags { get; set; }
|
||||||
|
|
||||||
|
public TutorialProgressUpdateMessage() : base(0)
|
||||||
|
{
|
||||||
|
TutorialFlags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Destruct()
|
||||||
|
{
|
||||||
|
base.Destruct();
|
||||||
|
|
||||||
|
TutorialFlags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Encode()
|
||||||
|
{
|
||||||
|
base.Encode();
|
||||||
|
|
||||||
|
ByteStream.WriteInt(TutorialFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Decode()
|
||||||
|
{
|
||||||
|
base.Decode();
|
||||||
|
|
||||||
|
TutorialFlags = ByteStream.ReadInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetMessageType()
|
||||||
|
{
|
||||||
|
return 10210;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetServiceNodeType()
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
}
|
54
Supercell.GUT.Server/Database/DatabaseManager.cs
Normal file
54
Supercell.GUT.Server/Database/DatabaseManager.cs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
using Supercell.GUT.Server.Database.Document;
|
||||||
|
using Supercell.GUT.Server.Database.Options;
|
||||||
|
|
||||||
|
namespace Supercell.GUT.Server.Database;
|
||||||
|
|
||||||
|
public class DatabaseManager
|
||||||
|
{
|
||||||
|
private const string IdentifierCounterCollection = "t_id_counter";
|
||||||
|
private static readonly FindOneAndUpdateOptions<IdentifierCounterDocument> s_counterUpdateOptions = new() { ReturnDocument = ReturnDocument.After };
|
||||||
|
|
||||||
|
private readonly DatabaseOptions _options;
|
||||||
|
|
||||||
|
private readonly MongoClient _client;
|
||||||
|
private readonly IMongoDatabase _database;
|
||||||
|
|
||||||
|
private readonly IMongoCollection<IdentifierCounterDocument> _idCounters;
|
||||||
|
|
||||||
|
public DatabaseManager(IOptions<DatabaseOptions> options)
|
||||||
|
{
|
||||||
|
_options = options.Value;
|
||||||
|
|
||||||
|
_client = new MongoClient(_options.MongoConnectionString);
|
||||||
|
_database = _client.GetDatabase(_options.DatabaseName);
|
||||||
|
|
||||||
|
_idCounters = _database.GetCollection<IdentifierCounterDocument>(IdentifierCounterCollection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMongoCollection<TDatabaseDocument> GetCollection<TDatabaseDocument>(string collectionName) where TDatabaseDocument : IDatabaseDocument
|
||||||
|
{
|
||||||
|
return _database.GetCollection<TDatabaseDocument>(collectionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> GetNextLowIdAsync(string counterName)
|
||||||
|
{
|
||||||
|
var cursor = await _idCounters.FindAsync(doc => doc.CounterName == counterName);
|
||||||
|
if (!cursor.Any())
|
||||||
|
{
|
||||||
|
await _idCounters.InsertOneAsync(new IdentifierCounterDocument
|
||||||
|
{
|
||||||
|
CounterName = counterName,
|
||||||
|
CurrentLowId = 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
IdentifierCounterDocument? document = await _idCounters.FindOneAndUpdateAsync<IdentifierCounterDocument>(
|
||||||
|
x => x.CounterName == counterName,
|
||||||
|
Builders<IdentifierCounterDocument>.Update.Inc(nameof(IdentifierCounterDocument.CurrentLowId), 1),
|
||||||
|
s_counterUpdateOptions);
|
||||||
|
|
||||||
|
return document.CurrentLowId;
|
||||||
|
}
|
||||||
|
}
|
19
Supercell.GUT.Server/Database/Document/AccountDocument.cs
Normal file
19
Supercell.GUT.Server/Database/Document/AccountDocument.cs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
using Supercell.GUT.Titan.Logic.Math;
|
||||||
|
|
||||||
|
namespace Supercell.GUT.Server.Database.Document;
|
||||||
|
public class AccountDocument : MongoSerializeableBase, IDatabaseDocument
|
||||||
|
{
|
||||||
|
public LogicLong DocumentId { get; set; }
|
||||||
|
public string SessionKey { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public AccountDocument()
|
||||||
|
{
|
||||||
|
DocumentId = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountDocument(LogicLong id, string token)
|
||||||
|
{
|
||||||
|
DocumentId = id;
|
||||||
|
SessionKey = token;
|
||||||
|
}
|
||||||
|
}
|
28
Supercell.GUT.Server/Database/Document/AvatarDocument.cs
Normal file
28
Supercell.GUT.Server/Database/Document/AvatarDocument.cs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
using Supercell.GUT.Logic.Avatar;
|
||||||
|
using Supercell.GUT.Titan.Logic.Math;
|
||||||
|
|
||||||
|
namespace Supercell.GUT.Server.Database.Document;
|
||||||
|
|
||||||
|
public class AvatarDocument : MongoSerializeableBase, IDatabaseDocument
|
||||||
|
{
|
||||||
|
public LogicLong DocumentId { get; set; }
|
||||||
|
|
||||||
|
public LogicClientAvatar LogicClientAvatar { get; set; } = new();
|
||||||
|
|
||||||
|
public int LastSaveTime { get; set; }
|
||||||
|
|
||||||
|
public AvatarDocument()
|
||||||
|
{
|
||||||
|
DocumentId = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AvatarDocument(LogicLong id)
|
||||||
|
{
|
||||||
|
DocumentId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetId(LogicLong id)
|
||||||
|
{
|
||||||
|
LogicClientAvatar.Id = id;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
using Supercell.GUT.Titan.Logic.Math;
|
||||||
|
|
||||||
|
namespace Supercell.GUT.Server.Database.Document;
|
||||||
|
|
||||||
|
public interface IDatabaseDocument
|
||||||
|
{
|
||||||
|
LogicLong DocumentId { get; set; }
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Supercell.GUT.Server.Database.Document;
|
||||||
|
|
||||||
|
internal class IdentifierCounterDocument : MongoSerializeableBase
|
||||||
|
{
|
||||||
|
public string CounterName { get; set; } = string.Empty;
|
||||||
|
public int CurrentLowId { get; set; }
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace Supercell.GUT.Server.Database.Document;
|
||||||
|
|
||||||
|
public abstract class MongoSerializeableBase
|
||||||
|
{
|
||||||
|
[BsonId]
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
[JsonIgnore]
|
||||||
|
public string? MongoId { get; set; }
|
||||||
|
}
|
7
Supercell.GUT.Server/Database/Options/DatabaseOptions.cs
Normal file
7
Supercell.GUT.Server/Database/Options/DatabaseOptions.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Supercell.GUT.Server.Database.Options;
|
||||||
|
|
||||||
|
public class DatabaseOptions
|
||||||
|
{
|
||||||
|
public required string MongoConnectionString { get; set; }
|
||||||
|
public required string DatabaseName { get; set; }
|
||||||
|
}
|
86
Supercell.GUT.Server/Document/DocumentManager.cs
Normal file
86
Supercell.GUT.Server/Document/DocumentManager.cs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
using MongoDB.Driver;
|
||||||
|
using Supercell.GUT.Server.Database;
|
||||||
|
using Supercell.GUT.Server.Database.Document;
|
||||||
|
using Supercell.GUT.Server.Util;
|
||||||
|
using Supercell.GUT.Titan.Logic.Math;
|
||||||
|
|
||||||
|
namespace Supercell.GUT.Server.Document;
|
||||||
|
|
||||||
|
internal class DocumentManager
|
||||||
|
{
|
||||||
|
private const string AccountCollectionName = "t_account_info";
|
||||||
|
private const string AvatarCollectionName = "t_player_avatar";
|
||||||
|
|
||||||
|
private const string AccountIdCounterName = "AccountId";
|
||||||
|
|
||||||
|
private readonly DatabaseManager _databaseManager;
|
||||||
|
|
||||||
|
public LogicLong Id { get; private set; } = new();
|
||||||
|
|
||||||
|
public AccountDocument? AccountDocument { get; private set; }
|
||||||
|
public AvatarDocument? AvatarDocument { get; private set; }
|
||||||
|
|
||||||
|
public DocumentManager(DatabaseManager databaseManager)
|
||||||
|
{
|
||||||
|
_databaseManager = databaseManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SaveAsync()
|
||||||
|
{
|
||||||
|
if (AccountDocument != null)
|
||||||
|
{
|
||||||
|
IMongoCollection<AccountDocument> accountCollection = _databaseManager.GetCollection<AccountDocument>(AccountCollectionName);
|
||||||
|
await accountCollection.ReplaceOneAsync(doc => doc.DocumentId.Equals(AccountDocument.DocumentId), AccountDocument);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AvatarDocument != null)
|
||||||
|
{
|
||||||
|
AvatarDocument.LastSaveTime = TimeUtil.GetCurrentTimestamp();
|
||||||
|
|
||||||
|
IMongoCollection<AvatarDocument> avatarCollection = _databaseManager.GetCollection<AvatarDocument>(AvatarCollectionName);
|
||||||
|
await avatarCollection.ReplaceOneAsync(doc => doc.DocumentId.Equals(AvatarDocument.DocumentId), AvatarDocument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CreateAccount()
|
||||||
|
{
|
||||||
|
if (AccountDocument != null) throw new InvalidOperationException("DocumentManager::CreateAccount: called when AccountDocument already created!");
|
||||||
|
|
||||||
|
int lowId = await _databaseManager.GetNextLowIdAsync(AccountIdCounterName);
|
||||||
|
|
||||||
|
AccountDocument = new(new(0, lowId), "ToDoRandomToken");
|
||||||
|
IMongoCollection<AccountDocument> accountCollection = _databaseManager.GetCollection<AccountDocument>(AccountCollectionName);
|
||||||
|
|
||||||
|
await accountCollection.InsertOneAsync(AccountDocument);
|
||||||
|
Id = AccountDocument.DocumentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task EnsureAccountDocument()
|
||||||
|
{
|
||||||
|
if (AccountDocument != null) return;
|
||||||
|
|
||||||
|
IMongoCollection<AccountDocument> accountCollection = _databaseManager.GetCollection<AccountDocument>(AccountCollectionName);
|
||||||
|
AccountDocument = await (await accountCollection.FindAsync(document => document.DocumentId.Equals(Id))).SingleOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task EnsureAvatarDocument()
|
||||||
|
{
|
||||||
|
if (AvatarDocument != null) return;
|
||||||
|
|
||||||
|
IMongoCollection<AvatarDocument> avatarCollection = _databaseManager.GetCollection<AvatarDocument>(AvatarCollectionName);
|
||||||
|
AvatarDocument = await (await avatarCollection.FindAsync(document => document.DocumentId.Equals(Id))).SingleOrDefaultAsync();
|
||||||
|
|
||||||
|
if (AvatarDocument == null)
|
||||||
|
{
|
||||||
|
AvatarDocument = new(Id);
|
||||||
|
await avatarCollection.InsertOneAsync(AvatarDocument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetDocumentId(LogicLong id)
|
||||||
|
{
|
||||||
|
if (Id.LowerInt > 0) throw new InvalidOperationException("DocumentManager::SetDocumentId: trying to override Id.");
|
||||||
|
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using Supercell.GUT.Logic;
|
using Supercell.GUT.Logic;
|
||||||
|
using Supercell.GUT.Logic.Avatar;
|
||||||
using Supercell.GUT.Server.Protocol;
|
using Supercell.GUT.Server.Protocol;
|
||||||
using Supercell.GUT.Titan.Logic.Message;
|
using Supercell.GUT.Titan.Logic.Message;
|
||||||
|
|
||||||
|
@ -11,6 +12,8 @@ internal class ClientConnection
|
||||||
private readonly IConnectionListener _listener;
|
private readonly IConnectionListener _listener;
|
||||||
private readonly MessageManager _messageManager;
|
private readonly MessageManager _messageManager;
|
||||||
|
|
||||||
|
public LogicClientAvatar? LogicClientAvatar { get; set; }
|
||||||
|
|
||||||
private readonly byte[] _receiveBuffer;
|
private readonly byte[] _receiveBuffer;
|
||||||
private IProtocolEntity? _protocolEntity;
|
private IProtocolEntity? _protocolEntity;
|
||||||
private DateTime _lastKeepAliveTime;
|
private DateTime _lastKeepAliveTime;
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Supercell.GUT.Logic.Message;
|
using Supercell.GUT.Logic.Message;
|
||||||
|
using Supercell.GUT.Server.Database;
|
||||||
|
using Supercell.GUT.Server.Database.Options;
|
||||||
using Supercell.GUT.Server.Debugging;
|
using Supercell.GUT.Server.Debugging;
|
||||||
|
using Supercell.GUT.Server.Document;
|
||||||
using Supercell.GUT.Server.Network;
|
using Supercell.GUT.Server.Network;
|
||||||
using Supercell.GUT.Server.Network.Connection;
|
using Supercell.GUT.Server.Network.Connection;
|
||||||
using Supercell.GUT.Server.Network.Options;
|
using Supercell.GUT.Server.Network.Options;
|
||||||
|
@ -17,6 +20,7 @@ namespace Supercell.GUT.Server;
|
||||||
internal static class Program
|
internal static class Program
|
||||||
{
|
{
|
||||||
private const string GatewayOptionsSection = "Gateway";
|
private const string GatewayOptionsSection = "Gateway";
|
||||||
|
private const string DatabaseOptionsSection = "Database";
|
||||||
|
|
||||||
private static async Task Main(string[] args)
|
private static async Task Main(string[] args)
|
||||||
{
|
{
|
||||||
|
@ -25,6 +29,7 @@ internal static class Program
|
||||||
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
|
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
|
||||||
|
|
||||||
builder.Services.Configure<GatewayOptions>(builder.Configuration.GetRequiredSection(GatewayOptionsSection));
|
builder.Services.Configure<GatewayOptions>(builder.Configuration.GetRequiredSection(GatewayOptionsSection));
|
||||||
|
builder.Services.Configure<DatabaseOptions>(builder.Configuration.GetRequiredSection(DatabaseOptionsSection));
|
||||||
|
|
||||||
builder.Services.AddHandlers();
|
builder.Services.AddHandlers();
|
||||||
builder.Services.AddSingleton<IDebuggerListener, ServerDebuggerListener>();
|
builder.Services.AddSingleton<IDebuggerListener, ServerDebuggerListener>();
|
||||||
|
@ -34,6 +39,8 @@ internal static class Program
|
||||||
builder.Services.AddScoped<IConnectionListener, Messaging>();
|
builder.Services.AddScoped<IConnectionListener, Messaging>();
|
||||||
builder.Services.AddSingleton<LogicMessageFactory, GUTMessageFactory>();
|
builder.Services.AddSingleton<LogicMessageFactory, GUTMessageFactory>();
|
||||||
builder.Services.AddScoped<MessageManager>();
|
builder.Services.AddScoped<MessageManager>();
|
||||||
|
builder.Services.AddScoped<DocumentManager>();
|
||||||
|
builder.Services.AddSingleton<DatabaseManager>();
|
||||||
|
|
||||||
builder.Services.AddHostedService<GUTServer>();
|
builder.Services.AddHostedService<GUTServer>();
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Supercell.GUT.Logic.Message.Account;
|
using Supercell.GUT.Logic.Message.Account;
|
||||||
|
using Supercell.GUT.Server.Database.Document;
|
||||||
|
using Supercell.GUT.Server.Document;
|
||||||
using Supercell.GUT.Server.Network.Connection;
|
using Supercell.GUT.Server.Network.Connection;
|
||||||
using Supercell.GUT.Server.Protocol.Attributes;
|
using Supercell.GUT.Server.Protocol.Attributes;
|
||||||
|
|
||||||
|
@ -10,11 +12,19 @@ internal class AccountMessageHandler : MessageHandlerBase
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly ClientConnection _connection;
|
private readonly ClientConnection _connection;
|
||||||
|
private readonly DocumentManager _documentManager;
|
||||||
|
|
||||||
public AccountMessageHandler(ClientConnection connection, ILogger<AccountMessageHandler> logger)
|
public AccountMessageHandler(ClientConnection connection, ILogger<AccountMessageHandler> logger, DocumentManager documentManager)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_connection = connection;
|
_connection = connection;
|
||||||
|
_documentManager = documentManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MessageHandler(10108)]
|
||||||
|
public async Task OnKeepAlive(KeepAliveMessage keepAliveMessage)
|
||||||
|
{
|
||||||
|
await Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MessageHandler(10105)]
|
[MessageHandler(10105)]
|
||||||
|
@ -33,32 +43,59 @@ internal class AccountMessageHandler : MessageHandlerBase
|
||||||
[MessageHandler(10103)]
|
[MessageHandler(10103)]
|
||||||
public async Task OnCreateAccount(CreateAccountMessage createAccountMessage)
|
public async Task OnCreateAccount(CreateAccountMessage createAccountMessage)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Creating account! FacebookId: {fid} | GameCenterId: {gcid}",
|
await _documentManager.CreateAccount();
|
||||||
createAccountMessage.FacebookId,
|
|
||||||
createAccountMessage.GameCenterId);
|
AccountDocument? accountDocument = _documentManager.AccountDocument;
|
||||||
|
if (accountDocument == null)
|
||||||
|
{
|
||||||
|
await _connection.SendMessage(new CreateAccountFailedMessage()
|
||||||
|
{
|
||||||
|
ErrorCode = 1
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await _connection.SendMessage(new CreateAccountOkMessage()
|
await _connection.SendMessage(new CreateAccountOkMessage()
|
||||||
{
|
{
|
||||||
AccountIdHigherInt = 0,
|
AccountIdHigherInt = accountDocument.DocumentId.HigherInt,
|
||||||
AccountIdLowerInt = 1,
|
AccountIdLowerInt = accountDocument.DocumentId.LowerInt,
|
||||||
SessionKey = "telegram_is_@BL4D3_BR34D"
|
SessionKey = accountDocument.SessionKey
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[MessageHandler(10102)]
|
[MessageHandler(10102)]
|
||||||
public async Task OnLoginUsingSession(LoginUsingSessionMessage loginUsingSessionMessage)
|
public async Task OnLoginUsingSession(LoginUsingSessionMessage loginUsingSessionMessage)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Logging account! sessionkey: {sk} | GameCenterId: {gcid} | GameVersion: {cgv} | account: ({h}-{l})",
|
if (_documentManager.Id.LowerInt == 0)
|
||||||
loginUsingSessionMessage.SessionKey,
|
_documentManager.SetDocumentId(new (loginUsingSessionMessage.AccountIdHigherInt, loginUsingSessionMessage.AccountIdLowerInt));
|
||||||
loginUsingSessionMessage.GamecenterId,
|
|
||||||
loginUsingSessionMessage.ClientGameVersion,
|
await _documentManager.EnsureAccountDocument();
|
||||||
loginUsingSessionMessage.AccountIdHigherInt,
|
|
||||||
loginUsingSessionMessage.AccountIdLowerInt);
|
AccountDocument? accountDocument = _documentManager.AccountDocument;
|
||||||
|
if (accountDocument == null)
|
||||||
|
{
|
||||||
|
await _connection.SendMessage(new LoginFailedMessage()
|
||||||
|
{
|
||||||
|
ErrorCode = 2
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (accountDocument.SessionKey != loginUsingSessionMessage.SessionKey)
|
||||||
|
{
|
||||||
|
await _connection.SendMessage(new LoginFailedMessage()
|
||||||
|
{
|
||||||
|
ErrorCode = 5
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await _connection.SendMessage(new LoginOkMessage()
|
await _connection.SendMessage(new LoginOkMessage()
|
||||||
{
|
{
|
||||||
PrimaryAvatarIdHigherInt = loginUsingSessionMessage.AccountIdHigherInt,
|
PrimaryAvatarIdHigherInt = accountDocument.DocumentId.HigherInt,
|
||||||
PrimaryAvatarIdLowerInt = loginUsingSessionMessage.AccountIdLowerInt,
|
PrimaryAvatarIdLowerInt = accountDocument.DocumentId.LowerInt,
|
||||||
|
|
||||||
Fingerprint = "fece25cfc941db1a5bb3e79d4e6a60c34659f49e"
|
Fingerprint = "fece25cfc941db1a5bb3e79d4e6a60c34659f49e"
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Supercell.GUT.Logic.Avatar;
|
using Supercell.GUT.Logic.Avatar;
|
||||||
using Supercell.GUT.Logic.Message.Avatar;
|
using Supercell.GUT.Logic.Message.Avatar;
|
||||||
|
using Supercell.GUT.Server.Document;
|
||||||
using Supercell.GUT.Server.Network.Connection;
|
using Supercell.GUT.Server.Network.Connection;
|
||||||
using Supercell.GUT.Server.Protocol.Attributes;
|
using Supercell.GUT.Server.Protocol.Attributes;
|
||||||
using Supercell.GUT.Titan.Logic.Math;
|
|
||||||
|
|
||||||
namespace Supercell.GUT.Server.Protocol.Handlers;
|
namespace Supercell.GUT.Server.Protocol.Handlers;
|
||||||
|
|
||||||
|
@ -12,31 +12,52 @@ internal class AvatarMessageHandler : MessageHandlerBase
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly ClientConnection _connection;
|
private readonly ClientConnection _connection;
|
||||||
|
private readonly DocumentManager _documentManager;
|
||||||
|
|
||||||
public AvatarMessageHandler(ClientConnection connection, ILogger<AvatarMessageHandler> logger)
|
public AvatarMessageHandler(ClientConnection connection, ILogger<AvatarMessageHandler> logger, DocumentManager documentManager)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_connection = connection;
|
_connection = connection;
|
||||||
|
_documentManager = documentManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MessageHandler(10201)]
|
[MessageHandler(10201)]
|
||||||
public async Task OnSelectAvatar(SelectAvatarMessage selectAvatarMessage)
|
public async Task OnSelectAvatar(SelectAvatarMessage selectAvatarMessage)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("selecting avatar! avatar: ({h}-{l})",
|
await _documentManager.EnsureAvatarDocument();
|
||||||
selectAvatarMessage.AvatarIdHigherInt,
|
LogicClientAvatar logicClientAvatar = _documentManager.AvatarDocument!.LogicClientAvatar;
|
||||||
selectAvatarMessage.AvatarIdLowerInt);
|
|
||||||
|
if (logicClientAvatar.Id.LowerInt == 0)
|
||||||
|
{
|
||||||
|
_documentManager.AvatarDocument.SetId(_documentManager.AvatarDocument.DocumentId);
|
||||||
|
await _documentManager.SaveAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
_connection.LogicClientAvatar = logicClientAvatar;
|
||||||
|
|
||||||
await _connection.SendMessage(new AvatarDataMessage()
|
await _connection.SendMessage(new AvatarDataMessage()
|
||||||
{
|
{
|
||||||
LogicClientAvatar = new LogicClientAvatar()
|
LogicClientAvatar = _connection.LogicClientAvatar
|
||||||
{
|
|
||||||
Id = new LogicLong(selectAvatarMessage.AvatarIdHigherInt, selectAvatarMessage.AvatarIdLowerInt),
|
|
||||||
|
|
||||||
Name = "BreadDEV",
|
|
||||||
AvatarCode = "a1",
|
|
||||||
|
|
||||||
TutorialFlags = 999999
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MessageHandler(10210)]
|
||||||
|
public async Task OnTutorialProgressUpdate(TutorialProgressUpdateMessage tutorialProgressUpdateMessage)
|
||||||
|
{
|
||||||
|
_connection.LogicClientAvatar!.SetTutorialFlags(tutorialProgressUpdateMessage.TutorialFlags);
|
||||||
|
|
||||||
|
await _documentManager.SaveAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MessageHandler(10504)]
|
||||||
|
public async Task OnAskForFriendList(AskForFriendListMessage askForFriendListMessage)
|
||||||
|
{
|
||||||
|
await _connection.SendMessage(new FriendListMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
[MessageHandler(10503)]
|
||||||
|
public async Task OnAskForAddableFriends(AskForAddableFriendsMessage askForAddableFriendsMessage)
|
||||||
|
{
|
||||||
|
await _connection.SendMessage(new AddableFriendsMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||||
|
<PackageReference Include="MongoDB.Driver" Version="2.24.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
11
Supercell.GUT.Server/Util/TimeUtil.cs
Normal file
11
Supercell.GUT.Server/Util/TimeUtil.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
namespace Supercell.GUT.Server.Util;
|
||||||
|
|
||||||
|
public static class TimeUtil
|
||||||
|
{
|
||||||
|
private static readonly DateTime s_unixTime = new(1970, 1, 1);
|
||||||
|
|
||||||
|
public static int GetCurrentTimestamp()
|
||||||
|
{
|
||||||
|
return (int)DateTime.UtcNow.Subtract(s_unixTime).TotalSeconds;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,5 +2,9 @@
|
||||||
"Gateway": {
|
"Gateway": {
|
||||||
"Host": "0.0.0.0",
|
"Host": "0.0.0.0",
|
||||||
"Port": 9339
|
"Port": 9339
|
||||||
|
},
|
||||||
|
"Database": {
|
||||||
|
"MongoConnectionString": "mongodb://127.0.0.1:27017",
|
||||||
|
"DatabaseName": "gut"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -36,4 +36,12 @@ public class LogicLong
|
||||||
this.HigherInt = byteStream.ReadInt();
|
this.HigherInt = byteStream.ReadInt();
|
||||||
this.LowerInt = byteStream.ReadInt();
|
this.LowerInt = byteStream.ReadInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
if (obj is LogicLong logicLong)
|
||||||
|
return logicLong.HigherInt == this.HigherInt && logicLong.LowerInt == this.LowerInt;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue