diff --git a/MareSynchronos/MareConfiguration/Configurations/ServerConfig.cs b/MareSynchronos/MareConfiguration/Configurations/ServerConfig.cs index 103eb20..65e50a6 100644 --- a/MareSynchronos/MareConfiguration/Configurations/ServerConfig.cs +++ b/MareSynchronos/MareConfiguration/Configurations/ServerConfig.cs @@ -13,5 +13,7 @@ public class ServerConfig : IMareConfiguration { new ServerStorage() { ServerName = ApiController.MainServer, ServerUri = ApiController.MainServiceUri } }, }; + public bool SendCensusData { get; set; } = true; + public int Version { get; set; } = 1; } \ No newline at end of file diff --git a/MareSynchronos/PlayerData/Handlers/GameObjectHandler.cs b/MareSynchronos/PlayerData/Handlers/GameObjectHandler.cs index c30a915..ee2e71f 100644 --- a/MareSynchronos/PlayerData/Handlers/GameObjectHandler.cs +++ b/MareSynchronos/PlayerData/Handlers/GameObjectHandler.cs @@ -99,6 +99,10 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase ModelFilesInSlotLoaded } + public byte RaceId { get; private set; } + public byte Gender { get; private set; } + public byte TribeId { get; private set; } + public IntPtr Address { get; private set; } public string Name { get; private set; } public ObjectKind ObjectKind { get; } @@ -253,6 +257,19 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase if (((DrawObject*)DrawObjectAddress)->Object.GetObjectType() == ObjectType.CharacterBase && ((CharacterBase*)DrawObjectAddress)->GetModelType() == CharacterBase.ModelType.Human) { + var gender = ((Human*)DrawObjectAddress)->Customize.Sex; + var raceId = ((Human*)DrawObjectAddress)->Customize.Race; + var tribeId = ((Human*)DrawObjectAddress)->Customize.Clan; + + if (_isOwnedObject && ObjectKind == ObjectKind.Player + && (gender != Gender || raceId != RaceId || tribeId != TribeId)) + { + Mediator.Publish(new CensusUpdateMessage(gender, raceId, tribeId)); + Gender = gender; + RaceId = raceId; + TribeId = tribeId; + } + customizeDiff = CompareAndUpdateCustomizeData(((Human*)DrawObjectAddress)->Customize.Data); if (customizeDiff) Logger.LogTrace("Checking [{this}] customize data as human from draw obj, result: {diff}", this, customizeDiff); diff --git a/MareSynchronos/Services/Mediator/Messages.cs b/MareSynchronos/Services/Mediator/Messages.cs index c839d29..82c7966 100644 --- a/MareSynchronos/Services/Mediator/Messages.cs +++ b/MareSynchronos/Services/Mediator/Messages.cs @@ -75,6 +75,7 @@ public record OpenBanUserPopupMessage(Pair PairToBan, GroupFullInfoDto GroupFull public record OpenSyncshellAdminPanel(GroupFullInfoDto GroupInfo) : MessageBase; public record OpenPermissionWindow(Pair Pair) : MessageBase; public record DownloadLimitChangedMessage() : SameThreadMessage; +public record CensusUpdateMessage(byte Gender, byte RaceId, byte TribeId) : MessageBase; #pragma warning restore S2094 #pragma warning restore MA0048 // File name must match type name \ No newline at end of file diff --git a/MareSynchronos/Services/ServerConfiguration/ServerConfigurationManager.cs b/MareSynchronos/Services/ServerConfiguration/ServerConfigurationManager.cs index b7c717d..94c9983 100644 --- a/MareSynchronos/Services/ServerConfiguration/ServerConfigurationManager.cs +++ b/MareSynchronos/Services/ServerConfiguration/ServerConfigurationManager.cs @@ -31,6 +31,18 @@ public class ServerConfigurationManager public string CurrentApiUrl => CurrentServer.ServerUri; public ServerStorage CurrentServer => _configService.Current.ServerStorage[CurrentServerIndex]; + public bool SendCensusData + { + get + { + return _configService.Current.SendCensusData; + } + set + { + _configService.Current.SendCensusData = value; + _configService.Save(); + } + } public int CurrentServerIndex { diff --git a/MareSynchronos/UI/SettingsUi.cs b/MareSynchronos/UI/SettingsUi.cs index b238ced..ce0a22b 100644 --- a/MareSynchronos/UI/SettingsUi.cs +++ b/MareSynchronos/UI/SettingsUi.cs @@ -806,7 +806,7 @@ public class SettingsUi : WindowMediatorSubscriberBase if (ApiController.ServerAlive) { UiSharedService.FontText("Service Actions", _uiShared.UidFont); - + ImGuiHelpers.ScaledDummy(new Vector2(5, 5)); if (ImGui.Button("Delete all my files")) { _deleteFilesPopupModalShown = true; @@ -884,6 +884,21 @@ public class SettingsUi : WindowMediatorSubscriberBase } UiSharedService.FontText("Service & Character Settings", _uiShared.UidFont); + ImGuiHelpers.ScaledDummy(new Vector2(5, 5)); + var sendCensus = _serverConfigurationManager.SendCensusData; + if (ImGui.Checkbox("Send Statistical Census Data", ref sendCensus)) + { + _serverConfigurationManager.SendCensusData = sendCensus; + } + UiSharedService.DrawHelpText("This will allow sending census data to the currently connected service." + UiSharedService.TooltipSeparator + + "Census data contains:" + Environment.NewLine + + "- Current World" + Environment.NewLine + + "- Current Gender" + Environment.NewLine + + "- Current Race" + Environment.NewLine + + "- Current Clan (this is not your Free Company, this is e.g. Keeper or Seeker for Miqo'te)" + UiSharedService.TooltipSeparator + + "The census data is only saved temporarily and will be removed from the server on disconnect. It is stored temporarily associated with your UID while you are connected." + UiSharedService.TooltipSeparator + + "If you do not wish to participate in the statistical census, untick this box and reconnect to the server."); + ImGuiHelpers.ScaledDummy(new Vector2(10, 10)); var idx = _uiShared.DrawServiceSelection(); diff --git a/MareSynchronos/WebAPI/SignalR/ApIController.Functions.Users.cs b/MareSynchronos/WebAPI/SignalR/ApIController.Functions.Users.cs index a552834..819c69f 100644 --- a/MareSynchronos/WebAPI/SignalR/ApIController.Functions.Users.cs +++ b/MareSynchronos/WebAPI/SignalR/ApIController.Functions.Users.cs @@ -41,9 +41,9 @@ public partial class ApiController await CreateConnections().ConfigureAwait(false); } - public async Task> UserGetOnlinePairs() + public async Task> UserGetOnlinePairs(CensusDataDto? censusDataDto) { - return await _mareHub!.InvokeAsync>(nameof(UserGetOnlinePairs)).ConfigureAwait(false); + return await _mareHub!.InvokeAsync>(nameof(UserGetOnlinePairs), censusDataDto).ConfigureAwait(false); } public async Task> UserGetPairedClients() @@ -128,7 +128,16 @@ public partial class ApiController sb.AppendLine($"GlamourerData for {item.Key}: {!string.IsNullOrEmpty(item.Value)}"); } Logger.LogDebug("Chara data contained: {nl} {data}", Environment.NewLine, sb.ToString()); - await UserPushData(new(visibleCharacters, character)).ConfigureAwait(false); + + CensusDataDto? censusDto = null; + if (_serverManager.SendCensusData && _lastCensus != null) + { + var world = await _dalamudUtil.GetWorldIdAsync().ConfigureAwait(false); + censusDto = new((ushort)world, _lastCensus.RaceId, _lastCensus.TribeId, _lastCensus.Gender); + Logger.LogDebug("Attaching Census Data: {data}", censusDto); + } + + await UserPushData(new(visibleCharacters, character, censusDto)).ConfigureAwait(false); } } #pragma warning restore MA0040 \ No newline at end of file diff --git a/MareSynchronos/WebAPI/SignalR/ApiController.cs b/MareSynchronos/WebAPI/SignalR/ApiController.cs index a0df76e..3ff9f9f 100644 --- a/MareSynchronos/WebAPI/SignalR/ApiController.cs +++ b/MareSynchronos/WebAPI/SignalR/ApiController.cs @@ -2,6 +2,7 @@ using MareSynchronos.API.Data; using MareSynchronos.API.Data.Extensions; using MareSynchronos.API.Dto; +using MareSynchronos.API.Dto.User; using MareSynchronos.API.SignalR; using MareSynchronos.PlayerData.Pairs; using MareSynchronos.Services; @@ -34,6 +35,7 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM private string? _lastUsedToken; private HubConnection? _mareHub; private ServerState _serverState; + private CensusUpdateMessage? _lastCensus; public ApiController(ILogger logger, HubFactory hubFactory, DalamudUtilService dalamudUtil, PairManager pairManager, ServerConfigurationManager serverManager, MareMediator mediator, @@ -52,6 +54,7 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM Mediator.Subscribe(this, async (msg) => await MareHubOnReconnected().ConfigureAwait(false)); Mediator.Subscribe(this, (msg) => MareHubOnReconnecting(msg.Exception)); Mediator.Subscribe(this, (msg) => _ = CyclePause(msg.UserData)); + Mediator.Subscribe(this, (msg) => _lastCensus = msg); ServerState = ServerState.Offline; @@ -348,7 +351,15 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM private async Task LoadOnlinePairs() { - foreach (var entry in await UserGetOnlinePairs().ConfigureAwait(false)) + CensusDataDto? dto = null; + if (_serverManager.SendCensusData && _lastCensus != null) + { + var world = await _dalamudUtil.GetWorldIdAsync().ConfigureAwait(false); + dto = new((ushort)world, _lastCensus.RaceId, _lastCensus.TribeId, _lastCensus.Gender); + Logger.LogDebug("Attaching Census Data: {data}", dto); + } + + foreach (var entry in await UserGetOnlinePairs(dto).ConfigureAwait(false)) { Logger.LogDebug("Pair online: {pair}", entry); _pairManager.MarkPairOnline(entry, sendNotif: false);