You are viewing a potentially older version of this package. View all versions.
1010101110-serverpermadeath-0.0.1 icon

serverpermadeath

Server side only. Records deaths and bans characters when they die.

Date uploaded 3 years ago
Version 0.0.1
Download link 1010101110-serverpermadeath-0.0.1.zip
Downloads 501
Dependency string 1010101110-serverpermadeath-0.0.1

This mod requires the following mods to function

denikson-BepInExPack_Valheim-5.4.2105 icon
denikson-BepInExPack_Valheim

BepInEx pack for Valheim. Preconfigured and includes unstripped Unity DLLs.

Preferred version: 5.4.2105

README

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 serverfresh mod to attempt to have a hardcore server (game is easy to cheat if you know what you're doing).

install

prerequisite: have bepinex installed on server

drag serverpermadeath.dll into bepinex/plugins folder

restart server

code

public class ZNetPatches
{
    public static SyncedList characterbans;
    public static Dictionary<string,int> timers;

    [HarmonyPatch(typeof(ZNet), "Awake")]
    public static class ZNetAwakeBan
    {
        private static void Postfix(ZNet __instance)
        {
            characterbans = new SyncedList(Utils.GetSaveDataPath() + "/permadeath.txt",
                "List of dead players by steamid|charname - ONE per line - serverpermadeath mod");
            timers = new Dictionary<string, int>();
        }
    }


    [HarmonyPatch(typeof(ZNet), "CheckWhiteList")]
    public static class ZNetVariablePatch
    {
        private static void Postfix(ZNet __instance)
        {
            if (__instance.IsServer())
            {
                foreach (ZNetPeer znetPeer in __instance.m_peers)
                {
                    if (znetPeer.IsReady() && !znetPeer.m_characterID.IsNone())
                    {
                        ZDO p = __instance.m_zdoMan.GetZDO(znetPeer.m_characterID);
                        
                        if(p != null)
                        {
                            var dead = p.GetBool("dead");
                            var bannedalready = characterbans.Contains(znetPeer.m_socket.GetHostName() + "|" + znetPeer.m_playerName);

                            //we haven't seen the player dead yet
                            if(!timers.ContainsKey(znetPeer.m_playerName))
                            {
                                //check if they are dead
                                if (dead)
                                {
                                    //send chat message on death
                                    ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "ChatMessage", new object[]
                                    {
                                    znetPeer.m_refPos,
                                    2,
                                    znetPeer.m_playerName,
                                    znetPeer.m_playerName + " DIED"
                                    });
                                    //log in server log
                                    ZLog.Log(znetPeer.m_playerName + " DIED");

                                    //timer for kicking them
                                    //allows them to say goodbye or rage
                                    timers.Add(znetPeer.m_playerName, 6);

                                    //add to permadeath list
                                    characterbans.Add(znetPeer.m_socket.GetHostName() + "|" + znetPeer.m_playerName);
                                }

                                //if someone banned got into server get rid of them
                                if (bannedalready)
                                {
                                    ZLog.Log(znetPeer.m_playerName + " permadeath user is already banned");
                                    //send client banned popup (it disconnects them)
                                    znetPeer.m_rpc.Invoke("Error", new object[]{8});
                                }
                            }
                            else
                            {
                                //player has been detected dead but we give them a little time to say goodbye
                                timers[znetPeer.m_playerName] = timers[znetPeer.m_playerName] - 1;
                                ZLog.Log("permadeath timer: " + timers[znetPeer.m_playerName]);

                                //timer expired, get rid of them
                                if (timers[znetPeer.m_playerName] < 1)
                                {
                                    ZLog.Log(znetPeer.m_playerName + " permadeath timer expired " + timers[znetPeer.m_playerName]);

                                    //remove from our permadeath timers
                                    timers.Remove(znetPeer.m_playerName);
                                    //send client banned popup (it disconnects them)
                                    znetPeer.m_rpc.Invoke("Error", new object[] { 8 });                                        
                                }
                            }
                        }
                    }
                }
            }
        }
    }

}