Jump to content
The Dark Mod Forums
Sign in to follow this  
stgatilov

Connection to TDM with automation

Recommended Posts

I have an idea of adding TDM connection management to DarkRadiant.
The plan is to combine it with TDM hot reload features later.
Here is a brief list of features:

  • start/connect to TDM, stop TDM
  • dmap/start current map
  • camera DR to TDM synchronization
  • showing selected entities/brushes in TDM
  • update entities in TDM immediately after they get changed in DR ("hot reload")

 

The idea is to use new automation framework to send commands from DR to TDM.
It already supports running console commands, moving player, clicking GUI elements.

The core of automation framework is socket-based network protocol. TDM engine listens on a socket, receives some commands and sends back responses.
There are also Python scripts which can send automation requests to TDM and provide some high-level API.
The Python code is currently located in TDM assets repo in devel/auto.

 

For what I see, any feature in DR can be implemented in three places:

  • core (C++, all games)
  • plugin (C++, TDM-specific)
  • scripts (Python embedded)

Initially I thought I would try to use automation as Python scripts, but there some problems with this approach.
The DR scripting API is not suitable for running persistent Python tasks.
Mainly, there are no events, and no way for Python script to live long and react to events.

Since automation is only implemented in new versions of TDM, it should not go into core.
So I imagine the best idea would be to create a new TDM-only plugin.

 

Even if automation will be in C++ plugin, it would be helpful to use automation Python scripts.
I have seen at least two problems with it:

  1. Embedded Python is 3.6, while my code has strict type annotations, and use some feature of 3.7. Don't remember which, but the line from __future__ import annotations does not work in 3.6.
  2. Embedded Python has socket.pyc, but does not have _socket.pyd, making it unable to interact with sockets.

On the other hand, I can copy/paste automation message framing from TDM code, then somehow hack process creation/destruction in C++, and live without Python.

 

I wonder if there are any issues or limitations with plugins.
Can they listen to events or execute some code regularly? Do they have access to underlying data? Can they have their own GUI elements, like windows, buttons, menus, etc?

  • Like 2

Share this post


Link to post
Share on other sites
On 7/25/2020 at 7:53 AM, stgatilov said:
  • dmap/start current map

For dmap specifically, I wonder if this would be a good candidate to move out of the game altogether, and into DR, either by splitting out the code into a command-line tool that DR can run, or as a library that DR can call into? Map compilation seems like something that might be better off in the editor (for improved user feedback etc) rather than in the game itself.

The other suggestions (like hot reload) are clearly things which need the IPC-based automation mechanism.

Quote

Initially I thought I would try to use automation as Python scripts, but there some problems with this approach.

The DR scripting API is not suitable for running persistent Python tasks.
Mainly, there are no events, and no way for Python script to live long and react to events.

Do you really need persistent, event-based Python scripts for those tasks though? It seems that most of them are "push functionality" which happen in response to clearly-defined DR user actions (such as saving the map), rather than ongoing synchronisation. Maybe bidirectional camera synchronisation — moving the DR camera in response to player movement in game — could benefit from event handling, but would you really want this functionality to be "always on" rather than moving the DR camera when the user specifically chooses to update it by clicking a button? I would have thought that the DR camera jumping around in response to another application could become very confusing and annoying.

Quote

I wonder if there are any issues or limitations with plugins. Can they listen to events or execute some code regularly? Do they have access to underlying data? Can they have their own GUI elements, like windows, buttons, menus, etc?

Yes, they can do all those things. "Plugins" in DR are really more like Linux kernel modules: there is no binary API, plugins have full access to all DR structures, and must be built at the same time. The decision whether to put some code in the core binary or a plugin is somewhat arbitrary, and the only use of plugins currently is to make it possible to build two packages on Linux, so that users can install core without the Dark Mod plugins. On Windows there's only a single installer so you always get the Dark Mod plugins anyway (although you could delete them from disk if you really wanted and DR would run fine).

Share this post


Link to post
Share on other sites
1 hour ago, OrbWeaver said:

For dmap specifically, I wonder if this would be a good candidate to move out of the game altogether, and into DR, either by splitting out the code into a command-line tool that DR can run, or as a library that DR can call into? Map compilation seems like something that might be better off in the editor (for improved user feedback etc) rather than in the game itself.

You will have to move the whole material system, decl manager and such. Not to mention the a huge part of idlib, which is used everywhere.
Also, as far as I have heard DarkRadiant is intended to work with other D3-based games, which means that it won't be able to fully migrate to its own dmap.

Sounds like a big story with uncertain goals and benefits.

Quote

Do you really need persistent, event-based Python scripts for those tasks though? It seems that most of them are "push functionality" which happen in response to clearly-defined DR user actions (such as saving the map), rather than ongoing synchronisation.

I think only camera synchronization needs persistent connection to be smooth. All the rest can probably happen on the basis of "connect to socket, send on command, get the response, terminate".

Quote

Yes, they can do all those things.

Well, I guess I will try to write C++-only plugin, and see how it goes.

Share this post


Link to post
Share on other sites
On 7/24/2020 at 11:53 PM, stgatilov said:
  • start/connect to TDM, stop TDM
  • dmap/start current map

This would be handy to have a button in DR linked to the TDM executable, and feed it the parameters for running dmap and loading the map. On the flip-side, it's also pretty easy to make a desktop shorcut/application launcher which does this. But it would be handy for DR to apply the map path/name so the user doesn't have to edit the shortcut every time they want to dmap a different mission.

  • Like 1

Latest Mageia Linux Cauldron version blah blah blah. I'm done with updating 'uname -a' results in this sig.

Share this post


Link to post
Share on other sites
14 hours ago, stgatilov said:

You will have to move the whole material system, decl manager and such. Not to mention the a huge part of idlib, which is used everywhere.

Right, so a library-based dmap is probably a non-starter unless large parts of idLib were integrated into DR, which would be a huge task.

A command-line tool ought to be possible though. Instead of building the main game, you'd use different compiler settings to produce an executable which only ran dmap on a command-line argument (it would be quite a fat binary of course, but I doubt people care much about executable sizes these days). I seem to recall the open-source Quake 3 did something like this, and they provide a q3map2 binary along with the game engine.

14 hours ago, stgatilov said:

Also, as far as I have heard DarkRadiant is intended to work with other D3-based games, which means that it won't be able to fully migrate to its own dmap.

I don't think that would be a problem — the map compilation process is pretty much the same across all D3-based games, isn't it? Or have we made a load of compilation changes specific to the Dark Mod?

14 hours ago, stgatilov said:

Sounds like a big story with uncertain goals and benefits.

You're right, it probably is of limited benefit. Being able to pass dmap arguments directly from DarkRadiant and read the log output would be nice, but this can be achieved with the socket approach just as easily (or just parsing a log file that dmap writes out to disk).

Share this post


Link to post
Share on other sites

Wow, this is a really exciting project and will improve the workflow of our mappers significantly!! I am wondering, since we have borderless window, can it be achieved that the TDM renderview actually (optionally) replaces the DR preview? That would be incredible!

Share this post


Link to post
Share on other sites
3 hours ago, OrbWeaver said:

You're right, it probably is of limited benefit. Being able to pass dmap arguments directly from DarkRadiant and read the log output would be nice, but this can be achieved with the socket approach just as easily (or just parsing a log file that dmap writes out to disk).

As of now, automation allows you to send arbitrary TDM console commands and get back its output.
I seriously advise getting assets SVN and running devel/auto/console.py. It is so damn fun! 🤣

2 hours ago, STiFU said:

I am wonder, since we have borderless window, can it be achieved that the TDM renderview actually (optionally) replaces the DR preview? That would be incredible!

I was thinking more about running them side-by-side. Especially good with two monitors.
Trying to replace one view with another would be a lot of work and will always look messy (two windows will never be in perfect sync on move and resize).

Share this post


Link to post
Share on other sites
On 7/25/2020 at 8:53 AM, stgatilov said:
  • camera DR to TDM synchronization

Another idea: Could this synchronization be achieved bidirectionally?

Use-Case: Mapper checks his work ingame, finds something he/she dislikes and wants to edit, DR camera moves synchronously with TDM camera, so he can directly apply the change within DR.

Share this post


Link to post
Share on other sites
8 minutes ago, STiFU said:

Another idea: Could this synchronization be achieved bidirectionally?

The simplest implementation would be for him to Alt+Tab and click on button "Sync Camera to DR" (I guess there should be a group of buttons and checkboxes).
The automation sends getviewpos command to TDM, parses response, and sets these coords + angles in DR.

BTW, I suppose DR still has no way to teleport to specified coordinates (created: 5310)?

Share this post


Link to post
Share on other sites

Based on the conversation i'm sure that will never happen but the idea of moving dmap to DR sounded really awesome.

Share this post


Link to post
Share on other sites
4 hours ago, HMart said:

Based on the conversation i'm sure that will never happen but the idea of moving dmap to DR sounded really awesome.

I wonder if TDM could be launched without actually creating the window, i.e., just trigger a dmap in the tdm executable in the background.

  • Like 1

Share this post


Link to post
Share on other sites
12 hours ago, STiFU said:

Wow, this is a really exciting project and will improve the workflow of our mappers significantly!! I am wondering, since we have borderless window, can it be achieved that the TDM renderview actually (optionally) replaces the DR preview? That would be incredible!

I think Justin Marshall did that with his idtech4 PBR variant, but he was doing DoomEdit back then:

https://www.youtube.com/watch?v=3K2RCm3dPrk

Share this post


Link to post
Share on other sites
10 hours ago, STiFU said:

I wonder if TDM could be launched without actually creating the window, i.e., just trigger a dmap in the tdm executable in the background.

That is very similar to my suggestion for a separate command-line tool to run dmap. Essentially it would be the TDM binary but compiled in a mode which only ran dmap on a map specified as a command-line argument, and would not include any of the higher-level gameplay or rendering code. Running it as a command-line tool on demand (which then exits) would be much easier to manage than having a persistent process which accepted commands over IPC.

  • Like 1

Share this post


Link to post
Share on other sites
On 7/27/2020 at 5:04 PM, OrbWeaver said:

For dmap specifically, I wonder if this would be a good candidate to move out of the game altogether, and into DR, either by splitting out the code into a command-line tool that DR can run, or as a library that DR can call into? Map compilation seems like something that might be better off in the editor (for improved user feedback etc) rather than in the game itself.

Didn't DR use to accept dmap as a console command, but have it removed because it had never been fully ported to a working state? The only related tracker entry I found is 445, but I'm sure I remember at least one beginner asking for help who turned out to have used DR dmap, not TDM dmap.

However dmap ends up being implemented internally, I'd like to suggest that TDM's testmap command be kept working.


Some things I'm repeatedly thinking about...

 

- louder scream when you're dying

Share this post


Link to post
Share on other sites

What should I use to connect to a socket?

Boost.ASIO? I guess it needs static library.
Or copy idTCP from the game engine? Basically it uses some C library calls like socket, fcntl, read, write, and for some reason even has separate implementation on Windows and Linux...

Share this post


Link to post
Share on other sites
3 hours ago, stgatilov said:

What should I use to connect to a socket?

Boost.ASIO? I guess it needs static library.
Or copy idTCP from the game engine? Basically it uses some C library calls like socket, fcntl, read, write, and for some reason even has separate implementation on Windows and Linux...

Is there any problem with idTcp? I would try to reuse it

Share this post


Link to post
Share on other sites

To be honest, I feel that some third-party library would be necessary.

Maybe something like ZeroMQ with header-only C++ bindings. The core library has pure-C interface, so one DLL should fit everything, and wrappers are header-only. And it is quite popular.
The other option is Boost.ASIO, of course, since boost is already used.

Share this post


Link to post
Share on other sites

In DarkRadiant we heavily use Boost, so Boost.ASIO is a solid choice, although if you're not using Boost in the game itself I don't know how easy it would be to "manually construct" the other end of a Boost.ASIO channel. I guess you can just use Boost to connect to a pure TCP socket however.

ZeroMQ is also a very good toolkit. I have used it in a commercial project and it was very easy to use. Since it is header-only and doesn't require pulling in Boost.System, Boost.DateTime etc it might be easier to use ZMQ on the TDM side, which in turn means that you can use the same library for both ends of the connection.

Share this post


Link to post
Share on other sites

TDM will live on raw sockets, just as it does now.
I'm only asking about DarkRadiant side.

It seems that you are OK with both choices. I'll try ZeroMQ then, since I don't want to mess with boost build system.

Share this post


Link to post
Share on other sites
10 hours ago, OrbWeaver said:

In DarkRadiant we heavily use Boost, so Boost.ASIO is a solid choice, although if you're not using Boost in the game itself I don't know how easy it would be to "manually construct" the other end of a Boost.ASIO channel. I guess you can just use Boost to connect to a pure TCP socket however.

We used to rely on Boost for many things in DR, but this has changed in the meantime. I think right now the only thing left is Boost.Test in Linux, and Boost.Filesystem (but only for older GCCs lacking C++17 support).

I think I used Boost.Asio in 2007 to connect TDM and DR with each other, but I removed it from both codebases ages ago.

I'd personally vote for anything that is not making us include and compile the entire boost sources and static libraries in Windows again. I'm actually quite happy about having got rid of the compilation dependencies in Windows. I'm aware that I used to be a fan of Boost myself in the past, but the modern C++11,14,17 standards made it more and more obsolete, and it was actually easy to replace. In short, +1 for ZeroMQ (which I don't have any experience with).

Share this post


Link to post
Share on other sites
13 hours ago, greebo said:

We used to rely on Boost for many things in DR, but this has changed in the meantime. I think right now the only thing left is Boost.Test in Linux, and Boost.Filesystem (but only for older GCCs lacking C++17 support).

I guess you're talking about Boost libraries here? I think we are still using quite a few of the header-only Boost facilities, although it's mostly just simple things like the string comparison algorithms. As you say, most of the stuff we originally used Boost for can be replaced with modern C++ (std::function, std::shared_ptr etc).

13 hours ago, greebo said:

I'd personally vote for anything that is not making us include and compile the entire boost sources and static libraries in Windows again. I'm actually quite happy about having got rid of the compilation dependencies in Windows.

Agreed. The library dependencies are cumbersome even on Linux, so I definitely would vote for restricting ourselves to only those elements of Boost which are header-only (and only then if there is no standard library equivalent).

Share this post


Link to post
Share on other sites
9 hours ago, OrbWeaver said:

I guess you're talking about Boost libraries here? I think we are still using quite a few of the header-only Boost facilities, although it's mostly just simple things like the string comparison algorithms. As you say, most of the stuff we originally used Boost for can be replaced with modern C++ (std::function, std::shared_ptr etc).

Actually, I meant boost headers too. :) At least as far as the Windows compile is conerned, we don't need any boost to compile DR anymore.

After replacing the heavily-used helpers like boost::shared_ptr, boost::noncopyable, and the libs boost::thread and boost::filesystem, there weren't any references left except for a few string-manipulation functions and predicates. At this point I decided to bite the bullet and get rid of the entire boost dependencies - it didn't seem appropriate anymore to ship dozens of MB of headers just for those few string helpers.

Share this post


Link to post
Share on other sites
11 minutes ago, greebo said:

Actually, I meant boost headers too. :) At least as far as the Windows compile is conerned, we don't need any boost to compile DR anymore.

After replacing the heavily-used helpers like boost::shared_ptr, boost::noncopyable, and the libs boost::thread and boost::filesystem, there weren't any references left except for a few string-manipulation functions and predicates. At this point I decided to bite the bullet and get rid of the entire boost dependencies - it didn't seem appropriate anymore to ship dozens of MB of headers just for those few string helpers.

As you already said, most of that stuff can be achieved with modern C++, except for boost::filesystem. Just out of curiousity, what did you do to replace that to maintain cross-platform capabilities?

Share this post


Link to post
Share on other sites

There's std::filesystem in C++17. Its API is almost 100% the same, and we previously did a fair job of wrapping filesystem functionality in the os/*.h headers.

(In fact, the implementation shipping with the C++17 standard is almost a carbon copy of boost.filesystem. The people working in the std committee are often the same as the ones working on the boost libraries.)

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...