Refactor and Optimize Client

This commit is contained in:
raphaeIl 2024-11-16 06:55:27 -05:00
parent 23876dfdea
commit 33995fb87a
8 changed files with 138 additions and 309 deletions

View File

@ -1,17 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using SCHALE.GameServer.Services;
namespace SCHALE.GameClient.Controllers
{
public class ClientController : Controller
{
private readonly ILogger<ClientController> _logger;
private readonly PrivateClientService _privateClientService;
public ClientController(ILogger<ClientController> logger, PrivateClientService privateClientService)
{
_logger = logger;
_privateClientService = privateClientService;
}
}
}

View File

@ -1,92 +1,156 @@
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.IdentityModel.Tokens;
using MX.Core.Crypto;
using Newtonsoft.Json.Linq;
using SCHALE.Common.Crypto;
using SCHALE.Common.Crypto.XXHash;
using SCHALE.Common.FlatData;
using SCHALE.Common.NetworkProtocol;
using SCHALE.GameServer.Services;
using SCHALE.GameServer.Utils;
using Serilog;
using Serilog.Events;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http.Headers;
using System.Text.Json;
namespace SCHALE.GameServer
namespace SCHALE.GameServer.Services
{
public class GameServer
public class GameClient
{
public static async Task Main(string[] args)
{
var config = new ConfigurationBuilder()
.SetBasePath(Path.GetDirectoryName(AppContext.BaseDirectory)!)
.AddJsonFile("appsettings.json")
.AddJsonFile(
$"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json",
true
)
.AddJsonFile("appsettings.Local.json", true)
.Build();
private readonly HttpClient httpClient;
public static readonly string PS_URL = "http://10.0.0.149/api/gateway";
public static readonly string MITM_URL = "http://10.0.0.149:8080";
public static readonly string OFFICIAL_API_URL = "https://prod-game.bluearchiveyostar.com:5000/api/gateway";
private long AccountServerId = -1;
private string MxToken = "";
private long Hash = 0;
public GameClient()
{
var logFilePath = Path.Combine(
Path.GetDirectoryName(AppContext.BaseDirectory)!,
"logs",
"log.txt"
);
if (File.Exists(logFilePath))
{
var prevLogFilePath = Path.Combine(
Path.GetDirectoryName(logFilePath)!,
"log-prev.txt"
);
if (File.Exists(prevLogFilePath))
File.Delete(prevLogFilePath);
File.Move(logFilePath, prevLogFilePath);
}
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.File(
logFilePath,
restrictedToMinimumLevel: LogEventLevel.Verbose,
shared: true
)
.ReadFrom.Configuration(config)
.CreateBootstrapLogger();
.WriteTo.File("logs/log.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
Log.Information("Application starting up...");
httpClient = new HttpClient();
}
Log.Information("Starting...");
try
public static async Task Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
GameClient gameClient = new GameClient();
builder.Services.Configure<KestrelServerOptions>(op =>
op.AllowSynchronousIO = true
);
builder.Host.UseSerilog();
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddHttpClient<PrivateClientService>();
builder.Services.AddSingleton<PrivateClientService>();
builder.Services.AddPrivateClientService();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseAuthorization();
app.UseSerilogRequestLogging();
app.MapControllers();
app.Run();
} catch (Exception ex)
if (args.Length < 2 && (gameClient.AccountServerId == -1 || gameClient.MxToken == ""))
{
Log.Fatal(ex, "An unhandled exception occurred during runtime");
} finally
Log.Information("Please input the nessary data.");
return;
}
if (gameClient.AccountServerId == -1)
{
Log.CloseAndFlush();
}
gameClient.AccountServerId = int.Parse(args[0]);
}
if (gameClient.MxToken.IsNullOrEmpty())
{
gameClient.MxToken = args[1];
}
await gameClient.SendPostRequestAsync(OFFICIAL_API_URL, new AcademyGetInfoRequest(){ });
/*
await gameClient.SendPostRequestAsync(OFFICIAL_API_URL, new ShopBuyGacha3Request()
{
FreeRecruitId = 0,
Cost = new()
{
ParcelInfos = [
new()
{
Key = new()
{
Type = ParcelType.Currency,
Id = 4,
},
Amount = 120,
Multiplier = new(10000),
Probability = new(10000)
}
],
Currency = new()
{
currencyValue = new()
{
Values = new()
{
{ CurrencyTypes.Gem, 120 }
},
Tickets = new() { },
Property = new() { },
Gem = 120,
IsEmpty = false
},
Gold = 0,
Gem = 120,
},
EquipmentDBs = [],
ItemDBs = [],
FurnitureDBs = [],
ConsumeCondition = 0,
},
GoodsId = 35840,
ShopUniqueId = 50668,
});
*/
}
public async Task SendPostRequestAsync<T>(string url, T requestPacket) where T : RequestPacket
{
requestPacket.SessionKey = new()
{
MxToken = this.MxToken,
AccountServerId = this.AccountServerId,
};
requestPacket.Hash = this.Hash;
requestPacket.Resendable = true;
requestPacket.ClientUpTime = 0;
requestPacket.IsTest = false;
string packetJsonStr = JsonSerializer.Serialize((T)requestPacket);
Log.Information("Sending Post Request to " + url);
Log.Information($"Payload: {packetJsonStr}");
byte[] payload = PacketCryptManager.Instance.RequestToBinary(requestPacket.Protocol, packetJsonStr);
//File.WriteAllBytes("./mx.dat", payload);
Log.Information("Written All Bytes");
var request = new HttpRequestMessage(HttpMethod.Post, url);
request.Headers.Add("mx", "1");
request.Headers.Add("Bundle-Version", "li3pmyogha");
var content = new MultipartFormDataContent();
content.Add(new StreamContent(new MemoryStream(payload)), "mx", ".mx.dat");
request.Content = content;
Log.Information("Sending POST Request!");
var response = await httpClient.SendAsync(request);
// Response
Log.Information("Response Details:");
Log.Information($"Status Code: {response.StatusCode}");
string responseBody = await response.Content.ReadAsStringAsync();
Log.Information("Response Body:");
Log.Information(responseBody);
}
}
}

