[Feat] Респект и уважуха (#476)

* db

* wd comment

* manager & commands

* system & round end results

* raise ban event

* client manager & cached values

* role pick tweak

* tweak last commit

* more fixes

* weights fix

* Fix for short rounds

* tweak in cached dictionary

* reva pick system

* fix last commit

* cult role pick

* nukeops role picking

* fix cache in async & show command

* ooc msg show value

* move pick method to manager & traitor pick fix
This commit is contained in:
HitPanda
2023-10-08 15:53:28 +03:00
committed by Aviu00
parent a29e004eba
commit 7c9bd1d934
37 changed files with 3752 additions and 25 deletions

View File

@@ -23,6 +23,7 @@ using Content.Client.Viewport;
using Content.Client.Voting; using Content.Client.Voting;
using Content.Client.White.JoinQueue; using Content.Client.White.JoinQueue;
using Content.Client.White.Jukebox; using Content.Client.White.Jukebox;
using Content.Client.White.Reputation;
using Content.Client.White.Sponsors; using Content.Client.White.Sponsors;
using Content.Shared.Ame; using Content.Shared.Ame;
using Content.Client.White.Stalin; using Content.Client.White.Stalin;
@@ -82,6 +83,7 @@ namespace Content.Client.Entry
[Dependency] private readonly StalinManager _stalinManager = default!; [Dependency] private readonly StalinManager _stalinManager = default!;
[Dependency] private readonly ClientJukeboxSongsSyncManager _jukeboxSyncManager = default!; [Dependency] private readonly ClientJukeboxSongsSyncManager _jukeboxSyncManager = default!;
[Dependency] private readonly TTSManager _ttsManager = default!; [Dependency] private readonly TTSManager _ttsManager = default!;
[Dependency] private readonly ReputationManager _reputationManager = default!;
//WD-EDIT //WD-EDIT
public override void Init() public override void Init()
@@ -189,6 +191,7 @@ namespace Content.Client.Entry
_queueManager.Initialize(); _queueManager.Initialize();
_jukeboxSyncManager.Initialize(); _jukeboxSyncManager.Initialize();
_ttsManager.Initialize(); _ttsManager.Initialize();
_reputationManager.Initialize();
//WD-EDIT //WD-EDIT
_baseClient.RunLevelChanged += (_, args) => _baseClient.RunLevelChanged += (_, args) =>

View File

@@ -19,6 +19,7 @@ using Content.Client.Guidebook;
using Content.Client.Replay; using Content.Client.Replay;
using Content.Client.White.JoinQueue; using Content.Client.White.JoinQueue;
using Content.Client.White.Jukebox; using Content.Client.White.Jukebox;
using Content.Client.White.Reputation;
using Content.Client.White.Sponsors; using Content.Client.White.Sponsors;
using Content.Client.White.Stalin; using Content.Client.White.Stalin;
using Content.Client.White.Trail.Line.Manager; using Content.Client.White.Trail.Line.Manager;
@@ -59,6 +60,7 @@ namespace Content.Client.IoC
IoCManager.Register<ClientJukeboxSongsSyncManager>(); IoCManager.Register<ClientJukeboxSongsSyncManager>();
IoCManager.Register<TTSManager>(); IoCManager.Register<TTSManager>();
IoCManager.Register<ITrailLineManager, TrailSplineManager>(); IoCManager.Register<ITrailLineManager, TrailSplineManager>();
IoCManager.Register<ReputationManager>();
//WD-EDIT //WD-EDIT
} }
} }

View File

@@ -20,7 +20,7 @@ namespace Content.Client.RoundEnd
{ {
_entityManager = entityManager; _entityManager = entityManager;
MinSize = SetSize = new Vector2(520, 580); MinSize = SetSize = new Vector2(800, 580);
Title = Loc.GetString("round-end-summary-window-title"); Title = Loc.GetString("round-end-summary-window-title");
@@ -155,7 +155,8 @@ namespace Content.Client.RoundEnd
("playerOOCName", playerInfo.PlayerOOCName), ("playerOOCName", playerInfo.PlayerOOCName),
("icNameColor", icNameColor), ("icNameColor", icNameColor),
("playerICName", playerInfo.PlayerICName), ("playerICName", playerInfo.PlayerICName),
("playerRole", Loc.GetString(playerInfo.Role)))); ("playerRole", Loc.GetString(playerInfo.Role)),
("reputation", playerInfo.Reputation)));
} }
} }
hBox.AddChild(playerInfoText); hBox.AddChild(playerInfoText);

View File

@@ -0,0 +1,23 @@
using System.Diagnostics.CodeAnalysis;
using Content.Shared.White.Reputation;
using Robust.Shared.Network;
namespace Content.Client.White.Reputation;
public sealed class ReputationManager
{
[Dependency] private readonly IClientNetManager _netMgr = default!;
private ReputationInfo? _info;
public void Initialize()
{
_netMgr.RegisterNetMessage<ReputationNetMsg>(msg => _info = msg.Info);
}
public bool TryGetInfo([NotNullWhen(true)] out float? value)
{
value = _info?.Value;
return _info != null;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Content.Server.Database.Migrations.Postgres
{
/// <inheritdoc />
public partial class PlayerReputation : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "player_reputations",
columns: table => new
{
player_reputations_id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
user_id = table.Column<Guid>(type: "uuid", nullable: false),
reputation = table.Column<float>(type: "real", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_player_reputations", x => x.player_reputations_id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "player_reputations");
}
}
}

View File

@@ -689,6 +689,29 @@ namespace Content.Server.Database.Migrations.Postgres
}); });
}); });
modelBuilder.Entity("Content.Server.Database.PlayerReputation", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("player_reputations_id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<float>("Reputation")
.HasColumnType("real")
.HasColumnName("reputation");
b.Property<Guid>("UserId")
.HasColumnType("uuid")
.HasColumnName("user_id");
b.HasKey("Id")
.HasName("PK_player_reputations");
b.ToTable("player_reputations", (string)null);
});
modelBuilder.Entity("Content.Server.Database.Preference", b => modelBuilder.Entity("Content.Server.Database.Preference", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,36 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Content.Server.Database.Migrations.Sqlite
{
/// <inheritdoc />
public partial class PlayerReputation : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "player_reputations",
columns: table => new
{
player_reputations_id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
user_id = table.Column<Guid>(type: "TEXT", nullable: false),
reputation = table.Column<float>(type: "REAL", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_player_reputations", x => x.player_reputations_id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "player_reputations");
}
}
}

View File

@@ -647,6 +647,27 @@ namespace Content.Server.Database.Migrations.Sqlite
b.ToTable("player", (string)null); b.ToTable("player", (string)null);
}); });
modelBuilder.Entity("Content.Server.Database.PlayerReputation", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasColumnName("player_reputations_id");
b.Property<float>("Reputation")
.HasColumnType("REAL")
.HasColumnName("reputation");
b.Property<Guid>("UserId")
.HasColumnType("TEXT")
.HasColumnName("user_id");
b.HasKey("Id")
.HasName("PK_player_reputations");
b.ToTable("player_reputations", (string)null);
});
modelBuilder.Entity("Content.Server.Database.Preference", b => modelBuilder.Entity("Content.Server.Database.Preference", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")

View File

@@ -39,6 +39,7 @@ namespace Content.Server.Database
public DbSet<AdminNote> AdminNotes { get; set; } = null!; public DbSet<AdminNote> AdminNotes { get; set; } = null!;
public DbSet<AdminWatchlist> AdminWatchlists { get; set; } = null!; public DbSet<AdminWatchlist> AdminWatchlists { get; set; } = null!;
public DbSet<AdminMessage> AdminMessages { get; set; } = null!; public DbSet<AdminMessage> AdminMessages { get; set; } = null!;
public DbSet<PlayerReputation> PlayerReputations { get; set; } = default!; // WD edit
protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnModelCreating(ModelBuilder modelBuilder)
{ {
@@ -301,6 +302,15 @@ namespace Content.Server.Database
public abstract int CountAdminLogs(); public abstract int CountAdminLogs();
} }
// WD start
public class PlayerReputation
{
public int Id { get; set; }
public Guid UserId { get; set; }
public float Reputation { get; set; }
}
// WD end
public class Preference public class Preference
{ {
// NOTE: on postgres there SHOULD be an FK ensuring that the selected character slot always exists. // NOTE: on postgres there SHOULD be an FK ensuring that the selected character slot always exists.

View File

@@ -20,6 +20,7 @@ public sealed class BanCommand : LocalizedCommands
[Dependency] private readonly IBanManager _bans = default!; [Dependency] private readonly IBanManager _bans = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly UtkaTCPWrapper _utkaSockets = default!; // WD [Dependency] private readonly UtkaTCPWrapper _utkaSockets = default!; // WD
[Dependency] private readonly IEntityManager _entMan = default!; // WD
public override string Command => "ban"; public override string Command => "ban";
@@ -128,6 +129,7 @@ public sealed class BanCommand : LocalizedCommands
BanId = banId BanId = banId
}; };
_utkaSockets.SendMessageToAll(utkaBanned); _utkaSockets.SendMessageToAll(utkaBanned);
_entMan.EventBus.RaiseEvent(EventSource.Local, utkaBanned);
//WD end //WD end
} }

View File

@@ -31,6 +31,7 @@ public sealed class RoleBanManager
[Dependency] private readonly UtkaTCPWrapper _utkaSockets = default!; // WD [Dependency] private readonly UtkaTCPWrapper _utkaSockets = default!; // WD
[Dependency] private readonly IEntitySystemManager _systems = default!; // WD [Dependency] private readonly IEntitySystemManager _systems = default!; // WD
[Dependency] private readonly IBanManager _banManager = default!; // WD [Dependency] private readonly IBanManager _banManager = default!; // WD
[Dependency] private readonly IEntityManager _entMan = default!; // WD
private const string JobPrefix = "Job:"; private const string JobPrefix = "Job:";
@@ -425,6 +426,7 @@ public sealed class RoleBanManager
}; };
_utkaSockets.SendMessageToAll(utkaBanned); _utkaSockets.SendMessageToAll(utkaBanned);
_entMan.EventBus.RaiseEvent(EventSource.Local, utkaBanned);
} }
private async Task<int> UtkaGetBanId(string reason, string role, NetUserId targetUid) private async Task<int> UtkaGetBanId(string reason, string role, NetUserId targetUid)

View File

@@ -27,6 +27,7 @@ using Robust.Server.Containers;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Components;
using Content.Server.White.Reputation;
using Content.Shared.Players; using Content.Shared.Players;
namespace Content.Server.Antag; namespace Content.Server.Antag;
@@ -47,6 +48,7 @@ public sealed class AntagSelectionSystem : GameRuleSystem<GameRuleComponent>
[Dependency] private readonly EmergencyShuttleSystem _emergencyShuttle = default!; [Dependency] private readonly EmergencyShuttleSystem _emergencyShuttle = default!;
[Dependency] private readonly RoleSystem _roles = default!; // WD [Dependency] private readonly RoleSystem _roles = default!; // WD
[Dependency] private readonly SharedPlayerSystem _sharedPlayerSystem = default!; // WD [Dependency] private readonly SharedPlayerSystem _sharedPlayerSystem = default!; // WD
[Dependency] private readonly ReputationManager _reputationManager = default!; // WD
/// <summary> /// <summary>
/// Attempts to start the game rule by checking if there are enough players in lobby and readied. /// Attempts to start the game rule by checking if there are enough players in lobby and readied.
@@ -217,7 +219,12 @@ public sealed class AntagSelectionSystem : GameRuleSystem<GameRuleComponent>
for (var i = 0; i < antagCount; i++) for (var i = 0; i < antagCount; i++)
{ {
results.Add(_random.PickAndTake(prefList)); //results.Add(_random.PickAndTake(prefList));
// WD EDIT START
var pref = _reputationManager.PickPlayerBasedOnReputation(prefList);
prefList.Remove(pref);
results.Add(pref);
// WD EDIT END
Log.Info("Selected a preferred antag."); Log.Info("Selected a preferred antag.");
} }
return results; return results;

View File

