From a3d0e3f6a797f396ea24e3df79252560c058f8d7 Mon Sep 17 00:00:00 2001 From: Leo Date: Sun, 14 Feb 2021 11:59:56 -0300 Subject: [PATCH] OOC sent by an admin will have a different color (#3117) * Admin OOC is sent with a different color than regular OOC - Also adds the OOC color to the database * Command to set the color * Ooc -> OOC * Change default color to Red (`#ff0000`) * Outdated namespace --- Content.Client/Chat/ChatManager.cs | 30 +- Content.Client/Chat/StoredChatMessage.cs | 8 + Content.Client/ClientPreferencesManager.cs | 8 +- .../20210211211033_AdminOOCColor.Designer.cs | 580 ++++++++++++++++++ .../Postgres/20210211211033_AdminOOCColor.cs | 24 + .../PostgresServerDbContextModelSnapshot.cs | 5 + .../20210211211028_AdminOOCColor.Designer.cs | 547 +++++++++++++++++ .../Sqlite/20210211211028_AdminOOCColor.cs | 24 + .../SqliteServerDbContextModelSnapshot.cs | 5 + Content.Server.Database/Model.cs | 1 + .../Administration/Commands/SetAdminOOC.cs | 53 ++ Content.Server/Chat/ChatManager.cs | 10 +- Content.Server/Database/ServerDbBase.cs | 23 +- Content.Server/Database/ServerDbManager.cs | 8 + .../Preferences/ServerPreferencesManager.cs | 11 +- Content.Shared/Chat/MsgChatMessage.cs | 11 + .../Preferences/PlayerPreferences.cs | 6 +- 17 files changed, 1324 insertions(+), 30 deletions(-) create mode 100644 Content.Server.Database/Migrations/Postgres/20210211211033_AdminOOCColor.Designer.cs create mode 100644 Content.Server.Database/Migrations/Postgres/20210211211033_AdminOOCColor.cs create mode 100644 Content.Server.Database/Migrations/Sqlite/20210211211028_AdminOOCColor.Designer.cs create mode 100644 Content.Server.Database/Migrations/Sqlite/20210211211028_AdminOOCColor.cs create mode 100644 Content.Server/Administration/Commands/SetAdminOOC.cs diff --git a/Content.Client/Chat/ChatManager.cs b/Content.Client/Chat/ChatManager.cs index 040da90864..2b02428b45 100644 --- a/Content.Client/Chat/ChatManager.cs +++ b/Content.Client/Chat/ChatManager.cs @@ -205,23 +205,21 @@ namespace Content.Client.Chat messageText = string.Format(message.MessageWrap, messageText); } - switch (message.Channel) + if (message.MessageColorOverride != Color.Transparent) { - case ChatChannel.Server: - color = Color.Orange; - break; - case ChatChannel.Radio: - color = Color.Green; - break; - case ChatChannel.OOC: - color = Color.LightSkyBlue; - break; - case ChatChannel.Dead: - color = Color.MediumPurple; - break; - case ChatChannel.AdminChat: - color = Color.Red; - break; + color = message.MessageColorOverride; + } + else + { + color = message.Channel switch + { + ChatChannel.Server => Color.Orange, + ChatChannel.Radio => Color.Green, + ChatChannel.OOC => Color.LightSkyBlue, + ChatChannel.Dead => Color.MediumPurple, + ChatChannel.AdminChat => Color.Red, + _ => color + }; } _currentChatBox?.AddLine(messageText, message.Channel, color); diff --git a/Content.Client/Chat/StoredChatMessage.cs b/Content.Client/Chat/StoredChatMessage.cs index 083f889b60..eb70a96545 100644 --- a/Content.Client/Chat/StoredChatMessage.cs +++ b/Content.Client/Chat/StoredChatMessage.cs @@ -1,4 +1,6 @@ using Content.Shared.Chat; +using Robust.Shared.Log; +using Robust.Shared.Maths; namespace Content.Client.Chat { @@ -25,6 +27,11 @@ namespace Content.Client.Chat /// public string MessageWrap { get; set; } + /// + /// The override color of the message + /// + public Color MessageColorOverride { get; set; } + /// /// Constructor to copy a net message into stored client variety /// @@ -33,6 +40,7 @@ namespace Content.Client.Chat Message = netMsg.Message; Channel = netMsg.Channel; MessageWrap = netMsg.MessageWrap; + MessageColorOverride = netMsg.MessageColorOverride; } } } diff --git a/Content.Client/ClientPreferencesManager.cs b/Content.Client/ClientPreferencesManager.cs index 5d01c9705c..4c87277c36 100644 --- a/Content.Client/ClientPreferencesManager.cs +++ b/Content.Client/ClientPreferencesManager.cs @@ -39,7 +39,7 @@ namespace Content.Client public void SelectCharacter(int slot) { - Preferences = new PlayerPreferences(Preferences.Characters, slot); + Preferences = new PlayerPreferences(Preferences.Characters, slot, Preferences.AdminOOCColor); var msg = _netManager.CreateNetMessage(); msg.SelectedCharacterIndex = slot; _netManager.ClientSendMessage(msg); @@ -48,7 +48,7 @@ namespace Content.Client public void UpdateCharacter(ICharacterProfile profile, int slot) { var characters = new Dictionary(Preferences.Characters) {[slot] = profile}; - Preferences = new PlayerPreferences(characters, Preferences.SelectedCharacterIndex); + Preferences = new PlayerPreferences(characters, Preferences.SelectedCharacterIndex, Preferences.AdminOOCColor); var msg = _netManager.CreateNetMessage(); msg.Profile = profile; msg.Slot = slot; @@ -69,7 +69,7 @@ namespace Content.Client var l = lowest.Value; characters.Add(l, profile); - Preferences = new PlayerPreferences(characters, Preferences.SelectedCharacterIndex); + Preferences = new PlayerPreferences(characters, Preferences.SelectedCharacterIndex, Preferences.AdminOOCColor); UpdateCharacter(profile, l); } @@ -82,7 +82,7 @@ namespace Content.Client public void DeleteCharacter(int slot) { var characters = Preferences.Characters.Where(p => p.Key != slot); - Preferences = new PlayerPreferences(characters, Preferences.SelectedCharacterIndex); + Preferences = new PlayerPreferences(characters, Preferences.SelectedCharacterIndex, Preferences.AdminOOCColor); var msg = _netManager.CreateNetMessage(); msg.Slot = slot; _netManager.ClientSendMessage(msg); diff --git a/Content.Server.Database/Migrations/Postgres/20210211211033_AdminOOCColor.Designer.cs b/Content.Server.Database/Migrations/Postgres/20210211211033_AdminOOCColor.Designer.cs new file mode 100644 index 0000000000..e5341a532d --- /dev/null +++ b/Content.Server.Database/Migrations/Postgres/20210211211033_AdminOOCColor.Designer.cs @@ -0,0 +1,580 @@ +// +using System; +using System.Net; +using Content.Server.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +namespace Content.Server.Database.Migrations.Postgres +{ + [DbContext(typeof(PostgresServerDbContext))] + [Migration("20210211211033_AdminOOCColor")] + partial class AdminOOCColor + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .UseIdentityByDefaultColumns() + .HasAnnotation("Relational:MaxIdentifierLength", 63) + .HasAnnotation("ProductVersion", "5.0.0"); + + modelBuilder.Entity("Content.Server.Database.Admin", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.Property("AdminRankId") + .HasColumnType("integer") + .HasColumnName("admin_rank_id"); + + b.Property("Title") + .HasColumnType("text") + .HasColumnName("title"); + + b.HasKey("UserId"); + + b.HasIndex("AdminRankId"); + + b.ToTable("admin"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminFlag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("admin_flag_id") + .UseIdentityByDefaultColumn(); + + b.Property("AdminId") + .HasColumnType("uuid") + .HasColumnName("admin_id"); + + b.Property("Flag") + .IsRequired() + .HasColumnType("text") + .HasColumnName("flag"); + + b.Property("Negative") + .HasColumnType("boolean") + .HasColumnName("negative"); + + b.HasKey("Id"); + + b.HasIndex("AdminId"); + + b.HasIndex("Flag", "AdminId") + .IsUnique(); + + b.ToTable("admin_flag"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminRank", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("admin_rank_id") + .UseIdentityByDefaultColumn(); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.HasKey("Id"); + + b.ToTable("admin_rank"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("admin_rank_flag_id") + .UseIdentityByDefaultColumn(); + + b.Property("AdminRankId") + .HasColumnType("integer") + .HasColumnName("admin_rank_id"); + + b.Property("Flag") + .IsRequired() + .HasColumnType("text") + .HasColumnName("flag"); + + b.HasKey("Id"); + + b.HasIndex("AdminRankId"); + + b.HasIndex("Flag", "AdminRankId") + .IsUnique(); + + b.ToTable("admin_rank_flag"); + }); + + modelBuilder.Entity("Content.Server.Database.Antag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("antag_id") + .UseIdentityByDefaultColumn(); + + b.Property("AntagName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("antag_name"); + + b.Property("ProfileId") + .HasColumnType("integer") + .HasColumnName("profile_id"); + + b.HasKey("Id"); + + b.HasIndex("ProfileId", "AntagName") + .IsUnique(); + + b.ToTable("antag"); + }); + + modelBuilder.Entity("Content.Server.Database.AssignedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("assigned_user_id_id") + .UseIdentityByDefaultColumn(); + + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("user_name"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.HasIndex("UserName") + .IsUnique(); + + b.ToTable("assigned_user_id"); + }); + + modelBuilder.Entity("Content.Server.Database.Job", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("job_id") + .UseIdentityByDefaultColumn(); + + b.Property("JobName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("job_name"); + + b.Property("Priority") + .HasColumnType("integer") + .HasColumnName("priority"); + + b.Property("ProfileId") + .HasColumnType("integer") + .HasColumnName("profile_id"); + + b.HasKey("Id"); + + b.HasIndex("ProfileId"); + + b.ToTable("job"); + }); + + modelBuilder.Entity("Content.Server.Database.PostgresConnectionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("connection_log_id") + .UseIdentityByDefaultColumn(); + + b.Property("Address") + .IsRequired() + .HasColumnType("inet") + .HasColumnName("address"); + + b.Property("Time") + .HasColumnType("timestamp with time zone") + .HasColumnName("time"); + + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("user_name"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("connection_log"); + + b.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address"); + }); + + modelBuilder.Entity("Content.Server.Database.PostgresPlayer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("player_id") + .UseIdentityByDefaultColumn(); + + b.Property("FirstSeenTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("first_seen_time"); + + b.Property("LastSeenAddress") + .IsRequired() + .HasColumnType("inet") + .HasColumnName("last_seen_address"); + + b.Property("LastSeenTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_seen_time"); + + b.Property("LastSeenUserName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("last_seen_user_name"); + + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.HasKey("Id"); + + b.HasIndex("LastSeenUserName"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("player"); + + b.HasCheckConstraint("LastSeenAddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= last_seen_address"); + }); + + modelBuilder.Entity("Content.Server.Database.PostgresServerBan", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("server_ban_id") + .UseIdentityByDefaultColumn(); + + b.Property?>("Address") + .HasColumnType("inet") + .HasColumnName("address"); + + b.Property("BanTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("ban_time"); + + b.Property("BanningAdmin") + .HasColumnType("uuid") + .HasColumnName("banning_admin"); + + b.Property("ExpirationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("expiration_time"); + + b.Property("Reason") + .IsRequired() + .HasColumnType("text") + .HasColumnName("reason"); + + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.HasKey("Id"); + + b.HasIndex("Address"); + + b.HasIndex("UserId"); + + b.ToTable("server_ban"); + + b.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address"); + + b.HasCheckConstraint("HaveEitherAddressOrUserId", "address IS NOT NULL OR user_id IS NOT NULL"); + }); + + modelBuilder.Entity("Content.Server.Database.PostgresServerUnban", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("unban_id") + .UseIdentityByDefaultColumn(); + + b.Property("BanId") + .HasColumnType("integer") + .HasColumnName("ban_id"); + + b.Property("UnbanTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("unban_time"); + + b.Property("UnbanningAdmin") + .HasColumnType("uuid") + .HasColumnName("unbanning_admin"); + + b.HasKey("Id"); + + b.HasIndex("BanId") + .IsUnique(); + + b.ToTable("server_unban"); + }); + + modelBuilder.Entity("Content.Server.Database.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("preference_id") + .UseIdentityByDefaultColumn(); + + b.Property("AdminOOCColor") + .IsRequired() + .HasColumnType("text") + .HasColumnName("admin_ooc_color"); + + b.Property("SelectedCharacterSlot") + .HasColumnType("integer") + .HasColumnName("selected_character_slot"); + + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("preference"); + }); + + modelBuilder.Entity("Content.Server.Database.Profile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("profile_id") + .UseIdentityByDefaultColumn(); + + b.Property("Age") + .HasColumnType("integer") + .HasColumnName("age"); + + b.Property("Backpack") + .IsRequired() + .HasColumnType("text") + .HasColumnName("backpack"); + + b.Property("CharacterName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("char_name"); + + b.Property("Clothing") + .IsRequired() + .HasColumnType("text") + .HasColumnName("clothing"); + + b.Property("EyeColor") + .IsRequired() + .HasColumnType("text") + .HasColumnName("eye_color"); + + b.Property("FacialHairColor") + .IsRequired() + .HasColumnType("text") + .HasColumnName("facial_hair_color"); + + b.Property("FacialHairName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("facial_hair_name"); + + b.Property("Gender") + .IsRequired() + .HasColumnType("text") + .HasColumnName("gender"); + + b.Property("HairColor") + .IsRequired() + .HasColumnType("text") + .HasColumnName("hair_color"); + + b.Property("HairName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("hair_name"); + + b.Property("PreferenceId") + .HasColumnType("integer") + .HasColumnName("preference_id"); + + b.Property("PreferenceUnavailable") + .HasColumnType("integer") + .HasColumnName("pref_unavailable"); + + b.Property("Sex") + .IsRequired() + .HasColumnType("text") + .HasColumnName("sex"); + + b.Property("SkinColor") + .IsRequired() + .HasColumnType("text") + .HasColumnName("skin_color"); + + b.Property("Slot") + .HasColumnType("integer") + .HasColumnName("slot"); + + b.HasKey("Id"); + + b.HasIndex("PreferenceId"); + + b.HasIndex("Slot", "PreferenceId") + .IsUnique(); + + b.ToTable("profile"); + }); + + modelBuilder.Entity("Content.Server.Database.Admin", b => + { + b.HasOne("Content.Server.Database.AdminRank", "AdminRank") + .WithMany("Admins") + .HasForeignKey("AdminRankId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("AdminRank"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminFlag", b => + { + b.HasOne("Content.Server.Database.Admin", "Admin") + .WithMany("Flags") + .HasForeignKey("AdminId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Admin"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b => + { + b.HasOne("Content.Server.Database.AdminRank", "Rank") + .WithMany("Flags") + .HasForeignKey("AdminRankId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Rank"); + }); + + modelBuilder.Entity("Content.Server.Database.Antag", b => + { + b.HasOne("Content.Server.Database.Profile", "Profile") + .WithMany("Antags") + .HasForeignKey("ProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Profile"); + }); + + modelBuilder.Entity("Content.Server.Database.Job", b => + { + b.HasOne("Content.Server.Database.Profile", "Profile") + .WithMany("Jobs") + .HasForeignKey("ProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Profile"); + }); + + modelBuilder.Entity("Content.Server.Database.PostgresServerUnban", b => + { + b.HasOne("Content.Server.Database.PostgresServerBan", "Ban") + .WithOne("Unban") + .HasForeignKey("Content.Server.Database.PostgresServerUnban", "BanId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ban"); + }); + + modelBuilder.Entity("Content.Server.Database.Profile", b => + { + b.HasOne("Content.Server.Database.Preference", "Preference") + .WithMany("Profiles") + .HasForeignKey("PreferenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Preference"); + }); + + modelBuilder.Entity("Content.Server.Database.Admin", b => + { + b.Navigation("Flags"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminRank", b => + { + b.Navigation("Admins"); + + b.Navigation("Flags"); + }); + + modelBuilder.Entity("Content.Server.Database.PostgresServerBan", b => + { + b.Navigation("Unban"); + }); + + modelBuilder.Entity("Content.Server.Database.Preference", b => + { + b.Navigation("Profiles"); + }); + + modelBuilder.Entity("Content.Server.Database.Profile", b => + { + b.Navigation("Antags"); + + b.Navigation("Jobs"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Content.Server.Database/Migrations/Postgres/20210211211033_AdminOOCColor.cs b/Content.Server.Database/Migrations/Postgres/20210211211033_AdminOOCColor.cs new file mode 100644 index 0000000000..5c3235d354 --- /dev/null +++ b/Content.Server.Database/Migrations/Postgres/20210211211033_AdminOOCColor.cs @@ -0,0 +1,24 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Content.Server.Database.Migrations.Postgres +{ + public partial class AdminOOCColor : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "admin_ooc_color", + table: "preference", + type: "text", + nullable: false, + defaultValue: "#ff0000"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "admin_ooc_color", + table: "preference"); + } + } +} diff --git a/Content.Server.Database/Migrations/Postgres/PostgresServerDbContextModelSnapshot.cs b/Content.Server.Database/Migrations/Postgres/PostgresServerDbContextModelSnapshot.cs index b7a48063b5..cb42d609c3 100644 --- a/Content.Server.Database/Migrations/Postgres/PostgresServerDbContextModelSnapshot.cs +++ b/Content.Server.Database/Migrations/Postgres/PostgresServerDbContextModelSnapshot.cs @@ -358,6 +358,11 @@ namespace Content.Server.Database.Migrations.Postgres .HasColumnName("preference_id") .UseIdentityByDefaultColumn(); + b.Property("AdminOOCColor") + .IsRequired() + .HasColumnType("text") + .HasColumnName("admin_ooc_color"); + b.Property("SelectedCharacterSlot") .HasColumnType("integer") .HasColumnName("selected_character_slot"); diff --git a/Content.Server.Database/Migrations/Sqlite/20210211211028_AdminOOCColor.Designer.cs b/Content.Server.Database/Migrations/Sqlite/20210211211028_AdminOOCColor.Designer.cs new file mode 100644 index 0000000000..f11e1c7ab5 --- /dev/null +++ b/Content.Server.Database/Migrations/Sqlite/20210211211028_AdminOOCColor.Designer.cs @@ -0,0 +1,547 @@ +// +using System; +using Content.Server.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Content.Server.Database.Migrations.Sqlite +{ + [DbContext(typeof(SqliteServerDbContext))] + [Migration("20210211211028_AdminOOCColor")] + partial class AdminOOCColor + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "5.0.0"); + + modelBuilder.Entity("Content.Server.Database.Admin", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasColumnName("user_id"); + + b.Property("AdminRankId") + .HasColumnType("INTEGER") + .HasColumnName("admin_rank_id"); + + b.Property("Title") + .HasColumnType("TEXT") + .HasColumnName("title"); + + b.HasKey("UserId"); + + b.HasIndex("AdminRankId"); + + b.ToTable("admin"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminFlag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("admin_flag_id"); + + b.Property("AdminId") + .HasColumnType("TEXT") + .HasColumnName("admin_id"); + + b.Property("Flag") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("flag"); + + b.Property("Negative") + .HasColumnType("INTEGER") + .HasColumnName("negative"); + + b.HasKey("Id"); + + b.HasIndex("AdminId"); + + b.HasIndex("Flag", "AdminId") + .IsUnique(); + + b.ToTable("admin_flag"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminRank", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("admin_rank_id"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("name"); + + b.HasKey("Id"); + + b.ToTable("admin_rank"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("admin_rank_flag_id"); + + b.Property("AdminRankId") + .HasColumnType("INTEGER") + .HasColumnName("admin_rank_id"); + + b.Property("Flag") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("flag"); + + b.HasKey("Id"); + + b.HasIndex("AdminRankId"); + + b.HasIndex("Flag", "AdminRankId") + .IsUnique(); + + b.ToTable("admin_rank_flag"); + }); + + modelBuilder.Entity("Content.Server.Database.Antag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("antag_id"); + + b.Property("AntagName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("antag_name"); + + b.Property("ProfileId") + .HasColumnType("INTEGER") + .HasColumnName("profile_id"); + + b.HasKey("Id"); + + b.HasIndex("ProfileId", "AntagName") + .IsUnique(); + + b.ToTable("antag"); + }); + + modelBuilder.Entity("Content.Server.Database.AssignedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("assigned_user_id_id"); + + b.Property("UserId") + .HasColumnType("TEXT") + .HasColumnName("user_id"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("user_name"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.HasIndex("UserName") + .IsUnique(); + + b.ToTable("assigned_user_id"); + }); + + modelBuilder.Entity("Content.Server.Database.Job", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("job_id"); + + b.Property("JobName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("job_name"); + + b.Property("Priority") + .HasColumnType("INTEGER") + .HasColumnName("priority"); + + b.Property("ProfileId") + .HasColumnType("INTEGER") + .HasColumnName("profile_id"); + + b.HasKey("Id"); + + b.HasIndex("ProfileId"); + + b.ToTable("job"); + }); + + modelBuilder.Entity("Content.Server.Database.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("preference_id"); + + b.Property("AdminOOCColor") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("admin_ooc_color"); + + b.Property("SelectedCharacterSlot") + .HasColumnType("INTEGER") + .HasColumnName("selected_character_slot"); + + b.Property("UserId") + .HasColumnType("TEXT") + .HasColumnName("user_id"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("preference"); + }); + + modelBuilder.Entity("Content.Server.Database.Profile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("profile_id"); + + b.Property("Age") + .HasColumnType("INTEGER") + .HasColumnName("age"); + + b.Property("Backpack") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("backpack"); + + b.Property("CharacterName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("char_name"); + + b.Property("Clothing") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("clothing"); + + b.Property("EyeColor") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("eye_color"); + + b.Property("FacialHairColor") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("facial_hair_color"); + + b.Property("FacialHairName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("facial_hair_name"); + + b.Property("Gender") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("gender"); + + b.Property("HairColor") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("hair_color"); + + b.Property("HairName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("hair_name"); + + b.Property("PreferenceId") + .HasColumnType("INTEGER") + .HasColumnName("preference_id"); + + b.Property("PreferenceUnavailable") + .HasColumnType("INTEGER") + .HasColumnName("pref_unavailable"); + + b.Property("Sex") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("sex"); + + b.Property("SkinColor") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("skin_color"); + + b.Property("Slot") + .HasColumnType("INTEGER") + .HasColumnName("slot"); + + b.HasKey("Id"); + + b.HasIndex("PreferenceId"); + + b.HasIndex("Slot", "PreferenceId") + .IsUnique(); + + b.ToTable("profile"); + }); + + modelBuilder.Entity("Content.Server.Database.SqliteConnectionLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("connection_log_id"); + + b.Property("Address") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("address"); + + b.Property("Time") + .HasColumnType("TEXT") + .HasColumnName("time"); + + b.Property("UserId") + .HasColumnType("TEXT") + .HasColumnName("user_id"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("user_name"); + + b.HasKey("Id"); + + b.ToTable("connection_log"); + }); + + modelBuilder.Entity("Content.Server.Database.SqlitePlayer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("player_id"); + + b.Property("FirstSeenTime") + .HasColumnType("TEXT") + .HasColumnName("first_seen_time"); + + b.Property("LastSeenAddress") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("last_seen_address"); + + b.Property("LastSeenTime") + .HasColumnType("TEXT") + .HasColumnName("last_seen_time"); + + b.Property("LastSeenUserName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("last_seen_user_name"); + + b.Property("UserId") + .HasColumnType("TEXT") + .HasColumnName("user_id"); + + b.HasKey("Id"); + + b.HasIndex("LastSeenUserName"); + + b.ToTable("player"); + }); + + modelBuilder.Entity("Content.Server.Database.SqliteServerBan", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("ban_id"); + + b.Property("Address") + .HasColumnType("TEXT") + .HasColumnName("address"); + + b.Property("BanTime") + .HasColumnType("TEXT") + .HasColumnName("ban_time"); + + b.Property("BanningAdmin") + .HasColumnType("TEXT") + .HasColumnName("banning_admin"); + + b.Property("ExpirationTime") + .HasColumnType("TEXT") + .HasColumnName("expiration_time"); + + b.Property("Reason") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("reason"); + + b.Property("UserId") + .HasColumnType("TEXT") + .HasColumnName("user_id"); + + b.HasKey("Id"); + + b.ToTable("ban"); + }); + + modelBuilder.Entity("Content.Server.Database.SqliteServerUnban", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("unban_id"); + + b.Property("BanId") + .HasColumnType("INTEGER") + .HasColumnName("ban_id"); + + b.Property("UnbanTime") + .HasColumnType("TEXT") + .HasColumnName("unban_time"); + + b.Property("UnbanningAdmin") + .HasColumnType("TEXT") + .HasColumnName("unbanning_admin"); + + b.HasKey("Id"); + + b.HasIndex("BanId") + .IsUnique(); + + b.ToTable("unban"); + }); + + modelBuilder.Entity("Content.Server.Database.Admin", b => + { + b.HasOne("Content.Server.Database.AdminRank", "AdminRank") + .WithMany("Admins") + .HasForeignKey("AdminRankId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("AdminRank"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminFlag", b => + { + b.HasOne("Content.Server.Database.Admin", "Admin") + .WithMany("Flags") + .HasForeignKey("AdminId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Admin"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b => + { + b.HasOne("Content.Server.Database.AdminRank", "Rank") + .WithMany("Flags") + .HasForeignKey("AdminRankId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Rank"); + }); + + modelBuilder.Entity("Content.Server.Database.Antag", b => + { + b.HasOne("Content.Server.Database.Profile", "Profile") + .WithMany("Antags") + .HasForeignKey("ProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Profile"); + }); + + modelBuilder.Entity("Content.Server.Database.Job", b => + { + b.HasOne("Content.Server.Database.Profile", "Profile") + .WithMany("Jobs") + .HasForeignKey("ProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Profile"); + }); + + modelBuilder.Entity("Content.Server.Database.Profile", b => + { + b.HasOne("Content.Server.Database.Preference", "Preference") + .WithMany("Profiles") + .HasForeignKey("PreferenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Preference"); + }); + + modelBuilder.Entity("Content.Server.Database.SqliteServerUnban", b => + { + b.HasOne("Content.Server.Database.SqliteServerBan", "Ban") + .WithOne("Unban") + .HasForeignKey("Content.Server.Database.SqliteServerUnban", "BanId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ban"); + }); + + modelBuilder.Entity("Content.Server.Database.Admin", b => + { + b.Navigation("Flags"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminRank", b => + { + b.Navigation("Admins"); + + b.Navigation("Flags"); + }); + + modelBuilder.Entity("Content.Server.Database.Preference", b => + { + b.Navigation("Profiles"); + }); + + modelBuilder.Entity("Content.Server.Database.Profile", b => + { + b.Navigation("Antags"); + + b.Navigation("Jobs"); + }); + + modelBuilder.Entity("Content.Server.Database.SqliteServerBan", b => + { + b.Navigation("Unban"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Content.Server.Database/Migrations/Sqlite/20210211211028_AdminOOCColor.cs b/Content.Server.Database/Migrations/Sqlite/20210211211028_AdminOOCColor.cs new file mode 100644 index 0000000000..cf9015f796 --- /dev/null +++ b/Content.Server.Database/Migrations/Sqlite/20210211211028_AdminOOCColor.cs @@ -0,0 +1,24 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Content.Server.Database.Migrations.Sqlite +{ + public partial class AdminOOCColor : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "admin_ooc_color", + table: "preference", + type: "text", + nullable: false, + defaultValue: "#ff0000"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "admin_ooc_color", + table: "preference"); + } + } +} diff --git a/Content.Server.Database/Migrations/Sqlite/SqliteServerDbContextModelSnapshot.cs b/Content.Server.Database/Migrations/Sqlite/SqliteServerDbContextModelSnapshot.cs index 8e93f4acbf..b4fca5d3e2 100644 --- a/Content.Server.Database/Migrations/Sqlite/SqliteServerDbContextModelSnapshot.cs +++ b/Content.Server.Database/Migrations/Sqlite/SqliteServerDbContextModelSnapshot.cs @@ -196,6 +196,11 @@ namespace Content.Server.Database.Migrations.Sqlite .HasColumnType("INTEGER") .HasColumnName("preference_id"); + b.Property("AdminOOCColor") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("admin_ooc_color"); + b.Property("SelectedCharacterSlot") .HasColumnType("INTEGER") .HasColumnName("selected_character_slot"); diff --git a/Content.Server.Database/Model.cs b/Content.Server.Database/Model.cs index ed5c51e8c6..dcd305f87f 100644 --- a/Content.Server.Database/Model.cs +++ b/Content.Server.Database/Model.cs @@ -80,6 +80,7 @@ namespace Content.Server.Database [Column("preference_id")] public int Id { get; set; } [Column("user_id")] public Guid UserId { get; set; } [Column("selected_character_slot")] public int SelectedCharacterSlot { get; set; } + [Column("admin_ooc_color")] public string AdminOOCColor { get; set; } = null!; public List Profiles { get; } = new(); } diff --git a/Content.Server/Administration/Commands/SetAdminOOC.cs b/Content.Server/Administration/Commands/SetAdminOOC.cs new file mode 100644 index 0000000000..aa331951f1 --- /dev/null +++ b/Content.Server/Administration/Commands/SetAdminOOC.cs @@ -0,0 +1,53 @@ +#nullable enable + +using Content.Server.Database; +using Content.Server.Interfaces; +using Content.Shared.Administration; +using Robust.Server.Player; +using Robust.Shared.Console; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Maths; + +namespace Content.Server.Administration.Commands +{ + [AdminCommand(AdminFlags.Admin)] + internal class SetAdminOOC : IConsoleCommand + { + public string Command => "setadminooc"; + public string Description => Loc.GetString($"Sets the color of your OOC messages. Color must be in hex format, example: {Command} #c43b23"); + public string Help => Loc.GetString($"Usage: {Command} "); + + public void Execute(IConsoleShell shell, string argStr, string[] args) + { + if (!(shell.Player is IPlayerSession)) + { + shell.WriteError(Loc.GetString("Only players can use this command")); + return; + } + + if (args.Length < 1) + return; + + var colorArg = string.Join(" ", args).Trim(); + if (string.IsNullOrEmpty(colorArg)) + return; + + var color = Color.TryFromHex(colorArg); + if (!color.HasValue) + { + shell.WriteError(Loc.GetString("Invalid color hex!")); + return; + } + + var userId = shell.Player.UserId; + // Save the DB + var dbMan = IoCManager.Resolve(); + dbMan.SaveAdminOOCColorAsync(userId, color.Value); + // Update the cached preference + var prefManager = IoCManager.Resolve(); + var prefs = prefManager.GetPreferences(userId); + prefs.AdminOOCColor = color.Value; + } + } +} diff --git a/Content.Server/Chat/ChatManager.cs b/Content.Server/Chat/ChatManager.cs index f949e5054d..4a7d558bee 100644 --- a/Content.Server/Chat/ChatManager.cs +++ b/Content.Server/Chat/ChatManager.cs @@ -8,6 +8,7 @@ using Content.Server.GameObjects.Components.Observer; using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces; using Content.Server.Interfaces.Chat; +using Content.Shared.Administration; using Content.Shared.Chat; using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.EntitySystems.ActionBlocker; @@ -47,6 +48,7 @@ namespace Content.Server.Chat [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IMoMMILink _mommiLink = default!; [Dependency] private readonly IAdminManager _adminManager = default!; + [Dependency] private readonly IServerPreferencesManager _preferencesManager = default!; public void Initialize() { @@ -187,7 +189,7 @@ namespace Content.Server.Chat public void SendOOC(IPlayerSession player, string message) { - // Check if message exceeds the character limi + // Check if message exceeds the character limit if (message.Length > MaxMessageLength) { DispatchServerMessage(player, Loc.GetString(MaxLengthExceededMessage, MaxMessageLength)); @@ -198,6 +200,12 @@ namespace Content.Server.Chat msg.Channel = ChatChannel.OOC; msg.Message = message; msg.MessageWrap = $"OOC: {player.Name}: {{0}}"; + if (_adminManager.HasAdminFlag(player, AdminFlags.Admin)) + { + var prefs = _preferencesManager.GetPreferences((player.UserId)); + msg.MessageColorOverride = prefs.AdminOOCColor; + } + //TODO: player.Name color, this will need to change the structure of the MsgChatMessage _netManager.ServerSendToAll(msg); _mommiLink.SendOOCMessage(player.Name, message); diff --git a/Content.Server/Database/ServerDbBase.cs b/Content.Server/Database/ServerDbBase.cs index 541a2f0c0d..ffc4430605 100644 --- a/Content.Server/Database/ServerDbBase.cs +++ b/Content.Server/Database/ServerDbBase.cs @@ -15,6 +15,8 @@ namespace Content.Server.Database { public abstract class ServerDbBase { + + #region Preferences public async Task GetPlayerPreferencesAsync(NetUserId userId) { await using var db = await GetDb(); @@ -34,7 +36,7 @@ namespace Content.Server.Database profiles[profile.Slot] = ConvertProfiles(profile); } - return new PlayerPreferences(profiles, prefs.SelectedCharacterSlot); + return new PlayerPreferences(profiles, prefs.SelectedCharacterSlot, Color.FromHex(prefs.AdminOOCColor)); } public async Task SaveSelectedCharacterIndexAsync(NetUserId userId, int index) @@ -99,7 +101,8 @@ namespace Content.Server.Database var prefs = new Preference { UserId = userId.UserId, - SelectedCharacterSlot = 0 + SelectedCharacterSlot = 0, + AdminOOCColor = Color.Red.ToHex() }; prefs.Profiles.Add(profile); @@ -108,7 +111,7 @@ namespace Content.Server.Database await db.DbContext.SaveChangesAsync(); - return new PlayerPreferences(new[] {new KeyValuePair(0, defaultProfile)}, 0); + return new PlayerPreferences(new[] {new KeyValuePair(0, defaultProfile)}, 0, Color.FromHex(prefs.AdminOOCColor)); } public async Task DeleteSlotAndSetSelectedIndex(NetUserId userId, int deleteSlot, int newSlot) @@ -121,6 +124,19 @@ namespace Content.Server.Database await db.DbContext.SaveChangesAsync(); } + public async Task SaveAdminOOCColorAsync(NetUserId userId, Color color) + { + await using var db = await GetDb(); + var prefs = await db.DbContext + .Preference + .Include(p => p.Profiles) + .SingleAsync(p => p.UserId == userId.UserId); + prefs.AdminOOCColor = color.ToHex(); + + await db.DbContext.SaveChangesAsync(); + + } + private static async Task SetSelectedCharacterSlotAsync(NetUserId userId, int newSlot, ServerDbContext db) { var prefs = await db.Preference.SingleAsync(p => p.UserId == userId.UserId); @@ -203,6 +219,7 @@ namespace Content.Server.Database return entity; } + #endregion public async Task GetAssignedUserIdAsync(string name) { diff --git a/Content.Server/Database/ServerDbManager.cs b/Content.Server/Database/ServerDbManager.cs index dc12dbba9c..56dfcd68ca 100644 --- a/Content.Server/Database/ServerDbManager.cs +++ b/Content.Server/Database/ServerDbManager.cs @@ -14,6 +14,7 @@ using Robust.Shared.Configuration; using Robust.Shared.ContentPack; using Robust.Shared.IoC; using Robust.Shared.Log; +using Robust.Shared.Maths; using Robust.Shared.Network; using LogLevel = Robust.Shared.Log.LogLevel; using MSLogLevel = Microsoft.Extensions.Logging.LogLevel; @@ -32,6 +33,8 @@ namespace Content.Server.Database Task SaveCharacterSlotAsync(NetUserId userId, ICharacterProfile? profile, int slot); + Task SaveAdminOOCColorAsync(NetUserId userId, Color color); + // Single method for two operations for transaction. Task DeleteSlotAndSetSelectedIndex(NetUserId userId, int deleteSlot, int newSlot); Task GetPlayerPreferencesAsync(NetUserId userId); @@ -151,6 +154,11 @@ namespace Content.Server.Database return _db.DeleteSlotAndSetSelectedIndex(userId, deleteSlot, newSlot); } + public Task SaveAdminOOCColorAsync(NetUserId userId, Color color) + { + return _db.SaveAdminOOCColorAsync(userId, color); + } + public Task GetPlayerPreferencesAsync(NetUserId userId) { return _db.GetPlayerPreferencesAsync(userId); diff --git a/Content.Server/Preferences/ServerPreferencesManager.cs b/Content.Server/Preferences/ServerPreferencesManager.cs index 2ef846fd6a..fc3592bacb 100644 --- a/Content.Server/Preferences/ServerPreferencesManager.cs +++ b/Content.Server/Preferences/ServerPreferencesManager.cs @@ -12,6 +12,7 @@ using Robust.Server.Player; using Robust.Shared.Configuration; using Robust.Shared.IoC; using Robust.Shared.Log; +using Robust.Shared.Maths; using Robust.Shared.Network; using Robust.Shared.Prototypes; @@ -72,7 +73,7 @@ namespace Content.Server.Preferences return; } - prefsData.Prefs = new PlayerPreferences(curPrefs.Characters, index); + prefsData.Prefs = new PlayerPreferences(curPrefs.Characters, index, curPrefs.AdminOOCColor); if (ShouldStorePrefs(message.MsgChannel.AuthType)) { @@ -111,7 +112,7 @@ namespace Content.Server.Preferences [slot] = HumanoidCharacterProfile.EnsureValid((HumanoidCharacterProfile) profile, _protos) }; - prefsData.Prefs = new PlayerPreferences(profiles, slot); + prefsData.Prefs = new PlayerPreferences(profiles, slot, curPrefs.AdminOOCColor); if (ShouldStorePrefs(message.MsgChannel.AuthType)) { @@ -156,7 +157,7 @@ namespace Content.Server.Preferences var arr = new Dictionary(curPrefs.Characters); arr.Remove(slot); - prefsData.Prefs = new PlayerPreferences(arr, nextSlot ?? curPrefs.SelectedCharacterIndex); + prefsData.Prefs = new PlayerPreferences(arr, nextSlot ?? curPrefs.SelectedCharacterIndex, curPrefs.AdminOOCColor); if (ShouldStorePrefs(message.MsgChannel.AuthType)) { @@ -181,7 +182,7 @@ namespace Content.Server.Preferences PrefsLoaded = Task.CompletedTask, Prefs = new PlayerPreferences( new[] {new KeyValuePair(0, HumanoidCharacterProfile.Default())}, - 0) + 0, Color.Transparent) }; _cachedPlayerPrefs[session.UserId] = prefsData; @@ -279,7 +280,7 @@ namespace Content.Server.Preferences } return new KeyValuePair(p.Key, newProf); - }), prefs.SelectedCharacterIndex); + }), prefs.SelectedCharacterIndex, prefs.AdminOOCColor); } public IEnumerable> GetSelectedProfilesForPlayers( diff --git a/Content.Shared/Chat/MsgChatMessage.cs b/Content.Shared/Chat/MsgChatMessage.cs index ff117d22ce..2452438bbd 100644 --- a/Content.Shared/Chat/MsgChatMessage.cs +++ b/Content.Shared/Chat/MsgChatMessage.cs @@ -1,5 +1,7 @@ +using JetBrains.Annotations; using Lidgren.Network; using Robust.Shared.GameObjects; +using Robust.Shared.Maths; using Robust.Shared.Network; namespace Content.Shared.Chat @@ -7,6 +9,7 @@ namespace Content.Shared.Chat /// /// Sent from server to client to notify the client about a new chat message. /// + [UsedImplicitly] public sealed class MsgChatMessage : NetMessage { #region REQUIRED @@ -38,6 +41,12 @@ namespace Content.Shared.Chat /// public EntityUid SenderEntity { get; set; } + /// + /// The override color of the message + /// + public Color MessageColorOverride { get; set; } = Color.Transparent; + + public override void ReadFromBuffer(NetIncomingMessage buffer) { Channel = (ChatChannel) buffer.ReadInt16(); @@ -53,6 +62,7 @@ namespace Content.Shared.Chat SenderEntity = buffer.ReadEntityUid(); break; } + MessageColorOverride = buffer.ReadColor(); } public override void WriteToBuffer(NetOutgoingMessage buffer) @@ -70,6 +80,7 @@ namespace Content.Shared.Chat buffer.Write(SenderEntity); break; } + buffer.Write(MessageColorOverride); } } } diff --git a/Content.Shared/Preferences/PlayerPreferences.cs b/Content.Shared/Preferences/PlayerPreferences.cs index 1556a85803..4fedad6e8b 100644 --- a/Content.Shared/Preferences/PlayerPreferences.cs +++ b/Content.Shared/Preferences/PlayerPreferences.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Robust.Shared.Maths; using Robust.Shared.Serialization; using Robust.Shared.Utility; @@ -15,10 +16,11 @@ namespace Content.Shared.Preferences { private Dictionary _characters; - public PlayerPreferences(IEnumerable> characters, int selectedCharacterIndex) + public PlayerPreferences(IEnumerable> characters, int selectedCharacterIndex, Color adminOOCColor) { _characters = new Dictionary(characters); SelectedCharacterIndex = selectedCharacterIndex; + AdminOOCColor = adminOOCColor; } /// @@ -41,6 +43,8 @@ namespace Content.Shared.Preferences /// public ICharacterProfile SelectedCharacter => Characters[SelectedCharacterIndex]; + public Color AdminOOCColor { get; set; } + public int FirstEmptySlot() { var firstEmpty = IndexOfCharacter(null);