View File

@ -1,38 +0,0 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:22994",
"sslPort": 44306
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5141",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7267;http://localhost:5141",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>

View File

@ -1,161 +0,0 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using MX.Core.Crypto;
using Newtonsoft.Json.Linq;
using SCHALE.Common.Crypto;
using SCHALE.Common.Crypto.XXHash;
using SCHALE.Common.FlatData;
using SCHALE.Common.NetworkProtocol;
using SCHALE.GameServer.Utils;
using Serilog;
using System.Net.Http.Headers;
using System.Text.Json;
namespace SCHALE.GameServer.Services
{
public class PrivateClientService : BackgroundService
{
private readonly HttpClient _httpClient;
public static readonly string PS_URL = "http://10.0.0.149/api/gateway";
public static readonly string MITM_URL = "http://10.0.0.149:8080";
public static readonly string OFFICIAL_API_URL = "http://prod-gateway.bluearchiveyostar.com:5100/api/";
private readonly long AccountServerId = -1;
private readonly string MxToken = "";
private readonly long Hash = 0;
public PrivateClientService(HttpClient httpClient)
{
_httpClient = httpClient;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
//await SendPostRequestAsync(OFFICIAL_API_URL, new AcademyGetInfoRequest(){ });
await SendPostRequestAsync(OFFICIAL_API_URL, new ShopBuyGacha3Request()
{
FreeRecruitId = 0,
Cost = new()
{
ParcelInfos = [
new()
{
Key = new()
{
Type = ParcelType.Currency,
Id = 4,
},
Amount = 120,
Multiplier = new(10000),
Probability = new(10000)
}
],
Currency = new()
{
currencyValue = new()
{
Values = new()
{
{ CurrencyTypes.Gem, 120 }
},
Tickets = new() { },
Property = new() { },
Gem = 120,
IsEmpty = false
},
Gold = 0,
Gem = 120,
},
EquipmentDBs = [],
ItemDBs = [],
FurnitureDBs = [],
ConsumeCondition = 0,
},
GoodsId = 35840,
ShopUniqueId = 50668,
});
}
public async Task SendPostRequestAsync<T>(string url, T requestPacket) where T : RequestPacket
{
requestPacket.SessionKey = new()
{
MxToken = this.MxToken,
AccountServerId = this.AccountServerId,
};
requestPacket.Hash = this.Hash;
requestPacket.Resendable = true;
requestPacket.ClientUpTime = 0;
requestPacket.IsTest = false;
string packetJsonStr = JsonSerializer.Serialize((T)requestPacket);
Log.Information("Sending Post Request to " + url);
Log.Information($"Payload: {packetJsonStr}");
byte[] payload = PacketCryptManager.Instance.RequestToBinary(requestPacket.Protocol, packetJsonStr);
File.WriteAllBytes("./mx.dat", payload);
Log.Information("Writeen All Bytes");
return;
using var fileStream = new FileStream("./mx.dat", FileMode.Create, FileAccess.Write);
using var binaryWriterFile = new BinaryWriter(fileStream);
binaryWriterFile.Write(payload);
var mxFile = new StreamContent(binaryWriterFile.BaseStream);
mxFile.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
// Add the in-memory content as a file with a name
var boundary = "BestHTTP_HTTPMultiPartForm_328B5160";
using var content = new MultipartFormDataContent(boundary);
content.Add(mxFile, "mx", "1");
content.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data");
content.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("boundary", boundary));
// Set up custom headers to match the request shown
_httpClient.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
_httpClient.DefaultRequestHeaders.Add("Bundle-Version", "li3pmyogha");
_httpClient.DefaultRequestHeaders.Connection.Add("Keep-Alive");
_httpClient.DefaultRequestHeaders.Connection.Add("TE");
_httpClient.DefaultRequestHeaders.Add("Keep-Alive", "timeout=21");
//_httpClient.DefaultRequestHeaders.Add("TE", "identity");
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("BestHTTP/2 v2.4.0");
// Send the POST request
HttpResponseMessage response = await _httpClient.PostAsync(url, content);
if (response.IsSuccessStatusCode)
{
string responseData = await response.Content.ReadAsStringAsync();
Log.Information("Success: " + responseData);
}
else
{
Log.Information($"Error: {response.StatusCode}");
}
}
}
internal static class PrivateClientServiceExtensions
{
public static void AddPrivateClientService(this IServiceCollection services)
{
services.AddHostedService<PrivateClientService>();
}
}
}