@@ -1,6 +1,7 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Content.Server.Administration.Logs; using Content.Server.Administration.Logs;
using Content.Server.Administration.Managers; using Content.Server.Administration.Managers;
using Content.Server.Administration.Systems; using Content.Server.Administration.Systems;
@@ -8,6 +9,7 @@ using Content.Server.MoMMI;
using Content.Server.Players; using Content.Server.Players;
using Content.Server.Preferences.Managers; using Content.Server.Preferences.Managers;
using Content.Server.UtkaIntegration; using Content.Server.UtkaIntegration;
using Content.Server.White.Reputation;
using Content.Server.White.Sponsors; using Content.Server.White.Sponsors;
using Content.Shared.Administration; using Content.Shared.Administration;
using Content.Shared.CCVar; using Content.Shared.CCVar;
@@ -16,6 +18,7 @@ using Content.Shared.Database;
using Content.Shared.Mind; using Content.Shared.Mind;
using Content.Shared.White; using Content.Shared.White;
using Robust.Server.Player; using Robust.Server.Player;
using Robust.Shared.Asynchronous;
using Robust.Shared.Configuration; using Robust.Shared.Configuration;
using Robust.Shared.Network; using Robust.Shared.Network;
using Robust.Shared.Player; using Robust.Shared.Player;
@@ -54,6 +57,8 @@ namespace Content.Server.Chat.Managers
[Dependency] private readonly SponsorsManager _sponsorsManager = default!; [Dependency] private readonly SponsorsManager _sponsorsManager = default!;
[Dependency] private readonly UtkaTCPWrapper _utkaSocketWrapper = default!; [Dependency] private readonly UtkaTCPWrapper _utkaSocketWrapper = default!;
[Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly ReputationManager _repManager = default!;
[Dependency] private readonly ITaskManager _taskManager = default!;
/// WD-EDIT /// WD-EDIT
/// <summary> /// <summary>
@@ -296,8 +301,22 @@ namespace Content.Server.Chat.Managers
if (!TrySendNewMessage(player, message)) // WD if (!TrySendNewMessage(player, message)) // WD
return; return;
// WD start
//_repManager.GetCachedPlayerReputation(player.UserId, out var value);
var task = Task.Run(async () => await _repManager.GetPlayerReputation(player.UserId));
_taskManager.BlockWaitOnTask(task);
var value = task.GetAwaiter().GetResult();
var reputation = "";
if (value != null)
{
var color = value >= 0 ? "green" : "red";
reputation = $"[color={color}]({value})[/color]";
}
// WD end
Color? colorOverride = null; Color? colorOverride = null;
var wrappedMessage = Loc.GetString("chat-manager-send-ooc-wrap-message", ("playerName",player.Name), ("message", FormattedMessage.EscapeText(message))); var wrappedMessage = Loc.GetString("chat-manager-send-ooc-wrap-message", ("playerName",player.Name), ("message", FormattedMessage.EscapeText(message)), ("rep", reputation));
if (_adminManager.HasAdminFlag(player, AdminFlags.Admin)) if (_adminManager.HasAdminFlag(player, AdminFlags.Admin))
{ {
var prefs = _preferencesManager.GetPreferences(player.UserId); var prefs = _preferencesManager.GetPreferences(player.UserId);
@@ -306,13 +325,13 @@ namespace Content.Server.Chat.Managers
if (player.Channel.UserData.PatronTier is { } patron && if (player.Channel.UserData.PatronTier is { } patron &&
PatronOocColors.TryGetValue(patron, out var patronColor)) 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))); wrappedMessage = Loc.GetString("chat-manager-send-ooc-patron-wrap-message", ("patronColor", patronColor),("playerName", player.Name), ("message", FormattedMessage.EscapeText(message)), ("rep", reputation));
} }
//WD-EDIT //WD-EDIT
if (_sponsorsManager.TryGetInfo(player.UserId, out var sponsorData) && sponsorData.OOCColor != null) 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))); wrappedMessage = Loc.GetString("chat-manager-send-ooc-patron-wrap-message", ("patronColor", sponsorData.OOCColor),("playerName", player.Name), ("message", FormattedMessage.EscapeText(message)), ("rep", reputation));
} }
//WD-EDIT //WD-EDIT

View File

