adventuregamestudio / ags

AGS editor and engine source code
Other
708 stars 159 forks source link

Proposal: AGS 3.6 and beyond roadmap #762

Closed sonneveld closed 1 year ago

sonneveld commented 5 years ago

Okay, summary: my hopes are that 3.6 is an actual minor release, only doing bug fixes and porting to SDL2 (which would require some update/rendering refactoring). 3.7 and beyond we look at how we refactor to make it easier for new people to add features but still keep compatibility. You might note that I've only been thinking about the backend and engine, not so much new features just yet.

My suggestions, just to start off the conversation:

3.6

3.7 These are some ideas that I'd like myself or others to pursue, but not necessarily everything we could do (in no particular order):

sonneveld commented 5 years ago

I think having an in-engine migration might help with adding new features, sort of like database migrations. I don't know if it would work, but for each major version we could could add a 'migrate_to_version_3_6' mechanism. It would take data from, say load_game_3_5_or_older and migrate to 3.6. Older games might have to go through several migration steps.

We sort of have a similar process in place now, but it's done with fixups after the loading. That suggests the fixups always have to be updated if we change our internal structs. Instead, we would just have a simple 3_5 struct and a 3_6 struct, completely separate. Only the migration code would know how to map them. Then engine would only work with 3_6 structures. Then we could optionally compile out the migration and older structs for a forward compatible engine.

(note: I'm not suggesting we have multiple structs for all the versions that exist. Maybe just 3_5_and_legacy and 3_6 to begin with)

My experiences with keeping my sdl2 branch up to date with ags3 have suggested that if we keep separate ags3 and ags4 branches, it won't be long before it will be very difficult to port fixes across. I still care about supporting the hundreds of legacy games out there.

edit: To borrow an idea from cmake, they have an idea called policies which affects behavior, and newer versions enable more policies by default. We could possibly use this for deprecated behavior that needs to be passed on and can't be done just via struct mapping.

sonneveld commented 5 years ago

One request: please be civil. I might hide comments that are rude and non-constructive.

ghost commented 5 years ago

For the reference: old ags4 draft : #450

i30817 commented 5 years ago

I'm a bit afraid of ambitions like 'become always multi-threaded' in a language like C++. I honestly wouldn't feel it's a good idea without the language being rust or something like that can statically verify against race conditions. There is a reason that mozilla invented rust before servo was done and why google bothered with Go, and that's because they had experience of how painful it would be otherwise in C++.

ghost commented 5 years ago

Also, a note, I changed bunch of things in ags4 branch, cutting out restrictions imposed by legacy script API and plugin API to the internal engine structs layout, dropping support for plugin API that required exact backend like DirectDraw, and something else along these lines. One could investigate commits made to ags4 in 2018 for the reference.

sonneveld commented 5 years ago

I'm a bit afraid of ambitions like 'become always multi-threaded' in a language like C++.

ah, I didn't go into details but this is more like a coroutine, or just swapping execution between two threads. I wanted to have a traditional game loop with one spot where events, timing and rendering is done. The problem is that our game code can get recursive and have mini loops for gui, dialogs, etc.

All this does is run the game update loop in another thread, wait for a frame to be finished, then do the processing in the main thread. The engine just treats the game update code like an object with a "get frame" method. The separate thread allows us to return from a nested stack. Eventually we could untangle our nested update code and literally have a game object we call update on.

It was an experiment that seemed to work? /shrugs

edmundito commented 5 years ago

@sonneveld Is this only a technical roadmap? Is there also a product roadmap as well?

ericoporto commented 5 years ago

@sonneveld I suggest the 3.6 be of a reduced scope where the goal is move towards using SDL in place of Allegro with the expected benefit of easier/better multiplatform support. About OpenGL, maybe a small improvement would be moving the GUI system to use it instead of software drawing. I understand this means still having this version with that cutdown version of allegro in place, but a goal to remove it eventually would be helpful.

ericoporto commented 1 year ago

Use a slightly multi-threaded approach where timing and graphics are done in the main thread, and game loop is done in a separate thread (I have an experimental version in my sdl2 branch)

I always wanted to know what that meant, I think I found how this was done.

https://github.com/sonneveld/ags/blob/938b9cefcde544bcc6872a57ad5a9448b753b9f1/Engine/main/simple_engine.cpp

I don't understand what that means still, would it be like you can set game fps and script tps (ticks per second)? Or they are still kept at the same frame-ticks equivalence?

I was looking at the perspective of running Zniw, a 85fps game, with a 60fps vsync and still hit the same timings as 85fps.


About the rest of this issue, I think we may either close it or edit it saying, information below is outdated and left as a reference for future developments or something.

ivan-mogilko commented 1 year ago

I don't understand what that means still, would it be like you can set game fps and script tps (ticks per second)? Or they are still kept at the same frame-ticks equivalence?

The point is to have whole game logic run on a separate thread at its own fps, also known tps in some engines/games (ticks per second), while render and system events are done on the main thread using separate render fps. Basically, make game logical updates disconnected from the render times.

Your Zniw example is correct, but also slow games may benefit from higher speed render and smoother cursor movement.

In this case SetGameSpeed only applies to well, game speed, while render speed is player's/system's choice.

Overall this assumes that times of game update and render do not match, multiple game updates may happen between 2 renders if game runs faster; or multiple re-renders may happen between 2 game updates if game runs slower.

This assumes that there's a list of sprites, or "drawing operations" (as in sonneveld's example branch), kept at all times ready for the render, and it's only recreated at "sync points" in time. For example when both game is updated and we are going to render, or after each game update and kept ready for the next render, whenever it may take place.

