1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
# Undercooked - a game about cooking
# Copyright 2024 metamuffin
# Copyright 2024 nokoe
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, version 3 of the License only.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
class_name GameServer
extends Node
var thread = null
var pid = null
var state = State.TESTING
enum State {
TESTING,
UNAVAILABLE,
FAILED,
STOPPED,
STARTING,
RUNNING,
}
var sem = Semaphore.new()
var thread_result = null;
func _ready():
state = State.TESTING
thread = Thread.new()
thread.start(_test_server)
func test():
pass
func start():
if state != State.STOPPED and state != State.FAILED:
push_error("server cant be started")
return
state = State.STARTING
thread = Thread.new()
thread.start(_server_exec)
func stop():
if state != State.RUNNING:
push_error("server cant be stopped")
return
OS.kill(pid)
func _test_server():
var output = []
thread_result = OS.execute(get_server_path(), ["-v"], output, true, false)
sem.post()
func _server_exec():
var args = []
var data_path = get_server_data()
if data_path != null:
args.push_back("--data-dir")
args.push_back(data_path)
thread_result = OS.create_process(get_server_path(), args, false)
print(get_server_path(), args)
if thread_result >= 0:
var ok = false
while not ok:
var conn = StreamPeerTCP.new()
if conn.connect_to_host("127.0.0.1", 27032) == OK:
while conn.poll() == OK:
if conn.get_status() == StreamPeerTCP.STATUS_ERROR: break
elif conn.get_status() == StreamPeerTCP.STATUS_CONNECTED: ok = true; break
OS.delay_msec(10)
OS.delay_msec(500 if not ok else 50)
if !OS.is_process_running(thread_result):
thread_result = -1
break
sem.post()
func get_server_path() -> String:
var path: String = Global.get_setting("server_binary")
if path != "":
return path
else:
return "undercooked-server"
func get_server_data():
var path: String = Global.get_setting("server_data")
if path != "":
return path
else:
return null
func _process(_delta):
match state:
State.TESTING:
if sem.try_wait():
print("Server: Test result=", thread_result)
if thread_result == 0: state = State.STOPPED
else: state = State.UNAVAILABLE
thread.wait_to_finish()
thread = null
State.STARTING:
if sem.try_wait():
if thread_result >= 0:
state = State.RUNNING
pid = thread_result
print("Server: Started pid=", thread_result)
else:
state = State.FAILED
print("Server: Failed")
thread.wait_to_finish()
thread = null
State.RUNNING:
if not OS.is_process_running(pid):
print("Server: Stopped")
state = State.STOPPED
pid = null
func _exit_tree():
if thread != null: thread.wait_to_finish()
if pid != null: OS.kill(pid)
|