@@ -1401,6 +1401,69 @@ INSERT INTO player_round (players_id, rounds_id) VALUES ({players[player]}, {id}
#endregion #endregion
#region Player Reputation (WD edit)
public async Task SetPlayerReputation(Guid player, float value)
{
await using var db = await GetDb();
var reputation = await db.DbContext.PlayerReputations
.SingleOrDefaultAsync(p => p.UserId == player);
if (reputation == null)
{
reputation = new PlayerReputation()
{
UserId = player,
Reputation = value
};
db.DbContext.PlayerReputations.Add(reputation);
}
else
{
reputation.Reputation = value;
}
await db.DbContext.SaveChangesAsync();
}
public async Task ModifyPlayerReputation(Guid player, float value)
{
await using var db = await GetDb();
var reputation = await db.DbContext.PlayerReputations
.SingleOrDefaultAsync(p => p.UserId == player);
if (reputation == null)
{
reputation = new PlayerReputation()
{
UserId = player,
Reputation = 0f + value
};
db.DbContext.PlayerReputations.Add(reputation);
}
else
{
reputation.Reputation += value;
}
await db.DbContext.SaveChangesAsync();
}
public async Task<float> GetPlayerReputation(Guid player)
{
await using var db = await GetDb();
var reputation = await db.DbContext.PlayerReputations
.SingleOrDefaultAsync(p => p.UserId == player);
return reputation?.Reputation ?? 0f;
}
#endregion
protected abstract Task<DbGuard> GetDb([CallerMemberName] string? name = null); protected abstract Task<DbGuard> GetDb([CallerMemberName] string? name = null);
protected void LogDbOp(string? name) protected void LogDbOp(string? name)

View File

@@ -281,6 +281,31 @@ namespace Content.Server.Database
Task MarkMessageAsSeen(int id); Task MarkMessageAsSeen(int id);
#endregion #endregion
#region Player Reputation (WD edit)
/// <summary>
/// Set player's reputation to the certain value.
/// </summary>
/// <param name="player">Guid of the player to set the value.</param>
/// <param name="value">Value to set.</param>
Task SetPlayerReputation(Guid player, float value);
/// <summary>
/// Modify player's reputation by adding value (currentValue + value).
/// </summary>
/// <param name="player">Guid of the player to modify the value.</param>
/// <param name="value">Value to add.</param>
Task ModifyPlayerReputation(Guid player, float value);
/// <summary>
/// Gets value of player reputation.
/// </summary>
/// <param name="player">Guid of the player to get the value.</param>
/// <returns>Value of player's reputation.</returns>
Task<float> GetPlayerReputation(Guid player);
#endregion
} }
public sealed class ServerDbManager : IServerDbManager public sealed class ServerDbManager : IServerDbManager
@@ -502,6 +527,28 @@ namespace Content.Server.Database
#endregion #endregion
#region Player Reputation (WD edit)
public Task SetPlayerReputation(Guid player, float value)
{
DbWriteOpsMetric.Inc();
return RunDbCommand(() => _db.SetPlayerReputation(player, value));
}
public Task ModifyPlayerReputation(Guid player, float value)
{
DbWriteOpsMetric.Inc();
return RunDbCommand(() => _db.ModifyPlayerReputation(player, value));
}
public Task<float> GetPlayerReputation(Guid player)
{
DbWriteOpsMetric.Inc();
return RunDbCommand(() => _db.GetPlayerReputation(player));
}
#endregion
public Task UpdatePlayerRecordAsync( public Task UpdatePlayerRecordAsync(
NetUserId userId, NetUserId userId,
string userName, string userName,

View File

@@ -33,6 +33,7 @@ using Content.Server.UtkaIntegration;
using Content.Server.White; using Content.Server.White;
using Content.Server.White.JoinQueue; using Content.Server.White.JoinQueue;
using Content.Server.White.Jukebox; using Content.Server.White.Jukebox;
using Content.Server.White.Reputation;
using Content.Server.White.Sponsors; using Content.Server.White.Sponsors;
using Content.Server.White.Stalin; using Content.Server.White.Stalin;
using Content.Server.White.TTS; using Content.Server.White.TTS;

View File

@@ -22,6 +22,7 @@ using Robust.Shared.Random;
using Robust.Shared.Utility; using Robust.Shared.Utility;
using Content.Server.UtkaIntegration; using Content.Server.UtkaIntegration;
using System.Threading.Tasks; using System.Threading.Tasks;
using Content.Server.White.Reputation;
using Content.Server.White.Stalin; using Content.Server.White.Stalin;
using Content.Shared.Database; using Content.Shared.Database;
using Content.Shared.White; using Content.Shared.White;
@@ -37,6 +38,7 @@ namespace Content.Server.GameTicking
//WD-EDIT //WD-EDIT
[Dependency] private readonly UtkaTCPWrapper _utkaSocketWrapper = default!; [Dependency] private readonly UtkaTCPWrapper _utkaSocketWrapper = default!;
[Dependency] private readonly StalinManager _stalinManager = default!; [Dependency] private readonly StalinManager _stalinManager = default!;
[Dependency] private readonly ReputationSystem _repSys = default!;
//WD-EDIT //WD-EDIT
private static readonly Counter RoundNumberMetric = Metrics.CreateCounter( private static readonly Counter RoundNumberMetric = Metrics.CreateCounter(
@@ -394,6 +396,17 @@ namespace Content.Server.GameTicking
var roles = _roles.MindGetAllRoles(mindId); var roles = _roles.MindGetAllRoles(mindId);
// WD start
var reputation = "";
if (mind.Session != null &&
_repSys.TryModifyReputationOnRoundEnd(mind.Session.Name, out var value, out var delta))
{
var color = value >= 0 ? "green" : "red";
var change = delta >= 0 ? $"+{delta}" : $"{delta}";
reputation = $"[color={color}]{value} ({change})";
}
// WD end
var playerEndRoundInfo = new RoundEndMessageEvent.RoundEndPlayerInfo() var playerEndRoundInfo = new RoundEndMessageEvent.RoundEndPlayerInfo()
{ {
// Note that contentPlayerData?.Name sticks around after the player is disconnected. // Note that contentPlayerData?.Name sticks around after the player is disconnected.
@@ -407,7 +420,8 @@ namespace Content.Server.GameTicking
: roles.FirstOrDefault().Name ?? Loc.GetString("game-ticker-unknown-role"), : roles.FirstOrDefault().Name ?? Loc.GetString("game-ticker-unknown-role"),
Antag = antag, Antag = antag,
Observer = observer, Observer = observer,
Connected = connected Connected = connected,
Reputation = reputation
}; };
listOfPlayerInfo.Add(playerEndRoundInfo); listOfPlayerInfo.Add(playerEndRoundInfo);
} }

View File

@@ -29,6 +29,9 @@ using Content.Server.Station.Systems;
using Content.Server.Store.Components; using Content.Server.Store.Components;
using Content.Server.Store.Systems; using Content.Server.Store.Systems;
using Content.Shared.CCVar; using Content.Shared.CCVar;
using Content.Server.Traitor;
using Content.Server.White.Administration;
using Content.Server.White.Reputation;
using Content.Shared.Dataset; using Content.Shared.Dataset;
using Content.Shared.Humanoid; using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Prototypes; using Content.Shared.Humanoid.Prototypes;
@@ -86,6 +89,9 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
[Dependency] private readonly IAdminManager _adminManager = default!; [Dependency] private readonly IAdminManager _adminManager = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly WarDeclaratorSystem _warDeclarator = default!; [Dependency] private readonly WarDeclaratorSystem _warDeclarator = default!;
//WD EDIT
[Dependency] private readonly ReputationManager _reputationManager = default!;
//WD EDIT
[ValidatePrototypeId<CurrencyPrototype>] [ValidatePrototypeId<CurrencyPrototype>]
@@ -686,7 +692,9 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
} }
else else
{ {
nukeOp = _random.PickAndTake(cmdrPrefList); //nukeOp = _random.PickAndTake(cmdrPrefList);
nukeOp = _reputationManager.PickPlayerBasedOnReputation(cmdrPrefList); // WD edit
cmdrPrefList.Remove(nukeOp); // WD edit
everyone.Remove(nukeOp); everyone.Remove(nukeOp);
prefList.Remove(nukeOp); prefList.Remove(nukeOp);
medPrefList.Remove(nukeOp); medPrefList.Remove(nukeOp);
@@ -716,7 +724,9 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
} }
else else
{ {
nukeOp = _random.PickAndTake(medPrefList); //nukeOp = _random.PickAndTake(medPrefList);
nukeOp = _reputationManager.PickPlayerBasedOnReputation(medPrefList); // WD edit
medPrefList.Remove(nukeOp); // WD edit
everyone.Remove(nukeOp); everyone.Remove(nukeOp);
prefList.Remove(nukeOp); prefList.Remove(nukeOp);
Logger.InfoS("preset", "Insufficient preferred nukeop commanders, picking an agent"); Logger.InfoS("preset", "Insufficient preferred nukeop commanders, picking an agent");
@@ -725,7 +735,9 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
} }
else else
{ {
nukeOp = _random.PickAndTake(prefList); //nukeOp = _random.PickAndTake(prefList);
nukeOp = _reputationManager.PickPlayerBasedOnReputation(prefList); // WD edit
prefList.Remove(nukeOp); // WD edit
everyone.Remove(nukeOp); everyone.Remove(nukeOp);
Logger.InfoS("preset", "Selected a preferred nukeop commander."); Logger.InfoS("preset", "Selected a preferred nukeop commander.");
} }

View File

@@ -15,18 +15,15 @@ using Content.Shared.Mind;
using Content.Shared.Mobs.Systems; using Content.Shared.Mobs.Systems;
using Content.Shared.Objectives.Components; using Content.Shared.Objectives.Components;
using Content.Shared.PDA; using Content.Shared.PDA;
using Content.Shared.Preferences;
using Content.Shared.Roles; using Content.Shared.Roles;
using Content.Shared.Roles.Jobs; using Content.Shared.Roles.Jobs;
using Robust.Server.Player;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems; using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration; using Robust.Shared.Configuration;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Timing; using Robust.Shared.Timing;
using Content.Server.Objectives; using Content.Server.White.Reputation;
using Content.Shared.White.Mood; using Content.Shared.White.Mood;
namespace Content.Server.GameTicking.Rules; namespace Content.Server.GameTicking.Rules;
@@ -49,6 +46,8 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
[Dependency] private readonly ObjectivesSystem _objectives = default!; [Dependency] private readonly ObjectivesSystem _objectives = default!;
[Dependency] private readonly RoleSystem _roles = default!; // WD [Dependency] private readonly RoleSystem _roles = default!; // WD
private ISawmill _sawmill = default!;
private int PlayersPerTraitor => _cfg.GetCVar(CCVars.TraitorPlayersPerTraitor); private int PlayersPerTraitor => _cfg.GetCVar(CCVars.TraitorPlayersPerTraitor);
private int MaxTraitors => _cfg.GetCVar(CCVars.TraitorMaxTraitors); private int MaxTraitors => _cfg.GetCVar(CCVars.TraitorMaxTraitors);

View File

@@ -23,6 +23,7 @@ using Content.Server.UtkaIntegration;
using Content.Server.White; using Content.Server.White;
using Content.Server.White.JoinQueue; using Content.Server.White.JoinQueue;
using Content.Server.White.Jukebox; using Content.Server.White.Jukebox;
using Content.Server.White.Reputation;
using Content.Server.White.Sponsors; using Content.Server.White.Sponsors;
using Content.Server.White.Stalin; using Content.Server.White.Stalin;
using Content.Server.White.TTS; using Content.Server.White.TTS;
@@ -75,6 +76,7 @@ namespace Content.Server.IoC
IoCManager.Register<StalinManager>(); IoCManager.Register<StalinManager>();
IoCManager.Register<ServerJukeboxSongsSyncManager>(); IoCManager.Register<ServerJukeboxSongsSyncManager>();
IoCManager.Register<SalusManager>(); IoCManager.Register<SalusManager>();
IoCManager.Register<ReputationManager>();
// WD-EDIT // WD-EDIT
} }
} }

View File

@@ -2,6 +2,7 @@ using System.Linq;
using Content.Server.Administration.Managers; using Content.Server.Administration.Managers;
using Content.Server.Players.PlayTimeTracking; using Content.Server.Players.PlayTimeTracking;
using Content.Server.Station.Components; using Content.Server.Station.Components;
using Content.Server.White.Reputation;
using Content.Shared.Preferences; using Content.Shared.Preferences;
using Content.Shared.Roles; using Content.Shared.Roles;
using Robust.Shared.Network; using Robust.Shared.Network;
@@ -17,6 +18,7 @@ public sealed partial class StationJobsSystem
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IBanManager _banManager = default!; [Dependency] private readonly IBanManager _banManager = default!;
[Dependency] private readonly PlayTimeTrackingSystem _playTime = default!; [Dependency] private readonly PlayTimeTrackingSystem _playTime = default!;
[Dependency] private readonly ReputationManager _reputationManager = default!; // WD edit
private Dictionary<int, HashSet<string>> _jobsByWeight = default!; private Dictionary<int, HashSet<string>> _jobsByWeight = default!;
private List<int> _orderedWeights = default!; private List<int> _orderedWeights = default!;
@@ -245,7 +247,8 @@ public sealed partial class StationJobsSystem
continue; continue;
// Picking players it finds that have the job set. // Picking players it finds that have the job set.
var player = _random.Pick(jobPlayerOptions[job]); //var player = _random.Pick(jobPlayerOptions[job]);
var player = GetPlayerToAssign(jobPlayerOptions[job]); // WD edit
AssignPlayer(player, job, station); AssignPlayer(player, job, station);
stationShares[station]--; stationShares[station]--;
@@ -374,4 +377,33 @@ public sealed partial class StationJobsSystem
return outputDict; return outputDict;
} }
// WD start
private NetUserId GetPlayerToAssign(HashSet<NetUserId> players)
{
var list = new List<NetUserId>();
foreach (var player in players)
{
if (!_reputationManager.GetCachedPlayerReputation(player, out var value))
continue;
if (value == null)
continue;
var weight = _reputationManager.GetPlayerWeight(value.Value);
for (var i = 0; i < weight; i++)
{
list.Add(player);
}
}
if (list.Count == 0)
return _random.Pick(players);
var number = _random.Next(list.Count - 1);
return list[number];
}
// WD end
} }

View File

@@ -16,6 +16,8 @@ public sealed class UtkaBanCommand : IUtkaCommand
{ {
[Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private UtkaTCPWrapper _utkaSocketWrapper = default!; [Dependency] private UtkaTCPWrapper _utkaSocketWrapper = default!;
[Dependency] private readonly IServerDbManager _db = default!;
[Dependency] private readonly IEntityManager _entMan = default!;
private const ILocalizationManager LocalizationManager = default!; private const ILocalizationManager LocalizationManager = default!;
@@ -27,7 +29,6 @@ public sealed class UtkaBanCommand : IUtkaCommand
var plyMgr = IoCManager.Resolve<IPlayerManager>(); var plyMgr = IoCManager.Resolve<IPlayerManager>();
var locator = IoCManager.Resolve<IPlayerLocator>(); var locator = IoCManager.Resolve<IPlayerLocator>();
var dbMan = IoCManager.Resolve<IServerDbManager>();
IoCManager.InjectDependencies(this); IoCManager.InjectDependencies(this);
var locatedPlayer = await locator.LookupIdByNameOrIdAsync(message.ACkey!); var locatedPlayer = await locator.LookupIdByNameOrIdAsync(message.ACkey!);
@@ -87,7 +88,7 @@ public sealed class UtkaBanCommand : IUtkaCommand
IoCManager.Resolve<IEntitySystemManager>().TryGetEntitySystem<GameTicker>(out var ticker); IoCManager.Resolve<IEntitySystemManager>().TryGetEntitySystem<GameTicker>(out var ticker);
int? roundId = ticker == null || ticker.RoundId == 0 ? null : ticker.RoundId; int? roundId = ticker == null || ticker.RoundId == 0 ? null : ticker.RoundId;
var playtime = (await dbMan.GetPlayTimes(targetUid)).Find(p => p.Tracker == PlayTimeTrackingShared.TrackerOverall)?.TimeSpent ?? TimeSpan.Zero; var playtime = (await _db.GetPlayTimes(targetUid)).Find(p => p.Tracker == PlayTimeTrackingShared.TrackerOverall)?.TimeSpent ?? TimeSpan.Zero;
var banDef = new ServerBanDef( var banDef = new ServerBanDef(
null, null,
@@ -106,7 +107,7 @@ public sealed class UtkaBanCommand : IUtkaCommand
UtkaSendResponse(true); UtkaSendResponse(true);
await dbMan.AddServerBanAsync(banDef); await _db.AddServerBanAsync(banDef);
if (plyMgr.TryGetSessionById(targetUid, out var targetPlayer)) if (plyMgr.TryGetSessionById(targetUid, out var targetPlayer))
{ {
@@ -114,7 +115,7 @@ public sealed class UtkaBanCommand : IUtkaCommand
targetPlayer.ConnectedClient.Disconnect(msg); targetPlayer.ConnectedClient.Disconnect(msg);
} }
var banlist = await dbMan.GetServerBansAsync(null, targetUid, null); var banlist = await _db.GetServerBansAsync(null, targetUid, null);
var banId = banlist[^1].Id; var banId = banlist[^1].Id;
var utkaBanned = new UtkaBannedEvent() var utkaBanned = new UtkaBannedEvent()
@@ -129,6 +130,7 @@ public sealed class UtkaBanCommand : IUtkaCommand
BanId = banId BanId = banId
}; };
_utkaSocketWrapper.SendMessageToAll(utkaBanned); _utkaSocketWrapper.SendMessageToAll(utkaBanned);
_entMan.EventBus.RaiseEvent(EventSource.Local, utkaBanned);
} }
private void UtkaSendResponse(bool banned) private void UtkaSendResponse(bool banned)

View File

@@ -0,0 +1,43 @@
using Content.Server.Administration;
using Content.Shared.Administration;
using Robust.Server.Player;
using Robust.Shared.Console;
namespace Content.Server.White.Reputation.Commands;
[AdminCommand(AdminFlags.Admin)]
public sealed class GetPlayerReputationCommand : IConsoleCommand
{
public string Command => "getreput";
public string Description => "Get player's reputation value.";
public string Help => "Usage: getreput {ckey}";
public async void Execute(IConsoleShell shell, string argStr, string[] args)
{
var playerManager = IoCManager.Resolve<IPlayerManager>();
var repManager = IoCManager.Resolve<ReputationManager>();
if (args.Length < 1)
{
shell.WriteLine($"Not enough arguments.\n{Help}");
return;
}
if (!playerManager.TryGetPlayerDataByUsername(args[0], out var playerData))
{
shell.WriteLine($"Couldn't find player: {args[0]}.");
return;
}
var uid = playerData.UserId;
var value = await repManager.GetPlayerReputation(uid);
if (value == null)
{
shell.WriteLine("Couldn't get player's reputation.");
return;
}
shell.WriteLine($"Reputation of {args[0]}: {value}");
}
}

View File

@@ -0,0 +1,43 @@
using Content.Server.Administration;
using Content.Shared.Administration;
using Robust.Server.Player;
using Robust.Shared.Console;
namespace Content.Server.White.Reputation.Commands;
[AdminCommand(AdminFlags.Host)]
public sealed class ModifyReputationCommand : IConsoleCommand
{
public string Command => "modifyreput";
public string Description => "Add the value to user's reputation.";
public string Help => "Usage: modifyreput {ckey} {valueToAdd}";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var playerManager = IoCManager.Resolve<IPlayerManager>();
var repManager = IoCManager.Resolve<ReputationManager>();
if (args.Length < 2)
{
shell.WriteLine($"Not enough arguments.\n{Help}");
return;
}
if (!playerManager.TryGetPlayerDataByUsername(args[0], out var playerData))
{
shell.WriteLine($"Couldn't find player: {args[0]}.");
return;
}
if (!float.TryParse(args[1], out var value))
{
shell.WriteLine($"Invalid value: {args[1]}.");
return;
}
var uid = playerData.UserId;
repManager.ModifyPlayerReputation(uid, value);
shell.WriteLine($"Added {args[1]} to the reputation of {args[0]}.");
}
}

View File

@@ -0,0 +1,43 @@
using Content.Server.Administration;
using Content.Shared.Administration;
using Robust.Server.Player;
using Robust.Shared.Console;
namespace Content.Server.White.Reputation.Commands;
[AdminCommand(AdminFlags.Host)]
public sealed class SetReputationCommand : IConsoleCommand
{
public string Command => "setreput";
public string Description => "Sets the reputation to the certain value.";
public string Help => "Usage: setrep {ckey} {value}";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var playerManager = IoCManager.Resolve<IPlayerManager>();
var repManager = IoCManager.Resolve<ReputationManager>();
if (args.Length < 2)
{
shell.WriteLine($"Not enough arguments.\n{Help}");
return;
}
if (!playerManager.TryGetPlayerDataByUsername(args[0], out var playerData))
{
shell.WriteLine($"Couldn't find player: {args[0]}.");
return;
}
if (!float.TryParse(args[1], out var value))
{
shell.WriteLine($"Invalid value: {args[1]}.");
return;
}
var uid = playerData.UserId;
repManager.SetPlayerReputation(uid, value);
shell.WriteLine($"Set reputation of {args[0]} to {args[1]}.");
}
}

View File

@@ -0,0 +1,30 @@
using Content.Shared.Administration;
using Robust.Shared.Console;
namespace Content.Server.White.Reputation.Commands;
[AnyCommand]
public sealed class ShowReputationCommand : IConsoleCommand
{
[Dependency] private readonly ReputationManager _repManager = default!;
public string Command => "showreput";
public string Description => "Узнать свою репутацию.";
public string Help => "Использование: showreput";
public async void Execute(IConsoleShell shell, string argStr, string[] args)
{
IoCManager.InjectDependencies(this);
if (shell.Player == null)
return;
var value = await _repManager.GetPlayerReputation(shell.Player.UserId);
if (value == null)
{
shell.WriteLine("Не удалось получить данные о репутации. Обратитесь к кодерам или попробуйте ещё раз.");
return;
}
shell.WriteLine($"Ваша репутация: {value}");
}
}

View File

@@ -0,0 +1,201 @@
using System.Linq;
using System.Threading.Tasks;
using Content.Server.Database;
using Content.Shared.GameTicking;
using Content.Shared.White.Reputation;
using Robust.Server.Player;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Random;
namespace Content.Server.White.Reputation;
public sealed class ReputationManager : EntitySystem
{
[Dependency] private readonly IServerDbManager _db = default!;
[Dependency] private readonly IServerNetManager _netMgr = default!;
[Dependency] private readonly IRobustRandom _random = default!;
private readonly Dictionary<NetUserId, ReputationInfo> _cacheReputation = new();
public override void Initialize()
{
base.Initialize();
_netMgr.RegisterNetMessage<ReputationNetMsg>();
_netMgr.Connecting += OnConnecting;
_netMgr.Connected += OnConnected;
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestartCleanup);
SubscribeLocalEvent<UpdateCachedReputationEvent>(UpdateCachedReputation);
}
#region Cache
private void OnConnected(object? sender, NetChannelArgs e)
{
_cacheReputation.TryGetValue(e.Channel.UserId, out var info);
var msg = new ReputationNetMsg() { Info = info };
_netMgr.ServerSendMessage(msg, e.Channel);
}
private async Task OnConnecting(NetConnectingArgs e)
{
var uid = e.UserId;
var value = await GetPlayerReputation(uid);
if (value == null)
return;
var info = new ReputationInfo() { Value = value.Value };
_cacheReputation[e.UserId] = info;
}
private async void UpdateCachedReputation(UpdateCachedReputationEvent ev)
{
var player = ev.Player;
if (!_cacheReputation.TryGetValue(player, out _))
return;
var value = await GetPlayerReputation(player);
if (value == null)
return;
var info = new ReputationInfo() { Value = value.Value };
_cacheReputation[player] = info;
}
private void OnRoundRestartCleanup(RoundRestartCleanupEvent ev)
{
var connectedPlayers = _netMgr.Channels.Select(channel => channel.UserId).ToList();
var newDictionary = _cacheReputation
.Where(player => connectedPlayers.Contains(player.Key))
.ToDictionary(player => player.Key, player => player.Value);
_cacheReputation.Clear();
foreach (var kvp in newDictionary)
{
_cacheReputation.Add(kvp.Key, kvp.Value);
}
}
#endregion
#region PublicApi
public async void SetPlayerReputation(NetUserId player, float value)
{
var guid = player.UserId;
await SetPlayerReputationTask(guid, value);
RaiseLocalEvent(new UpdateCachedReputationEvent(player));
}
public async void ModifyPlayerReputation(NetUserId player, float value)
{
var guid = player.UserId;
await ModifyPlayerReputationTask(guid, value);
RaiseLocalEvent(new UpdateCachedReputationEvent(player));
}
public async Task<float?> GetPlayerReputation(NetUserId player)
{
var guid = player.UserId;
return await GetPlayerReputationTask(guid);
}
public bool GetCachedPlayerReputation(NetUserId player, out float? value)
{
var success = _cacheReputation.TryGetValue(player, out var info);
value = info?.Value;
return success;
}
public int GetPlayerWeight(float reputation)
{
return reputation switch
{
> 1000 => 9,
> 700 => 8,
> 500 => 7,
> 300 => 6,
> 100 => 5,
> 50 => 4,
> 15 => 3,
< 0 => 1,
_ => 2
};
}
public ICommonSession PickPlayerBasedOnReputation(List<ICommonSession> prefList)
{
var list = new List<ICommonSession>();
foreach (var session in prefList)
{
if (!GetCachedPlayerReputation(session.UserId, out var value))
continue;
if (value == null)
continue;
var weight = GetPlayerWeight(value.Value);
for (var i = 0; i < weight; i++)
{
list.Add(session);
}
}
if (list.Count == 0)
return _random.Pick(prefList);
var number = _random.Next(list.Count - 1);
return list[number];
}
#endregion
#region Private
private async Task SetPlayerReputationTask(Guid player, float value)
{
try
{
await _db.SetPlayerReputation(player, value);
}
catch (Exception)
{
// Nope
}
}
private async Task ModifyPlayerReputationTask(Guid player, float value)
{
try
{
await _db.ModifyPlayerReputation(player, value);
}
catch (Exception)
{
// Nope
}
}
private async Task<float?> GetPlayerReputationTask(Guid player)
{
try
{
return await _db.GetPlayerReputation(player);
}
catch (Exception)
{
return null;
}
}
#endregion
}

View File

@@ -0,0 +1,167 @@
using System.Linq;
using System.Threading.Tasks;
using Content.Server.Administration;
using Content.Server.GameTicking;
using Content.Server.Mind.Components;
using Content.Server.UtkaIntegration;
using Content.Server.White.AspectsSystem.Base;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Robust.Server.Player;
using Robust.Shared.Asynchronous;
using Robust.Shared.Network;
using Robust.Shared.Utility;
namespace Content.Server.White.Reputation;
public sealed class ReputationSystem : EntitySystem
{
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly ReputationManager _repManager = default!;
[Dependency] private readonly GameTicker _gameTicker = default!;
[Dependency] private readonly ITaskManager _taskManager = default!;
[Dependency] private readonly IPlayerLocator _locator = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<UtkaBannedEvent>(ModifyReputationOnPlayerBanned);
}
/// <summary>
/// Tries to modify reputation on round end and then returns it's new value and delta value if successful.
/// </summary>
/// <param name="name">Player to get new values for.</param>
/// <param name="newValue">Modified player's reputation value.</param>
/// <param name="deltaValue"></param>
/// <returns>Success in modifying player's reputation.</returns>
public bool TryModifyReputationOnRoundEnd(string name, out float? newValue, out float? deltaValue)
{
newValue = null;
deltaValue = null;
if (!_playerManager.TryGetSessionByUsername(name, out var session) || session.AttachedEntity == null)
return false;
if (!TryCalculatePlayerReputation(session.AttachedEntity.Value, out var delta))
return false;
var uid = session.UserId;
_repManager.GetCachedPlayerReputation(uid, out var value);
if (value == null)
return false;
var longRound = _gameTicker.RoundDuration().Minutes >= 25;
if (delta != 0 && longRound)
{
_repManager.ModifyPlayerReputation(uid, delta);
}
deltaValue = longRound ? delta : 0f;
newValue = value + deltaValue;
return true;
}
private bool TryCalculatePlayerReputation(EntityUid entity, out float deltaValue)
{
deltaValue = 0f;
var aspect = false;
if (!TryComp<MobStateComponent>(entity, out var state) || state.CurrentState is MobState.Dead or MobState.Invalid)
return true;
var ruleEnt = _gameTicker.GetActiveGameRules()
.Where(HasComp<AspectComponent>)
.FirstOrNull();
if (ruleEnt != null)
{
if (TryComp<AspectComponent>(ruleEnt, out var comp))
{
deltaValue += comp.Weight switch
{
3 => 2f,
2 => 3f,
1 => 4f,
_ => 0f
};
aspect = true;
}
}
if (!aspect)
deltaValue += 1f;
if (TryComp<MindContainerComponent>(entity, out var mind)
&& mind.Mind != null
&& mind.Mind.AllRoles.Any(role => role.Antagonist))
{
var condCompleted = 0;
var totalCond = 0;
foreach (var obj in mind.Mind.AllObjectives)
{
foreach (var condition in obj.Conditions)
{
totalCond++;
if (condition.Progress > 0.99f)
condCompleted++;
}
}
if (aspect)
{
if (condCompleted == totalCond)
deltaValue += 1f + condCompleted;
else
deltaValue += 1f + condCompleted * 0.5f;
}
else
{
if (condCompleted == totalCond)
deltaValue += 2f + condCompleted * 0.5f;
else
deltaValue += condCompleted * 0.5f;
}
}
return true;
}
private async void ModifyReputationOnPlayerBanned(UtkaBannedEvent ev)
{
NetUserId uid;
float value;
if (ev.Bantype == "server")
{
value = ev.Duration switch
{
> 10080 => -10f,
> 4320 => -7f,
> 1440 => -5f,
0 => -25f,
_ => -3f
};
}
else
value = -2f;
if (_playerManager.TryGetPlayerDataByUsername(ev.Ckey!, out var data))
uid = data.UserId;
else
{
var located = await _locator.LookupIdByNameAsync(ev.Ckey!);
if (located == null)
return;
uid = located.UserId;
}
_repManager.ModifyPlayerReputation(uid, value);
}
}

View File

@@ -0,0 +1,14 @@
using Robust.Shared.Network;
namespace Content.Server.White.Reputation;
[Serializable]
public sealed class UpdateCachedReputationEvent : EntityEventArgs
{
public NetUserId Player;
public UpdateCachedReputationEvent(NetUserId player)
{
Player = player;
}
}

View File

@@ -148,6 +148,7 @@ namespace Content.Shared.GameTicking
public bool Antag; public bool Antag;
public bool Observer; public bool Observer;
public bool Connected; public bool Connected;
public string Reputation; // WD edit
} }
public string GamemodeTitle { get; } public string GamemodeTitle { get; }

View File

@@ -0,0 +1,49 @@
using System.IO;
using System.Text.Json.Serialization;
using Lidgren.Network;
using Robust.Shared.Network;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
namespace Content.Shared.White.Reputation;
public sealed class ReputationNetMsg : NetMessage
{
public override MsgGroups MsgGroup => MsgGroups.Command;
public ReputationInfo? Info;
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
{
var success = buffer.ReadBoolean();
buffer.ReadPadBits();
if (!success)
return;
var length = buffer.ReadVariableInt32();
using var stream = buffer.ReadAlignedMemory(length);
serializer.DeserializeDirect(stream, out Info);
}
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
{
buffer.Write(Info != null);
buffer.WritePadBits();
if (Info == null)
return;
var stream = new MemoryStream();
serializer.SerializeDirect(stream, Info);
buffer.WriteVariableInt32((int) stream.Length);
buffer.Write(stream.AsSpan());
}
}
[Serializable, NetSerializable]
public sealed class ReputationInfo
{
[JsonPropertyName("value")]
public float Value { get; set; }
}

View File

@@ -34,8 +34,8 @@ chat-manager-entity-me-wrap-message = [italic]{ PROPER($entity) ->
} }
chat-manager-entity-looc-wrap-message = LOOC: [bold]{$entityName}:[/bold] {$message} chat-manager-entity-looc-wrap-message = LOOC: [bold]{$entityName}:[/bold] {$message}
chat-manager-send-ooc-wrap-message = OOC: [bold]{$playerName}:[/bold] {$message} chat-manager-send-ooc-wrap-message = OOC: [bold]{$playerName}{$rep}:[/bold] {$message}
chat-manager-send-ooc-patron-wrap-message = OOC: [bold][color={$patronColor}]{$playerName}[/color]:[/bold] {$message} chat-manager-send-ooc-patron-wrap-message = OOC: [bold][color={$patronColor}]{$playerName}[/color]{$rep}:[/bold] {$message}
chat-manager-send-dead-chat-wrap-message = {$deadChannelName}: [bold][BubbleHeader]{$playerName}[/BubbleHeader]:[/bold] [BubbleContent]{$message}[/BubbleContent] chat-manager-send-dead-chat-wrap-message = {$deadChannelName}: [bold][BubbleHeader]{$playerName}[/BubbleHeader]:[/bold] [BubbleContent]{$message}[/BubbleContent]
chat-manager-send-admin-dead-chat-wrap-message = {$adminChannelName}: [bold]([BubbleHeader]{$userName}[/BubbleHeader]):[/bold] [BubbleContent]{$message}[/BubbleContent] chat-manager-send-admin-dead-chat-wrap-message = {$adminChannelName}: [bold]([BubbleHeader]{$userName}[/BubbleHeader]):[/bold] [BubbleContent]{$message}[/BubbleContent]

View File

@@ -5,4 +5,4 @@ round-end-summary-window-round-id-label = Round [color=white]#{$roundId}[/color]
round-end-summary-window-gamemode-name-label = The game mode was [color=white]{$gamemode}[/color]. round-end-summary-window-gamemode-name-label = The game mode was [color=white]{$gamemode}[/color].
round-end-summary-window-duration-label = It lasted for [color=yellow]{$hours} hours, {$minutes} minutes, and {$seconds} seconds. round-end-summary-window-duration-label = It lasted for [color=yellow]{$hours} hours, {$minutes} minutes, and {$seconds} seconds.
round-end-summary-window-player-info-if-observer-text = [color=gray]{$playerOOCName}[/color] was [color=lightblue]{$playerICName}[/color], an observer. round-end-summary-window-player-info-if-observer-text = [color=gray]{$playerOOCName}[/color] was [color=lightblue]{$playerICName}[/color], an observer.
round-end-summary-window-player-info-if-not-observer-text = [color=gray]{$playerOOCName}[/color] was [color={$icNameColor}]{$playerICName}[/color] playing role of [color=orange]{$playerRole}[/color]. round-end-summary-window-player-info-if-not-observer-text = [color=gray]{$playerOOCName}[/color] was [color={$icNameColor}]{$playerICName}[/color] playing role of [color=orange]{$playerRole}[/color]. { $reputation }

View File

@@ -31,8 +31,8 @@ chat-manager-entity-whisper-unknown-wrap-message = [font size=11][italic][Bubble
chat-manager-entity-me-wrap-message = { $entityName } { $message } chat-manager-entity-me-wrap-message = { $entityName } { $message }
chat-manager-entity-looc-wrap-message = LOOC: [bold]{$entityName}:[/bold] {$message} chat-manager-entity-looc-wrap-message = LOOC: [bold]{$entityName}:[/bold] {$message}
chat-manager-send-ooc-wrap-message = OOC: [bold]{$playerName}:[/bold] {$message} chat-manager-send-ooc-wrap-message = OOC: [bold]{$playerName}{$rep}:[/bold] {$message}
chat-manager-send-ooc-patron-wrap-message = OOC: [bold][color={$patronColor}]{$playerName}[/color]:[/bold] {$message} chat-manager-send-ooc-patron-wrap-message = OOC: [bold][color={$patronColor}]{$playerName}[/color]{$rep}:[/bold] {$message}
chat-manager-send-dead-chat-wrap-message = {$deadChannelName}: [bold][BubbleHeader]{$playerName}[/BubbleHeader]:[/bold] [BubbleContent]{$message}[/BubbleContent] chat-manager-send-dead-chat-wrap-message = {$deadChannelName}: [bold][BubbleHeader]{$playerName}[/BubbleHeader]:[/bold] [BubbleContent]{$message}[/BubbleContent]
chat-manager-send-admin-dead-chat-wrap-message = {$adminChannelName}: [bold]([BubbleHeader]{$userName}[/BubbleHeader]):[/bold] [BubbleContent]{$message}[/BubbleContent] chat-manager-send-admin-dead-chat-wrap-message = {$adminChannelName}: [bold]([BubbleHeader]{$userName}[/BubbleHeader]):[/bold] [BubbleContent]{$message}[/BubbleContent]

View File

@@ -5,4 +5,4 @@ round-end-summary-window-round-id-label = Раунд [color=white]#{ $roundId }[
round-end-summary-window-gamemode-name-label = Игровой режим был [color=white]{ $gamemode }[/color]. round-end-summary-window-gamemode-name-label = Игровой режим был [color=white]{ $gamemode }[/color].
round-end-summary-window-duration-label = Он длился [color=yellow]{ $hours } ч., { $minutes } мин., и { $seconds } сек. round-end-summary-window-duration-label = Он длился [color=yellow]{ $hours } ч., { $minutes } мин., и { $seconds } сек.
round-end-summary-window-player-info-if-observer-text = [color=gray]{ $playerOOCName }[/color] был [color=lightblue]{ $playerICName }[/color], наблюдатель. round-end-summary-window-player-info-if-observer-text = [color=gray]{ $playerOOCName }[/color] был [color=lightblue]{ $playerICName }[/color], наблюдатель.
round-end-summary-window-player-info-if-not-observer-text = [color=gray]{ $playerOOCName }[/color] был [color={ $icNameColor }]{ $playerICName }[/color], в роли [color=orange]{ $playerRole }[/color]. round-end-summary-window-player-info-if-not-observer-text = [color=gray]{ $playerOOCName }[/color] был [color={ $icNameColor }]{ $playerICName }[/color], в роли [color=orange]{ $playerRole }[/color]. { $reputation }