diff --git a/Content.Client/Entry/EntryPoint.cs b/Content.Client/Entry/EntryPoint.cs index 7f921fc1a6..67c9ccd033 100644 --- a/Content.Client/Entry/EntryPoint.cs +++ b/Content.Client/Entry/EntryPoint.cs @@ -74,6 +74,9 @@ public sealed class EntryPoint : GameClient [Dependency] private readonly ILogManager _logManager = default!; [Dependency] private readonly JoinQueueManager _joinQueue = default!; [Dependency] private readonly DiscordAuthManager _discordAuth = default!; + #if LPP_Sponsors // _LostParadise-Sponsors + [Dependency] private readonly SponsorsManager _sponsorsManager = default!; + #endif public override void Init() { @@ -165,6 +168,11 @@ public override void PostInit() _voteManager.Initialize(); _userInterfaceManager.SetDefaultTheme("SS14DefaultTheme"); _userInterfaceManager.SetActiveTheme(_configManager.GetCVar(CVars.InterfaceTheme)); + + #if LPP_Sponsors + _sponsorsManager.Initialize(); // _LostParadise-Sponsors + #endif + _documentParsingManager.Initialize(); _joinQueue.Initialize(); _discordAuth.Initialize(); diff --git a/Content.Client/IoC/ClientContentIoC.cs b/Content.Client/IoC/ClientContentIoC.cs index 01c8f38281..7a3c2d7c1b 100644 --- a/Content.Client/IoC/ClientContentIoC.cs +++ b/Content.Client/IoC/ClientContentIoC.cs @@ -57,6 +57,9 @@ public static void Register() collection.Register(); IoCManager.Register(); IoCManager.Register(); + #if LPP_Sponsors // _LostParadise-Sponsors + collection.Register(); + #endif } } } diff --git a/Content.Client/Preferences/ClientPreferencesManager.cs b/Content.Client/Preferences/ClientPreferencesManager.cs index aca7159504..4fad97592c 100644 --- a/Content.Client/Preferences/ClientPreferencesManager.cs +++ b/Content.Client/Preferences/ClientPreferencesManager.cs @@ -9,6 +9,9 @@ using Robust.Shared.Network; using Robust.Shared.Prototypes; using Robust.Shared.Utility; +#if LPP_Sponsors // _LostParadise-Sponsors + using Content.Client._LostParadise.Sponsors; +#endif namespace Content.Client.Preferences { @@ -24,6 +27,9 @@ public sealed class ClientPreferencesManager : IClientPreferencesManager [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly IPrototypeManager _prototypes = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; + #if LPP_Sponsors // _LostParadise-Sponsors + [Dependency] private readonly SponsorsManager _sponsorsManager = default!; + #endif public event Action? OnServerDataLoaded; @@ -67,6 +73,13 @@ public void SelectCharacter(int slot) public void UpdateCharacter(ICharacterProfile profile, int slot) { var collection = IoCManager.Instance!; + + #if LPP_Sponsors // _LostParadise-Sponsors + var allowedMarkings = _sponsorsManager.TryGetInfo(out var sponsor) ? sponsor.AllowedMarkings : []; + var session = _playerManager.LocalSession!; + profile.EnsureValid(session, collection, allowedMarkings); + #endif + profile.EnsureValid(_playerManager.LocalSession!, collection); var characters = new Dictionary(Preferences.Characters) {[slot] = profile}; Preferences = new PlayerPreferences(characters, Preferences.SelectedCharacterIndex, Preferences.AdminOOCColor); diff --git a/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs b/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs index 5165db5479..33b1d11178 100644 --- a/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs +++ b/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs @@ -111,8 +111,22 @@ private void UpdateUI() Loc.GetString("character-setup-gui-create-new-character-button-tooltip", ("maxCharacters", _preferencesManager.Settings!.MaxCharacterSlots)); + #if LPP_Sponsors + var isDisplayedMaxSlots = false; // _LostParadise-Sponsors возможно использование дополнительных слотов + #endif + foreach (var (slot, character) in _preferencesManager.Preferences!.Characters) { + if (character is null) + { + continue; + } + + #if LPP_SUBS // _LostParadise-Sponsors + isDisplayedMaxSlots = numberOfFullSlots >= _preferencesManager.Settings.MaxCharacterSlots; + if (isDisplayedMaxSlots) break; + #endif + numberOfFullSlots++; var characterPickerButton = new CharacterPickerButton(_entityManager, _preferencesManager, @@ -133,8 +147,12 @@ private void UpdateUI() }; } + #if LPP_Sponsors // _LostParadise-Sponsors + _createNewCharacterButton.Disabled = isDisplayedMaxSlots; + #else _createNewCharacterButton.Disabled = numberOfFullSlots >= _preferencesManager.Settings.MaxCharacterSlots; + #endif Characters.AddChild(_createNewCharacterButton); // TODO: Move this shit to the Lobby UI controller } diff --git a/Content.Server.Database/Model.cs b/Content.Server.Database/Model.cs index d34bb489c9..d7c2c8f015 100644 --- a/Content.Server.Database/Model.cs +++ b/Content.Server.Database/Model.cs @@ -40,6 +40,7 @@ protected ServerDbContext(DbContextOptions options) : base(options) public DbSet AdminNotes { get; set; } = null!; public DbSet AdminWatchlists { get; set; } = null!; public DbSet AdminMessages { get; set; } = null!; + public DbSet Sponsors { get; set; } = null!; // _LostParadise-Sponsors protected override void OnModelCreating(ModelBuilder modelBuilder) { @@ -1025,4 +1026,17 @@ public class AdminMessage : IAdminRemarksCommon /// public bool Dismissed { get; set; } } + + [Table("sponsors")] // _LostParadise-Sponsors + public class Sponsor + { + [Required, Key] public Guid UserId { get; set; } + public int Tier { get; set; } + public string OOCColor { get; set; } = "#00FF00"; + public bool HavePriorityJoin { get; set; } + public string AllowedMarkings { get; set; } = null!; + public int ExtraSlots { get; set; } + public DateTime ExpireDate {get;set;} + public bool AllowJob { get; set; } = false; + } } diff --git a/Content.Server/Chat/Managers/ChatManager.cs b/Content.Server/Chat/Managers/ChatManager.cs index 812aed80bd..7cfaed45d0 100644 --- a/Content.Server/Chat/Managers/ChatManager.cs +++ b/Content.Server/Chat/Managers/ChatManager.cs @@ -18,6 +18,9 @@ using Robust.Shared.Replays; using Robust.Shared.Timing; using Robust.Shared.Utility; +#if LPP_Sponsors // _LostParadise-Sponsors + using Content.Server._LostParadise.Sponsors; +#endif namespace Content.Server.Chat.Managers { @@ -45,6 +48,9 @@ internal sealed partial class ChatManager : IChatManager [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; + #if LPP_Sponsors // _LostParadise-Sponsors + [Dependency] private readonly SponsorsManager _sponsorsManager = default!; + #endif /// /// The maximum length a player-sent message can be sent @@ -244,11 +250,18 @@ private void SendOOC(ICommonSession player, string message) var prefs = _preferencesManager.GetPreferences(player.UserId); colorOverride = prefs.AdminOOCColor; } - if ( _netConfigManager.GetClientCVar(player.Channel, CCVars.ShowOocPatronColor) && player.Channel.UserData.PatronTier is { } patron && PatronOocColors.TryGetValue(patron, out var patronColor)) + if (_netConfigManager.GetClientCVar(player.Channel, CCVars.ShowOocPatronColor) && player.Channel.UserData.PatronTier is { } patron && PatronOocColors.TryGetValue(patron, out var patronColor)) { wrappedMessage = Loc.GetString("chat-manager-send-ooc-patron-wrap-message", ("patronColor", patronColor),("playerName", player.Name), ("message", FormattedMessage.EscapeText(message))); } + #if LPP_Sponsors // _LostParadise-Sponsors + if (_sponsorsManager.TryGetInfo(player.UserId, out var sponsorData) && sponsorData.OOCColor != null) + { + wrappedMessage = Loc.GetString("chat-manager-send-ooc-patron-wrap-message", ("patronColor", sponsorData.OOCColor),("playerName", player.Name), ("message", FormattedMessage.EscapeText(message))); + } + #endif + //TODO: player.Name color, this will need to change the structure of the MsgChatMessage ChatMessageToAll(ChatChannel.OOC, message, wrappedMessage, EntityUid.Invalid, hideChat: false, recordReplay: true, colorOverride: colorOverride, author: player.UserId); _mommiLink.SendOOCMessage(player.Name, message); diff --git a/Content.Server/Connection/ConnectionManager.cs b/Content.Server/Connection/ConnectionManager.cs index 64e93c5af1..9b68304d83 100644 --- a/Content.Server/Connection/ConnectionManager.cs +++ b/Content.Server/Connection/ConnectionManager.cs @@ -12,6 +12,10 @@ using Robust.Shared.Configuration; using Robust.Shared.Network; using Robust.Shared.Timing; +#if LPP_Sponsors // _LostParadise-Sponsors + using Content.Server._LostParadise.Sponsors; + using Content.Shared._LostParadise.CCVar; +#endif namespace Content.Server.Connection @@ -49,6 +53,9 @@ public sealed class ConnectionManager : IConnectionManager [Dependency] private readonly ServerDbEntryManager _serverDbEntry = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly ILogManager _logManager = default!; + #if LPP_Sponsors // _LostParadise-Sponsors + [Dependency] private readonly SponsorsManager _sponsorsManager = default!; + #endif private readonly Dictionary _temporaryBypasses = []; private ISawmill _sawmill = default!; @@ -157,7 +164,12 @@ private async Task NetMgrOnConnecting(NetConnectingArgs e) var adminData = await _dbManager.GetAdminDataForAsync(e.UserId); - if (_cfg.GetCVar(CCVars.PanicBunkerEnabled) && adminData == null) + #if LPP_Sponsors // _LostParadise-Sponsors + var isPrivileged = await HavePrivilegedJoin(e.UserId); + if (_cfg.GetCVar(CCVars.PanicBunkerEnabled) && adminData == null && !isPrivileged) + #else + if (_cfg.GetCVar(CCVars.PanicBunkerEnabled) && adminData == null) + #endif { var showReason = _cfg.GetCVar(CCVars.PanicBunkerShowReason); var customReason = _cfg.GetCVar(CCVars.PanicBunkerCustomReason); @@ -310,7 +322,16 @@ public async Task HasPrivilegedJoin(NetUserId userId) var wasInGame = EntitySystem.TryGet(out var ticker) && ticker.PlayerGameStatuses.TryGetValue(userId, out var status) && status == PlayerGameStatus.JoinedGame; - return isAdmin || wasInGame; + + #if LPP_Sponsors // _LostParadise-Sponsors + var havePriorityJoin = _sponsorsManager.TryGetInfo(userId, out var sponsor) && sponsor.HavePriorityJoin; + #endif + + return isAdmin || + #if LPP_Sponsors // _LostParadise-Sponsors + havePriorityJoin || + #endif + wasInGame; } } } diff --git a/Content.Server/Database/ServerDbBase.cs b/Content.Server/Database/ServerDbBase.cs index fceeb4d487..dcffe63081 100644 --- a/Content.Server/Database/ServerDbBase.cs +++ b/Content.Server/Database/ServerDbBase.cs @@ -1580,5 +1580,19 @@ protected abstract class DbGuard : IAsyncDisposable public abstract ValueTask DisposeAsync(); } + + #region Sponsors + public async Task GetSponsorInfo(NetUserId userId) // _LostParadise-Sponsors + { + await using var db = await GetDb(); + return await db.DbContext.Sponsors.AsNoTracking().FirstOrDefaultAsync(x => x.UserId == userId.UserId); + } + + public async Task GetSponsorList() // _LostParadise-Sponsors + { + await using var db = await GetDb(); + return await db.DbContext.Sponsors.AsNoTracking().ToArrayAsync(); + } + #endregion } } diff --git a/Content.Server/Database/ServerDbManager.cs b/Content.Server/Database/ServerDbManager.cs index 554dd30743..814c905660 100644 --- a/Content.Server/Database/ServerDbManager.cs +++ b/Content.Server/Database/ServerDbManager.cs @@ -285,6 +285,11 @@ Task AddConnectionLogAsync( Task MarkMessageAsSeen(int id, bool dismissedToo); #endregion + + #region Sponsors + Task GetSponsorInfo(NetUserId userId, CancellationToken cancel = default); //_LostParadise-Sponsors + Task GetSponsorList(CancellationToken cancel = default); + #endregion } public sealed class ServerDbManager : IServerDbManager @@ -916,6 +921,19 @@ private IAsyncEnumerable RunDbCommand(Func> command) return enumerable; } + // _LostParadise-Sponsors + public async Task GetSponsorInfo(NetUserId userId, CancellationToken cancel = default) + { + DbWriteOpsMetric.Inc(); + return await _db.GetSponsorInfo(userId); + } + + public async Task GetSponsorList(CancellationToken cancel = default) + { + DbWriteOpsMetric.Inc(); + return await _db.GetSponsorList(); + } + private DbContextOptions CreatePostgresOptions() { var host = _cfg.GetCVar(CCVars.DatabasePgHost); diff --git a/Content.Server/Entry/EntryPoint.cs b/Content.Server/Entry/EntryPoint.cs index 9c52020b17..c9eec87a95 100644 --- a/Content.Server/Entry/EntryPoint.cs +++ b/Content.Server/Entry/EntryPoint.cs @@ -32,6 +32,9 @@ using Robust.Shared.Prototypes; using Robust.Shared.Timing; using Robust.Shared.Utility; +#if LPP_Sponsors // _LostParadise-Sponsors + using Content.Server._LostParadise.Sponsors; +#endif namespace Content.Server.Entry { @@ -109,6 +112,9 @@ public override void Init() IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); + #if LPP_Sponsors // _LostParadise-Sponsors + IoCManager.Resolve().Initialize(); + #endif _voteManager.Initialize(); _updateManager.Initialize(); diff --git a/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs b/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs index f1f7de5c11..97e3a94d62 100644 --- a/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs +++ b/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs @@ -219,11 +219,29 @@ public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearanc hairStyleId = HairStyles.DefaultHairStyle; } + #if LPP_Sponsors // _LostParadise-Sponsors + if (proto.TryIndex(hairStyleId, out MarkingPrototype? hairProto) && + hairProto.SponsorOnly && + !sponsorPrototypes.Contains(hairStyleId)) + { + hairStyleId = HairStyles.DefaultHairStyle; + } + #endif + if (!markingManager.MarkingsByCategory(MarkingCategories.FacialHair).ContainsKey(facialHairStyleId)) { facialHairStyleId = HairStyles.DefaultFacialHairStyle; } + #if LPP_Sponsors // _LostParadise-Sponsors + if (proto.TryIndex(facialHairStyleId, out MarkingPrototype? facialHairProto) && + facialHairProto.SponsorOnly && + !sponsorPrototypes.Contains(facialHairStyleId)) + { + facialHairStyleId = HairStyles.DefaultFacialHairStyle; + } + #endif + var markingSet = new MarkingSet(); var skinColor = appearance.SkinColor; if (proto.TryIndex(species, out SpeciesPrototype? speciesProto)) @@ -238,6 +256,9 @@ public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearanc markingSet.EnsureSpecies(species, skinColor, markingManager); markingSet.EnsureSexes(sex, markingManager); + #if LPP_Sponsors // _LostParadise-Sponsors + markingSet.FilterSponsor(sponsorPrototypes, markingManager); + #endif } return new HumanoidCharacterAppearance( diff --git a/Content.Shared/_LostParadise/CCVars.cs b/Content.Shared/_LostParadise/CCVars.cs index 912baa8e7f..1c9037dcd4 100644 --- a/Content.Shared/_LostParadise/CCVars.cs +++ b/Content.Shared/_LostParadise/CCVars.cs @@ -7,4 +7,20 @@ public sealed partial class AccVars { public static readonly CVarDef DiscordBanWebhook = CVarDef.Create("discord.ban_webhook", "", CVar.SERVERONLY); + + /// + /// URL of the sponsors server API. + /// + public static readonly CVarDef SponsorsApiUrl = + CVarDef.Create("sponsor.api_url", "", CVar.SERVERONLY); + + /* + * Queue + */ + + /// + /// Controls if the connections queue is enabled. If enabled stop kicking new players after `SoftMaxPlayers` cap and instead add them to queue. + /// + public static readonly CVarDef + QueueEnabled = CVarDef.Create("queue.enabled", false, CVar.SERVERONLY); }