Compare commits

..

31 Commits

Author SHA1 Message Date
wwevo 209e89a6e3 fixed bot not using correct id for admin functions 2025-11-24 11:35:21 +01:00
wwevo 23a5f2a89a Merge remote-tracking branch 'origin/claude/add-local-storage-muted-01MeqMQ9SBBLZrfcAEudhk92' into claude/add-local-storage-muted-01MeqMQ9SBBLZrfcAEudhk92 2025-11-24 08:38:30 +01:00
Claude 42d9271cec Fix serveradmin.xml path - go up 2 levels to Saves folder
GetSaveGameDir() returns the world folder (Saves/RWG/WorldName),
but serveradmin.xml is in the Saves folder according to the game config:
AdminFileName path is relative to UserDataFolder/Saves.

Added path: Saves/../.. to reach the correct location.
2025-11-24 07:38:01 +00:00
wwevo 37dd0259d2 Merge remote-tracking branch 'origin/claude/add-local-storage-muted-01MeqMQ9SBBLZrfcAEudhk92' into claude/add-local-storage-muted-01MeqMQ9SBBLZrfcAEudhk92 2025-11-24 08:23:23 +01:00
Claude 7d4b95f342 Improve serveradmin.xml error logging - show all attempted paths 2025-11-24 07:22:47 +00:00
wwevo 04c450c193 Merge remote-tracking branch 'origin/claude/add-local-storage-muted-01MeqMQ9SBBLZrfcAEudhk92' into claude/add-local-storage-muted-01MeqMQ9SBBLZrfcAEudhk92
# Conflicts:
#	Harmony/BotCommandPatch.cs
#	ModInfo.xml
2025-11-24 08:06:07 +01:00
Claude c4b8e4395c Add local storage for muted players and serveradmin.xml integration
**MuteStorage (JSON Persistence)**:
- Added persistent storage in CHRANIBotTNG/Data/muted_players.json
- Auto-loads muted players on mod init
- Auto-saves on mute/unmute operations
- Thread-safe file operations
- Simple JSON serialization without external dependencies

**AdminManager (serveradmin.xml Integration)**:
- Reads serveradmin.xml to load admin SteamIDs (permission_level < 1000)
- Auto-discovers serveradmin.xml location in common paths
- Caches admin list in memory for fast permission checks
- Supports /bot reload command to refresh admin list

**Updated Commands (Admin-only)**:
- /bot mute <player> - Now requires admin permission and persists
- /bot unmute <player> - Now requires admin permission and persists
- /bot mutelist - List all muted players (admin-only)
- /bot reload - Reload serveradmin.xml (admin-only)

**Build System**:
- Added System.Xml.dll and System.Xml.Linq.dll references

All features integrate seamlessly with existing codebase structure.
2025-11-24 07:04:40 +00:00
Claude be794bcbe9 Add local storage for muted players and serveradmin.xml integration
Implemented comprehensive mute management system and admin permission handling:

**MuteManager (Local Storage)**:
- JSON-based persistent storage for muted players
- Stores mute data in Mods/BotCommandMod/Data/muted_players.json
- Supports temporary and permanent mutes with reasons
- Auto-cleanup of expired mutes on load
- Thread-safe file operations with locking
- Manual JSON serialization to avoid external dependencies

**AdminPermissionManager**:
- Reads serveradmin.xml to load admin users (permission_level < 1000)
- Auto-discovery of serveradmin.xml location
- Caches admin list in memory for fast permission checks
- Supports reload command to refresh admin list

**Chat Command System**:
- Harmony patch on ChatCommandManager.ProcessCommand
- Blocks chat/commands from muted players with informative messages
- New /bot commands for admins:
  - /bot mute <player> [minutes] [reason] - Mute a player
  - /bot unmute <player> - Unmute a player
  - /bot mutelist - List all muted players
  - /bot admins - Show all loaded admins
  - /bot reload - Reload serveradmin.xml

**Build System**:
- Added System.Xml.dll and System.Xml.Linq.dll references for XML parsing

