#!/home/autismbot1/ze_runner/venv/bin/python3 import os import sys import subprocess import atexit from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler import random import signal import socket import codecs import json import datetime import time import glob restart_time = datetime.datetime.now() + datetime.timedelta(hours=5) whoami = subprocess.getoutput(["whoami"]) with open(f'/home/{whoami}/ze_runner/config.json') as jsonfile: data_ports = json.load(jsonfile) looptestPath = f"/home/{whoami}/.steam/debian-installation/steamapps/common/Counter-Strike Source/cstrike/cfg/looptest.cfg" chatmsg = "" def overwrite_file_access(): #setting defaults with setfacl for the download directory does not work seemingly subprocess.Popen(["chmod", "-R", "g+rwx", f"/home/{whoami}/.steam/debian-installation/steamapps/common/Counter-Strike Source/cstrike/download"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).communicate() def writeCfgInput(Input_user): with open(looptestPath, 'w') as f: f.write(Input_user) #print("wrote to file: ", Input_user) if "connect " in Input_user: time.sleep(1.0) open(looptestPath, 'w').close() #clearing file. elif "wait" in Input_user: time.sleep(0.35) else: time.sleep(0.5) open(looptestPath, 'w').close() #clearing file. def close_observer(observer): observer.stop() observer.join() #supposedly needed to clear resources again. def clean_up_files(): #deleting POSIX shared memory objects, as long as one process has them open they exist. THis is to prevent /dev/shm from being full #due to steam child processes. #even with steam turned offline might there be chromium web browsers left over from steam who still hold processes open. #only kind of potential issues from this is steam cloud being out of sync, which is really fucking irrelevant. subprocess.Popen(["rm -rf /tmp/steam*"], shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).communicate()[0] subprocess.Popen(["rm -rf /tmp/dbus*"], shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).communicate()[0] subprocess.Popen(["rm -rf /tmp/pressure*"], shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).communicate()[0] subprocess.Popen(["rm -rf /tmp/tigervnc*"], shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).communicate()[0] subprocess.Popen(["rm -rf /tmp/dumps*"], shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).communicate()[0] subprocess.Popen(["rm -rf /dev/shm/u100*"], shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).communicate()[0] #users should only have permissions to delete their own files probably #check if any bz2 files left over. for f in glob.glob(f"/home/{whoami}/.steam/steam/steamapps/common/Counter-Strike Source/cstrike/download/**/*.bz2", recursive=True): file_size = None while True: time.sleep(10) stdout, stderr = subprocess.Popen(["ls", "-l", f], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() if stderr: break #finished downloading, bz2 file is removed. if stdout: cur_file_size = stdout.decode().split("autismbots")[1].strip().split(" ")[0] if file_size == cur_file_size: #delete the bz2 file if its not progressing downloading subprocess.Popen(["rm", f], stdout=subprocess.DEVNULL).communicate()[0] break file_size = cur_file_size def exit_handler(): print('reached exithandler') writeCfgInput('') #securing the looptest.cfg wont be stuck accidently with commands kill_owned_process("pidof cstrike_linux64") kill_owned_process("pidof xterm") clean_up_files() subprocess.getoutput([f"pkill -9 -u {whoami}"]) def bot_process_movement(input_line): dist_target = input_line[input_line.index("dist_target:") + len("dist_target:"):input_line.index("enemy_distance")] enemy_distance = input_line[input_line.index("enemy_distance:") + len("enemy_distance:"):input_line.index("targeteam:")] targeteam = input_line[input_line.index("targeteam:") + len("targeteam:"):input_line.index("state:")] state = input_line[input_line.index("state:") + len("state:"):] state = int(state.strip()) dist_target = float(dist_target) enemy_distance = float(enemy_distance) targeteam = int(targeteam) #request by bane that bots should simply not infect people shrug strInput = "-attack; wait 2; -use; wait 5; -attack; wait 5; cl_minmodels 1; wait 2; +use; wait 5; " if targeteam == 3: strInput = "-attack; wait 2; -use; wait 5; -attack; wait 5; cl_minmodels 1; wait 2; +use; wait 5; " #python has no switches and such if state in [5, 7]: strInput += "-forward; wait 2; use weapon_knife; wait 5;" elif state >= 3: strInput += "use weapon_knife; wait 5; +forward; wait 2;" elif state == 0: strInput += "use weapon_p90; wait 2; -forward; wait 2;" elif state == 1: strInput += "wait 2; use weapon_elite; wait 3; +forward; wait 2;" elif state == 2: strInput += "-forward; wait 2; use weapon_elite; wait 3;" elif state == 8: strInput += "use weapon_knife; wait 5; +forward; wait 2;" #print('dist_target: ', dist_target, ' enemy distance: ', enemy_distance, ' targeteam: ', targeteam, ' state:', state) if state not in [0, 2, 5, 7, 8]: strInput = strinput_append(strInput, 2) #print('strInput final:', strInput) writeCfgInput(strInput) def strinput_append(strInput, nth): for _ in range(3 * nth): boolean_val = random.choice([True, False]) if boolean_val: strInput += " +moveleft; wait 15; -moveleft; " else: strInput += " +moveright; wait 15; -moveright; " return strInput def kill_user_owned_pid(pid): #print('pid: ', pid, ' killed') pid = int(pid.strip()) os.kill(pid, signal.SIGKILL) time.sleep(10) def return_user_owned_pid(pidof): owner_pid = subprocess.getoutput([f"{pidof}"]) if owner_pid: for pid in owner_pid.split(" "): username = subprocess.getoutput([f"""ps -o user= -p {pid}"""]) if username == whoami: return pid return None def kill_owned_process(pidof): pid = return_user_owned_pid(pidof) while pid: kill_user_owned_pid(pid) pid = return_user_owned_pid(pidof) def restart_sdl_and_steam(): #subprocess.getoutput(["screen -XS XTERM quit"]) kill_owned_process("pidof cstrike_linux64") kill_owned_process("pidof xterm") subprocess.getoutput([f'vncserver -kill']) #only displays vncservers for the specific user. time.sleep(5) cmd = f'vncserver -localhost no -geometry 1x1 -depth 24' #cmd = f'vncserver -localhost no -geometry 800x800 -depth 24' #print(f'cmd: {cmd}') subprocess.getoutput([cmd]) print('reached .bashrc executing steam and variables') def bot_connect(data): #use whatever ip you want here to connect with str1 = "" if "connect to ze" == data: str1 = f"connect {data_ports['server_ip_port_ze']};" elif "connect to ze2" == data: str1 = f"connect {data_ports['server_ip_port_ze2']};" #wait 15000; writeCfgInput(str1) def cpulimit_pid_of_game(): # ' > /dev/null' redirects stdout to /dev/null # '2>&1' redirects stderr to the same place as stdout pid = return_user_owned_pid("pidof cstrike_linux64") cmd = f"cpulimit --pid={pid} --limit=35 --background > /dev/null 2>&1" subprocess.Popen([cmd], shell=True, stdout=subprocess.PIPE).communicate()[0] def delete_lock_file(): #just delete the tmp source_engine .lock file here so multiple instances can run at same time. subprocess.Popen(["rm -f /tmp/source_engine*.lock"], shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).communicate()[0] def my_file_created_function(event_path): #print(f"New file created: {event_path}") if not event_path.lower().endswith(".bsp.bz2"): return file_size = None while True: time.sleep(10) stdout, stderr = subprocess.Popen(["ls", "-l", event_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() #print('stdout: ', stdout) #print('stderr: ', stderr) if stderr: print('finished downloading the bz2 file.') break user = stdout.decode().split("autismbots")[0] if whoami not in user: writeCfgInput("disconnect;") print("disconnected from server until other user finished downloading bz2 file") continue #in case the bz2 download is not progressing just delete the file and disconnect. cur_file_size = stdout.decode().split("autismbots")[1].strip().split(" ")[0] print('cur_file_size: ', cur_file_size, ' stdout decode: ', stdout.decode()) if file_size == cur_file_size: print("Aborting connection. file download is stuck.") writeCfgInput("disconnect;") subprocess.Popen(["rm", event_path], stdout=subprocess.DEVNULL).communicate()[0] break file_size = cur_file_size class NewFileHandler(FileSystemEventHandler): def on_created(self, event): my_file_created_function(event.src_path) def handle_bz2_files(): #mostly its just downloading maps that we will be doing root_dir = f"/home/{whoami}/.steam/debian-installation/steamapps/common/Counter-Strike Source/cstrike/download" event_handler = NewFileHandler() observer = Observer() # Schedule the observer to watch the root directory and its subdirectories recursively observer.schedule(event_handler, root_dir, recursive=True) observer.start() return observer if __name__ == '__main__': atexit.register(exit_handler) local_port = data_ports['udp_port'] external_port_messages = data_ports['chat_external_port'] buffer_size = 4096 #potentially not large enough? clean_up_files() delete_lock_file() observer = handle_bz2_files() maps_folder_size = subprocess.Popen(["du", "-sh", f"/home/{whoami}/.steam/debian-installation/steamapps/common/Counter-Strike Source/cstrike/download/maps"], stdout=subprocess.PIPE).communicate()[0].decode().split("\t")[0] #deleting when maps folder larger than some GB if maps_folder_size.endswith("G"): maps_folder_size = float(maps_folder_size[:-1]) if maps_folder_size > 40.0: for f in glob.glob(f"/home/{whoami}/.steam/debian-installation/steamapps/common/Counter-Strike Source/cstrike/download/maps/*"): subprocess.Popen(["rm", f], stdout=subprocess.PIPE).communicate()[0] restart_sdl_and_steam() is_bot_connected_to_ze2 = False print('preparing to launch game....') sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind(("", local_port)) sock.settimeout(5.0) messager_name = "" #give the game some time to launch fail_safe = 5 while return_user_owned_pid("pidof cstrike_linux64") is None: #just a fail safe to prevent being stuck forever. if fail_safe <= 0: sys.exit(1) time.sleep(10) print("launching game...") fail_safe -= 1 time.sleep(10) cpulimit_pid_of_game() try: while True: try: #print("socket waiting for recvfrom") data, addr = sock.recvfrom(buffer_size) except socket.timeout: continue data = codecs.decode(data, "utf-8", "ignore") ip = addr[0] port = addr[1] #print('port: ', port, " ip: ", ip) #print('data: ', data) if not data: continue delete_lock_file() #print("ip: ", ip, " port: ", port) if ip == data_ports['discord_bot_ip'] and port == external_port_messages: if messager_name in data: messager_name = "" response_msg = f"""say {messager_name} {data}""" print("remote UDP packet response_msg: ", response_msg) writeCfgInput(response_msg) if ip != data_ports['ovh_ip']: continue elif data == "rtv": response_msg = "say rtv" writeCfgInput(response_msg) elif data == "bot kicked server full": print('bot kicked server full: ', datetime.datetime.now().time()) elif "autismo connected to ze" == data: print('Bot connected to ze!') #cpulimit_pid_of_game() is_bot_connected_to_ze2 = False overwrite_file_access() elif "not connected to ze2" == data: is_bot_connected_to_ze2 = False elif "autismo connected to ze2" == data: print('Bot connected to ze2!') #cpulimit_pid_of_game() is_bot_connected_to_ze2 = True overwrite_file_access() elif "connect to ze" == data or ("connect to ze2" == data and not is_bot_connected_to_ze2): if datetime.datetime.now() >= restart_time: kill_owned_process("pidof cstrike_linux64") sock.close() close_observer(observer) print('exiting after running the game for several hours.') sys.exit(1) else: print('data: ', data) bot_connect(data) elif "clientmessage:" in data: messager_name = data.split("clientmessage:", 1)[1].split(f" {data_ports['magic_secret']}")[0] databyte_send_message = messager_name + data.split(f"{data_ports['magic_secret']}")[1] sock.sendto(databyte_send_message.encode(), (data_ports["discord_bot_ip"], external_port_messages)) #print('databyte_send_message: ', databyte_send_message) elif data.startswith("dist_target:"): bot_process_movement(data) elif data.startswith("surfing:"): bot_process_surf(data) elif data.startswith("hull info:"): hull_info = data[data.index("hull info:") + len("hull info:"):] strInput = "" if hull_info == "jump": strInput += "+jump; wait 5; -jump; +duck; wait 50; -duck; wait 5; " elif hull_info == "crouch": strInput += "+duck; wait 50; -duck; wait 5; " writeCfgInput(strInput) finally: sock.close() close_observer(observer)