serverpermadeath
Server side only. Records deaths and bans characters when they die.
Last updated | 2 years ago |
Total downloads | 662 |
Total rating | 0 |
Categories | Server-side |
Dependency string | 1010101110-serverpermadeath-1.0.0 |
Dependants | 2 other packages depend on this package |
This mod requires the following mods to function
denikson-BepInExPack_Valheim
BepInEx pack for Valheim. Preconfigured and includes unstripped Unity DLLs.
Preferred version: 5.4.2105README
serverpermadeath
this mod runs on the server only. The goal of this mod is to give server authority / no client mod solution to permadeath. We don't want to use the originally bannedlist.txt because that will ban a player all together. We want players to continue playing, they just can't use a character that has died.
new server textfile permadeath.txt
Server checks for dead players. if a player dies:
- adds steamid|charactername to permadeath.txt
- shout that player has died
- start a 30 sec timer giving them time to say goodbye
- kicks them, shows Banned popup
Server checks permadeath.txt and all players connected. if player|charactername is on list:
- kicks them, shows Banned popup
Combine this with servercharacters https://valheim.thunderstore.io/package/Smoothbrain/ServerCharacters/ to have a hardcore server
install
prerequisite: have bepinex installed on server
drag serverpermadeath.dll into bepinex/plugins folder
restart server
code
public static SyncedList characterbans;
public static Dictionary<string, int> timers = new Dictionary<string, int>();
//initialize the synced list used for tracking bans
[HarmonyPatch(typeof(ZNet), "Awake")]
public static class awakepatch{
private static void Postfix()
{
characterbans = new SyncedList(Utils.GetSaveDataPath(FileHelpers.FileSource.Local) + "/permadeath.txt",
"List of dead players by steamid|charname - ONE per line - serverpermadeath mod");
}
}
[HarmonyPatch(typeof(ZNet), "CheckWhiteList")]
public static class CheckCharWhitelist
{
private static bool Prefix(ZNet __instance)
{
//runs every 5s
//check whitelist
if (__instance.m_peers != null)
{
if (__instance.m_peers.Count > 0)
{
foreach (ZNetPeer znetPeer in __instance.m_peers.ToList<ZNetPeer>())
{
if (znetPeer.IsReady() && !znetPeer.m_characterID.IsNone())
{
string charName = znetPeer.m_playerName;
string id = znetPeer.m_socket.GetHostName();
string idandname = id + "|" + charName;
bool bannedalready = characterbans.Contains(idandname);
//they are banned, gtfo
if (bannedalready)
{
ZNet.instance.InternalKick(znetPeer);
}
else
{
//check if they're dead
ZDO zdo = __instance.m_zdoMan.GetZDO(znetPeer.m_characterID);
if (zdo != null)
{
bool dead = zdo.GetBool("dead", false);
if (dead && !TrippingPatches.timers.ContainsKey(idandname))
{
//tell everyone they are dead
ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "ChatMessage", new object[]
{
znetPeer.m_refPos,
2,
znetPeer.m_playerName,
znetPeer.m_playerName + " has been slain"
});
ZLog.Log(znetPeer.m_playerName + " DIED " + znetPeer.m_refPos.ToString());
//start a timer to kick them
TrippingPatches.timers.Add(idandname, 5);
}
}
}
}
}
}
}
//clean up the timers
foreach (string key in TrippingPatches.timers.Keys.ToList<string>())
{
TrippingPatches.timers[key] = TrippingPatches.timers[key] - 1;
if (TrippingPatches.timers[key] < 0)
{
//add them to the banned list
characterbans.Add(key);
//remove the timer
TrippingPatches.timers.Remove(key);
}
}
return true;
}
}