Первый commit
This commit is contained in:
parent
feb5c5d724
commit
8706a4fe47
164
Daemon/kf2-server.py
Executable file
164
Daemon/kf2-server.py
Executable file
@ -0,0 +1,164 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import signal
|
||||
import shutil
|
||||
import logging
|
||||
import tempfile
|
||||
import configparser
|
||||
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
### функция перехвата сигнала от системы
|
||||
def receiveSignal(signalNumber, frame):
|
||||
print(f"I'm killed - {os.getpid()}")
|
||||
raise KeyboardInterrupt()
|
||||
|
||||
### функция для преобразования элемента в список
|
||||
def ini_item(value: str=""):
|
||||
tmp=value.split(',')
|
||||
if len(tmp) > 1:
|
||||
return tmp
|
||||
return value
|
||||
|
||||
### функция вычисления номера порта
|
||||
def set_port(value: list, c: int):
|
||||
if len(value) > 1:
|
||||
try:
|
||||
factor=int(value[2])
|
||||
except Exception:
|
||||
factor=1
|
||||
port=int(value[0])+1*factor*c
|
||||
if int(value[1])>int(value[0]) and port<=int(value[1]):
|
||||
return port
|
||||
elif c<int(value[1]):
|
||||
return port
|
||||
else:
|
||||
print(f"I'm killed - {os.getpid()}")
|
||||
logging.error("You have exceeded the server port limit")
|
||||
raise KeyboardInterrupt()
|
||||
return value
|
||||
|
||||
|
||||
### функция запуска сервера
|
||||
def daemon_server(count:int, game:str, dif:int, config:str):
|
||||
try:
|
||||
server_id=f"#{str(count+1)}" # id сервера (используем для именования папки и добавляем к имени сервера)
|
||||
# конфигурационный файл серверов
|
||||
c_cfg = configparser.ConfigParser()
|
||||
c_cfg.optionxform = str # для правельного учета регистра
|
||||
c_cfg.read(config)
|
||||
cfg_settings={}
|
||||
# пробегаем основные параметры
|
||||
for key, value in c_cfg.items("SETTINGS"):
|
||||
cfg_settings[key]=ini_item(value)
|
||||
|
||||
# создаем объект класса logging
|
||||
logging.basicConfig(filename=cfg_settings['log'], encoding='utf-8', level=logging.INFO,format='%(asctime)s.%(msecs)03d %(levelname)s %(message)s', datefmt='%Y-%m-%d %H:%M:%S',)
|
||||
|
||||
# путь к папке с конфигурацией сервера
|
||||
c_dir_ini=os.path.join(cfg_settings['dir_server_data'], f"KFGame/Config/{server_id}")
|
||||
try:
|
||||
# удаляем старый ln
|
||||
shutil.rmtree(c_dir_ini, True)
|
||||
os.remove(c_dir_ini)
|
||||
except FileNotFoundError:
|
||||
None
|
||||
# создаём временную дерриктори под конфиг
|
||||
tmp_dir=tempfile.TemporaryDirectory()
|
||||
# изменяем владельца
|
||||
shutil.chown(tmp_dir.name, cfg_settings['sys_user'], cfg_settings['sys_group'])
|
||||
# создаем ln в папку с сервером
|
||||
os.symlink(tmp_dir.name, c_dir_ini)
|
||||
|
||||
# пробегаем дополнительные параметры конфигурации сервера
|
||||
for key1 in c_cfg.sections():
|
||||
if key1 != "SETTINGS":
|
||||
# путь к файлу inic_dir_ini
|
||||
c_file_ini=f"{c_dir_ini}/{key1}"
|
||||
# если в теге есть параметры то анализируем
|
||||
c_key=c_cfg.items(key1)
|
||||
if len(c_key) > 0:
|
||||
c_ini = configparser.ConfigParser(strict=False)
|
||||
c_ini.optionxform = str # для правельного учета регистра
|
||||
# пробегаем парметры деррективы
|
||||
for key2, value in c_key:
|
||||
# разделяем ключ и значение
|
||||
c_param=ini_item(key2)
|
||||
# изменяем параметр
|
||||
if not c_param[0] in c_ini:
|
||||
c_ini[c_param[0]] = {}
|
||||
# дописываем индекс в название сервера
|
||||
if c_param[1] == 'ServerName' or c_param[1] == 'ClanMotto':
|
||||
value+=f" {server_id}"
|
||||
# обработка мараметра динамической конфигурации
|
||||
if c_param[1] == 'bUsedForTakeover':
|
||||
if int(value) > 0 and count < int(value):
|
||||
value="FALSE"
|
||||
else:
|
||||
value="TRUE"
|
||||
c_ini[c_param[0]][c_param[1]] = value
|
||||
# пишем изменения в файл
|
||||
with open(c_file_ini, "w") as f:
|
||||
c_ini.write(f)
|
||||
c_ini.clear()
|
||||
|
||||
# запускаем бинарник сервера
|
||||
command=f"{cfg_settings['bin_server']} kf-bioticslab?Game={game}?Difficulty={dif} -Port={set_port(cfg_settings['port_game'], count)} -QueryPort={set_port(cfg_settings['port_query'], count)} -WebAdminPort={set_port(cfg_settings['port_webadmin'], count)} -ConfigSubDir={server_id}" # команды запуска
|
||||
while True:
|
||||
with Popen(command, stdout=PIPE, stderr=PIPE, shell=True, user=cfg_settings['sys_user'], group=cfg_settings['sys_group'], ) as process: # запускаем процесс от пользователя steam
|
||||
logging.info(f"Start: {command}")
|
||||
process.communicate() # ждём, пока работает процеес и есть вывод в терминал
|
||||
logging.info(f"Stop: {command}")
|
||||
except KeyboardInterrupt:
|
||||
None
|
||||
except Exception as err:
|
||||
logging.info(f"Unexpected termination: {err}")
|
||||
# при завершение подчищаем за собой
|
||||
tmp_dir.cleanup()
|
||||
try:
|
||||
shutil.rmtree(c_dir_ini, True)
|
||||
os.remove(c_dir_ini)
|
||||
except FileNotFoundError:
|
||||
None
|
||||
# убиваемся
|
||||
logging.info(f"Stop: {command}")
|
||||
os.killpg(os.getpgid(process.pid), signal.SIGINT)
|
||||
|
||||
### главная функция
|
||||
if __name__ == '__main__':
|
||||
sys.stderr = open('/dev/null')
|
||||
# ключи асоциативного массива
|
||||
c_args_name=['script', 'count', 'game', 'dif', 'config']
|
||||
# если 2 аргумента, вызов из run скрипта
|
||||
if len(sys.argv) == 2:
|
||||
c_args_value=sys.argv[1].split()
|
||||
c_args_value.insert(0, sys.argv[0])
|
||||
else:
|
||||
# если 4 аргумента, вызов из shell
|
||||
c_args_value=sys.argv
|
||||
# проверяем кол-во передынных параветров вызова
|
||||
if len(c_args_value) <= 4:
|
||||
print("Incorrect number of arguments")
|
||||
raise KeyError()
|
||||
# получаем ассоциативный массив аргументов
|
||||
c_args=dict(zip(c_args_name, c_args_value))
|
||||
# перехватываем сигналы от системы
|
||||
signal.signal(signal.SIGHUP, receiveSignal)
|
||||
#signal.signal(signal.SIGINT, receiveSignal)
|
||||
signal.signal(signal.SIGQUIT, receiveSignal)
|
||||
signal.signal(signal.SIGILL, receiveSignal)
|
||||
signal.signal(signal.SIGTRAP, receiveSignal)
|
||||
signal.signal(signal.SIGABRT, receiveSignal)
|
||||
signal.signal(signal.SIGBUS, receiveSignal)
|
||||
signal.signal(signal.SIGFPE, receiveSignal)
|
||||
#signal.signal(signal.SIGKILL, receiveSignal)
|
||||
signal.signal(signal.SIGUSR1, receiveSignal)
|
||||
signal.signal(signal.SIGSEGV, receiveSignal)
|
||||
signal.signal(signal.SIGUSR2, receiveSignal)
|
||||
signal.signal(signal.SIGPIPE, receiveSignal)
|
||||
signal.signal(signal.SIGALRM, receiveSignal)
|
||||
signal.signal(signal.SIGTERM, receiveSignal)
|
||||
# запускаем экземпляр сервера
|
||||
daemon_server(int(c_args['count']), c_args['game'], int(c_args['dif']), c_args['config'])
|
180
Daemon/run.py
Executable file
180
Daemon/run.py
Executable file
@ -0,0 +1,180 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import json
|
||||
import psutil
|
||||
import signal
|
||||
import logging
|
||||
import requests
|
||||
import argparse
|
||||
import configparser
|
||||
|
||||
from subprocess import Popen, PIPE
|
||||
from multiprocessing.pool import ThreadPool
|
||||
|
||||
### функция для преобразования элемента в список
|
||||
def ini_item(value: str=""):
|
||||
tmp=value.split(',')
|
||||
if len(tmp) > 1:
|
||||
return tmp
|
||||
return value
|
||||
|
||||
### функция запуска сервера
|
||||
def server_start(param):
|
||||
return Popen(["/usr/bin/python3", param[0], f"{param[1]} {str(param[2])} {param[3]} {str(param[4])} >/dev/null 2>&1"], stdout=PIPE, stderr=PIPE, shell=False).pid
|
||||
|
||||
### функция проверки версии игры
|
||||
def server_version(ver):
|
||||
try:
|
||||
if 'steamcmd_update_check' in cfg_settings and cfg_settings['steamcmd_update_check'] != "":
|
||||
# делаем запрос к api steam
|
||||
result = requests.get(cfg_settings['steamcmd_update_check'] + str(ver))
|
||||
if result.status_code == 200:
|
||||
result=result.json()
|
||||
print(result)
|
||||
# если версия устарела, возвращаем текущую
|
||||
if not result['response']['up_to_date']:
|
||||
return str(result['response']['required_version'])
|
||||
elif 'steamcmd_news_update_check' in cfg_settings and cfg_settings['steamcmd_news_update_check'] != "":
|
||||
# делаем запрос к api steam
|
||||
result = requests.get(cfg_settings['steamcmd_news_update_check'])
|
||||
if result.status_code == 200:
|
||||
result=result.json()['appnews']['newsitems'][0]
|
||||
# проверяем связана ли новость с обновлением
|
||||
title=str(result['title']).lower()
|
||||
contents=str(result['contents']).lower()
|
||||
if title and contents and \
|
||||
('fix' in title or 'fix' in contents or \
|
||||
'version' in title or 'version' in contents or \
|
||||
'changelog' in title or 'changelog' in contents or \
|
||||
'update' in title or 'update' in contents):
|
||||
# если дата новости не равна текущей
|
||||
if str(ver) != str(result['date']):
|
||||
return str(result['date'])
|
||||
except:
|
||||
None
|
||||
# если версия актуальна, или код ответа с ошибкой
|
||||
return True
|
||||
|
||||
### главная функция
|
||||
if __name__ == "__main__":
|
||||
sys.stderr = open('/dev/null')
|
||||
# парсим аргументы
|
||||
parser = argparse.ArgumentParser(add_help=False)
|
||||
parser.add_argument("action", choices=["start", "stop", "restart", "status"])
|
||||
parser.add_argument("config")
|
||||
args = parser.parse_args()
|
||||
|
||||
# конфигурационный файл серверов
|
||||
c_cfg = configparser.ConfigParser()
|
||||
c_cfg.optionxform = str # для правельного учета регистра
|
||||
c_cfg.read(args.config)
|
||||
cfg_settings={}
|
||||
|
||||
# пробегаем основные параметры
|
||||
for key, value in c_cfg.items("SETTINGS"):
|
||||
cfg_settings[key]=ini_item(value)
|
||||
|
||||
# создаем объект класса logging
|
||||
logging.basicConfig(filename=cfg_settings['log'], encoding='utf-8', level=logging.INFO,format='%(asctime)s.%(msecs)03d %(levelname)s %(message)s', datefmt='%Y-%m-%d %H:%M:%S',)
|
||||
|
||||
# пытаемся прочитать текущую версию из файла
|
||||
try:
|
||||
with open(cfg_settings['steamcmd_game_version'], "r") as f:
|
||||
c_version = f.read()
|
||||
except FileNotFoundError:
|
||||
c_version=""
|
||||
|
||||
## функция запуска сервиса
|
||||
def s_start(c_version, cfg_settings, args_config):
|
||||
print("Start ...")
|
||||
count=0
|
||||
c_pid=str(os.getppid())
|
||||
pool = ThreadPool()
|
||||
for game in cfg_settings['modes_game']:
|
||||
for dif in cfg_settings['difficulty_game']:
|
||||
time.sleep(0.5)
|
||||
c=pool.map(server_start, ([os.path.join(cfg_settings['dir_work'],"Daemon") + "/kf2-server.py", count, game, dif, args_config] ,))
|
||||
c_pid+=f" {c[0]}"
|
||||
count+=1
|
||||
if game in ['KFGameContent.KFGameInfo_WeeklySurvival', 'KFGameContent.KFGameInfo_VersusSurvival']:
|
||||
break
|
||||
pool.close()
|
||||
pool.join()
|
||||
# пишем в файл pid процессов
|
||||
with open(cfg_settings['pid_kf2'], "w") as f:
|
||||
f.write(str(c_pid))
|
||||
while True:
|
||||
# проверяем наличие обновлений в цикле
|
||||
version=server_version(c_version)
|
||||
if version != True:
|
||||
# если прилетели обновления, обновляем
|
||||
command=f"echo {cfg_settings['sys_user']} | su --pty - {cfg_settings['sys_user']} -c \"steamcmd +force_install_dir {cfg_settings['dir_server_data']} {cfg_settings['steamcmd_update_key']}\""
|
||||
with Popen(command, stdout=PIPE, stderr=PIPE, shell=True, user=cfg_settings['sys_user'], group=cfg_settings['sys_group'], ) as process: # запускаем процесс от пользователя steam
|
||||
print("Update ...")
|
||||
logging.info(f"Update: New version - {version}, old - {c_version}")
|
||||
c_version=str(version)
|
||||
process.communicate()
|
||||
# после обновления пишим новую версию в файл
|
||||
with open(cfg_settings['steamcmd_game_version'], "w") as f:
|
||||
f.write(str(version))
|
||||
# после обновления перезапускаемся
|
||||
s_stop(1)
|
||||
return s_start(c_version, cfg_settings, args_config)
|
||||
time.sleep(3600) # проверяем обновление каждый час
|
||||
|
||||
## функция остановки сервиса
|
||||
def s_stop(split: int=0):
|
||||
global c_version,cfg_settings
|
||||
print("Stop ...")
|
||||
with open(cfg_settings['pid_kf2'], "r") as f:
|
||||
c_pid = f.read()
|
||||
c_pid=c_pid.split()
|
||||
for i in range(len(c_pid)-split):
|
||||
try:
|
||||
os.killpg(os.getpgid(int(c_pid[(i+split)])), signal.SIGINT)
|
||||
time.sleep(0.5)
|
||||
except:
|
||||
None
|
||||
|
||||
# если старт
|
||||
if args.action == "start":
|
||||
try:
|
||||
# проверка на запущенность сервиса, проверяем первый pid
|
||||
with open(cfg_settings['pid_kf2'], "r") as f:
|
||||
c_pid = f.read()
|
||||
c_pid=c_pid.split()
|
||||
if str(os.getppid()) != c_pid[0]:
|
||||
try:
|
||||
# если запущен, выходим
|
||||
os.getpgid(int(c_pid[0]))
|
||||
raise KeyboardInterrupt()
|
||||
except OSError:
|
||||
# если не запущен, запускаем
|
||||
s_start(c_version, cfg_settings, args.config)
|
||||
# если запускаем из терминала
|
||||
s_start(c_version, cfg_settings, args.config)
|
||||
except Exception:
|
||||
# если файл pid не существует, запускаем
|
||||
s_start(c_version, cfg_settings, args.config)
|
||||
# если стоп
|
||||
elif args.action == "stop":
|
||||
s_stop()
|
||||
# если перезапуск
|
||||
elif args.action == "restart":
|
||||
s_stop()
|
||||
time.sleep(1)
|
||||
s_start()
|
||||
# если информация о работе
|
||||
elif args.action == "status":
|
||||
bin_name=os.path.basename(cfg_settings['bin_server'])
|
||||
# проверяем все системные процессы и показываем наши сервера
|
||||
for pid in psutil.pids():
|
||||
p = psutil.Process(pid)
|
||||
if p.name() == bin_name:
|
||||
print(f"[{pid}] {' '.join(p.cmdline())}")
|
||||
# значение по умолчанию
|
||||
else:
|
||||
parser.print_help()
|
86
config.ini
Normal file
86
config.ini
Normal file
@ -0,0 +1,86 @@
|
||||
; глобальные параметры
|
||||
[SETTINGS]
|
||||
; имя пользователя от которого запущен сервер
|
||||
sys_user=steam
|
||||
; группа пользователя от которой запущен сервер
|
||||
sys_group=steam
|
||||
; pid файл сервиса
|
||||
pid_kf2=/var/run/kf2.pid
|
||||
; рабочая папка со всеми файлами сервера
|
||||
dir_work=/opt/KillingFloor2
|
||||
; путь установки сервера игры
|
||||
dir_server_data=/opt/KillingFloor2/Data
|
||||
; bin файл сервера
|
||||
bin_server=/opt/KillingFloor2/Data/Binaries/Win64/KFGameSteamServer.bin.x86_64
|
||||
; файл версии игры, нужно для проверки обновлений по API
|
||||
steamcmd_game_version=/tmp/kf2_version.txt
|
||||
; дополнительные параметры для выгрузки обновлений, путь берем из предыдущего параметра
|
||||
steamcmd_update_key=+login anonymous +app_update 232130 validate +exit
|
||||
; ссылка Api Steam, для проверки обновлений. Json формат ответа, приоритет steamcmd_update_check
|
||||
;steamcmd_update_check=http://api.steampowered.com/ISteamApps/UpToDateCheck/v1?appid=232130&version=
|
||||
steamcmd_news_update_check=http://api.steampowered.com/ISteamNews/GetNewsForApp/v0002/?appid=232090&count=1&maxlength=0&format=json
|
||||
; порты сервера, вторым параметром можно указать кол-во итераций
|
||||
port_game=7780,30,2
|
||||
; порты для Query, вторым параметром можно указать кол-во итераций
|
||||
port_query=27100,30
|
||||
; порты для Web Admin(ки), вторым параметром можно указать кол-во итераций
|
||||
port_webadmin=9100,30
|
||||
; сложность игры: 0 = Нормально, 1 = Тяжело, 2 = Суицидально, 3 = Ад на Земле
|
||||
difficulty_game=1,2,3
|
||||
; режимы игры:
|
||||
; KFGameContent.KFGameInfo_Endless - Бесконечный
|
||||
; KFGameContent.KFGameInfo_Objective - Цель
|
||||
; KFGameContent.KFGameInfo_Survival - Выживание
|
||||
; KFGameContent.KFGameInfo_VersusSurvival - Выживания на 2 команды
|
||||
; KFGameContent.KFGameInfo_WeeklySurvival - Еженедельные задания
|
||||
modes_game=KFGameContent.KFGameInfo_Endless,KFGameContent.KFGameInfo_Objective,KFGameContent.KFGameInfo_Survival,KFGameContent.KFGameInfo_WeeklySurvival,KFGameContent.KFGameInfo_VersusSurvival,KFGameContent.KFGameInfo_Endless,KFGameContent.KFGameInfo_Objective,KFGameContent.KFGameInfo_Survival,KFGameContent.KFGameInfo_WeeklySurvival,KFGameContent.KFGameInfo_VersusSurvival
|
||||
; файл лога
|
||||
log=/opt/KillingFloor2/Log/killingfloor2.log
|
||||
; временная tpmfs деррриктория
|
||||
tmp=/opt/KillingFloor2/Tmp
|
||||
|
||||
; custom параметры в файле KFAI.ini
|
||||
[KFAI.ini]
|
||||
|
||||
; custom параметры в файле KFWeb.ini
|
||||
[KFWeb.ini]
|
||||
; включить веб админку
|
||||
IpDrv.WebServer,bEnabled=true
|
||||
|
||||
; custom параметры в файле KFWebAdmin.ini
|
||||
[KFWebAdmin.ini]
|
||||
|
||||
; custom параметры в файле LinuxServer-KFEngine.ini
|
||||
[LinuxServer-KFEngine.ini]
|
||||
|
||||
; custom параметры в файле LinuxServer-KFGame.ini
|
||||
[LinuxServer-KFGame.ini]
|
||||
; имя сервера
|
||||
Engine.GameReplicationInfo,ServerName=KillingFloor2
|
||||
; пароль администратора
|
||||
Engine.AccessControl,AdminPassword=1q2w3e4r5t
|
||||
; время голосования за карту
|
||||
Engine.GameInfo,VoteTime=5.0
|
||||
; кол-во волн
|
||||
; 0 - Short (4 волны)
|
||||
; 1 - Normal (7 волн)
|
||||
; 2 - Long (10 волн)
|
||||
; 3 - Custom
|
||||
KFGame.KFGameInfo,GameLength=2
|
||||
; банер
|
||||
KFGame.KFGameInfo,BannerLink=http://art.tripwirecdn.com/TestItemIcons/MOTDServer.png
|
||||
; преведствие
|
||||
KFGame.KFGameInfo,ServerMOTD=\n Welcome to our server:\n KillingFloor2\n
|
||||
KFGame.KFGameInfo,ClanMotto=KillingFloor2
|
||||
; сайт
|
||||
KFGame.KFGameInfo,WebsiteLink=https://killingfloor2.com/
|
||||
; указываем кол-во серверов с фиксированной конфигурацией,
|
||||
; остальные с открытой конфигурацией
|
||||
; если не хотим фиксировать, убираем параметр или ставим в 0
|
||||
Engine.GameEngine,bUsedForTakeover=11
|
||||
|
||||
; custom параметры в файле LinuxServer-KFInput.ini
|
||||
[LinuxServer-KFInput.ini]
|
||||
|
||||
; custom параметры в файле LinuxServer-KFSystemSettings.ini
|
||||
[LinuxServer-KFSystemSettings.ini]
|
20
kf2.service
Normal file
20
kf2.service
Normal file
@ -0,0 +1,20 @@
|
||||
[Unit]
|
||||
Description=KF2 game service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/opt/KillingFloor2
|
||||
RestartSec=60
|
||||
KillSignal=SIGINT
|
||||
ExecStart=/usr/bin/sh -c '/opt/KillingFloor2/Daemon/run.py start "/opt/KillingFloor2/config.ini"'
|
||||
ExecStop=/usr/bin/sh -c '/opt/KillingFloor2/Daemon/run.py stop "/opt/KillingFloor2/config.ini"'
|
||||
#ExecRestart=/opt/KillingFloor2/Daemon/run.py restart $CFG
|
||||
#ExecStatus=/opt/KillingFloor2/Daemon/run.py status $CFG
|
||||
Restart=always
|
||||
User=root
|
||||
Group=root
|
||||
TimeoutStartSec=15s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
32
steamcmd
Executable file
32
steamcmd
Executable file
@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
# Copyright (C) 2015 Alexandre Detiste <alexandre@detiste.be>
|
||||
# License: MIT
|
||||
|
||||
# check for old install < 0~20180105-4
|
||||
if [ -e ~/.steam/steamcmd ]
|
||||
then
|
||||
exec ~/.steam/steamcmd/steamcmd.sh $@
|
||||
fi
|
||||
|
||||
# create a fake Steam installation to avoid
|
||||
# that steamcmd uses "/home/$user/Steam" instead
|
||||
|
||||
STEAMROOT="${XDG_DATA_HOME:-"$HOME/.local/share"}/Steam"
|
||||
if [ ! -e ~/.steam ]
|
||||
then
|
||||
mkdir -p "$STEAMROOT/.steam/appcache/"
|
||||
mkdir -p "$STEAMROOT/.steam/config/"
|
||||
mkdir -p "$STEAMROOT/.steam/logs/"
|
||||
mkdir -p "$STEAMROOT/.steam/SteamApps/common/"
|
||||
ln -s "$STEAMROOT" ~/.steam/root
|
||||
ln -s "$STEAMROOT" ~/.steam/steam
|
||||
fi
|
||||
|
||||
if [ ! -e "$STEAMROOT/steamcmd" ]
|
||||
then
|
||||
mkdir -p "$STEAMROOT/steamcmd/linux32"
|
||||
# steamcmd will replace these files with newer ones itself on first run
|
||||
cp /usr/lib/games/steam/steamcmd.sh "$STEAMROOT/steamcmd/"
|
||||
cp /usr/lib/games/steam/steamcmd "$STEAMROOT/steamcmd/linux32/"
|
||||
fi
|
||||
exec "$STEAMROOT/steamcmd/steamcmd.sh" $@
|
Loading…
x
Reference in New Issue
Block a user