diff --git a/Core/Callbacks/LauncherCallbacks.cs b/Core/Callbacks/LauncherCallbacks.cs
index a616dd84..c1a07552 100644
--- a/Core/Callbacks/LauncherCallbacks.cs
+++ b/Core/Callbacks/LauncherCallbacks.cs
@@ -20,71 +20,80 @@ public class LauncherCallbacks
SaveServer saveServer,
Watermark watermark)
{
-
+ _httpResponseUtil = httpResponse;
+ _launcherController = launcherController;
+ _saveServer = saveServer;
+ _watermark = watermark;
}
public string Connect()
{
- throw new NotImplementedException();
+ return _httpResponseUtil.NoBody(_launcherController.Connect());
}
public string Login(string url, LoginRequestData info, string sessionID)
{
- throw new NotImplementedException();
+ var output = _launcherController.Login(info);
+ return output ?? "FAILED";
}
public string Register(string url, RegisterData info, string sessionID)
{
- throw new NotImplementedException();
+ var output = _launcherController.Register(info);
+ return string.IsNullOrEmpty(output) ? "FAILED" : "OK";
}
public string Get(string url, LoginRequestData info, string sessionID)
{
- throw new NotImplementedException();
+ var output = _launcherController.Find(_launcherController.Login(info));
+ return _httpResponseUtil.NoBody(output);
}
public string ChangeUsername(string url, ChangeRequestData info, string sessionID)
{
- throw new NotImplementedException();
+ var output = _launcherController.ChangeUsername(info);
+ return string.IsNullOrEmpty(output) ? "FAILED" : "OK";
}
public string ChangePassword(string url, ChangeRequestData info, string sessionID)
{
- throw new NotImplementedException();
+ var output = _launcherController.ChangePassword(info);
+ return string.IsNullOrEmpty(output) ? "FAILED" : "OK";
}
public string Wipe(string url, RegisterData info, string sessionID)
{
- throw new NotImplementedException();
+ var output = _launcherController.Wipe(info);
+ return string.IsNullOrEmpty(output) ? "FAILED" : "OK";
}
public string GetServerVersion()
{
- throw new NotImplementedException();
+ return _httpResponseUtil.NoBody(_watermark.GetVersionTag());
}
public string Ping(string url, EmptyRequestData info, string sessionID)
{
- throw new NotImplementedException();
+ return _httpResponseUtil.NoBody("pong!");
}
public string RemoveProfile(string url, RemoveProfileData info, string sessionID)
{
- throw new NotImplementedException();
+ return _httpResponseUtil.NoBody(_saveServer.RemoveProfile(sessionID));
}
public string GetCompatibleTarkovVersion()
{
- throw new NotImplementedException();
+ return _httpResponseUtil.NoBody(_launcherController.GetCompatibleTarkovVersion());
}
public string GetLoadedServerMods()
{
- throw new NotImplementedException();
+ return _httpResponseUtil.NoBody(_launcherController.GetLoadedServerMods());
}
public string GetServerModsProfileUsed(string url, EmptyRequestData info, string sessionID)
{
- throw new NotImplementedException();
+ return _httpResponseUtil.NoBody(_launcherController.GetServerModsProfileUsed(sessionID));
}
}
diff --git a/Core/Controllers/LauncherController.cs b/Core/Controllers/LauncherController.cs
index 787783cc..684d6860 100644
--- a/Core/Controllers/LauncherController.cs
+++ b/Core/Controllers/LauncherController.cs
@@ -1,149 +1,241 @@
+using System.Text.Json.Serialization;
using Core.Annotations;
+using Core.Helpers;
+using Core.Models.Eft.Common.Tables;
using Core.Models.Eft.Launcher;
using Core.Models.Eft.Profile;
+using Core.Models.Enums;
+using Core.Models.Spt.Config;
using Core.Models.Spt.Mod;
+using Core.Servers;
+using Core.Services;
+using Core.Utils;
+using Core.Utils.Extensions;
+using ILogger = Core.Models.Utils.ILogger;
+using Info = Core.Models.Eft.Profile.Info;
namespace Core.Controllers;
[Injectable]
public class LauncherController
{
- ///
- ///
- ///
- ///
+ protected CoreConfig _coreConfig;
+
+ protected ILogger _logger;
+ protected HashUtil _hashUtil;
+ protected TimeUtil _timeUtil;
+ protected RandomUtil _randomUtil;
+ protected SaveServer _saveServer;
+ protected HttpServerHelper _httpServerHelper;
+ protected ProfileHelper _profileHelper;
+ protected DatabaseService _databaseService;
+ protected LocalisationService _localisationService;
+
+
+ public LauncherController(
+ Models.Utils.ILogger logger,
+ HashUtil hashUtil,
+ TimeUtil timeUtil,
+ RandomUtil randomUtil,
+ SaveServer saveServer,
+ HttpServerHelper httpServerHelper,
+ ProfileHelper profileHelper,
+ DatabaseService databaseService,
+ LocalisationService localisationService,
+ // TODO => @inject("PreSptModLoader") protected preSptModLoader: PreSptModLoader,
+ ConfigServer configServer
+ ) {
+ _logger = logger;
+ _hashUtil = hashUtil;
+ _timeUtil = timeUtil;
+ _randomUtil = randomUtil;
+ _saveServer = saveServer;
+ _httpServerHelper = httpServerHelper;
+ _profileHelper = profileHelper;
+ _databaseService = databaseService;
+ _localisationService = localisationService;
+ _coreConfig = configServer.GetConfig(ConfigTypes.CORE);
+ }
+
public ConnectResponse Connect()
{
- throw new NotImplementedException();
+ // Get all possible profile types + filter out any that are blacklisted
+
+ var profiles = typeof(ProfileTemplates).GetProperties()
+ .Select(p => p.GetJsonName())
+ .Where(profileName => !_coreConfig.Features.CreateNewProfileTypesBlacklist.Contains(profileName))
+ .ToList();
+
+ return new ConnectResponse(){
+ BackendUrl = _httpServerHelper.GetBackendUrl(),
+ Name = _coreConfig.ServerName,
+ Editions = profiles,
+ ProfileDescriptions = GetProfileDescriptions(),
+ };
}
- ///
- /// Get descriptive text for each of the profile edtions a player can choose, keyed by profile.json profile type
- /// e.g. "Edge Of Darkness"
- ///
- /// Dictionary of profile types with related descriptive text
- private Dictionary GetProfileDescriptions()
+ /**
+ * Get descriptive text for each of the profile edtions a player can choose, keyed by profile.json profile type e.g. "Edge Of Darkness"
+ * @returns Dictionary of profile types with related descriptive text
+ */
+ protected Dictionary GetProfileDescriptions()
{
- throw new NotImplementedException();
+ var result = new Dictionary();
+ var dbProfiles = _databaseService.GetProfiles();
+ foreach (var templatesProperty in typeof(ProfileTemplates).GetProperties())
+ {
+ var propertyValue = templatesProperty.GetValue(dbProfiles);
+ if (propertyValue == null) {
+ _logger.Warning(_localisationService.GetText("launcher-missing_property", templatesProperty));
+ continue;
+ }
+
+ var casterPropertyValue = propertyValue as ProfileSides;
+ result[templatesProperty.GetJsonName()] = _localisationService.GetText(casterPropertyValue.DescriptionLocaleKey);
+ }
+
+ return result;
}
- ///
- ///
- ///
- ///
- ///
- public Info Find(string sessionId)
+ public Info? Find(string sessionId)
{
- throw new NotImplementedException();
+ return _saveServer.GetProfiles().TryGetValue(sessionId, out var profile) ? profile.ProfileInfo : null;
}
- ///
- ///
- ///
- ///
- ///
public string Login(LoginRequestData info)
{
- throw new NotImplementedException();
+ foreach (var sessionID in _saveServer.GetProfiles()) {
+ var account = _saveServer.GetProfile(sessionID.Key).ProfileInfo;
+ if (info.Username == account.UserName) {
+ return sessionID.Key;
+ }
+ }
+
+ return "";
}
- ///
- ///
- ///
- ///
- ///
public string Register(RegisterData info)
{
- throw new NotImplementedException();
+ foreach (var sessionID in _saveServer.GetProfiles()) {
+ if (info.Username == _saveServer.GetProfile(sessionID.Key).ProfileInfo.UserName) {
+ return "";
+ }
+ }
+
+ return CreateAccount(info);
}
- ///
- ///
- ///
- ///
- ///
- private string CreateAccount(RegisterData info)
+ protected string CreateAccount(RegisterData info)
{
- throw new NotImplementedException();
+ var profileId = GenerateProfileId();
+ var scavId = GenerateProfileId();
+ var newProfileDetails = new Info(){
+ ProfileId = profileId,
+ ScavengerId = scavId,
+ Aid = _hashUtil.GenerateAccountId(),
+ UserName = info.Username,
+ Password = info.Password,
+ IsWiped = true,
+ Edition = info.Edition,
+ };
+ _saveServer.CreateProfile(newProfileDetails);
+
+ _saveServer.LoadProfile(profileId);
+ _saveServer.SaveProfile(profileId);
+
+ return profileId;
}
- ///
- ///
- ///
- ///
- private string GenerateProfileId()
+ protected string GenerateProfileId()
{
- throw new NotImplementedException();
+ var timestamp = _timeUtil.GetTimeStamp();
+
+ return FormatID(timestamp, timestamp * _randomUtil.GetInt(1, 1000000));
}
- ///
- ///
- ///
- ///
- ///
- ///
- private string FormatId(
- long timeStamp,
- int counter)
+ protected string FormatID(long timeStamp, long counter)
{
- throw new NotImplementedException();
+
+ var timeStampStr = Convert.ToString(timeStamp, 16).PadLeft(8, '0');
+ var counterStr = Convert.ToString(counter, 16).PadLeft(16, '0');
+
+ return timeStampStr.ToLower() + counterStr.ToLower();
}
- ///
- ///
- ///
- ///
- ///
public string ChangeUsername(ChangeRequestData info)
{
- throw new NotImplementedException();
+ var sessionID = Login(info);
+
+ if (!string.IsNullOrEmpty(sessionID)) {
+ _saveServer.GetProfile(sessionID).ProfileInfo.UserName = info.Change;
+ }
+
+ return sessionID;
}
- ///
- ///
- ///
- ///
- ///
public string ChangePassword(ChangeRequestData info)
{
- throw new NotImplementedException();
+ var sessionID = Login(info);
+
+ if (!string.IsNullOrEmpty(sessionID)) {
+ _saveServer.GetProfile(sessionID).ProfileInfo.Password = info.Change;
+ }
+
+ return sessionID;
}
- ///
- /// Handle launcher requesting profile be wiped
- ///
- /// RegisterData
- /// Session id
- public string Wipe(RegisterData info)
+ /**
+ * Handle launcher requesting profile be wiped
+ * @param info IRegisterData
+ * @returns Session id
+ */
+ public string? Wipe(RegisterData info)
{
- throw new NotImplementedException();
+ if (!_coreConfig.AllowProfileWipe) {
+ return null;
+ }
+
+ var sessionID = Login(info);
+
+ if (!string.IsNullOrEmpty(sessionID)) {
+ var profileInfo = _saveServer.GetProfile(sessionID).ProfileInfo;
+ profileInfo.Edition = info.Edition;
+ profileInfo.IsWiped = true;
+ }
+
+ return sessionID;
}
- ///
- ///
- ///
- ///
public string GetCompatibleTarkovVersion()
{
- throw new NotImplementedException();
+ return _coreConfig.CompatibleTarkovVersion;
}
- ///
- /// Get the mods the server has currently loaded
- ///
- /// Dictionary of mod name and mod details
- public Dictionary GetLoadedServerMods() // TODO: We no longer use a package.json
+ /**
+ * Get the mods the server has currently loaded
+ * @returns Dictionary of mod name and mod details
+ */
+ public Dictionary GetLoadedServerMods()
{
- throw new NotImplementedException();
+ return new Dictionary();
+ // TODO => return this.preSptModLoader.getImportedModDetails();
}
- ///
- /// Get the mods a profile has ever loaded into game with
- ///
- /// Player id
- /// List of mod details
+ /**
+ * Get the mods a profile has ever loaded into game with
+ * @param sessionId Player id
+ * @returns Array of mod details
+ */
public List GetServerModsProfileUsed(string sessionId)
{
- throw new NotImplementedException();
+ var profile = _profileHelper.GetFullProfile(sessionId);
+
+ /* TODO => modding
+ if (profile?.spt?.mods) {
+ return this.preSptModLoader.GetProfileModsGroupedByModName(profile?.spt?.mods);
+ }
+ */
+
+ return [];
}
}
diff --git a/Core/Helpers/ProfileHelper.cs b/Core/Helpers/ProfileHelper.cs
index 42e4c8de..409d330a 100644
--- a/Core/Helpers/ProfileHelper.cs
+++ b/Core/Helpers/ProfileHelper.cs
@@ -1,10 +1,12 @@
-using Core.Models.Eft.Common;
+using Core.Annotations;
+using Core.Models.Eft.Common;
using Core.Models.Eft.Common.Tables;
using Core.Models.Eft.Profile;
using Core.Models.Enums;
namespace Core.Helpers;
+[Injectable]
public class ProfileHelper
{
///
diff --git a/Core/Servers/Http/SptHttpListener.cs b/Core/Servers/Http/SptHttpListener.cs
index 434cfa1d..5c7cbb73 100644
--- a/Core/Servers/Http/SptHttpListener.cs
+++ b/Core/Servers/Http/SptHttpListener.cs
@@ -106,6 +106,7 @@ public class SptHttpListener : IHttpListener
if (IsDebugRequest(req)) {
// Send only raw response without transformation
SendJson(resp, output, sessionID);
+ Console.WriteLine($"Response: {output}");
// TODO: this.logRequest(req, output);
return;
}
@@ -118,7 +119,7 @@ public class SptHttpListener : IHttpListener
// No serializer can handle the request (majority of requests dont), zlib the output and send response back
SendZlibJson(resp, output, sessionID);
}
-
+ Console.WriteLine($"Response: {output}");
// TODO: this.LogRequest(req, output);
}
@@ -181,8 +182,15 @@ public class SptHttpListener : IHttpListener
public void SendZlibJson(HttpResponse resp, string? output, string sessionID)
{
- if (!string.IsNullOrEmpty(output))
- new ZLibStream(resp.Body, CompressionLevel.SmallestSize, false).WriteAsync(Encoding.UTF8.GetBytes(output)).AsTask().Wait();
+ using (var ms = new MemoryStream())
+ {
+ using (var deflateStream = new ZLibStream(ms, CompressionLevel.SmallestSize))
+ {
+ deflateStream.WriteAsync(Encoding.UTF8.GetBytes(output)).AsTask().Wait();
+ }
+ var bytes = ms.ToArray();
+ resp.Body.WriteAsync(bytes, 0, bytes.Length).Wait();
+ }
resp.StartAsync().Wait();
resp.CompleteAsync().Wait();
}
diff --git a/Core/Utils/Extensions/MemberInfoExtensions.cs b/Core/Utils/Extensions/MemberInfoExtensions.cs
new file mode 100644
index 00000000..0d90d062
--- /dev/null
+++ b/Core/Utils/Extensions/MemberInfoExtensions.cs
@@ -0,0 +1,15 @@
+using System.Reflection;
+using System.Text.Json.Serialization;
+
+namespace Core.Utils.Extensions;
+
+public static class MemberInfoExtensions
+{
+ public static string GetJsonName(this MemberInfo memberInfo)
+ {
+ return Attribute.IsDefined(memberInfo, typeof(JsonPropertyNameAttribute))
+ ? (Attribute.GetCustomAttribute(memberInfo, typeof(JsonPropertyNameAttribute)) as JsonPropertyNameAttribute).Name
+ : memberInfo.Name;
+ }
+
+}
diff --git a/Core/Utils/JsonUtil.cs b/Core/Utils/JsonUtil.cs
index a2627e3b..368771eb 100644
--- a/Core/Utils/JsonUtil.cs
+++ b/Core/Utils/JsonUtil.cs
@@ -10,8 +10,9 @@ namespace Core.Utils;
[Injectable(InjectionType.Singleton)]
public class JsonUtil
{
- private readonly JsonSerializerOptions jsonSerializerOptions = new()
+ private static readonly JsonSerializerOptions jsonSerializerOptionsNoIndent = new()
{
+ WriteIndented = false,
UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow,
Converters =
{
@@ -23,27 +24,30 @@ public class JsonUtil
new EftEnumConverter()
}
};
+ private static readonly JsonSerializerOptions jsonSerializerOptionsIndented = new(jsonSerializerOptionsNoIndent)
+ {
+ WriteIndented = true
+ };
+
public T? Deserialize(string? json)
{
- return string.IsNullOrEmpty(json) ? default : JsonSerializer.Deserialize(json, jsonSerializerOptions);
+ return string.IsNullOrEmpty(json) ? default : JsonSerializer.Deserialize(json, jsonSerializerOptionsNoIndent);
}
public object? Deserialize(string? json, Type type)
{
- return string.IsNullOrEmpty(json) ? null : JsonSerializer.Deserialize(json, type, jsonSerializerOptions);
+ return string.IsNullOrEmpty(json) ? null : JsonSerializer.Deserialize(json, type, jsonSerializerOptionsNoIndent);
}
public string? Serialize(T? obj, bool indented = false)
{
- jsonSerializerOptions.WriteIndented = indented;
- return obj == null ? null : JsonSerializer.Serialize(obj, jsonSerializerOptions);
+ return obj == null ? null : JsonSerializer.Serialize(obj, indented ? jsonSerializerOptionsIndented : jsonSerializerOptionsNoIndent);
}
public string? Serialize(object? obj, Type type, bool indented = false)
{
- jsonSerializerOptions.WriteIndented = indented;
- return obj == null ? null : JsonSerializer.Serialize(obj, type, jsonSerializerOptions);
+ return obj == null ? null : JsonSerializer.Serialize(obj, type, indented ? jsonSerializerOptionsIndented : jsonSerializerOptionsNoIndent);
}
}