Skip to content

Commit 0777e41

Browse files
committed
tools: support concurrent editor and runtime instances
1 parent 78990ee commit 0777e41

2 files changed

Lines changed: 139 additions & 11 deletions

File tree

tools/level_editor/level_editor.vala

Lines changed: 120 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,68 @@ public const string PANEL_EDITOR = "panel-editor";
2323
public const string PANEL_PROJECTS_LIST = "panel-projects-list";
2424
public const string PANEL_NEW_PROJECT = "panel-new-project";
2525

26+
public bool parse_port_from_string(out uint16 port, string str)
27+
{
28+
port = 0;
29+
30+
string trimmed = str.strip();
31+
if (trimmed == "")
32+
return false;
33+
34+
for (int i = 0; i < trimmed.length; ++i) {
35+
if (trimmed[i] < '0' || trimmed[i] > '9')
36+
return false;
37+
}
38+
39+
int parsed = int.parse(trimmed);
40+
if (parsed < 1 || parsed > 65535)
41+
return false;
42+
43+
port = (uint16)parsed;
44+
return true;
45+
}
46+
47+
public bool wait_port_file(out uint16 port, string file_path, int num_tries, int interval)
48+
{
49+
port = 0;
50+
for (int tries = 0; tries < num_tries; ++tries) {
51+
try {
52+
string contents = null;
53+
GLib.FileUtils.get_contents(file_path, out contents);
54+
if (parse_port_from_string(out port, contents))
55+
return true;
56+
} catch (FileError e) {
57+
}
58+
59+
GLib.Thread.usleep(interval*1000);
60+
}
61+
62+
return false;
63+
}
64+
65+
public bool create_port_file_path(out string file_path, string prefix)
66+
{
67+
file_path = "";
68+
69+
try {
70+
string dir_path = GLib.DirUtils.make_tmp("crown_%s_port_XXXXXX".printf(prefix));
71+
file_path = GLib.Path.build_filename(dir_path, "console_port");
72+
return true;
73+
} catch (FileError e) {
74+
loge("Could not create temporary directory for `%s`: %s".printf(prefix, e.message));
75+
return false;
76+
}
77+
}
78+
79+
public void cleanup_port_file_path(string file_path)
80+
{
81+
try {
82+
GLib.File.new_for_path(file_path).delete();
83+
} catch (Error e) {
84+
// Ignore.
85+
}
86+
}
87+
2688
public bool widget_activate_action_variant(Gtk.Widget widget, string name, GLib.Variant? args = null)
2789
{
2890
#if CROWN_GTK3
@@ -760,7 +822,7 @@ public class LevelEditorApplication : Gtk.Application
760822
public LevelEditorApplication()
761823
{
762824
Object(application_id: "org.crownengine.Crown"
763-
, flags: GLib.ApplicationFlags.FLAGS_NONE
825+
, flags: GLib.ApplicationFlags.NON_UNIQUE
764826
);
765827

766828
GLib.Environment.set_prgname(this.application_id); // FIXME: Drop after GTK4 port.
@@ -1571,6 +1633,10 @@ public class LevelEditorApplication : Gtk.Application
15711633
{
15721634
yield stop_backend();
15731635

1636+
string port_file;
1637+
if (!create_port_file_path(out port_file, "data_compiler"))
1638+
return false;
1639+
15741640
// Spawn the data compiler.
15751641
string args[] =
15761642
{
@@ -1582,6 +1648,8 @@ public class LevelEditorApplication : Gtk.Application
15821648
"--map-source-dir",
15831649
"core",
15841650
_project.toolchain_dir(),
1651+
"--port-file",
1652+
port_file,
15851653
"--server",
15861654
"--wait-console"
15871655
};
@@ -1596,8 +1664,20 @@ public class LevelEditorApplication : Gtk.Application
15961664
_editor_stack.set_visible_child_name(COMPILER_CONNECTING);
15971665
_inspector_stack.set_visible_child_name(COMPILER_CONNECTING);
15981666

1667+
uint16 data_compiler_port = 0;
1668+
bool has_port = wait_port_file(out data_compiler_port
1669+
, port_file
1670+
, DATA_COMPILER_CONNECTION_TRIES
1671+
, DATA_COMPILER_CONNECTION_INTERVAL
1672+
);
1673+
cleanup_port_file_path(port_file);
1674+
if (!has_port) {
1675+
loge("Cannot read data_compiler port");
1676+
return false;
1677+
}
1678+
15991679
int tries = yield _compiler.connect_async(DATA_COMPILER_ADDRESS
1600-
, DATA_COMPILER_TCP_PORT
1680+
, data_compiler_port
16011681
, DATA_COMPILER_CONNECTION_TRIES
16021682
, DATA_COMPILER_CONNECTION_INTERVAL
16031683
);
@@ -1689,14 +1769,18 @@ public class LevelEditorApplication : Gtk.Application
16891769
return;
16901770
}
16911771

1772+
string port_file;
1773+
if (!create_port_file_path(out port_file, "game"))
1774+
return;
1775+
16921776
// Spawn the game.
16931777
string args[] =
16941778
{
16951779
ENGINE_EXE,
16961780
"--data-dir",
16971781
_project.data_dir(),
1698-
"--console-port",
1699-
GAME_TCP_PORT.to_string(),
1782+
"--port-file",
1783+
port_file,
17001784
"--wait-console",
17011785
"--lua-string",
17021786
sg == StartGame.TEST ? "TEST=true" : ""
@@ -1708,9 +1792,21 @@ public class LevelEditorApplication : Gtk.Application
17081792
loge(e.message);
17091793
}
17101794

1795+
uint16 game_port = 0;
1796+
bool has_port = wait_port_file(out game_port
1797+
, port_file
1798+
, GAME_CONNECTION_TRIES
1799+
, GAME_CONNECTION_INTERVAL
1800+
);
1801+
cleanup_port_file_path(port_file);
1802+
if (!has_port) {
1803+
loge("Cannot read game port");
1804+
return;
1805+
}
1806+
17111807
// Try to connect to the game.
17121808
int tries = yield _game.connect_async(GAME_ADDRESS
1713-
, GAME_TCP_PORT
1809+
, game_port
17141810
, GAME_CONNECTION_TRIES
17151811
, GAME_CONNECTION_INTERVAL
17161812
);
@@ -1722,15 +1818,19 @@ public class LevelEditorApplication : Gtk.Application
17221818

17231819
public async void start_thumbnail()
17241820
{
1821+
string port_file;
1822+
if (!create_port_file_path(out port_file, "thumbnail"))
1823+
return;
1824+
17251825
string args[] =
17261826
{
17271827
ENGINE_EXE,
17281828
"--data-dir",
17291829
_project.data_dir(),
17301830
"--boot-dir",
17311831
THUMBNAIL_BOOT_DIR,
1732-
"--console-port",
1733-
THUMBNAIL_TCP_PORT.to_string(),
1832+
"--port-file",
1833+
port_file,
17341834
"--wait-console",
17351835
"--pumped",
17361836
"--hidden"
@@ -1742,9 +1842,21 @@ public class LevelEditorApplication : Gtk.Application
17421842
loge(e.message);
17431843
}
17441844

1845+
uint16 thumbnail_port = 0;
1846+
bool has_port = wait_port_file(out thumbnail_port
1847+
, port_file
1848+
, THUMBNAIL_CONNECTION_TRIES
1849+
, THUMBNAIL_CONNECTION_INTERVAL
1850+
);
1851+
cleanup_port_file_path(port_file);
1852+
if (!has_port) {
1853+
loge("Cannot read thumbnail port");
1854+
return;
1855+
}
1856+
17451857
// Try to connect to the game.
17461858
int tries = yield _thumbnail.connect_async(THUMBNAIL_ADDRESS
1747-
, THUMBNAIL_TCP_PORT
1859+
, thumbnail_port
17481860
, THUMBNAIL_CONNECTION_TRIES
17491861
, THUMBNAIL_CONNECTION_INTERVAL
17501862
);

tools/widgets/editor_viewport.vala

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ public class EditorViewport : Gtk.Bin
8585
return;
8686

8787
// Spawn the level editor.
88+
string port_file;
89+
if (!create_port_file_path(out port_file, _runtime._name))
90+
return;
91+
8892
string args[] =
8993
{
9094
ENGINE_EXE,
@@ -94,8 +98,8 @@ public class EditorViewport : Gtk.Bin
9498
_boot_dir,
9599
"--parent-window",
96100
window_xid.to_string(),
97-
"--console-port",
98-
_console_port.to_string(),
101+
"--port-file",
102+
port_file,
99103
"--wait-console",
100104
_render_mode == ViewportRenderMode.PUMPED ? "--pumped" : "",
101105
"--window-rect", "0", "0", width.to_string(), height.to_string(),
@@ -107,9 +111,21 @@ public class EditorViewport : Gtk.Bin
107111
loge(e.message);
108112
}
109113

114+
uint16 console_port = 0;
115+
bool has_port = wait_port_file(out console_port
116+
, port_file
117+
, EDITOR_CONNECTION_TRIES
118+
, EDITOR_CONNECTION_INTERVAL
119+
);
120+
cleanup_port_file_path(port_file);
121+
if (!has_port) {
122+
loge("Cannot read console port for %s".printf(_runtime._name));
123+
return;
124+
}
125+
110126
// Try to connect to the level editor.
111127
int tries = yield _runtime.connect_async(_console_address
112-
, _console_port
128+
, console_port
113129
, EDITOR_CONNECTION_TRIES
114130
, EDITOR_CONNECTION_INTERVAL
115131
);

0 commit comments

Comments
 (0)