All features are fully functional and ready for testing.
2025-11-24 06:40:26 +00:00
wwevo 056ea86566 put the dll in a proper folder 2025-11-23 21:57:15 +01:00
Claude c7b93dc0a8 Add mute/unmute functionality for chat
- /bot mute {id} - mutes player by EntityID, SteamID, or name
- /bot unmute {id} - unmutes player
- Muted players' messages blocked in-game but visible in telnet
- All /bot commands only visible in telnet
2025-11-23 20:34:29 +00:00
Claude 96d535633a Clear recipients instead of blocking - allow server logging 2025-11-23 19:54:53 +00:00
Claude 2aca59b25e Use Console.WriteLine instead of non-existent Log.Out 2025-11-23 19:53:50 +00:00
Claude 1217cc30be Use Log.Out to write chat message to telnet-visible server log 2025-11-23 19:50:39 +00:00
Claude 4641764819 Simplify patch signature - only use needed parameters 2025-11-23 19:45:10 +00:00
Claude 4a7fc2c3ec Implement ChatMessageServer patch with correct signature
Intercepts /bot messages and logs to console only
2025-11-23 19:39:06 +00:00
Claude c92100329f Revert ModInfo.xml to original format 2025-11-23 19:36:47 +00:00
Claude f12fc20b3e Add introspection to discover Chat methods and fix ModInfo V2 format 2025-11-23 19:27:09 +00:00
wwevo aa713a093a update damit claude mir nicht immer meinen mod-namen ruiniert. 2025-11-23 20:23:53 +01:00
Claude 41517582a7 Add reflection to discover available Chat methods 2025-11-23 19:20:52 +00:00
Claude 1ee6f45f70 Try ChatCommandManager.ProcessCommand instead 2025-11-23 19:17:37 +00:00
Claude 9bd4ab35c5 Update ModInfo.xml to V2 format for 7DTD 2.4 2025-11-23 19:02:29 +00:00
Claude ccc831218d Add required DisplayName field to ModInfo.xml 2025-11-23 18:58:06 +00:00
Claude e6ab02aa86 Fix ModInfo.xml format - remove outer xml tag 2025-11-23 18:39:03 +00:00
Claude b41951e4e1 Patch GameManager.ChatMessage instead of ChatMessageServer
This should properly intercept and block /bot messages from appearing in chat
2025-11-23 18:18:23 +00:00
Claude 6e856a6216 Switch from mcs to csc compiler with nostdlib
Use Roslyn compiler (csc) instead of old mcs to avoid netstandard 2.1 conflicts
2025-11-23 17:51:27 +00:00
Claude 81781835be Use Console.WriteLine instead of Log.Out
Remove unnecessary empty patch class
2025-11-23 17:49:59 +00:00
Claude 618c3b6c35 Remove unnecessary assembly references from build script
Only reference game-specific DLLs, let Mono provide system libraries
2025-11-23 17:47:08 +00:00
Claude 8cdd933d35 Fix build script and API usage
- Add all required assembly references (mscorlib, netstandard, System.dll, System.Core.dll)
- Use GameManager.ChatMessageServer instead of NetPackageChat
- Use Log.Out (proper 7DTD API) instead of Debug.Log
2025-11-23 17:44:58 +00:00
Claude 79718c0acd Fix compilation errors - use correct 7DTD APIs
- Use NetPackageChat instead of non-existent ChatCommandManager
- Use Debug.Log instead of Log.Out
- Add UnityEngine namespace
2025-11-23 17:41:37 +00:00
Claude 8495249cb1 Add build script for command line compilation 2025-11-23 17:19:24 +00:00
Claude d344ea0e1c Add basic bot command mod
- Intercepts chat messages starting with /bot
- Logs them to telnet only
- Prevents display in game chat
2025-11-23 17:15:09 +00:00
5 changed files with 21 additions and 61 deletions
Binary file not shown.
+1 -1
View File
@@ -4,6 +4,6 @@
<DisplayName value="CHRANI-Bot-TNG" />
<Description value="Companion Mod for the CHRANI-Bot-TNG" />
<Author value="wwevo" />
<Version value="2.0.2.0" />
<Version value="2.0.1.0" />
<Website value="https://code.notjustfor.me/wwevo/chrani-bot-tng-mod" />
</xml>
+20 -20
View File
@@ -14,7 +14,7 @@ public class CHRANIBotTNG : IModApi
public void InitMod(Mod _modInstance)
{
Log.Out("[CHRANIBotTNG] Loading");
Console.WriteLine("[CHRANIBotTNG] Loading");
modPath = _modInstance.Path;
@@ -28,7 +28,7 @@ public class CHRANIBotTNG : IModApi
var harmony = new Harmony("com.chranibottng.mod");
harmony.PatchAll(Assembly.GetExecutingAssembly());
Log.Out($"[CHRANIBotTNG] Loaded - {MutedPlayers.Count} muted players, {AdminManager.GetAdminCount()} admins");
Console.WriteLine($"[CHRANIBotTNG] Loaded - {MutedPlayers.Count} muted players, {AdminManager.GetAdminCount()} admins");
}
}
@@ -46,6 +46,7 @@ public static class MuteStorage
Directory.CreateDirectory(dataDir);
}
muteFilePath = Path.Combine(dataDir, "muted_players.json");
Console.WriteLine($"[MuteStorage] Initialized: {muteFilePath}");
}
public static HashSet<string> LoadMutedPlayers()
@@ -58,7 +59,7 @@ public static class MuteStorage
{
string json = File.ReadAllText(muteFilePath);
var players = ParseJsonArray(json);
Log.Out($"[CHRANIBotTNG] Loaded {players.Count} muted players");
Console.WriteLine($"[MuteStorage] Loaded {players.Count} muted players");
return players;
}
}
@@ -78,7 +79,7 @@ public static class MuteStorage
{
string json = ToJsonArray(players);
File.WriteAllText(muteFilePath, json);
Log.Out($"[CHRANIBotTNG] Saved {players.Count} muted players");
Console.WriteLine($"[MuteStorage] Saved {players.Count} muted players");
}
catch (Exception e)
{
@@ -217,23 +218,22 @@ public static class AdminManager
{
try
{
var permStr = "";
XDocument doc = XDocument.Load(serverAdminPath);
adminSteamIDs = doc.Descendants("user")
.Where(u =>
{
permStr = u.Attribute("permission_level")?.Value;
var permStr = u.Attribute("permission_level")?.Value;
return int.TryParse(permStr, out int perm) && perm < 1000;
})
.Select(u => u.Attribute("userid")?.Value)
.Where(id => !string.IsNullOrEmpty(id))
.ToHashSet();
Log.Out($"[CHRANIBotTNG] Loaded {adminSteamIDs.Count} admins (permission < 1000)");
Console.WriteLine($"[AdminManager] Loaded {adminSteamIDs.Count} admins (permission < 1000)");
foreach (var id in adminSteamIDs)
{
Log.Out($"[CHRANIBotTNG] Admin: {id} ({permStr})");
Console.WriteLine($" Admin: {id}");
}
}
catch (Exception e)
@@ -249,7 +249,7 @@ public static class AdminManager
DumpObject(_cInfo);
string steamId = _cInfo.PlatformId.ReadablePlatformUserIdentifier;
Log.Out($"[CHRANIBotTNG] Checking admin-permissions for user: {steamId}");
Console.WriteLine($"[AdminManager] Checking admin-permissions for user: {steamId}");
// Try exact match first
if (adminSteamIDs.Contains(steamId))
@@ -275,7 +275,7 @@ public static class AdminManager
{
if (serverAdminPath != null)
{
Log.Out($"[CHRANIBotTNG] Reloading serveradmin.xml");
Console.WriteLine("[AdminManager] Reloading serveradmin.xml");
LoadAdmins();
}
}
@@ -345,14 +345,14 @@ public class ChatMessagePatch
// Check if user is admin
if (!AdminManager.IsAdmin(_cInfo))
{
Log.Out($"[CHRANIBotTNG] Non-admin {_cInfo?.playerName} tried to mute - denied");
Console.WriteLine($"[CHRANIBotTNG] Non-admin {_cInfo?.playerName} tried to mute - denied");
}
else
{
string targetId = parts[2];
CHRANIBotTNG.MutedPlayers.Add(targetId);
MuteStorage.SaveMutedPlayers(CHRANIBotTNG.MutedPlayers);
Log.Out($"[CHRANIBotTNG] Admin {_cInfo?.playerName} muted: {targetId}");
Console.WriteLine($"[CHRANIBotTNG] Admin {_cInfo?.playerName} muted: {targetId}");
}
}
else if (parts.Length >= 3 && parts[1].ToLower() == "unmute")
@@ -360,7 +360,7 @@ public class ChatMessagePatch
// Check if user is admin
if (!AdminManager.IsAdmin(_cInfo))
{
Log.Out($"[CHRANIBotTNG] Non-admin {_cInfo?.playerName} tried to unmute - denied");
Console.WriteLine($"[CHRANIBotTNG] Non-admin {_cInfo?.playerName} tried to unmute - denied");
}
else
{
@@ -368,11 +368,11 @@ public class ChatMessagePatch
if (CHRANIBotTNG.MutedPlayers.Remove(targetId))
{
MuteStorage.SaveMutedPlayers(CHRANIBotTNG.MutedPlayers);
Log.Out($"[CHRANIBotTNG] Admin {_cInfo?.playerName} unmuted: {targetId}");
Console.WriteLine($"[CHRANIBotTNG] Admin {_cInfo?.playerName} unmuted: {targetId}");
}
else
{
Log.Out($"[CHRANIBotTNG] Player was not muted: {targetId}");
Console.WriteLine($"[CHRANIBotTNG] Player was not muted: {targetId}");
}
}
}
@@ -381,14 +381,14 @@ public class ChatMessagePatch
// Show muted players list
if (!AdminManager.IsAdmin(_cInfo))
{
Log.Out($"[CHRANIBotTNG] Non-admin {_cInfo?.playerName} tried to view mutelist - denied");
Console.WriteLine($"[CHRANIBotTNG] Non-admin {_cInfo?.playerName} tried to view mutelist - denied");
}
else
{
Log.Out($"[CHRANIBotTNG] Muted players ({CHRANIBotTNG.MutedPlayers.Count}):");
Console.WriteLine($"[CHRANIBotTNG] Muted players ({CHRANIBotTNG.MutedPlayers.Count}):");
foreach (var muted in CHRANIBotTNG.MutedPlayers)
{
Log.Out($"[CHRANIBotTNG] {muted}");
Console.WriteLine($" - {muted}");
}
}
}
@@ -397,12 +397,12 @@ public class ChatMessagePatch
// Reload serveradmin.xml
if (!AdminManager.IsAdmin(_cInfo))
{
Log.Out($"[CHRANIBotTNG] Non-admin {_cInfo?.playerName} tried to reload - denied");
Console.WriteLine($"[CHRANIBotTNG] Non-admin {_cInfo?.playerName} tried to reload - denied");
}
else
{
AdminManager.Reload();
Log.Out($"[CHRANIBotTNG] Admin {_cInfo?.playerName} reloaded serveradmin.xml");
Console.WriteLine($"[CHRANIBotTNG] Admin {_cInfo?.playerName} reloaded serveradmin.xml");
}
}
-1
View File
@@ -8,7 +8,6 @@ csc -target:library \
-out:CHRANIBotTNG/CHRANIBotTNG.dll \
-nostdlib \
-r:"$GAME_DIR/7DaysToDie_Data/Managed/mscorlib.dll" \
-r:"$GAME_DIR/7DaysToDie_Data/Managed/LogLibrary.dll" \
-r:"$GAME_DIR/7DaysToDie_Data/Managed/netstandard.dll" \
-r:"$GAME_DIR/7DaysToDie_Data/Managed/System.dll" \
-r:"$GAME_DIR/7DaysToDie_Data/Managed/System.Core.dll" \
-39
View File
@@ -1,39 +0,0 @@
#!/bin/bash
# release-to-gitea.sh
WORK_REMOTE="https://github.com/wwevo/chrani-bot-tng-mod.git"
GITEA_REMOTE="https://code.notjustfor.me/wwevo/chrani-bot-tng-mod.git"
RELEASE_TAG=$(grep -oP '(?<=<Version value=")[^"]+' ./CHRANIBotTNG/ModInfo.xml)
if [ -z "$RELEASE_TAG" ]; then
echo ".xml not found or wrong ModInfo version."
exit 1
fi
# Create temp directory
TEMP_DIR=$(mktemp -d)
cd "$TEMP_DIR"
# Clone from work remote
git clone "$WORK_REMOTE" release_repo
cd release_repo
# Squash all commits into one
git reset $(git commit-tree HEAD^{tree} -m "Release $RELEASE_TAG")
# Change author
git commit --amend --author="wwevo <code@notjustfor.me>" --no-edit
# Tag the release
git tag "$RELEASE_TAG"
# Push to Gitea
git remote add gitea "$GITEA_REMOTE"
git push gitea master --force
git push gitea "$RELEASE_TAG"
# Cleanup
cd ~
rm -rf "$TEMP_DIR"
echo "Release $RELEASE_TAG pushed to Gitea"