Compare commits

...

2 commits

Author SHA1 Message Date
3c9f65e121 zio fork 1.8.2b-zio5: staff chat shows rank
Some checks are pending
Build and Publish / build (push) Waiting to run
Build and Publish / publish (push) Blocked by required conditions
@ in team chat and css_asay read ">[STAFF][RANK] name: message", and @ in all chat and a
player's css_say read ">[RANK] name: message", with the rank from the sender's highest #rank/...
group (O, SA, A, TA, M, TM, H). Staff in no rank group get ">[STAFF] name" and "> name". A
non-staff player's @ team chat reads ">[PLAYER] name: message". Console's messages are unchanged.
The lines are new en.json keys: sa_staffchat_template, sa_staffsay_template, their _norank
variants and sa_staffchat_template_player.
2026-09-28 18:01:44 +01:00
bc6e32892d zio fork 1.8.2b-zio4: release the whole plugin and shared API, not just the changed files 2026-09-28 14:59:30 +01:00
7 changed files with 94 additions and 34 deletions

View file

@ -22,7 +22,7 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdmin
public override string ModuleName => "CS2-SimpleAdmin" + (Helper.IsDebugBuild ? " (DEBUG)" : " (RELEASE)");
public override string ModuleDescription => "Simple admin plugin for Counter-Strike 2 :)";
public override string ModuleAuthor => "daffyy";
public override string ModuleVersion => "1.8.2b-zio3";
public override string ModuleVersion => "1.8.2b-zio5";
public override void Load(bool hotReload)
{

View file

@ -29,13 +29,23 @@ public partial class CS2_SimpleAdmin
foreach (var player in Helper.GetValidPlayers()
.Where(p => AdminManager.PlayerHasPermissions(new SteamID(p.SteamID), "@css/chat")))
{
if (_localizer != null)
player.PrintToChat(_localizer["sa_adminchat_template_admin",
caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName,
utf8String]);
if (_localizer == null) continue;
// zio: players get ">[STAFF][RANK] name: message", like @ in team chat.
player.PrintToChat(caller == null
? _localizer["sa_adminchat_template_admin", _localizer["sa_console"], utf8String]
: StaffChatMessage(caller, utf8String.Trim()));
}
}
// zio: staff chat line, ">[STAFF][RANK] name: message" ("[RANK]" left out without a rank group).
private static string StaffChatMessage(CCSPlayerController sender, string message)
{
var rank = Helper.GetStaffRankTag(sender);
return rank == null
? _localizer!["sa_staffchat_template_norank", sender.PlayerName, message]
: _localizer!["sa_staffchat_template", rank, sender.PlayerName, message];
}
/// <summary>
/// Sends a custom chat message to all players with color tags processed.
/// </summary>
@ -73,6 +83,20 @@ public partial class CS2_SimpleAdmin
var utf8String = Encoding.UTF8.GetString(utf8BytesString);
Helper.LogCommand(caller, command);
// zio: from a player (including @ in all chat), ">[RANK] name: message" with no [SA] prefix.
// Console (and the web panel over RCON) keeps the plain "ADMIN:" message.
if (caller != null && _localizer != null)
{
var rank = Helper.GetStaffRankTag(caller);
var line = rank == null
? _localizer["sa_staffsay_template_norank", caller.PlayerName, utf8String.Trim()]
: _localizer["sa_staffsay_template", rank, caller.PlayerName, utf8String.Trim()];
foreach (var player in Helper.GetValidPlayers())
player.PrintToChat(line);
return;
}
foreach (var player in Helper.GetValidPlayers())
{
player.SendLocalizedMessage(_localizer,

View file

@ -376,7 +376,8 @@ public partial class CS2_SimpleAdmin
StringBuilder sb = new();
if (AdminManager.PlayerHasPermissions(new SteamID(player.SteamID), "@css/chat"))
{
sb.Append(_localizer!["sa_adminchat_template_admin", player.PlayerName, info.GetArg(1).Remove(0, 1)]);
// zio: ">[STAFF][RANK] name: message".
sb.Append(StaffChatMessage(player, info.GetArg(1).Remove(0, 1)));
foreach (var p in Utilities.GetPlayers().Where(p => p.IsValid && p is { IsBot: false, IsHLTV: false } && AdminManager.PlayerHasPermissions(new SteamID(p.SteamID), "@css/chat")))
{
p.PrintToChat(sb.ToString());
@ -384,7 +385,8 @@ public partial class CS2_SimpleAdmin
}
else
{
sb.Append(_localizer!["sa_adminchat_template_player", player.PlayerName, info.GetArg(1).Remove(0, 1)]);
// zio: ">[PLAYER] name: message".
sb.Append(_localizer!["sa_staffchat_template_player", player.PlayerName, info.GetArg(1).Remove(0, 1)]);
player.PrintToChat(sb.ToString());
foreach (var p in Utilities.GetPlayers().Where(p => p is { IsValid: true, IsBot: false, IsHLTV: false } && AdminManager.PlayerHasPermissions(new SteamID(p.SteamID), "@css/chat")))
{

View file

@ -144,6 +144,30 @@ internal static class Helper
return string.Join(" ", parts);
}
// zio: staff rank groups, highest first, and their chat abbreviations.
private static readonly (string Group, string Tag)[] StaffRanks =
[
("#rank/owner", "O"),
("#rank/senioradmin", "SA"),
("#rank/admin", "A"),
("#rank/trialadmin", "TA"),
("#rank/mod", "M"),
("#rank/trialmod", "TM"),
("#rank/helper", "H"),
];
// zio: the player's highest staff rank abbreviation, or null if they're in no rank group.
internal static string? GetStaffRankTag(CCSPlayerController player)
{
var groups = AdminManager.GetPlayerAdminData(new SteamID(player.SteamID))?.Groups;
if (groups == null) return null;
foreach (var (group, tag) in StaffRanks)
{
if (groups.Contains(group)) return tag;
}
return null;
}
public static void KickPlayer(int userId, NetworkDisconnectionReason reason = NetworkDisconnectionReason.NETWORK_DISCONNECT_KICKED, int delay = 0)
{
var player = Utilities.GetPlayerFromUserid(userId);

View file

@ -141,6 +141,11 @@
"sa_admin_voice_unlisten_all": "{Default}You no longer hear {lime}all {default}players",
"sa_adminsay_prefix": "{RED}ADMIN: {lightred}{0}{default}",
"sa_adminchat_template_admin": "{LIME}(ADMIN) {lightred}{0}{default}: {lightred}{1}{default}",
"sa_staffchat_template": "{default}>[{yellow}STAFF{default}][{lime}{0}{default}] {yellow}{1}{default}: {grey}{2}{default}",
"sa_staffchat_template_norank": "{default}>[{yellow}STAFF{default}] {yellow}{0}{default}: {grey}{1}{default}",
"sa_staffchat_template_player": "{default}>[{lightblue}PLAYER{default}] {lightblue}{0}{default}: {grey}{1}{default}",
"sa_staffsay_template": "{default}>[{lime}{0}{default}] {yellow}{1}{default}: {grey}{2}{default}",
"sa_staffsay_template_norank": "{default}> {yellow}{0}{default}: {grey}{1}{default}",
"sa_adminchat_template_player": "{SILVER}(PLAYER) {lightred}{0}{default}: {lightred}{1}{default}",
"sa_discord_log_command": "**{0}** issued command `{1}` on server `HOSTNAME`",
"sa_menu_pluginsmanager_loaded": "{lime}Enabled {default}plugin {lime}{0}",

View file

@ -14,11 +14,21 @@ from the `build-1.8.2b` tag). Changes, all marked `zio:` in the code:
- New permission `@css/bypassipban`, for players or groups: IP bans, and bans on other accounts
that share their IP, don't apply to them; a ban on their own SteamID still does. `@css/root`
has it, as it has every `@css` flag.
- Staff chat shows the sender's rank, from their highest `#rank/...` group (O, SA, A, TA, M, TM,
H for helper): `@message` in team chat and `css_asay` read `>[STAFF][RANK] name: message`, and
`@message` in all chat and `css_say` from a player read `>[RANK] name: message` (`> name: message`
if they have no rank group). A non-staff player's `@message` in team chat reads
`>[PLAYER] name: message`. Console's `css_say`/`css_asay` are unchanged. New lang keys
`sa_staffchat_template`, `sa_staffsay_template`, their `_norank` variants and
`sa_staffchat_template_player`, in `lang/en.json` only.
Publish with `FORGEJO_TOKEN=... ./release.sh v<ModuleVersion>` (ModuleVersion is `1.8.2b-zioN`).
It rebuilds from the committed source and uploads `SimpleAdmin-<tag>.tar.gz` to git.zio.sh
(`cs2/SimpleAdmin`), holding only `CS2-SimpleAdmin.dll` and `lang/en.json`. The rest of the plugin
and `shared/CS2-SimpleAdminApi` stay as the upstream 1.8.2b release installed them.
(`cs2/SimpleAdmin`), laid out like `game/csgo/`. It holds the whole plugin (its libraries, all lang
files and migrations) and `shared/CS2-SimpleAdminApi`, as upstream's own release does, so nothing
from upstream needs installing first. It leaves out the optional FunCommands and StealthModule
modules and `configs/`. The NickFox007 dependencies (AnyBaseLib, PlayerSettings, MenuManager) aren't
in it either; the server's `pre.sh` installs them from their own releases.
---

View file

@ -10,11 +10,13 @@
# Asset: SimpleAdmin-<tag>.tar.gz, laid out like the server's game/csgo/ - extract it there:
# tar -xzf SimpleAdmin-<tag>.tar.gz -C /srv/cs2/game/csgo
#
# addons/counterstrikesharp/plugins/CS2-SimpleAdmin/ CS2-SimpleAdmin.dll, lang/en.json
# addons/counterstrikesharp/plugins/CS2-SimpleAdmin/ the plugin, its libraries, lang/, migrations
# addons/counterstrikesharp/shared/CS2-SimpleAdminApi/ the shared API (unchanged from upstream)
#
# Only the files the fork changes. Everything else in the plugin folder (its libraries, other lang
# files, migrations) and shared/CS2-SimpleAdminApi stay as the upstream 1.8.2b release installed
# them; the fork doesn't touch the API. No configs/: those stay the server's.
# The whole plugin, packaged the way upstream's CI packages its release, so nothing of upstream's
# has to be installed first. Not included: the optional FunCommands and StealthModule modules, and
# the NickFox007 dependencies (AnyBaseLib, PlayerSettings, MenuManager), which pre.sh installs from
# their own releases. No configs/: the database settings stay the server's.
set -euo pipefail
FORGEJO_URL="https://git.zio.sh"
@ -24,13 +26,6 @@ REPO="SimpleAdmin"
# Only uploading needs it; downloading from the public repo doesn't. Don't commit a real token.
FORGEJO_TOKEN="${FORGEJO_TOKEN:-CHANGE_ME_FORGEJO_TOKEN}"
# Only these ship from the publish output. CounterStrikeSharp.API.dll is excluded by the csproj
# (ExcludeAssets=runtime); the server already provides it.
PLUGIN_FILES=(
CS2-SimpleAdmin.dll
lang/en.json
)
TAG="${1:-}"
if [[ -z "$TAG" ]]; then
echo "usage: $0 <tag> (e.g. v1.8.2b-zio1)" >&2
@ -60,24 +55,24 @@ fi
# --- Build -----------------------------------------------------------------------
OUT="release-out"
PUBLISH="$OUT/publish"
rm -rf CS2-SimpleAdmin/bin CS2-SimpleAdmin/obj CS2-SimpleAdminApi/bin CS2-SimpleAdminApi/obj "$OUT"
# dotnet build, as upstream's CI does: the csproj sets PublishTrimmed, which a plugin mustn't be.
podman run --rm -v "$(pwd)":/src:Z -w /src \
mcr.microsoft.com/dotnet/sdk:10.0 dotnet build CS2-SimpleAdmin/CS2-SimpleAdmin.csproj -c Release -o "/src/$PUBLISH"
# --- Stage (layout of game/csgo/) and package ----------------------------------------
STAGE="$OUT/stage"
PLUGIN_DIR="$STAGE/addons/counterstrikesharp/plugins/CS2-SimpleAdmin"
mkdir -p "$PLUGIN_DIR"
for file in "${PLUGIN_FILES[@]}"; do
mkdir -p "$PLUGIN_DIR/$(dirname "$file")"
cp "$PUBLISH/$file" "$PLUGIN_DIR/$file"
done
CSS_DIR="addons/counterstrikesharp"
rm -rf CS2-SimpleAdmin/bin CS2-SimpleAdmin/obj CS2-SimpleAdminApi/bin CS2-SimpleAdminApi/obj "$OUT"
# dotnet build straight into the staged layout, as upstream's CI does: the csproj sets
# PublishTrimmed, which a plugin mustn't be. CounterStrikeSharp.API.dll is kept out by the csproj
# (ExcludeAssets=runtime); the server already provides it.
podman run --rm -v "$(pwd)":/src:Z -w /src mcr.microsoft.com/dotnet/sdk:10.0 sh -c "
dotnet build CS2-SimpleAdmin/CS2-SimpleAdmin.csproj -c Release -o '/src/$STAGE/$CSS_DIR/plugins/CS2-SimpleAdmin' &&
dotnet build CS2-SimpleAdminApi/CS2-SimpleAdminApi.csproj -c Release -o '/src/$STAGE/$CSS_DIR/shared/CS2-SimpleAdminApi'"
if find "$STAGE" -name CounterStrikeSharp.API.dll | grep -q .; then
echo "CounterStrikeSharp.API.dll ended up in the build output; not packaging it." >&2
exit 1
fi
# --- Package (layout of game/csgo/) ------------------------------------------------
TARBALL="SimpleAdmin-${TAG}.tar.gz"
tar -czf "$OUT/$TARBALL" -C "$STAGE" addons
rm -rf "$STAGE" "$PUBLISH"
rm -rf "$STAGE"
echo "Packaged:"
tar -tzf "$OUT/$TARBALL"