View File

@ -1,8 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@ -1,12 +0,0 @@
{
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
},
"AllowedHosts": "*"
}

View File

@ -7,7 +7,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SCHALE.GameServer", "SCHALE
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SCHALE.Common", "SCHALE.Common\SCHALE.Common.csproj", "{D8ED8CB5-EA39-46BE-9236-7FC1F46FE15B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SCHALE.GameClient", "SCHALE.GameClient\SCHALE.GameClient.csproj", "{EBA95AE2-BBCA-4386-ADB3-FC6EC2102E88}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SCHALE.GameClient", "SCHALE.GameClient\SCHALE.GameClient.csproj", "{27F99AC7-2101-48F3-AF4E-8AC1AA78FB32}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -23,10 +23,10 @@ Global
{D8ED8CB5-EA39-46BE-9236-7FC1F46FE15B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D8ED8CB5-EA39-46BE-9236-7FC1F46FE15B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D8ED8CB5-EA39-46BE-9236-7FC1F46FE15B}.Release|Any CPU.Build.0 = Release|Any CPU
{EBA95AE2-BBCA-4386-ADB3-FC6EC2102E88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EBA95AE2-BBCA-4386-ADB3-FC6EC2102E88}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBA95AE2-BBCA-4386-ADB3-FC6EC2102E88}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBA95AE2-BBCA-4386-ADB3-FC6EC2102E88}.Release|Any CPU.Build.0 = Release|Any CPU
{27F99AC7-2101-48F3-AF4E-8AC1AA78FB32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{27F99AC7-2101-48F3-AF4E-8AC1AA78FB32}.Debug|Any CPU.Build.0 = Debug|Any CPU
{27F99AC7-2101-48F3-AF4E-8AC1AA78FB32}.Release|Any CPU.ActiveCfg = Release|Any CPU
{27F99AC7-2101-48F3-AF4E-8AC1AA78FB32}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE