diff --git a/Supercell.GUT.Logic/Avatar/LogicAvatarGame.cs b/Supercell.GUT.Logic/Avatar/LogicAvatarGame.cs new file mode 100644 index 0000000..5213acb --- /dev/null +++ b/Supercell.GUT.Logic/Avatar/LogicAvatarGame.cs @@ -0,0 +1,26 @@ +using Supercell.GUT.Logic.Base; +using Supercell.GUT.Titan.Logic.DataStream; + +namespace Supercell.GUT.Logic.Avatar; + +public class LogicAvatarGame : LogicBase +{ + public LogicAvatarGame() : base(20486) + { + } + + public override void Destruct() + { + base.Destruct(); + } + + public override void Encode(ChecksumEncoder checksumEncoder) + { + base.Encode(checksumEncoder); + } + + public override void Decode(ByteStream byteStream) + { + base.Decode(byteStream); + } +} diff --git a/Supercell.GUT.Logic/Avatar/LogicClientAvatar.cs b/Supercell.GUT.Logic/Avatar/LogicClientAvatar.cs new file mode 100644 index 0000000..c52523b --- /dev/null +++ b/Supercell.GUT.Logic/Avatar/LogicClientAvatar.cs @@ -0,0 +1,75 @@ +using Supercell.GUT.Logic.Base; +using Supercell.GUT.Logic.Player; +using Supercell.GUT.Titan.Logic.DataStream; +using Supercell.GUT.Titan.Logic.Math; +using Supercell.GUT.Titan.Logic.Util; + +namespace Supercell.GUT.Logic.Avatar; + +public class LogicClientAvatar : LogicBase +{ + public LogicLong Id { get; set; } + public int ActiveMission { get; set; } + public string Name { get; set; } + public string AvatarCode { get; set; } + public LogicArrayList AvatarGames { get; set; } + public LogicArrayList MissionStatus { get; set; } + public LogicPlayerAttributes PlayerAttributes { get; set; } + public LogicInventory Inventory { get; set; } + public LogicPlayerStats PlayerStats { get; set; } + + public int TutorialFlags { get; set; } + + public LogicClientAvatar() : base(20486) + { + this.Id = new LogicLong(); + this.ActiveMission = -1; + + this.Name = string.Empty; + this.AvatarCode = string.Empty; + + this.AvatarGames = new LogicArrayList(); + this.MissionStatus = new LogicArrayList(); + this.PlayerAttributes = new LogicPlayerAttributes(20486); + this.Inventory = new LogicInventory(20486); + this.PlayerStats = new LogicPlayerStats(20486); + } + + public override void Destruct() + { + base.Destruct(); + } + + public override void Decode(ByteStream byteStream) + { + base.Decode(byteStream); + } + + public override void Encode(ChecksumEncoder checksumEncoder) + { + base.Encode(checksumEncoder); + + checksumEncoder.WriteLong(this.Id); + checksumEncoder.WriteInt(this.ActiveMission); + checksumEncoder.WriteString(this.Name); + checksumEncoder.WriteString(this.AvatarCode); + + checksumEncoder.WriteInt(this.AvatarGames.Size()); + for (int i = 0; i < this.AvatarGames.Size(); i++) + { + this.AvatarGames[i].Encode(checksumEncoder); + } + + checksumEncoder.WriteInt(this.MissionStatus.Size()); + for (int i = 0; i < this.MissionStatus.Size(); i++) + { + checksumEncoder.WriteInt(this.MissionStatus[i]); + } + + this.PlayerAttributes.Encode(checksumEncoder); + this.Inventory.Encode(checksumEncoder); + this.PlayerStats.Encode(checksumEncoder); + + checksumEncoder.WriteInt(this.TutorialFlags); + } +} diff --git a/Supercell.GUT.Logic/Base/LogicBase.cs b/Supercell.GUT.Logic/Base/LogicBase.cs index a47f1e1..5c8d53e 100644 --- a/Supercell.GUT.Logic/Base/LogicBase.cs +++ b/Supercell.GUT.Logic/Base/LogicBase.cs @@ -1,5 +1,4 @@ -using Supercell.GUT.Titan.Encoding; -using Supercell.GUT.Titan.Encoding.Streamed; +using Supercell.GUT.Titan.Logic.DataStream; namespace Supercell.GUT.Logic.Base; @@ -31,7 +30,7 @@ public abstract class LogicBase { this.Destruct(); - ByteStream byteStream = new ByteStream(0); + ByteStream byteStream = new ByteStream(); logicBase.Encode(byteStream); byteStream.ResetOffset(); diff --git a/Supercell.GUT.Logic/Game/LogicGameCalendar.cs b/Supercell.GUT.Logic/Game/LogicGameCalendar.cs new file mode 100644 index 0000000..e2e98ae --- /dev/null +++ b/Supercell.GUT.Logic/Game/LogicGameCalendar.cs @@ -0,0 +1,59 @@ +using Supercell.GUT.Logic.Base; +using Supercell.GUT.Titan.Logic.DataStream; + +namespace Supercell.GUT.Logic.Game; + +public class LogicGameCalendar : LogicBase +{ + public LogicGameCalendar() : base(0) + { + ; + } + + public LogicGameCalendar(int logicDataVersion) : base(logicDataVersion) + { + ; + } + + public override void Encode(ChecksumEncoder checksumEncoder) + { + checksumEncoder.WriteInt(0); + checksumEncoder.WriteByte(0); + checksumEncoder.WriteByte(0); + checksumEncoder.WriteByte(0); + checksumEncoder.WriteByte(0); + checksumEncoder.WriteByte(0); + checksumEncoder.WriteInt(0); + checksumEncoder.WriteInt(0); + } + + public override void Decode(ByteStream byteStream) + { + ; + } + + public void CalculateDateVariablesFromDayIndex(int index) + { + ; + } + + public void AddSeconds(int seconds) + { + ; + } + + public int GetRemainingSeconds(LogicGameCalendar gameCalendar) + { + return 0; + } + + public void CalculateMonth(int month, bool isLeapYear) + { + ; + } + + public override void Destruct() + { + ; + } +} diff --git a/Supercell.GUT.Logic/Message/Account/CreateAccountFailedMessage.cs b/Supercell.GUT.Logic/Message/Account/CreateAccountFailedMessage.cs index 6338f5c..c32e531 100644 --- a/Supercell.GUT.Logic/Message/Account/CreateAccountFailedMessage.cs +++ b/Supercell.GUT.Logic/Message/Account/CreateAccountFailedMessage.cs @@ -1,5 +1,5 @@ using Supercell.GUT.Logic.Message.Attributes; -using Supercell.GUT.Titan.Message; +using Supercell.GUT.Titan.Logic.Message; namespace Supercell.GUT.Logic.Message.Account; diff --git a/Supercell.GUT.Logic/Message/Account/CreateAccountMessage.cs b/Supercell.GUT.Logic/Message/Account/CreateAccountMessage.cs index c1feb55..7f5ab6d 100644 --- a/Supercell.GUT.Logic/Message/Account/CreateAccountMessage.cs +++ b/Supercell.GUT.Logic/Message/Account/CreateAccountMessage.cs @@ -1,5 +1,5 @@ using Supercell.GUT.Logic.Message.Attributes; -using Supercell.GUT.Titan.Message; +using Supercell.GUT.Titan.Logic.Message; namespace Supercell.GUT.Logic.Message.Account; diff --git a/Supercell.GUT.Logic/Message/Account/CreateAccountOkMessage.cs b/Supercell.GUT.Logic/Message/Account/CreateAccountOkMessage.cs index 28ceaac..fe6e77e 100644 --- a/Supercell.GUT.Logic/Message/Account/CreateAccountOkMessage.cs +++ b/Supercell.GUT.Logic/Message/Account/CreateAccountOkMessage.cs @@ -1,5 +1,5 @@ using Supercell.GUT.Logic.Message.Attributes; -using Supercell.GUT.Titan.Message; +using Supercell.GUT.Titan.Logic.Message; namespace Supercell.GUT.Logic.Message.Account; diff --git a/Supercell.GUT.Logic/Message/Account/LoginFailedMessage.cs b/Supercell.GUT.Logic/Message/Account/LoginFailedMessage.cs new file mode 100644 index 0000000..4743d15 --- /dev/null +++ b/Supercell.GUT.Logic/Message/Account/LoginFailedMessage.cs @@ -0,0 +1,39 @@ +using Supercell.GUT.Logic.Message.Attributes; +using Supercell.GUT.Titan.Logic.Message; + +namespace Supercell.GUT.Logic.Message.Account; + +[VersionedMessage(20103)] +public class LoginFailedMessage : VersionedMessage +{ + public int ErrorCode { get; set; } + + public LoginFailedMessage() : base(0) + { + this.ErrorCode = 0; + } + + public override void Encode() + { + base.Encode(); + + this.ByteStream.WriteInt(this.ErrorCode); + } + + public override void Decode() + { + base.Decode(); + + this.ErrorCode = this.ByteStream.ReadInt(); + } + + public override int GetMessageType() + { + return 20103; + } + + public override int GetServiceNodeType() + { + return 1; + } +} diff --git a/Supercell.GUT.Logic/Message/Account/LoginOkMessage.cs b/Supercell.GUT.Logic/Message/Account/LoginOkMessage.cs new file mode 100644 index 0000000..20a967d --- /dev/null +++ b/Supercell.GUT.Logic/Message/Account/LoginOkMessage.cs @@ -0,0 +1,79 @@ +using Supercell.GUT.Logic.Game; +using Supercell.GUT.Logic.Message.Attributes; +using Supercell.GUT.Titan.Logic.Message; + +namespace Supercell.GUT.Logic.Message.Account; + +[VersionedMessage(20104)] +public class LoginOkMessage : VersionedMessage +{ + public int PrimaryAvatarIdHigherInt { get; set; } + public int PrimaryAvatarIdLowerInt { get; set; } + + public string? Fingerprint { get; set; } + + public int Env { get; set; } + public int ServerVersion { get; set; } + public int SessionCount { get; set; } + + public LogicGameCalendar ServerCalendar { get; set; } + + public LoginOkMessage() : base(0) + { + this.PrimaryAvatarIdHigherInt = 0; + this.PrimaryAvatarIdLowerInt = 0; + this.Fingerprint = string.Empty; + this.Env = 0; + this.ServerVersion = 0; + this.SessionCount = 0; + this.ServerCalendar = new LogicGameCalendar(); + } + + public override void Encode() + { + base.Encode(); + + this.ByteStream.WriteInt(0); + this.ByteStream.WriteInt(0); + this.ByteStream.WriteInt(this.PrimaryAvatarIdHigherInt); + this.ByteStream.WriteInt(this.PrimaryAvatarIdLowerInt); + this.ByteStream.WriteInt(0); + this.ByteStream.WriteInt(this.Env); + this.ByteStream.WriteInt(this.ServerVersion); + this.ByteStream.WriteInt(this.SessionCount); + this.ByteStream.WriteString(null); + this.ServerCalendar.Encode(this.ByteStream); + this.ByteStream.WriteString(null); + this.ByteStream.WriteString(this.Fingerprint); + this.ByteStream.WriteInt(0); + } + + public override void Decode() + { + base.Decode(); + + // TODO + } + + public override int GetMessageType() + { + return 20104; + } + + public override int GetServiceNodeType() + { + return 1; + } + + public override void Destruct() + { + base.Destruct(); + + this.PrimaryAvatarIdHigherInt = 0; + this.PrimaryAvatarIdLowerInt = 0; + this.Fingerprint = string.Empty; + this.Env = 0; + this.ServerVersion = 0; + this.SessionCount = 0; + } +} diff --git a/Supercell.GUT.Logic/Message/Account/LoginUsingSessionMessage.cs b/Supercell.GUT.Logic/Message/Account/LoginUsingSessionMessage.cs new file mode 100644 index 0000000..a03fc26 --- /dev/null +++ b/Supercell.GUT.Logic/Message/Account/LoginUsingSessionMessage.cs @@ -0,0 +1,73 @@ +using Supercell.GUT.Logic.Message.Attributes; +using Supercell.GUT.Titan.Logic.Message; + +namespace Supercell.GUT.Logic.Message.Account; + +[VersionedMessage(10102)] +public class LoginUsingSessionMessage : VersionedMessage +{ + public int AccountIdHigherInt { get; set; } + public int AccountIdLowerInt { get; set; } + public int ClientGameVersion { get; set; } + + public string? SessionKey { get; set; } + public string? GamecenterId { get; set; } + + public LoginUsingSessionMessage() : base(0) + { + this.AccountIdHigherInt = 0; + this.AccountIdLowerInt = 0; + this.ClientGameVersion = 0; + this.SessionKey = string.Empty; + this.SessionKey = string.Empty; + } + + public override void Encode() + { + base.Encode(); + + this.ByteStream.WriteInt(this.AccountIdHigherInt); + this.ByteStream.WriteInt(this.AccountIdLowerInt); + this.ByteStream.WriteInt(this.ClientGameVersion); + this.ByteStream.WriteInt(0); + this.ByteStream.WriteString(this.SessionKey); + this.ByteStream.WriteString(null); + this.ByteStream.WriteString(null); + this.ByteStream.WriteString(this.GamecenterId); + } + + public override void Decode() + { + base.Decode(); + + this.AccountIdHigherInt = this.ByteStream.ReadInt(); + this.AccountIdLowerInt = this.ByteStream.ReadInt(); + this.ClientGameVersion = this.ByteStream.ReadInt(); + this.ByteStream.ReadInt(); + this.SessionKey = this.ByteStream.ReadString(); + this.ByteStream.ReadString(); + this.ByteStream.ReadString(); + this.GamecenterId = this.ByteStream.ReadString(); + } + + public override int GetMessageType() + { + return 10102; + } + + public override int GetServiceNodeType() + { + return 1; + } + + public override void Destruct() + { + base.Destruct(); + + this.AccountIdHigherInt = 0; + this.AccountIdLowerInt = 0; + this.ClientGameVersion = 0; + this.SessionKey = string.Empty; + this.SessionKey = string.Empty; + } +} diff --git a/Supercell.GUT.Logic/Message/Account/SecureConnectionOkMessage.cs b/Supercell.GUT.Logic/Message/Account/SecureConnectionOkMessage.cs index 9f8f506..7d42c93 100644 --- a/Supercell.GUT.Logic/Message/Account/SecureConnectionOkMessage.cs +++ b/Supercell.GUT.Logic/Message/Account/SecureConnectionOkMessage.cs @@ -1,6 +1,6 @@ using Supercell.GUT.Logic.Message.Attributes; -using Supercell.GUT.Titan.Message; -using Supercell.GUT.Titan.Util; +using Supercell.GUT.Titan.Logic.Message; +using Supercell.GUT.Titan.Logic.Util; namespace Supercell.GUT.Logic.Message.Account; diff --git a/Supercell.GUT.Logic/Message/Account/StartSecureConnectionMessage.cs b/Supercell.GUT.Logic/Message/Account/StartSecureConnectionMessage.cs index 872dd1e..072be41 100644 --- a/Supercell.GUT.Logic/Message/Account/StartSecureConnectionMessage.cs +++ b/Supercell.GUT.Logic/Message/Account/StartSecureConnectionMessage.cs @@ -1,5 +1,5 @@ using Supercell.GUT.Logic.Message.Attributes; -using Supercell.GUT.Titan.Message; +using Supercell.GUT.Titan.Logic.Message; namespace Supercell.GUT.Logic.Message.Account; diff --git a/Supercell.GUT.Logic/Message/Avatar/AvatarDataMessage.cs b/Supercell.GUT.Logic/Message/Avatar/AvatarDataMessage.cs new file mode 100644 index 0000000..355785f --- /dev/null +++ b/Supercell.GUT.Logic/Message/Avatar/AvatarDataMessage.cs @@ -0,0 +1,46 @@ +using Supercell.GUT.Logic.Avatar; +using Supercell.GUT.Logic.Message.Attributes; +using Supercell.GUT.Titan.Logic.Message; + +namespace Supercell.GUT.Logic.Message.Avatar; + +[VersionedMessage(20201)] +public class AvatarDataMessage : VersionedMessage +{ + public LogicClientAvatar LogicClientAvatar { get; set; } + + public AvatarDataMessage() : base(0) + { + ; + } + + public override void Destruct() + { + base.Destruct(); + } + + public override void Encode() + { + base.Encode(); + + LogicClientAvatar.Encode(ByteStream); + } + + public override void Decode() + { + base.Decode(); + + LogicClientAvatar = new LogicClientAvatar(); + LogicClientAvatar.Decode(ByteStream); + } + + public override int GetMessageType() + { + return 20201; + } + + public override int GetServiceNodeType() + { + return 3; + } +} diff --git a/Supercell.GUT.Logic/Message/Avatar/SelectAvatarMessage.cs b/Supercell.GUT.Logic/Message/Avatar/SelectAvatarMessage.cs new file mode 100644 index 0000000..6c9bd30 --- /dev/null +++ b/Supercell.GUT.Logic/Message/Avatar/SelectAvatarMessage.cs @@ -0,0 +1,51 @@ +using Supercell.GUT.Logic.Message.Attributes; +using Supercell.GUT.Titan.Logic.Message; + +namespace Supercell.GUT.Logic.Message.Avatar; + +[VersionedMessage(10201)] +public class SelectAvatarMessage : VersionedMessage +{ + public int AvatarIdHigherInt { get; set; } + public int AvatarIdLowerInt { get; set; } + + public SelectAvatarMessage() : base(0) + { + AvatarIdHigherInt = 0; + AvatarIdLowerInt = 0; + } + + public override void Encode() + { + base.Encode(); + + ByteStream.WriteInt(AvatarIdHigherInt); + ByteStream.WriteInt(AvatarIdLowerInt); + } + + public override void Decode() + { + base.Decode(); + + AvatarIdHigherInt = ByteStream.ReadInt(); + AvatarIdLowerInt = ByteStream.ReadInt(); + } + + public override int GetMessageType() + { + return 10201; + } + + public override int GetServiceNodeType() + { + return 3; + } + + public override void Destruct() + { + base.Destruct(); + + AvatarIdHigherInt = 0; + AvatarIdLowerInt = 0; + } +} diff --git a/Supercell.GUT.Logic/Message/GUTMessageFactory.cs b/Supercell.GUT.Logic/Message/GUTMessageFactory.cs index 7024631..5a6b35f 100644 --- a/Supercell.GUT.Logic/Message/GUTMessageFactory.cs +++ b/Supercell.GUT.Logic/Message/GUTMessageFactory.cs @@ -1,5 +1,5 @@ using Supercell.GUT.Logic.Message.Attributes; -using Supercell.GUT.Titan.Message; +using Supercell.GUT.Titan.Logic.Message; using System.Collections.Immutable; using System.Reflection; diff --git a/Supercell.GUT.Logic/Player/LogicInventory.cs b/Supercell.GUT.Logic/Player/LogicInventory.cs new file mode 100644 index 0000000..9063984 --- /dev/null +++ b/Supercell.GUT.Logic/Player/LogicInventory.cs @@ -0,0 +1,34 @@ +using Supercell.GUT.Logic.Base; +using Supercell.GUT.Titan.Logic.DataStream; + +namespace Supercell.GUT.Logic.Player; + +public class LogicInventory : LogicBase +{ + public LogicInventory(int logicDataVersion) : base(logicDataVersion) + { + } + + public override void Destruct() + { + base.Destruct(); + } + + public override void Encode(ChecksumEncoder checksumEncoder) + { + base.Encode(checksumEncoder); + + checksumEncoder.WriteInt(0); + } + + public override void Decode(ByteStream byteStream) + { + base.Decode(byteStream); + + int count = byteStream.ReadInt(); + for (int i = 0; i < count; i++) + { + + } + } +} diff --git a/Supercell.GUT.Logic/Player/LogicPlayerAttributes.cs b/Supercell.GUT.Logic/Player/LogicPlayerAttributes.cs new file mode 100644 index 0000000..7dec821 --- /dev/null +++ b/Supercell.GUT.Logic/Player/LogicPlayerAttributes.cs @@ -0,0 +1,94 @@ +using Supercell.GUT.Logic.Base; +using Supercell.GUT.Logic.Team; +using Supercell.GUT.Titan.Logic.DataStream; +using Supercell.GUT.Titan.Logic.Util; + +namespace Supercell.GUT.Logic.Player; + +public class LogicPlayerAttributes : LogicBase +{ + public int ExpLevel { get; set; } + public int ExpPoints { get; set; } + public int Money { get; set; } + public int Diamonds { get; set; } + public int LeagueMmr { get; set; } + public int LeagueMmrKFactor { get; set; } + public string TeamName { get; set; } + public LogicArrayList TeamUnits { get; set; } + public LogicArrayList ReadHandbooks { get; set; } + + public LogicPlayerAttributes(int logicDataVersion) : base(logicDataVersion) + { + this.TeamName = string.Empty; + + this.TeamUnits = new LogicArrayList(); + + for (int i = 0; i <= 4; i++) + { + LogicTeamUnit logicTeamUnit = LogicTeamUnit.CreateDefaultUnit(i); + + switch (i) + { + case 0: + logicTeamUnit.SetSkill("sk_magnum0"); + break; + case 1: + logicTeamUnit.SetSkill("sk_grenade0"); + break; + case 2: + logicTeamUnit.SetSkill("sk_magnum0"); + break; + case 3: + logicTeamUnit.SetSkill("sk_magnum0"); + break; + case 4: + logicTeamUnit.SetSkill("sk_grenade0"); + break; + default: + break; + } + + this.TeamUnits.Add(logicTeamUnit); + } + + this.ReadHandbooks = new LogicArrayList(); + } + + public override void Destruct() + { + base.Destruct(); + } + + public override void Encode(ChecksumEncoder checksumEncoder) + { + base.Encode(checksumEncoder); + + checksumEncoder.WriteInt(this.ExpLevel); + checksumEncoder.WriteInt(this.ExpPoints); + checksumEncoder.WriteInt(this.Money); + checksumEncoder.WriteInt(this.Diamonds); + checksumEncoder.WriteInt(this.LeagueMmr); + checksumEncoder.WriteInt(this.LeagueMmrKFactor); + checksumEncoder.WriteString(this.TeamName); + + checksumEncoder.WriteInt(this.TeamUnits.Size()); + for (int i = 0; i < this.TeamUnits.Size(); i++) + { + this.TeamUnits[i].Encode(checksumEncoder); + } + + checksumEncoder.WriteInt(this.ReadHandbooks.Size()); + for (int i = 0; i < this.ReadHandbooks.Size(); i++) + { + checksumEncoder.WriteString(this.ReadHandbooks[i]); + } + + checksumEncoder.WriteInt(-1); + checksumEncoder.WriteInt(0); + } + + public override void Decode(ByteStream byteStream) + { + base.Decode(byteStream); + } +} diff --git a/Supercell.GUT.Logic/Player/LogicPlayerStats.cs b/Supercell.GUT.Logic/Player/LogicPlayerStats.cs new file mode 100644 index 0000000..bd82b3a --- /dev/null +++ b/Supercell.GUT.Logic/Player/LogicPlayerStats.cs @@ -0,0 +1,58 @@ +using Supercell.GUT.Logic.Base; +using Supercell.GUT.Titan.Logic.DataStream; + +namespace Supercell.GUT.Logic.Player; + +public class LogicPlayerStats : LogicBase +{ + public int Score { get; set; } + public int MatchCount { get; set; } + public int WinCount { get; set; } + public int KillCount { get; set; } + + public LogicPlayerStats() : base(20486) + { + this.Score = 0; + this.MatchCount = 0; + this.WinCount = 0; + this.KillCount = 0; + } + + public LogicPlayerStats(int logicDataVersion) : base(logicDataVersion) + { + this.Score = 0; + this.MatchCount = 0; + this.WinCount = 0; + this.KillCount = 0; + } + + public override void Destruct() + { + base.Destruct(); + + this.Score = 0; + this.MatchCount = 0; + this.WinCount = 0; + this.KillCount = 0; + } + + public override void Encode(ChecksumEncoder checksumEncoder) + { + base.Encode(checksumEncoder); + + checksumEncoder.WriteInt(this.Score); + checksumEncoder.WriteInt(this.MatchCount); + checksumEncoder.WriteInt(this.WinCount); + checksumEncoder.WriteInt(this.KillCount); + } + + public override void Decode(ByteStream byteStream) + { + base.Decode(byteStream); + + this.Score = byteStream.ReadInt(); + this.MatchCount = byteStream.ReadInt(); + this.WinCount = byteStream.ReadInt(); + this.KillCount = byteStream.ReadInt(); + } +} diff --git a/Supercell.GUT.Logic/Team/LogicTeamUnit.cs b/Supercell.GUT.Logic/Team/LogicTeamUnit.cs new file mode 100644 index 0000000..f6a45cf --- /dev/null +++ b/Supercell.GUT.Logic/Team/LogicTeamUnit.cs @@ -0,0 +1,54 @@ +using Supercell.GUT.Logic.Base; +using Supercell.GUT.Titan.Logic.DataStream; +using Supercell.GUT.Titan.Logic.Util; + +namespace Supercell.GUT.Logic.Team; +public class LogicTeamUnit : LogicBase +{ + public string Name { get; set; } + public LogicArrayList Skills { get; set; } + + public LogicTeamUnit() : base(0) + { + this.Skills = new LogicArrayList(); + } + + public override void Destruct() + { + base.Destruct(); + } + + public override void Encode(ChecksumEncoder checksumEncoder) + { + base.Encode(checksumEncoder); + + checksumEncoder.WriteInt(0); + checksumEncoder.WriteString(this.Name); + + checksumEncoder.WriteInt(this.Skills.Size()); + for (int i = 0; i < this.Skills.Size(); i++) + { + checksumEncoder.WriteString(this.Skills[i]); + } + + checksumEncoder.WriteString(null); + } + + public override void Decode(ByteStream byteStream) + { + base.Decode(byteStream); + } + + public void SetSkill(string skill) + { + this.Skills.Add(skill); + } + + public static LogicTeamUnit CreateDefaultUnit(int index) + { + return new LogicTeamUnit + { + Name = $"un_default{index}" + }; + } +} diff --git a/Supercell.GUT.SDK/Program.cs b/Supercell.GUT.SDK/Program.cs new file mode 100644 index 0000000..61144c0 --- /dev/null +++ b/Supercell.GUT.SDK/Program.cs @@ -0,0 +1,23 @@ +namespace Supercell.GUT.SDK; + +internal static class Program +{ + private static async Task Main(string[] args) + { + Console.Title = "Supercell.GUT | SDK"; + + WebApplicationBuilder builder = WebApplication.CreateBuilder(args); + builder.WebHost.UseUrls("http://*:80"); + + WebApplication app = builder.Build(); + + app.MapGet("/fece25cfc941db1a5bb3e79d4e6a60c34659f49e/fingerprint.json", GetFingerprintJSON); // hardcode! maybe later i will fix it + + await app.RunAsync(); + } + + private static string GetFingerprintJSON(HttpContext context) + { + return "{\"files\":[{\"sha\":\"505f650e5cabad8f139687c3f9aa66712d883a40\",\"file\":\"data\\/about.csv\",\"checksum\":\"71befcab\"},{\"sha\":\"51fde1a650aa0b66333ad5b66f59b22e8e54c4e5\",\"file\":\"data\\/ai_units.csv\",\"checksum\":\"afc97037\"},{\"sha\":\"19d3b1573cbd3ed59ee337c89bc5f82e8f30c68a\",\"file\":\"data\\/avatar.csv\",\"checksum\":\"f2eb9b6b\"},{\"sha\":\"0482673d8a493c8903babaf4066985e26018b919\",\"file\":\"data\\/billing_packages.csv\",\"checksum\":\"ce55b6c9\"},{\"sha\":\"97b4e6e365c9c110f38e5d55871512b75ce4bc3a\",\"file\":\"data\\/credits.csv\",\"checksum\":\"32376eed\"},{\"sha\":\"3cc18120f0fd00e073ace85d9326f38ce93b1cd7\",\"file\":\"data\\/cutscene.csv\",\"checksum\":\"b36efeb1\"},{\"sha\":\"b4dea5cb966a9a55eb050bdcab3cc39c6108509e\",\"file\":\"data\\/gadget.csv\",\"checksum\":\"4576288d\"},{\"sha\":\"03a0a7661ef1024d668ab0c5485696b05ccc5092\",\"file\":\"data\\/game_const.csv\",\"checksum\":\"e11bbf82\"},{\"sha\":\"fafee2358474f289ddefb241d6c8337908dc8168\",\"file\":\"data\\/gamelevel.csv\",\"checksum\":\"995dbb23\"},{\"sha\":\"a633224eee7bccb4ad0b10945694d7a70c5ad93d\",\"file\":\"data\\/gui.csv\",\"checksum\":\"27230b9d\"},{\"sha\":\"dee03d769deb41f0d823a77b8f95deccd5892fba\",\"file\":\"data\\/handbook.csv\",\"checksum\":\"e489859a\"},{\"sha\":\"ebe15e0d095677a16a3a2f466ce5cc8dd1972931\",\"file\":\"data\\/inboxmessage.csv\",\"checksum\":\"2fef1fae\"},{\"sha\":\"c0d921b74e476ea85470dfe97ca5de0b498764f6\",\"file\":\"data\\/item.csv\",\"checksum\":\"9ae439cd\"},{\"sha\":\"1e8b8532d5b6f2f9c129e6870f3b4529bb926479\",\"file\":\"data\\/lang.csv\",\"checksum\":\"b0acc094\"},{\"sha\":\"91e08d3857aab5ecceda43f9ae6b1d25def92f7c\",\"file\":\"data\\/leagues.csv\",\"checksum\":\"a448bd6e\"},{\"sha\":\"84b7125afd12c834e98ba0fd7eda3ba3c76246d7\",\"file\":\"data\\/level.csv\",\"checksum\":\"359e1925\"},{\"sha\":\"fe2aec13f1855e01ef6f8b255f0e7bf48cb58179\",\"file\":\"data\\/mission.csv\",\"checksum\":\"368649a8\"},{\"sha\":\"551df4fb20dba5a20e9281e50682d03f99859c9e\",\"file\":\"data\\/mission_tree.csv\",\"checksum\":\"55276023\"},{\"sha\":\"ae3ff2b07fcf5cef9a0f642c2ce6eae6ac00f0cd\",\"file\":\"data\\/moneybag.csv\",\"checksum\":\"29c04cff\"},{\"sha\":\"a8e4643f7157624432b6066e4d09d3722c40c4f3\",\"file\":\"data\\/readingtimes.csv\",\"checksum\":\"1e7bdc9b\"},{\"sha\":\"953289348875f3d8f6502d6cc1f60ea333841f8a\",\"file\":\"data\\/shop.csv\",\"checksum\":\"20449e2e\"},{\"sha\":\"a0f879b889aa8a25dcf03bf2d2bde85d9544600e\",\"file\":\"data\\/skill.csv\",\"checksum\":\"61288ccd\"},{\"sha\":\"e4c8e78e8aa71b70feb8c0959fd4c9a7e183bfbd\",\"file\":\"data\\/sounds.csv\",\"checksum\":\"195e7e52\"},{\"sha\":\"20495a2034755d8042016965ccea119f2efb173d\",\"file\":\"data\\/sounds_ipad1.csv\",\"checksum\":\"1531642f\"},{\"sha\":\"3b5047a6c8fab85bb8b0b313b8faabd61151bea1\",\"file\":\"data\\/speedup.csv\",\"checksum\":\"c96ef3ea\"},{\"sha\":\"1388ecfea65b98d1e9e4be785dac1a8a5964df57\",\"file\":\"data\\/trainingtimes.csv\",\"checksum\":\"811f4bd1\"},{\"sha\":\"a3055faddd0a1eff4f4da59df958235e3e5521c9\",\"file\":\"data\\/unit.csv\",\"checksum\":\"3c1ba78c\"},{\"sha\":\"6d37f4b27604df00c356e6776c6639b2e06a3669\",\"file\":\"data\\/upgrade.csv\",\"checksum\":\"e5f57998\"},{\"sha\":\"de893824bdf5e43ac377b276520ec65f399bb987\",\"file\":\"data\\/weapon.csv\",\"checksum\":\"a3079a59\"},{\"sha\":\"828dc22a8256dc0ffbc790983ad6a535221fe01d\",\"file\":\"gut.ini\",\"checksum\":\"601b736\"},{\"sha\":\"828dc22a8256dc0ffbc790983ad6a535221fe01d\",\"file\":\"gut_ipad2.ini\",\"checksum\":\"601b736\"},{\"sha\":\"828dc22a8256dc0ffbc790983ad6a535221fe01d\",\"file\":\"gut_ipad3.ini\",\"checksum\":\"601b736\"},{\"sha\":\"0d643a9c5bf2b8be58ba76cc0b3d25d84618a305\",\"file\":\"gut_iphone3.ini\",\"checksum\":\"5e8a6d2c\"},{\"sha\":\"0d643a9c5bf2b8be58ba76cc0b3d25d84618a305\",\"file\":\"gut_iphone4.ini\",\"checksum\":\"5e8a6d2c\"}],\"sha\":\"fece25cfc941db1a5bb3e79d4e6a60c34659f49e\"}\r\n"; + } +} diff --git a/Supercell.GUT.SDK/Properties/launchSettings.json b/Supercell.GUT.SDK/Properties/launchSettings.json new file mode 100644 index 0000000..52f9e3c --- /dev/null +++ b/Supercell.GUT.SDK/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:63724", + "sslPort": 0 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "http://localhost:5223", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/Supercell.GUT.SDK/Supercell.GUT.SDK.csproj b/Supercell.GUT.SDK/Supercell.GUT.SDK.csproj new file mode 100644 index 0000000..1b28a01 --- /dev/null +++ b/Supercell.GUT.SDK/Supercell.GUT.SDK.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/Supercell.GUT.SDK/appsettings.Development.json b/Supercell.GUT.SDK/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/Supercell.GUT.SDK/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/Supercell.GUT.SDK/appsettings.json b/Supercell.GUT.SDK/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/Supercell.GUT.SDK/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/Supercell.GUT.Server/Debugging/ServerDebuggerListener.cs b/Supercell.GUT.Server/Debugging/ServerDebuggerListener.cs index f85ffe9..d4816ae 100644 --- a/Supercell.GUT.Server/Debugging/ServerDebuggerListener.cs +++ b/Supercell.GUT.Server/Debugging/ServerDebuggerListener.cs @@ -1,5 +1,5 @@ using Microsoft.Extensions.Logging; -using Supercell.GUT.Titan.Debugging; +using Supercell.GUT.Titan.Logic.Debug; namespace Supercell.GUT.Server.Debugging; internal class ServerDebuggerListener : IDebuggerListener diff --git a/Supercell.GUT.Server/GUTServer.cs b/Supercell.GUT.Server/GUTServer.cs index 789e649..9e666fa 100644 --- a/Supercell.GUT.Server/GUTServer.cs +++ b/Supercell.GUT.Server/GUTServer.cs @@ -1,6 +1,6 @@ using Microsoft.Extensions.Hosting; using Supercell.GUT.Server.Network; -using Supercell.GUT.Titan.Debugging; +using Supercell.GUT.Titan.Logic.Debug; namespace Supercell.GUT.Server; internal class GUTServer : IHostedService diff --git a/Supercell.GUT.Server/Network/Connection/ClientConnection.cs b/Supercell.GUT.Server/Network/Connection/ClientConnection.cs index 2828436..60f34f5 100644 --- a/Supercell.GUT.Server/Network/Connection/ClientConnection.cs +++ b/Supercell.GUT.Server/Network/Connection/ClientConnection.cs @@ -1,6 +1,6 @@ using Supercell.GUT.Logic; using Supercell.GUT.Server.Protocol; -using Supercell.GUT.Titan.Message; +using Supercell.GUT.Titan.Logic.Message; namespace Supercell.GUT.Server.Network.Connection; internal class ClientConnection diff --git a/Supercell.GUT.Server/Network/Connection/IConnectionListener.cs b/Supercell.GUT.Server/Network/Connection/IConnectionListener.cs index a66e147..cb4bbff 100644 --- a/Supercell.GUT.Server/Network/Connection/IConnectionListener.cs +++ b/Supercell.GUT.Server/Network/Connection/IConnectionListener.cs @@ -1,4 +1,4 @@ -using Supercell.GUT.Titan.Message; +using Supercell.GUT.Titan.Logic.Message; namespace Supercell.GUT.Server.Network.Connection; internal interface IConnectionListener diff --git a/Supercell.GUT.Server/Program.cs b/Supercell.GUT.Server/Program.cs index 095ceb4..43a192b 100644 --- a/Supercell.GUT.Server/Program.cs +++ b/Supercell.GUT.Server/Program.cs @@ -9,8 +9,8 @@ using Supercell.GUT.Server.Network.Options; using Supercell.GUT.Server.Network.Tcp; using Supercell.GUT.Server.Protocol; using Supercell.GUT.Server.Protocol.Extensions; -using Supercell.GUT.Titan.Debugging; -using Supercell.GUT.Titan.Message; +using Supercell.GUT.Titan.Logic.Debug; +using Supercell.GUT.Titan.Logic.Message; namespace Supercell.GUT.Server; diff --git a/Supercell.GUT.Server/Protocol/Handlers/AccountMessageHandler.cs b/Supercell.GUT.Server/Protocol/Handlers/AccountMessageHandler.cs index 69b89d7..70c60c6 100644 --- a/Supercell.GUT.Server/Protocol/Handlers/AccountMessageHandler.cs +++ b/Supercell.GUT.Server/Protocol/Handlers/AccountMessageHandler.cs @@ -41,7 +41,26 @@ internal class AccountMessageHandler : MessageHandlerBase { AccountIdHigherInt = 0, AccountIdLowerInt = 1, - SessionKey = "telegram_is_@BL4D3_BR43D" + SessionKey = "telegram_is_@BL4D3_BR34D" + }); + } + + [MessageHandler(10102)] + public async Task OnLoginUsingSession(LoginUsingSessionMessage loginUsingSessionMessage) + { + _logger.LogInformation("Logging account! sessionkey: {sk} | GameCenterId: {gcid} | GameVersion: {cgv} | account: ({h}-{l})", + loginUsingSessionMessage.SessionKey, + loginUsingSessionMessage.GamecenterId, + loginUsingSessionMessage.ClientGameVersion, + loginUsingSessionMessage.AccountIdHigherInt, + loginUsingSessionMessage.AccountIdLowerInt); + + await _connection.SendMessage(new LoginOkMessage() + { + PrimaryAvatarIdHigherInt = loginUsingSessionMessage.AccountIdHigherInt, + PrimaryAvatarIdLowerInt = loginUsingSessionMessage.AccountIdLowerInt, + + Fingerprint = "fece25cfc941db1a5bb3e79d4e6a60c34659f49e" }); } } diff --git a/Supercell.GUT.Server/Protocol/Handlers/AvatarMessageHandler.cs b/Supercell.GUT.Server/Protocol/Handlers/AvatarMessageHandler.cs new file mode 100644 index 0000000..b5fcdd9 --- /dev/null +++ b/Supercell.GUT.Server/Protocol/Handlers/AvatarMessageHandler.cs @@ -0,0 +1,42 @@ +using Microsoft.Extensions.Logging; +using Supercell.GUT.Logic.Avatar; +using Supercell.GUT.Logic.Message.Avatar; +using Supercell.GUT.Server.Network.Connection; +using Supercell.GUT.Server.Protocol.Attributes; +using Supercell.GUT.Titan.Logic.Math; + +namespace Supercell.GUT.Server.Protocol.Handlers; + +[ServiceNode(3)] +internal class AvatarMessageHandler : MessageHandlerBase +{ + private readonly ILogger _logger; + private readonly ClientConnection _connection; + + public AvatarMessageHandler(ClientConnection connection, ILogger logger) + { + _logger = logger; + _connection = connection; + } + + [MessageHandler(10201)] + public async Task OnSelectAvatar(SelectAvatarMessage selectAvatarMessage) + { + _logger.LogInformation("selecting avatar! avatar: ({h}-{l})", + selectAvatarMessage.AvatarIdHigherInt, + selectAvatarMessage.AvatarIdLowerInt); + + await _connection.SendMessage(new AvatarDataMessage() + { + LogicClientAvatar = new LogicClientAvatar() + { + Id = new LogicLong(selectAvatarMessage.AvatarIdHigherInt, selectAvatarMessage.AvatarIdLowerInt), + + Name = "BreadDEV", + AvatarCode = "a1", + + TutorialFlags = 999999 + } + }); + } +} diff --git a/Supercell.GUT.Server/Protocol/Handlers/MessageHandlerBase.cs b/Supercell.GUT.Server/Protocol/Handlers/MessageHandlerBase.cs index 8f71a41..ccceebb 100644 --- a/Supercell.GUT.Server/Protocol/Handlers/MessageHandlerBase.cs +++ b/Supercell.GUT.Server/Protocol/Handlers/MessageHandlerBase.cs @@ -1,7 +1,7 @@ using System.Collections.Immutable; using System.Reflection; using Supercell.GUT.Server.Protocol.Attributes; -using Supercell.GUT.Titan.Message; +using Supercell.GUT.Titan.Logic.Message; namespace Supercell.GUT.Server.Protocol.Handlers; internal abstract class MessageHandlerBase diff --git a/Supercell.GUT.Server/Protocol/MessageManager.cs b/Supercell.GUT.Server/Protocol/MessageManager.cs index 1dc1707..fa6fae1 100644 --- a/Supercell.GUT.Server/Protocol/MessageManager.cs +++ b/Supercell.GUT.Server/Protocol/MessageManager.cs @@ -4,7 +4,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Supercell.GUT.Server.Protocol.Attributes; using Supercell.GUT.Server.Protocol.Handlers; -using Supercell.GUT.Titan.Message; +using Supercell.GUT.Titan.Logic.Message; namespace Supercell.GUT.Server.Protocol; internal class MessageManager diff --git a/Supercell.GUT.Server/Protocol/Messaging.cs b/Supercell.GUT.Server/Protocol/Messaging.cs index 015e647..1d2eff8 100644 --- a/Supercell.GUT.Server/Protocol/Messaging.cs +++ b/Supercell.GUT.Server/Protocol/Messaging.cs @@ -1,7 +1,7 @@ using Microsoft.Extensions.Logging; using Supercell.GUT.Server.Network.Connection; using Supercell.GUT.Titan.Encryption; -using Supercell.GUT.Titan.Message; +using Supercell.GUT.Titan.Logic.Message; namespace Supercell.GUT.Server.Protocol; internal class Messaging : IConnectionListener @@ -73,7 +73,7 @@ internal class Messaging : IConnectionListener { if (message.ByteStream.Offset == 0) message.Encode(); - byte[] encodingBytes = message.ByteStream.Buffer.Take(message.ByteStream.Offset).ToArray(); + byte[] encodingBytes = message.ByteStream.ByteArray!.Take(message.ByteStream.Offset).ToArray(); _encrypter?.Encrypt(encodingBytes); diff --git a/Supercell.GUT.Titan/Encoding/ChecksumEncoder.cs b/Supercell.GUT.Titan/Encoding/ChecksumEncoder.cs deleted file mode 100644 index c388f33..0000000 --- a/Supercell.GUT.Titan/Encoding/ChecksumEncoder.cs +++ /dev/null @@ -1,79 +0,0 @@ -using Supercell.GUT.Titan.Math; -using System.Runtime.CompilerServices; - -namespace Supercell.GUT.Titan.Encoding; -public class ChecksumEncoder -{ - private int _checksum; - private int _snapshotChecksum; - - public ChecksumEncoder() - { - IsChecksumEnabled = true; - } - - public virtual bool IsCheckSumOnlyMode => true; - - public virtual ChecksumEncoder WriteBoolean(bool value) => UpdateCheckSum(value ? 13 : 7); - - public virtual ChecksumEncoder WriteByte(byte value) => UpdateCheckSum(value + 11); - - public virtual ChecksumEncoder WriteShort(short value) => UpdateCheckSum(value + 19); - - public virtual ChecksumEncoder WriteInt(int value) => UpdateCheckSum(value + 9); - - public virtual void WriteLong(LogicLong value) => value.Encode(this); - - public virtual ChecksumEncoder WriteString(string? value) => - UpdateCheckSum(value != null ? value.Length + 28 : 27); - - public virtual ChecksumEncoder WriteBytes(ReadOnlySpan value) => - UpdateCheckSum(value.Length + 28); - - public bool IsChecksumEnabled { get; private set; } - - public int CheckSum => IsChecksumEnabled ? _checksum : _snapshotChecksum; - - public ChecksumEncoder EnableCheckSum(bool enable) - { - if (!IsChecksumEnabled && enable) - { - _checksum = _snapshotChecksum; - } - else - { - _snapshotChecksum = _checksum; - } - - IsChecksumEnabled = enable; - return this; - } - - public ChecksumEncoder ResetCheckSum() - { - _checksum = 0; - return this; - } - - public override bool Equals(object? obj) - { - ChecksumEncoder? otherEncoder = obj as ChecksumEncoder; - return otherEncoder?.CheckSum == CheckSum; - } - - public override int GetHashCode() - { - // original: Debugger::error("ChecksumEncoder hashCode not designed"); - return CheckSum; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private ChecksumEncoder UpdateCheckSum(int value) - { - _checksum = value + Ror4(_checksum, 31); - return this; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int Ror4(int v, int c) => v >> c | v << 32 - c; -} diff --git a/Supercell.GUT.Titan/Encoding/Streamed/ByteStream.cs b/Supercell.GUT.Titan/Encoding/Streamed/ByteStream.cs deleted file mode 100644 index 8ccce37..0000000 --- a/Supercell.GUT.Titan/Encoding/Streamed/ByteStream.cs +++ /dev/null @@ -1,302 +0,0 @@ -using Supercell.GUT.Titan.Math; -using System.Buffers.Binary; -using System.Runtime.CompilerServices; -using TextEncoding = System.Text.Encoding; - -namespace Supercell.GUT.Titan.Encoding.Streamed; - -public class ByteStream : ChecksumEncoder -{ - public byte[] Buffer { get; set; } - - private int _bitIndex; - private int _length; - - public int Offset { get; set; } - - public int Length => _length > 0 ? _length : Offset; - - public ByteStream(byte[] buffer, int length) - { - Buffer = buffer; - _length = length; - } - - public ByteStream(int capacity) - { - Buffer = new byte[capacity]; - } - - public ByteStream() - { - Buffer = new byte[10]; - } - - public void SetByteArray(byte[] buffer, int length) - { - Buffer = buffer; - _length = length; - } - - public bool ReadBoolean() - { - if (_bitIndex == 0) - ++Offset; - - bool value = (Buffer[Offset - 1] & 1 << _bitIndex) != 0; - _bitIndex = _bitIndex + 1 & 7; - return value; - } - - public byte ReadByte() - { - _bitIndex = 0; - return Buffer[Offset++]; - } - - public short ReadShort() - { - _bitIndex = 0; - - short ret = BinaryPrimitives.ReadInt16BigEndian(Buffer.AsSpan()[Offset..]); - Offset += 2; - - return ret; - } - - public int ReadInt() - { - _bitIndex = 0; - - int ret = BinaryPrimitives.ReadInt32BigEndian(Buffer.AsSpan()[Offset..]); - Offset += 4; - - return ret; - } - - public int ReadVInt() - { - _bitIndex = 0; - - int value = 0; - byte byteValue = Buffer[Offset++]; - - if ((byteValue & 0x40) != 0) - { - value |= byteValue & 0x3F; - - if ((byteValue & 0x80) != 0) - { - value |= ((byteValue = Buffer[Offset++]) & 0x7F) << 6; - - if ((byteValue & 0x80) != 0) - { - value |= ((byteValue = Buffer[Offset++]) & 0x7F) << 13; - - if ((byteValue & 0x80) != 0) - { - value |= ((byteValue = Buffer[Offset++]) & 0x7F) << 20; - - if ((byteValue & 0x80) != 0) - { - value |= ((_ = Buffer[Offset++]) & 0x7F) << 27; - return (int)(value | 0x80000000); - } - - return (int)(value | 0xF8000000); - } - - return (int)(value | 0xFFF00000); - } - - return (int)(value | 0xFFFFE000); - } - - return (int)(value | 0xFFFFFFC0); - } - - value |= byteValue & 0x3F; - - if ((byteValue & 0x80) != 0) - { - value |= ((byteValue = Buffer[Offset++]) & 0x7F) << 6; - - if ((byteValue & 0x80) != 0) - { - value |= ((byteValue = Buffer[Offset++]) & 0x7F) << 13; - - if ((byteValue & 0x80) != 0) - { - value |= ((byteValue = Buffer[Offset++]) & 0x7F) << 20; - - if ((byteValue & 0x80) != 0) - { - value |= ((_ = Buffer[Offset++]) & 0x7F) << 27; - } - } - } - } - - return value; - } - - public LogicLong ReadLong() - { - LogicLong ll = new(); - ll.Decode(this); - - return ll; - } - - public string? ReadString() - { - int length = ReadInt(); - if (length is < 0 or > 900000) - return null; - else if (length == 0) - return string.Empty; - - string ret = TextEncoding.UTF8.GetString(Buffer, Offset, length); - Offset += length; - - return ret; - } - - public string ReadStringReference() - { - int length = ReadInt(); - if (length is <= 0 or > 900000) return string.Empty; - - string ret = TextEncoding.UTF8.GetString(Buffer, Offset, length); - Offset += length; - - return ret; - } - - public byte[] ReadBytes(int length) - { - _bitIndex = 0; - - byte[] ret = Buffer.Skip(Offset).Take(length).ToArray(); - Offset += length; - - return ret; - } - - public override ChecksumEncoder WriteBoolean(bool value) - { - base.WriteBoolean(value); - - if (_bitIndex == 0) - { - EnsureCapacity(1); - Buffer[Offset++] = 0; - } - - Buffer[Offset - 1] |= (byte)(value ? 1 : 0); - _bitIndex = _bitIndex + 1 & 7; - - return this; - } - - public override ChecksumEncoder WriteByte(byte value) - { - base.WriteByte(value); - EnsureCapacity(1); - - Buffer[Offset++] = value; - - return this; - } - - public override ChecksumEncoder WriteShort(short value) - { - base.WriteShort(value); - EnsureCapacity(2); - - BinaryPrimitives.WriteInt16BigEndian(Buffer.AsSpan()[Offset..], value); - Offset += 2; - - return this; - } - - public override ChecksumEncoder WriteInt(int value) - { - base.WriteInt(value); - EnsureCapacity(4); - - WriteIntToByteArray(value); - return this; - } - - public override ChecksumEncoder WriteString(string? value) - { - base.WriteString(value); - if (value == null) - { - WriteIntToByteArray(-1); - return this; - } - - int size = TextEncoding.UTF8.GetByteCount(value); - WriteIntToByteArray(size); - - EnsureCapacity(size); - TextEncoding.UTF8.GetBytes(value, Buffer.AsSpan()[Offset..]); - - Offset += size; - return this; - } - - public override ChecksumEncoder WriteBytes(ReadOnlySpan value) - { - base.WriteBytes(value); - - WriteIntToByteArray(value.Length); - - EnsureCapacity(value.Length); - value.CopyTo(Buffer.AsSpan()[Offset..]); - Offset += value.Length; - - return this; - } - - public override bool IsCheckSumOnlyMode => false; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void WriteIntToByteArray(int value) - { - EnsureCapacity(4); - - BinaryPrimitives.WriteInt32BigEndian(Buffer.AsSpan()[Offset..], value); - Offset += 4; - } - - public void EnsureCapacity(int capacity) - { - _bitIndex = 0; - int bufferLength = Buffer.Length; - - if (Offset + capacity > bufferLength) - { - byte[] tmpBuffer = new byte[Buffer.Length + capacity + 100]; - System.Buffer.BlockCopy(Buffer, 0, tmpBuffer, 0, bufferLength); - Buffer = tmpBuffer; - } - } - - public bool IsAtEnd() - { - return Offset >= Buffer.Length; - } - - public void ResetOffset() - { - this.Offset = 0; - } - - public void Destruct() - { - ; - } -} \ No newline at end of file diff --git a/Supercell.GUT.Titan/Logic/DataStream/ByteStream.cs b/Supercell.GUT.Titan/Logic/DataStream/ByteStream.cs new file mode 100644 index 0000000..24f1f19 --- /dev/null +++ b/Supercell.GUT.Titan/Logic/DataStream/ByteStream.cs @@ -0,0 +1,298 @@ +using Supercell.GUT.Titan.Logic.Debug; +using Supercell.GUT.Titan.Logic.Math; +using Supercell.GUT.Titan.Logic.Util; + +namespace Supercell.GUT.Titan.Logic.DataStream; + +public class ByteStream : ChecksumEncoder +{ + public int Offset { get; set; } + public int Length { get; set; } + public int BitIndex { get; set; } + + public byte[]? ByteArray { get; set; } + + public ByteStream() : base() + { + this.Offset = 0; + this.Length = 0; + this.BitIndex = 0; + + this.ByteArray = new byte[10]; + } + + public void ResetOffset() + { + this.Offset = 0; + this.BitIndex = 0; + } + + public int GetLength() + { + if (this.Offset < this.Length) + return this.Length; + + return this.Offset; + } + + public override bool IsCheckSumOnlyMode() + { + return false; + } + + public void SetOffset(int offset) + { + this.Offset = offset; + this.BitIndex = 0; + } + + public int GetOffset() + { + return this.Offset; + } + + public override void WriteString(string? value) + { + base.WriteString(value); + + if (value == null) + { + this.WriteIntToByteArray(-1); + } + else + { + byte[] bytes = LogicStringUtil.GetBytes(value); + int length = bytes.Length; + + if (length <= 900000) + { + this.EnsureCapacity(length + 4); + this.WriteIntToByteArray(length); + + Buffer.BlockCopy(bytes, 0, this.ByteArray!, this.Offset, length); + + this.Offset += length; + } + else + { + Debugger.Warning("ByteStream::writeString invalid string length " + length); + this.WriteIntToByteArray(-1); + } + } + } + + public void WriteIntToByteArray(int value) + { + this.EnsureCapacity(4); + + this.BitIndex = 0; + + this.ByteArray![this.Offset++] = (byte)(value >> 24); + this.ByteArray![this.Offset++] = (byte)(value >> 16); + this.ByteArray![this.Offset++] = (byte)(value >> 8); + this.ByteArray![this.Offset++] = (byte)value; + } + + public string? ReadString() + { + int length = this.ReadInt(); + if (length > -1) + { + if (length >= 900001) + { + Debugger.Error("Too long String encountered."); + } + + string result = LogicStringUtil.CreateString(this.ByteArray!, this.Offset, length); + + this.Offset += length; + + return result; + } + else + { + if (length != -1) + Debugger.Error("Negative String length encountered."); + } + + return null; + } + + public override void WriteBoolean(bool value) + { + base.WriteBoolean(value); + + if (this.BitIndex == 0) + { + this.EnsureCapacity(1); + this.ByteArray![this.Offset++] = 0; + } + + if (value) + this.ByteArray![this.Offset - 1] |= (byte)(1 << this.BitIndex); + + this.BitIndex = (this.BitIndex + 1) & 7; + } + + public bool ReadBoolean() + { + if (this.BitIndex == 0) + ++this.Offset; + + bool value = (this.ByteArray![this.Offset - 1] & (1 << this.BitIndex)) != 0; + this.BitIndex = (this.BitIndex + 1) & 7; + return value; + } + + public override void WriteInt(int value) + { + base.WriteInt(value); + this.WriteIntToByteArray(value); + } + + public override void WriteByte(byte value) + { + base.WriteByte(value); + this.EnsureCapacity(1); + + this.BitIndex = 0; + + this.ByteArray![this.Offset++] = (byte)value; + } + + public override void WriteShort(short value) + { + base.WriteShort(value); + this.EnsureCapacity(2); + + this.BitIndex = 0; + + this.ByteArray![this.Offset++] = (byte)(value >> 8); + this.ByteArray[this.Offset++] = (byte)value; + } + + public int ReadInt() + { + this.BitIndex = 0; + + return (this.ByteArray![this.Offset++] << 24) | + (this.ByteArray[this.Offset++] << 16) | + (this.ByteArray[this.Offset++] << 8) | + this.ByteArray[this.Offset++]; + } + + public byte ReadByte() + { + this.BitIndex = 0; + + return this.ByteArray![this.Offset++]; + } + + public short ReadShort() + { + this.BitIndex = 0; + + return (short)((this.ByteArray![this.Offset++] << 8) | + this.ByteArray[this.Offset++]); + } + + public LogicLong ReadLong() + { + return this.ReadLong(null); + } + + public LogicLong ReadLong(LogicLong? logicLong) + { + LogicLong? v2 = logicLong; + if (logicLong == null) + v2 = new LogicLong(); + + v2!.Decode(this); + + return v2; + } + + public override void WriteBytes(byte[]? value, int length) + { + base.WriteBytes(value, length); + + if (value == null) + { + this.WriteIntToByteArray(-1); + } + else + { + this.EnsureCapacity(length + 4); + this.WriteIntToByteArray(length); + + Buffer.BlockCopy(value, 0, this.ByteArray!, this.Offset, length); + + this.Offset += length; + } + } + + public int ReadBytesLength() + { + return this.ReadInt(); + } + + public byte[]? ReadBytes(int length) + { + this.BitIndex = 0; + + if (length > -1) + { + byte[] array = new byte[length]; + Buffer.BlockCopy(this.ByteArray!, this.Offset, array, 0, length); + this.Offset += length; + return array; + } + else + { + if (length != -1) + Debugger.Error("Negative readBytes length encountered."); + } + + return null; + } + + public void SetByteArray(byte[] byteArray, int length) + { + this.Offset = 0; + this.Length = length; + this.BitIndex = 0; + + this.ByteArray = byteArray; + } + + public override void Destruct() + { + this.Offset = 0; + this.Length = 0; + this.BitIndex = 0; + + this.ByteArray = null; + } + + public bool IsAtEnd() + { + return this.Offset >= this.Length; + } + + public byte GetDataPointer() + { + return this.ByteArray![this.Offset]; + } + + private void EnsureCapacity(int capacity) + { + int bufferLength = this.ByteArray!.Length; + + if (this.Offset + capacity > bufferLength) + { + byte[] tmpBuffer = new byte[this.ByteArray.Length + capacity + 100]; + Buffer.BlockCopy(this.ByteArray, 0, tmpBuffer, 0, bufferLength); + this.ByteArray = tmpBuffer; + } + } +} \ No newline at end of file diff --git a/Supercell.GUT.Titan/Logic/DataStream/ChecksumEncoder.cs b/Supercell.GUT.Titan/Logic/DataStream/ChecksumEncoder.cs new file mode 100644 index 0000000..85c8d9a --- /dev/null +++ b/Supercell.GUT.Titan/Logic/DataStream/ChecksumEncoder.cs @@ -0,0 +1,98 @@ +using Supercell.GUT.Titan.Logic.Math; + +namespace Supercell.GUT.Titan.Logic.DataStream; + +public class ChecksumEncoder +{ + public int CheckSum { get; set; } + public int SnapshotCheckSum { get; set; } + public bool IsChecksumEnabled { get; set; } + + public ChecksumEncoder() + { + this.CheckSum = 0; + this.SnapshotCheckSum = 0; + this.IsChecksumEnabled = true; + } + + public virtual bool IsCheckSumOnlyMode() + { + return true; + } + + public virtual void WriteString(string? value) + { + int v2 = (this.CheckSum >> 0x1F) & 0x7FFFFFFF | (2 * this.CheckSum); + if (value != null) + this.CheckSum = value.Length + v2 + 28; + else + this.CheckSum = v2 + 0x1B; + } + + public virtual void WriteBoolean(bool value) + { + int v2 = 7; + if (value) + v2 = 13; + this.CheckSum = ((this.CheckSum >> 0x1F) & 0x7FFFFFFF | (2 * this.CheckSum)) + v2; + } + + public virtual void WriteInt(int value) + { + this.CheckSum = ((this.CheckSum >> 0x1F) & 0x7FFFFFFF | (2 * this.CheckSum)) + value + 9; + } + + public virtual void WriteByte(byte value) + { + this.CheckSum = ((this.CheckSum >> 0x1F) & 0x7FFFFFFF | (2 * this.CheckSum)) + value + 11; + } + + public virtual void WriteShort(short value) + { + this.CheckSum = ((this.CheckSum >> 0x1F) & 0x7FFFFFFF | (2 * this.CheckSum)) + value + 19; + } + + public virtual void WriteBytes(byte[]? value, int length) + { + int v3 = (this.CheckSum >> 0x1F) & 0x7FFFFFFF | (2 * this.CheckSum); + + if (value != null) + this.CheckSum = length + v3 + 28; + else + this.CheckSum = v3 + 0x1B; + } + + public virtual void WriteLong(LogicLong logicLong) + { + logicLong.Encode(this); + } + + public override bool Equals(object? obj) + { + if (obj != null && obj is ChecksumEncoder checksumEncoder) + { + bool v4 = this.IsChecksumEnabled; + int v5 = checksumEncoder.CheckSum; + bool v6 = checksumEncoder.IsChecksumEnabled; + int v7 = checksumEncoder.SnapshotCheckSum; + if (!v6) + v5 = v7; + int v8 = this.CheckSum; + int v9 = this.SnapshotCheckSum; + int v10 = v5; + if (!v4) + v8 = v9; + if (v8 == v10) + return true; + } + + return false; + } + + public virtual void Destruct() + { + this.CheckSum = 0; + this.SnapshotCheckSum = 0; + this.IsChecksumEnabled = true; + } +} diff --git a/Supercell.GUT.Titan/Debugging/Debugger.cs b/Supercell.GUT.Titan/Logic/Debug/Debugger.cs similarity index 94% rename from Supercell.GUT.Titan/Debugging/Debugger.cs rename to Supercell.GUT.Titan/Logic/Debug/Debugger.cs index 6f0942a..714e027 100644 --- a/Supercell.GUT.Titan/Debugging/Debugger.cs +++ b/Supercell.GUT.Titan/Logic/Debug/Debugger.cs @@ -1,4 +1,5 @@ -namespace Supercell.GUT.Titan.Debugging; +namespace Supercell.GUT.Titan.Logic.Debug; + public static class Debugger { private static IDebuggerListener? _listener; diff --git a/Supercell.GUT.Titan/Debugging/IDebuggerListener.cs b/Supercell.GUT.Titan/Logic/Debug/IDebuggerListener.cs similarity index 79% rename from Supercell.GUT.Titan/Debugging/IDebuggerListener.cs rename to Supercell.GUT.Titan/Logic/Debug/IDebuggerListener.cs index d6dc866..97e7e16 100644 --- a/Supercell.GUT.Titan/Debugging/IDebuggerListener.cs +++ b/Supercell.GUT.Titan/Logic/Debug/IDebuggerListener.cs @@ -1,4 +1,5 @@ -namespace Supercell.GUT.Titan.Debugging; +namespace Supercell.GUT.Titan.Logic.Debug; + public interface IDebuggerListener { void OnPrint(string log); diff --git a/Supercell.GUT.Titan/Debugging/LogicException.cs b/Supercell.GUT.Titan/Logic/Debug/LogicException.cs similarity index 61% rename from Supercell.GUT.Titan/Debugging/LogicException.cs rename to Supercell.GUT.Titan/Logic/Debug/LogicException.cs index 7758612..e579458 100644 --- a/Supercell.GUT.Titan/Debugging/LogicException.cs +++ b/Supercell.GUT.Titan/Logic/Debug/LogicException.cs @@ -1,8 +1,9 @@ -namespace Supercell.GUT.Titan.Debugging; +namespace Supercell.GUT.Titan.Logic.Debug; + public class LogicException : Exception { public LogicException(string message) : base(message) { - // LogicException. + ; } } diff --git a/Supercell.GUT.Titan/Math/LogicLong.cs b/Supercell.GUT.Titan/Logic/Math/LogicLong.cs similarity index 86% rename from Supercell.GUT.Titan/Math/LogicLong.cs rename to Supercell.GUT.Titan/Logic/Math/LogicLong.cs index 81f8611..6905aa2 100644 --- a/Supercell.GUT.Titan/Math/LogicLong.cs +++ b/Supercell.GUT.Titan/Logic/Math/LogicLong.cs @@ -1,7 +1,6 @@ -using Supercell.GUT.Titan.Encoding; -using Supercell.GUT.Titan.Encoding.Streamed; +using Supercell.GUT.Titan.Logic.DataStream; -namespace Supercell.GUT.Titan.Math; +namespace Supercell.GUT.Titan.Logic.Math; public class LogicLong { diff --git a/Supercell.GUT.Titan/Math/LogicMath.cs b/Supercell.GUT.Titan/Logic/Math/LogicMath.cs similarity index 99% rename from Supercell.GUT.Titan/Math/LogicMath.cs rename to Supercell.GUT.Titan/Logic/Math/LogicMath.cs index 0cd26cb..4f34385 100644 --- a/Supercell.GUT.Titan/Math/LogicMath.cs +++ b/Supercell.GUT.Titan/Logic/Math/LogicMath.cs @@ -1,4 +1,4 @@ -namespace Supercell.GUT.Titan.Math; +namespace Supercell.GUT.Titan.Logic.Math; public static class LogicMath { diff --git a/Supercell.GUT.Titan/Math/LogicRandom.cs b/Supercell.GUT.Titan/Logic/Math/LogicRandom.cs similarity index 94% rename from Supercell.GUT.Titan/Math/LogicRandom.cs rename to Supercell.GUT.Titan/Logic/Math/LogicRandom.cs index 1a8573f..8a33482 100644 --- a/Supercell.GUT.Titan/Math/LogicRandom.cs +++ b/Supercell.GUT.Titan/Logic/Math/LogicRandom.cs @@ -1,4 +1,4 @@ -namespace Supercell.GUT.Titan.Math; +namespace Supercell.GUT.Titan.Logic.Math; public class LogicRandom { diff --git a/Supercell.GUT.Titan/Message/LogicMessageFactory.cs b/Supercell.GUT.Titan/Logic/Message/LogicMessageFactory.cs similarity index 83% rename from Supercell.GUT.Titan/Message/LogicMessageFactory.cs rename to Supercell.GUT.Titan/Logic/Message/LogicMessageFactory.cs index a44d394..7b4c259 100644 --- a/Supercell.GUT.Titan/Message/LogicMessageFactory.cs +++ b/Supercell.GUT.Titan/Logic/Message/LogicMessageFactory.cs @@ -1,4 +1,4 @@ -namespace Supercell.GUT.Titan.Message; +namespace Supercell.GUT.Titan.Logic.Message; public abstract class LogicMessageFactory { diff --git a/Supercell.GUT.Titan/Message/PiranhaMessage.cs b/Supercell.GUT.Titan/Logic/Message/PiranhaMessage.cs similarity index 88% rename from Supercell.GUT.Titan/Message/PiranhaMessage.cs rename to Supercell.GUT.Titan/Logic/Message/PiranhaMessage.cs index a146be0..a7b6d83 100644 --- a/Supercell.GUT.Titan/Message/PiranhaMessage.cs +++ b/Supercell.GUT.Titan/Logic/Message/PiranhaMessage.cs @@ -1,6 +1,6 @@ -using Supercell.GUT.Titan.Encoding.Streamed; +using Supercell.GUT.Titan.Logic.DataStream; -namespace Supercell.GUT.Titan.Message; +namespace Supercell.GUT.Titan.Logic.Message; public abstract class PiranhaMessage { diff --git a/Supercell.GUT.Titan/Message/VersionedMessage.cs b/Supercell.GUT.Titan/Logic/Message/VersionedMessage.cs similarity index 92% rename from Supercell.GUT.Titan/Message/VersionedMessage.cs rename to Supercell.GUT.Titan/Logic/Message/VersionedMessage.cs index 05c010f..126ca8a 100644 --- a/Supercell.GUT.Titan/Message/VersionedMessage.cs +++ b/Supercell.GUT.Titan/Logic/Message/VersionedMessage.cs @@ -1,4 +1,4 @@ -namespace Supercell.GUT.Titan.Message; +namespace Supercell.GUT.Titan.Logic.Message; public abstract class VersionedMessage : PiranhaMessage { diff --git a/Supercell.GUT.Titan/Logic/Util/LogicArrayList.cs b/Supercell.GUT.Titan/Logic/Util/LogicArrayList.cs new file mode 100644 index 0000000..db162a3 --- /dev/null +++ b/Supercell.GUT.Titan/Logic/Util/LogicArrayList.cs @@ -0,0 +1,131 @@ +using Supercell.GUT.Titan.Logic.Debug; + +namespace Supercell.GUT.Titan.Logic.Util; + +public class LogicArrayList +{ + private T[] m_items; + private int m_size; + + public LogicArrayList() + { + this.m_items = Array.Empty(); + } + + public LogicArrayList(int capacity) + { + this.m_items = new T[capacity]; + } + + public T this[int index] + { + get + { + if (this.m_size <= index) + { + Debugger.Error($"LogicArrayList.get out of bounds {index}/{this.m_size}"); + } + + return this.m_items[index]; + } + set + { + if (this.m_size <= index) + { + Debugger.Error($"LogicArrayList.set out of bounds {index}/{this.m_size}"); + } + + this.m_items[index] = value; + } + } + + public void Add(T item) + { + int size = this.m_items.Length; + + if (size == m_size) + { + this.EnsureCapacity(size != 0 ? size * 2 : 5); + } + + this.m_items[this.m_size++] = item; + } + + public void Add(int index, T item) + { + int size = this.m_items.Length; + + if (size == this.m_size) + { + this.EnsureCapacity(size != 0 ? size * 2 : 5); + } + + if (this.m_size > index) + { + Array.Copy(this.m_items, index, this.m_items, index + 1, this.m_size - index); + } + + this.m_items[index] = item; + this.m_size += 1; + } + + public void AddAll(LogicArrayList array) + { + this.EnsureCapacity(this.m_size + array.m_size); + + for (int i = 0, cnt = array.m_size; i < cnt; i++) + { + this.m_items[this.m_size++] = array[i]; + } + } + + public int IndexOf(T item) + { + return Array.IndexOf(this.m_items, item, 0, this.m_size); + } + + public T Remove(int index) + { + T item = default; + + if ((uint)index < m_size) + { + item = this.m_items[index]; + + this.m_size -= 1; + + if (index != m_size) + { + Array.Copy(this.m_items, index + 1, this.m_items, index, this.m_size - index); + } + } + + return item; + } + + public void EnsureCapacity(int count) + { + int size = this.m_items.Length; + + if (size < count) + { + Array.Resize(ref this.m_items, count); + } + } + + public int Size() + { + return this.m_size; + } + + public void Clear() + { + this.m_size = 0; + } + + public void Destruct() + { + this.m_items = null; + this.m_size = 0; + } +} \ No newline at end of file diff --git a/Supercell.GUT.Titan/Logic/Util/LogicStringUtil.cs b/Supercell.GUT.Titan/Logic/Util/LogicStringUtil.cs new file mode 100644 index 0000000..5d8fd27 --- /dev/null +++ b/Supercell.GUT.Titan/Logic/Util/LogicStringUtil.cs @@ -0,0 +1,30 @@ +using System.Text; + +namespace Supercell.GUT.Titan.Logic.Util; + +public static class LogicStringUtil +{ + public static string SafeString(string a1, string? a2, string a3) + { + if (a2 != null) + { + a1 = a2; + } + else + { + a1 = a3; + } + + return a1; + } + + public static string CreateString(byte[] byteArray, int offset, int length) + { + return Encoding.UTF8.GetString(byteArray, offset, length); + } + + public static byte[] GetBytes(string value) + { + return Encoding.UTF8.GetBytes(value); + } +} diff --git a/Supercell.GUT.Titan/Util/LogicStringUtil.cs b/Supercell.GUT.Titan/Util/LogicStringUtil.cs deleted file mode 100644 index b849454..0000000 --- a/Supercell.GUT.Titan/Util/LogicStringUtil.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Supercell.GUT.Titan.Util; - -public static class LogicStringUtil -{ - public static string SafeString(string a1, string? a2, string a3) - { - if (a2 != null) - { - a1 = a2; - } - else - { - a1 = a3; - } - - return a1; - } -} diff --git a/Supercell.GUT.sln b/Supercell.GUT.sln index f338db2..299ecda 100644 --- a/Supercell.GUT.sln +++ b/Supercell.GUT.sln @@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Supercell.GUT.Titan", "Supe EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Supercell.GUT.Logic", "Supercell.GUT.Logic\Supercell.GUT.Logic.csproj", "{4441B345-1B99-4DE6-9764-B34E3ED8A982}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Supercell.GUT.SDK", "Supercell.GUT.SDK\Supercell.GUT.SDK.csproj", "{CB2AD800-4FD4-4F84-8BFD-6791CC0CDCC6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,6 +29,10 @@ Global {4441B345-1B99-4DE6-9764-B34E3ED8A982}.Debug|Any CPU.Build.0 = Debug|Any CPU {4441B345-1B99-4DE6-9764-B34E3ED8A982}.Release|Any CPU.ActiveCfg = Release|Any CPU {4441B345-1B99-4DE6-9764-B34E3ED8A982}.Release|Any CPU.Build.0 = Release|Any CPU + {CB2AD800-4FD4-4F84-8BFD-6791CC0CDCC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CB2AD800-4FD4-4F84-8BFD-6791CC0CDCC6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB2AD800-4FD4-4F84-8BFD-6791CC0CDCC6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CB2AD800-4FD4-4F84-8BFD-6791CC0CDCC6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE