-
Notifications
You must be signed in to change notification settings - Fork 162
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Decoupling the game module build tools from the editor #872
Comments
I'm not sure why there are two script compilers, or what was wrong with the C# one, but I think the only one that is known to work, has tests, and is actively being refactored in a PR, is the C++ one. I think (just because I stumbled across this part recently, but I've not looked too closely) that the broader assembly of all of the parts when they are joined together is done in C#. So maybe this is less straight-forward that it first appears, but I also think it is absolutey the right thing to do. I'd suggest that it should also be expanded to handle resource packing (i.e. build the sprite cache and vox files for distribution). I also don't see any long term future for the Editor as it is works now and using a custom plug-in for Atom or VSCode, plus a separate compiler, looks a lot more suitainable. I guess I'm saying, portablility and integration with something else is probably more important that how it integrates with the existing Editor. I would like to say I'd meet you in the middle but it is difficult for me to commit when issues around the project's overall goal and how it operates in general remain unresolved. |
This comment was marked as abuse.
This comment was marked as abuse.
True but it shouldn't be too hard to port the existing C# code to C++. |
This comment was marked as abuse.
This comment was marked as abuse.
I get that you have a reluctance to use anything more than make and a C compiler. And your OS requires compilation of everything. But this is primarily a C#/C++ project (with a sprinkle of python scripts). How far should we accommodate you? |
As far as the "C# compiler" is concerned, the point is moot IMO. Last time I looked, there wasn't any C# compiler to speak of. There's code for pre-processing the sources, and that code is being used indeed, but all the scanning, tokenizing, and parsing code is from non-existent to rudimentary and not used. I'm currently rewriting the C++ compiler, although I took a break last month in order to participate in the MAGS June competition. I'm working within AGS 4, but the compiler is stand-alone, so once it does work it could be integrated into 3.5 fairly easily. |
This comment was marked as abuse.
This comment was marked as abuse.
This isn't strictly a Linux or Mac issue, Windows also requires the .net runtime. From what @ericoporto is saying, you can produce standalone binaries which don't require a separate runtime at all. For reference, the .net core binaries are less than 30 meg. (although I'm not sure if that includes enough for gui support) |
I got a few hints that the compiler itself was native and after digging a little deeper in the code I realized that the Compiler C# solution is only used to provide a few types to the Editor. My goal here to use whatever compiler is available, which I now realize is the C-based compiler that the editor invokes from the Native DLL. Primarily what I'm trying to do here is separate the logic of the editor that can load and build a game project. I updated the top post to make this more clear. |
i ripped off the script compiler code from ags repo and made it available as a standalone command line tool: https://github.com/rofl0r/ascc |
That's very interesting, how does one runs the generated binary file? |
the compiler creates only the binary script, which by itself cannot be run (except in
it's simply a matter of taking all object files except
that would be possible, yeah. there are not many changes against the vanilla upstream sources. of course it would take a lot longer to compile if it uses the "full" upstream sources. |
So, this is just two ideas, first, if this can be adapted to be PR'd back in this repository, it would be in sync with the AGS compiler, and it could benefit from @fernewelten refactoring once he is done with it. The thing about the frontend and building it as a library, is, because this code doesn't depend on anything, it would not be hard to turn it in JS using emscripten, imagining an usage of creating a webpage that explains AGS Scripting using this (and agssim). @rofl0r can you remove the license from agssim and just use the regular license from ags instead? The no C++ clause turns it really hard to reuse. Ah, I like to write plug-ins, and they usually pack along a header that is used to link their functions to the plug-in functions at build time by the Editor in some way, if you have ideas, I could change it so it would be readable by this in some way, for now this header is if def to be windows only. |
oh, sorry. i didn't see your post in notifications for some reason. trying to answer now...
yeah, as i said before, the sources are almost identical. it's easy to run a diff on the files and import the patches to ags repo.
tbh, i don't think the refactoring will be beneficial. the current script compiler is stable and well-tested, and the refactoring is IIRC already at 20 KLOC changed (which will certainly create new bugs), while providing no advantages over the current version that i can see. @fernewelten even goes to great lengths to ensure his refactored compiler creates the identical, utterly inefficient code...
even though i dislike bloated JS web stuff, this actually sounds quite appealing.
why does the license make it hard to use ? it explicitly allows linkage against C++ code, and the fact that it's written in C, which is a much simpler language than C++, actually makes it easier to use.
yeah, i've seen there are headers lying around in the ags plugin dir, and they seem to be automatically preprocessed by the script compiler when compiling a file. i didn't look in detail how the linking mechanism works yet. btw, i made some exciting improvements. for example, support for |
@rofl0r I literally make the plug-ins I write multiplatform and open source. You can check all of them, you could compile them yourself - but they are built on a continuous integration system and uploaded to GitHub Releases directly. The basic idea is have plug-ins with functionality that is not available on AGS itself, and the idea is, if people actually use the thing, then think on how to put the functionality in, but the main focus be, to not bloat the AGS source code. So far no one that's not me has used anything, so there has been no reason to PR anything. I think you need to know, 1, I find C not very expressive, so I could not understand what the commit meant, 2, again, the thing I am asking is an interface in the compiler that could pull the header from the plug-in, now this interface doesn't exist, they have been made for the AGS Editor only which have been ifdef out of the build, so if you could, evaluate if the current interface available on Windows should be ifdef in the Linux build too, or if a new interface is needed to retrieve the header. |
i managed to do a benchmarks of the engine using the factored out compiler. this well-known benchmark program here (taken from shootout benchmark game): #define MAX_N 64
int max(int a, int b)
{
if (a > b) return a;
return b;
}
int fannkuchredux()
{
int n = 8;
if (n > MAX_N) {
return -1;
}
int perm[MAX_N];
int perm1[MAX_N];
int count[MAX_N];
int maxFlipsCount = 0;
int permCount = 0;
int checksum = 0;
int i;
for (i=0; i<n; i+=1)
perm1[i] = i;
int r = n;
while (1) {
while (r != 1) {
count[r-1] = r;
r -= 1;
}
for (i=0; i<n; i+=1)
perm[i] = perm1[i];
int flipsCount = 0;
int k;
while (1) {
k = perm[0];
if(k == 0) break;
int k2 = (k+1) >> 1;
for (i=0; i<k2; i++) {
int temp = perm[i]; perm[i] = perm[k-i]; perm[k-i] = temp;
}
flipsCount += 1;
}
maxFlipsCount = max(maxFlipsCount, flipsCount);
int tmpflip;
if (permCount % 2 == 0) tmpflip = flipsCount;
else tmpflip = -flipsCount;
checksum += tmpflip;
/* Use incremental change to generate another permutation */
while (1) {
if (r == n) {
// print_int(checksum);
// puts("");
return maxFlipsCount;
}
int perm0 = perm1[0];
i = 0;
while (i < r) {
int j = i + 1;
perm1[i] = perm1[j];
i = j;
}
perm1[r] = perm0;
count[r] = count[r] - 1;
if (count[r] > 0) break;
r++;
}
permCount++;
}
} when compiled with gcc without any optimizations to native code: when compiled with gcc with -O3 to native code: with agssim (agssim compiled with -O3) agssim is pretty much optimized for speed, apart from doing safety checks before every memory access. with ags engine (hacked some code into the script interpreter that upon encountering a sourceline statement runs clock_gettime(CLOCK_MONOTONIC, &now); to save a timestamp with nanosecond precision, and upon the next ret shows the difference) python 2.7 fannkuchredux program with n=8: lua 5.1 version: so ags engine + its script compiler is 10x slower than python, 25x slower than lua, and 288x slower than native code. i'm showing these numbers here so the audience gets an impression how inefficient both the script compiler and the bytecode are. the speed of ags could be improved by approx 100-150% with a highly optimizing compiler, but it will never get even close to python due to the bytecode design. |
Well, I can only click my mouse so many times per microsecond. The Adventure Game Studio is a dedicated environment for creating point & click adventure games, so the engine just needs to be fast enough to keep pace with that. In my opinion, it is. For me, the thing that is much more limiting to the adventure game coder is the power of the language itself. For instance, AGS doesn't have either multidimensional arrays or brace initializers, so things that are easy to code in C are frustratingly onerous to code in AGS. For an example, typical C code:
Typical AGS code:
Or another matter, AGS insists on doing "one-pass runtime linking" (instead of two-pass bundling-time linking) with the modules. Therefore, each function etc. must be defined at a location that lies before its first call, making recursive algorithms impossible to code. These “rustic” elements of the language have sometimes annoyed me when coding adventure games, although there are certainly good ways to get around them, and overall, the requirements of the adventure game coder are catered for very well. But I've never been hampered with speed limitations in my point & click adventure games yet. |
As far as I remember, the speed limitations that have come up recently seem to be in the library part of the engine which is coded in C++ und runs in native machine language. For instance, huge sprites aren't served fast enough to the viewport in movie animations for 720p games. Speeding up the Bytecode engine or switching to Python wouldn't help any to solve these problems, would it? |
Sorry for barging in, but it seems the discussion above is about to go off-topic again (or maybe already had). Just wanted to remind that this ticket was dedicated to decoupling a script compiler from the editor program. In this context IMHO is desired to have at least one release where we have a compatible compiler, ideally that supports everything current embedded compiler supports, and optionally has some perfomance improvements. Total compiler rewrite, script language speed or switching to another script language, - these all are separate issues. For example, script language change has been discussed several times before, and mostly with the same results (some people stating it's slower than Lua, while others say that current speed is enough for them personally). So it's kind of going in circles. In any case, if you really like to discuss this, please open the new ticket. IMO the problems and questions related to standalone compiler are:
|
I don't believe this should be compiler's job to retrieve these script interfaces from plugin. And AFAIK in the Editor it was not compiler itself which was doing this. We might need to find another way to handle this. It may be not the bad option to simply provide *.ash files alongside with plugins, so that these headers could be passed into compiler directly. |
Agreed, alternatively maybe a tool extract the plug-in header. But yes, it should also be possible to just pass a header along, I just don't know how the compiler doesn't complain if there's nothing implementing the things it is importing. I believe currently a |
No, it does not. Linker does, but linking is currently a part of interpreter (engine). It's where it registers functions from all available sources (engine API, compiled script, plugins, built-in subs) and matches them to declared functions. Something I forgot to mention, as an optional solution, Editor may just get header from plugin and export it before compilation too (similar to #1007). This may be a way if it's wanted to keep plugin management strict, where plugins must be registered in project (but that may be separate question). |
i removed some of the limits in ascc. for example it now has proper support for char*, short* and int* pointers, which allows to implement low-level stuff and work around some of the limitations.
it depends on your game, naturally. if your script is just "if click was here, show this message" then yeah, the speed is good enough. other more elaborate games like operation forklift or last n'furious, or quest for infamy spend a lot of time in the script processor. for example, op. forklift runs at about 14 FPS on my machine, after applying the optimization passes of "agsoptimize" from agsutils, it runs at least at 21 fps, which makes it playable.
right, you probably use scripts pretty sparingly or your users all have 3 GHZ rockets under their table. but if you want to target mobile or embedded platforms, mentioned game titles are unplayable.
exactly what ascc does, then. :)
well that part is pretty clear to me:
it should behave like other command line compilers do, pretty much as i implemented it in ascc (i happen to maintain 2 cross-compiler toolchains and a distro that focuses on compiling from source, so i'm pretty familiar with compilers).
the output should be an object file with SCOM header, just like what the compiler already emits (but indirectly by shoving it into a "gamepack"), i.e. what ascc does.
right, this is the biggest issue at the moment. i could successfully compile your "last n furious" sources if some scripts wouldnt rely on constants defined inside the game xml data. (it's possible to work around it at the moment by disassembling compiled code and looking which constants are passed around, but that's clearly not something users would do). |
That's the standard way of handling code compilation. Visual Studio or the GCC suite do it that way too:
The AGS approach is to defer the linking process completely to the time when the game is actually run. So it treats all the compilation units as a sort of “DLL”. This is one of the common approaches; it isn't a special quirky thing that only AGS does. The downside of that approach is that the Engine might only find out at runtime that something vital is missing. Of course, nothing would stop the studio from doing a “static tryout linking” as part of the bundling (f7) to find out at this point, too, whether something important is missing. But AFAIK, this isn't implemented. |
Hey, I decided to experiment with github Projects, and made a project as a way to track the bigger task: @edmundito
Were you able to get any progress in that? EDIT: another topic of concern here is to not have all the related changes done as a single bulk, which may be difficult to review and merge without breaking something. PS. Not meaning to push or rush anyone, only wish everything related is tracked here for the reference. |
https://github.com/edmundito/ags/tree/edmundito/decouple-compiler These are all the efforts in the compiler I could find. It seems we need to find steps to advance that are bite sized and can be PR'd in, because doing a lot at once is hard to finish/merge. I suggest starting with figuring the directory to receive code reggarding command line tooling. The compiler is already somewhat separated, in the The preprocessor being built with C# appears to be useful for the editor since it needs to preprocess stuff to figure out what should be available in the autocomplete. It's also very well separated, except by the fact it picks the AGS Version from AGS.Types (it's the single reference to AGS.Types in it if we don't count a spurious We use AGS.Types for some things in the build process but There is some important questions above I will try to reply inline here.
In this repository. There's a top directory called
For now let's try to work with what we have already. There's a mix here of Script compiler and Game builder being discussed in this thread.
I don't know how it works today but at first this should work just like it's today. If we need file name suggestion for the compiled script I would go with
In the ags Project, it could be the
least capable to generate missing ones (because right now some of the data is either stored in big game XML, or generated by Editor in memory, or generated by plugins). |
Depends on how the version is used. It could be passed as a function/tool argument.
I have to disagree, "Compiled" was meant for final files (and some users already make mistake and upload whole contents of it with "Data", duplicating the game size). |
What about |
When I was trying to think how to do this, for purposes of separating components but mainly to be able to compile a game from the command line, I think that I eventually concluded that there needed to be a new type defined that represents a project. This Project type would need to know how to load/save/edit(+upgrade)/compile and then the Editor and a new command tool operate using this new type. This is pretty large task though, as project editing code is scattered everywhere and the Editor has a very poor concept of what a project is - to the point that when using the sprite manager it doesn't even know for sure which game it is editing. It was around this time it seemed much more appealing to look at redesigning the Editor and data formats and compilation outside of AGS 3 and once something decent exists look at how existing projects would be migrated. Also, outside of AGS3 you shouldn't have to worry about getting it right first time, particularly if no-one has run any data through it yet... |
@ericoporto I guessed you will suggest "intermediate" in the root, but this is going to be an obscure name for AGS users, as most are infamiliar with compilation technique and don't know what's going on under the hood. For that reason I'd propose using terms like "building", "temp" and similar, that clearly define what the folder is related to. |
Temp is short and clean. We can use that :) @morganwillcock, I opened #1092 which I think can be somewhat related to what you mentioned. Does anyone knows if I can put arbitrary code in the AGS Engine and have it run? Like, supposed I built a script with the ascc compiler, could I run it with the AGS Engine itself? |
I think you should also define what is for 3.* branch and what is for ags4 branch. For instance, this is roughly what was planned for 3.5.1 update: https://github.com/adventuregamestudio/ags/milestone/6
I am not sure if I understand the meaning of this question. But if a code were loaded into script interpreter, it could run it either by finding a function by name, or starting with certain random bytecode. |
Thanks @ivan-mogilko ! I was thinking if it would be possible to run the bytecode produced by the compiler from the Engine so one could check the behavior of the code. |
There are undefined details in this: what kinds of behavior are you going to test, and how do you plan to load and run this. For instance, you won't be able to test many API function calls without loading full game data. Engine also currently does not have arguments and logic to launch any random bytecode from startup (or load one from file at runtime). |
Thanks! I will use agssim for now. Ah, unless I am missing something, if we had a tool that understands ags project files, so it could read and "orchestrate" the other tools, it could build a game using only the tools from agsutils. Like, sprite packing done in a command line tool instead of the Native.dll way that I think we do. The tools could live in a If this is indeed true, I think we should make ags versions of the relevant ones using the ags code that already exists (like the Common library) as much as possible to avoid code duplication. |
Yes, that is indeed the point of this ticket. Don't think such tool should literally command other tools though, rather prepare an input for them, as the whole group could be run simply from a shell script. EDIT also, if I understand correctly, @morganwillcock 's suggestion was to treat whole dir as a project in future versions, which means file list could be taken directly from the dir, not project file (this may have unwanted consequences, so needs to be thought through beforehand). |
OK, it's alright too, just we need to make a tool to write some output files for other tools (erh, I imagine it basically pick pieces of the Game.agf xml file and spits the relevant parts in a separate one). This can be windows only and use AGS Types for simplicity. This forum message goes into the project as directories idea, which is a good one, don't know how to get there right now. Edit: removed some things from this comment to move to a new issue to avoid cluttering this discussion. |
Uhm, just in case I am understanding something wrong, the sprite files when they get into the game data, is it copyied directly from the spritecache (like concatenated with other data that goes there - in the game.ags file) or is it read from the source files and put into the data "stream" , erh, the binary blob part of the sprite files in the game data that is read by the engine. |
Sprite file is packed into game data as a whole. Sprites are not taken from source files when compiling the game, they are stored in sprite file when imported by the editor.
Yes, please, a ticket for separate task/discussion is a proper thing. |
i checked out the writeup @ivan-mogilko mentioned in #1121 and it seems the logical next step to go on with this would be to write a command line C++ tool that reads the game.agf xml file and extracts certain things, for starters it could generate the header files that currently exist only in memory during the gui-triggered game build process, and subsequently change the build process to 1) invoke the tool 2) read the generated headers for compile from disk, so the code lives only in a single place to avoid code duplication. should i open a new ticket for this? |
Yes, there are several things that may have to be read from Game.agf, done by one tool that can execute several operations, or several tools, but using similar xml parsing. I was thinking to start writing the tickets for this table too, since we mentioned that, but haven't got there yet, so certainly, do this if you want. |
I had a good experience with Cereal in the past : https://uscilab.github.io/cereal/ It's header only and builds on anything using c++11, it may be useful to deserialize and serialize obects. It comes with json and XML out of the box but it's easier to plug something like yaml in it too. |
@rofl0r @ericoporto ok, I wrote one: #1146, please comment if you have further suggestions. |
I have a feeling that it's better to close this and rewrite a new ticket for this - the discussion started at a time we had not researched much about this, it was a good kick in the butt to move a bit in this direction, but there isn't much in terms of actual practical design of what would be the code that fixes this. Probably with references to https://github.com/adventuregamestudio/ags/wiki/AGS-Game-Build-process-(3.5.*) |
Right, I propose the new ticket should have following points:
As a reminder, all this time there have been this "github project" which grouped related tickets: |
Closed in favor of #2316. |
Hello, here's another side project I started after talking and interacting with the number of AGS users who create commercial games:
Rationale
Work in Progress
I started pushing some changes into my fork. So far it doesn't seem very difficult other than time consuming and at least the first steps give me an idea of what areas to separate and where some refactoring may be needed. The primary bulk of the work is decoupling UI calls from the builds steps.
release-3.5.0...edmundito:edmundito/decouple-compiler (should probably rename to
decouple-builder
)With the work so far, here's what I'm thinking:
I am seeking some feedback and to talk about next steps. Send your thoughts in the comments 👇
The text was updated successfully, but these errors were encountered: