Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can we have option to stop the server if last player disconnected #32

Closed
nicedevil007 opened this issue Jan 21, 2024 · 20 comments · Fixed by #452
Closed

Can we have option to stop the server if last player disconnected #32

nicedevil007 opened this issue Jan 21, 2024 · 20 comments · Fixed by #452
Labels
enhancement New feature or request

Comments

@nicedevil007
Copy link

Is your feature request related to a problem? Please describe.
Pets may die during the time where nobody is looking for them (some people have to work :D)
On other steamcmd servers it was possible to set a flag to stop the server after the last player disconnected, I believe it was satisfactory, but don't hurt me if I'm wrong.

Describe the solution you'd like
We need an ENV variable that do the feature for us.

Describe alternatives you've considered
n.a.

Additional context
all said, at least I hope so :D

@thijsvanloef thijsvanloef added the enhancement New feature or request label Jan 21, 2024
@thijsvanloef
Copy link
Owner

Would be a great feature!

@Twanislas
Copy link

I support this, it would also prevent the server to reach huge number in days xD

I do think this might as well be implemented at the game level to have a feature to "freeze time" once the last player disconnects.

@fryfrog
Copy link
Contributor

fryfrog commented Jan 24, 2024

You could use something via RCON to watch the status of /ShowPlayers maybe? At least, it could shutdown when 0 players. The user would have to start it back up.

@Twanislas
Copy link

That's indeed an excellent workaround in the meantime, I might try and have a stab at it (and open a PR!) if I find the free cycles :)

Cheers !

@nicedevil007
Copy link
Author

You could use something via RCON to watch the status of /ShowPlayers maybe? At least, it could shutdown when 0 players. The user would have to start it back up.

I have no idea on how to implement this. Can you describe this a bot more?

@fremus89
Copy link

script.txt
Something like this do I have in mind, but is untested

@fryfrog
Copy link
Contributor

fryfrog commented Jan 25, 2024

I'd use rcon to list the players too.

@fremus89
Copy link

fremus89 commented Jan 26, 2024

#!/bin/bash

# Function to check players and take action based on the response
check_players() {
    players_output=$(docker exec -it palworld-server rcon-cli ShowPlayers)

    # Check if the response contains the header followed by an empty line
    if echo "$players_output" | grep -q "name,playeruid,steamid"$'\n'$'\n'; then
        echo "No players found. Shutting down the server."
        docker exec -it palworld-server rcon-cli Shutdown
    else
        echo "Players found. Server will continue running."
        # You can add additional actions or commands here if needed
    fi
}

check_players

this in a nice little loop with a delay et voilà

to start the server i have something similar, unfortunately, the server has to be reached twice, as the game times out during first connection and server boot.

#!/bin/bash

TARGET_PORT=8211

while true; do
    # Use tcpdump to capture incoming traffic on the target port
    capture_result=$(sudo tcpdump -n -c 1 -i any port $TARGET_PORT 2>/dev/null)

    # Check if any packets were captured
    if [ -n "$capture_result" ]; then
        # Trigger your event here (replace with your desired action)
        echo "Connection attempt detected on port $TARGET_PORT" 
        echo "starting server"
	docker start palworld-server

        # End the loop
        break
    fi

    # Adjust the sleep duration based on your monitoring requirements
    sleep 1
done

# Optionally, you can perform cleanup or additional actions after the loop
echo "Loop ended"

@Luatan Luatan mentioned this issue Feb 2, 2024
3 tasks
@olterman
Copy link

olterman commented Feb 3, 2024

Question is would this mean I need to manually start the server each time a new player wants to connect ?

@hoonlight
Copy link

hoonlight commented Feb 5, 2024

This is a Python script that dynamically pauses and restarts the server when it detects no players and when a player joins.

First, install tcpdump, then run the script.
Replace TARGET_PORT, CONTAINER_NAME, and sudo_password with your values.

import subprocess
import time

TARGET_PORT = 8211
CONTAINER_NAME = "palworld-server"
sudo_password = "your_sudo_password_here"


def check_players():
    players_output = run_command(
        f"docker exec -it {CONTAINER_NAME} rcon-cli ShowPlayers"
    )
    print(f"player: {players_output}")
    if players_output == "name,playeruid,steamid" or not players_output:
        return False
    else:
        return True


def run_command(command):
    """Helper function to run a shell command and return its output"""
    result = subprocess.run(
        command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, text=True
    )
    return result.stdout.strip()


def main():
    if not check_players():
        print("No players found. Restart the server.")
        run_command(f"docker restart {CONTAINER_NAME}")

        for sec in range(30, 0, -1):
            print(f"Waiting for restart to complete... {sec} seconds left")
            time.sleep(1)

        # if not players, pause server
        if not check_players():
            print("Restart complete. Pause the server.")
            run_command(f"docker pause {CONTAINER_NAME}")
            player = False
            print("Waiting for players to connect")
        else:
            player = True

        while not player:
            # Use tcpdump to capture incoming traffic on the target port
            capture_command = f"echo {sudo_password} | sudo -S tcpdump -n -c 1 -i any port {TARGET_PORT} 2>/dev/null"
            capture_result = run_command(capture_command)

            # Check if any packets were captured
            if capture_result:
                player = True
                print(f"Connection attempt detected on port {TARGET_PORT}")
                print("Starting server")
                run_command(f"docker unpause {CONTAINER_NAME}")

                for sec in range(30, 0, -1):
                    print(f"Waiting for players to connect... {sec} seconds left")
                    time.sleep(1)
            else:
                time.sleep(1)
    else:
        print("Players found. Server will continue running.")
        time.sleep(60)


if __name__ == "__main__":
    while True:
        main()
  1. detect players on the server every minute, and if there are no players, restart and pause the server.
    Restarting the server is for resource optimization, and pausing the server is for quick server restarts.

  2. When the server is paused, it detects connections. When a connection is detected, unpause the server.

This works well for me. Feel free to modify it to suit your needs.

@jh1950
Copy link

jh1950 commented Feb 8, 2024

@hoonlight

For users who do not ask for passwords when using the sudo command, the echo {sudo_password} | part must be deleted for normal operation. Otherwise, the tcpdump command will not wait for a request.

this

capture_command = f"echo {sudo_password} | sudo -S tcpdump -n -c 1 -i any port {TARGET_PORT} 2>/dev/null"

to

capture_command = f"sudo -S tcpdump -n -c 1 -i any port {TARGET_PORT} 2>/dev/null"

Therefore, I don't need part sudo_password = "your_sudo_password_here" too, delete it.


Sometimes Weird. This response is for another request. error is included in the result when using the rcon-cli command. If so, check_players is not returned properly.

If you modify the function as follows, it works fine.

def check_players():
    players_output = run_command(
        f"docker exec -it {CONTAINER_NAME} rcon-cli ShowPlayers"
    )
    print(f"player: {players_output}")
    return "," in players_output.replace("name,playeruid,steamid", "")

P.S. I'm using a modified Dockerfile for use in ARM64, and I have also changed the rcon-cli to https://github.com/itzg/rcon-cli. That may be why this is happening.

+ After writing this, I checked that the ARM version of Dockerfile was created in this repository. With this, this error doesn't seem to occur.

@MrSnekyDino
Copy link

MrSnekyDino commented Feb 12, 2024

Any way to do this in the background and at boot of my home server? Works great if it's actively running in my terminal window, but when I try to make it a cron job, it doesn't seem to recognize that there's anyone on the server and reboots then pauses after 60s. It does correctly detect when someone joins and unpauses the container though (but then repeats the cycle after 60s). I've also just tried starting it in the background with & but it immediately stops the job.

My cron was nohup python3 server.py & I suspect the fact that it reads outputs from print is the issue.

@fremus89
Copy link

i use it with tmux, so i can just detach the session and reattach, nohup caused issues for me as well
https://tmuxcheatsheet.com/

i usually reboot by hand, so i start the script again

@MrSnekyDino
Copy link

That's perfect, thank you!

@It0w
Copy link

It0w commented Feb 16, 2024

This is a Python script that dynamically pauses and restarts the server when it detects no players and when a player joins.

First, install tcpdump, then run the script. Replace TARGET_PORT, CONTAINER_NAME, and sudo_password with your values.

import subprocess
import time

TARGET_PORT = 8211
CONTAINER_NAME = "palworld-server"
sudo_password = "your_sudo_password_here"


def check_players():
    players_output = run_command(
        f"docker exec -it {CONTAINER_NAME} rcon-cli ShowPlayers"
    )
    print(f"player: {players_output}")
    if players_output == "name,playeruid,steamid" or not players_output:
        return False
    else:
        return True


def run_command(command):
    """Helper function to run a shell command and return its output"""
    result = subprocess.run(
        command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, text=True
    )
    return result.stdout.strip()


def main():
    if not check_players():
        print("No players found. Restart the server.")
        run_command(f"docker restart {CONTAINER_NAME}")

        for sec in range(30, 0, -1):
            print(f"Waiting for restart to complete... {sec} seconds left")
            time.sleep(1)

        # if not players, pause server
        if not check_players():
            print("Restart complete. Pause the server.")
            run_command(f"docker pause {CONTAINER_NAME}")
            player = False
            print("Waiting for players to connect")
        else:
            player = True

        while not player:
            # Use tcpdump to capture incoming traffic on the target port
            capture_command = f"echo {sudo_password} | sudo -S tcpdump -n -c 1 -i any port {TARGET_PORT} 2>/dev/null"
            capture_result = run_command(capture_command)

            # Check if any packets were captured
            if capture_result:
                player = True
                print(f"Connection attempt detected on port {TARGET_PORT}")
                print("Starting server")
                run_command(f"docker unpause {CONTAINER_NAME}")

                for sec in range(30, 0, -1):
                    print(f"Waiting for players to connect... {sec} seconds left")
                    time.sleep(1)
            else:
                time.sleep(1)
    else:
        print("Players found. Server will continue running.")
        time.sleep(60)


if __name__ == "__main__":
    while True:
        main()
1. detect players on the server every minute, and if there are no players, restart and pause the server.
   Restarting the server is for resource optimization, and pausing the server is for quick server restarts.

2. When the server is paused, it detects connections. When a connection is detected, unpause the server.

This works well for me. Feel free to modify it to suit your needs.

Hi, I was able to test the script on my server.
This seems to be a good solution to get around the problem with depressed pals.
This solution is fast enough that there is no connection abort when the server is paused and a player connects.

Thank you.

@dnwjn
Copy link

dnwjn commented Feb 16, 2024

I've played around with different ways to get this to work with a simple bash script. Also got inspired by @fremus89's example. I now have a script running locally on the server where I host the dedicated server for me and my friends. If anyone's interested, I put together a little Docker container that's ready to use in conjunction with this project's Docker container: https://github.com/dnwjn/palworld-server-watcher.

@Serneum
Copy link

Serneum commented Feb 17, 2024

I've played around with different ways to get this to work with a simple bash script. Also got inspired by @fremus89's example. I now have a script running locally on the server where I host the dedicated server for me and my friends. If anyone's interested, I put together a little Docker container that's ready to use in conjunction with this project's Docker container: https://github.com/dnwjn/palworld-server-watcher.

Just wanted to give you a shoutout here as this is exactly what I was looking for. I really didn't want to have to install Python and set up jobs to monitor my server. Having another Docker container that can handle it all is perfect, and it's been working great

@dnwjn
Copy link

dnwjn commented Feb 18, 2024

I've played around with different ways to get this to work with a simple bash script. Also got inspired by @fremus89's example. I now have a script running locally on the server where I host the dedicated server for me and my friends. If anyone's interested, I put together a little Docker container that's ready to use in conjunction with this project's Docker container: https://github.com/dnwjn/palworld-server-watcher.

Just wanted to give you a shoutout here as this is exactly what I was looking for. I really didn't want to have to install Python and set up jobs to monitor my server. Having another Docker container that can handle it all is perfect, and it's been working great

Happy to hear it's useful to someone else as well!

@thijsvanloef
Copy link
Owner

@dnwjn Would you mind if I add some documentation from your repo to my docs website?

@dnwjn
Copy link

dnwjn commented Feb 18, 2024

@dnwjn Would you mind if I add some documentation from your repo to my docs website?

Not at all! 😄

@thijsvanloef thijsvanloef linked a pull request Feb 26, 2024 that will close this issue
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.