There are various approaches to this; on one hand the "game update" may prepare this list of operations for a renderer to use whenever next update is complete. On another hand, the main thread may request game to do this whenever it needs to. (So it's a choice between taking something if it's ready or requesting something)

One thing that I just realized is that after this separation there will no longer be any game logic explicitly run "after draw", as it is coded now. All the logic will be updated at once, and whether any draw occur or not - will become irrelevant. Idk if that will lead to any compatibility issues with old games.

Unfortunately this was never documented as its own task in this tracker, but it may be. The task is briefly mentioned in the ags4 milestone ticket #1298.

I think @sonneveld 's work may be a good reference for both threading and "SceneGraph" interface/implementation. OTOH, the SDL2 also uses a similar concept of draw operations in its renderer, where "draw operation" may be not only drawing a texture, but drawing a arbitrary quad, or applying effect, and so on. This is simply for reference.

EDIT: it's not immediately clear whether #1349 must be done before this, or would simply make it easier. It's possible that it's not obligatory, except the engine will not call renderer directly from within these multiple update loops.

ivan-mogilko commented 1 year ago

About the rest of this issue, I think we may either close it or edit it saying, information below is outdated and left as a reference for future developments or something.

Yes, the development went a different way. This plan assumed that it will be kept in 3. branch with full compatibility, and serious effort would be put into developing an easier "legacy feature support" and "migration" systems. While we did SDL2 and unicode in 3., more effort is put into the stripped ags4 now.

Still, refactoring the engine and separating it into parts with only minimal connections might make it possible to return legacy support in a form of custom engine build, for instance, where the main engine code would only have some sort of "linkage points" to plug in legacy support. Migration tools do not have to be a part of the core team project either, all this may be done separately.

EDIT: I wanted to reread older "plan" tickets and update/close/recreate these depending on how they refer to the current situation.

ericoporto commented 1 year ago

Your Zniw example is correct, but also slow games may benefit from higher speed render and smoother cursor movement.

So, about the slow games, I don't think they will, because afaict the logic is ran in the script "engine", as an example, because tweens exist in script code (the tween module), this would actually make things less smooth. The mouse cursor I think it's either better solved by the OS Cursors (#1686), or some way to have things update at different fpss - so the mouse cursor could be updated at monitor speed, and the rest at a different one.

ivan-mogilko commented 1 year ago

The mouse cursor I think it's either better solved by the OS Cursors (#1686), or some way to have things update at different fpss - so the mouse cursor could be updated at monitor speed, and the rest at a different one.

That is what I meant: update the cursor position at render frequency.

ivan-mogilko commented 1 year ago

Closing this as outdated, but giving a small recap.

  1. 3.6.0 turned out to be a major updated, instead of SDL2-only update. Besides porting to SDL2 it also featured new audio subsystem, and full Unicode support (actually, mixed ASCII/Unicode support).
  2. ScummVM finally got a AGS port, which in a way delegates our responsibilities for maintaining old games, at least partially.
  3. AGS 4, an experimental branch with cut legacy features, had been developed more, and received few major additions, which make it actually interesting to work in. The first 4.0 alpha release for public test made recently.

Following distinct ideas from above list may still be useful, and should receive respective feature tickets at some point:

There's also a plan draft for the major engine refactor started here: https://github.com/adventuregamestudio/ags/wiki/AGS-4-Draft:-major-engine-refactor