Internal Map Handling
<i>This post was originally made by <b>danij</b> on the dengDevs blog. It was posted under the categories: Engine, Games.</i>
Currently the games do the job of finding the location of the map lumps (plus gl lumps) by way of invoking dpMapLoader, which returns the lump numbers in a couple of arrays. The game then passes these back to Doomsday so it can load the map using the new common map loading code.
I think it would make sense if we cut out the middle man. As map loading is now done engine side, there is no need for the games to be involved in the process of determining the lump offsets. From the games POV it should be enough to call:
<tt>P_LoadMap(char *mapidentifier)</tt> (eg "E1M1")
Furthermore, do we still need to fragment the process of setting up a map (using several calls in the games to <tt>the engine's R_SetupLevel</tt>)?
I understand this is due to polyobjects being managed game-side. Do you plan to move all polyobject mangement into the engine?
Currently the games do the job of finding the location of the map lumps (plus gl lumps) by way of invoking dpMapLoader, which returns the lump numbers in a couple of arrays. The game then passes these back to Doomsday so it can load the map using the new common map loading code.
I think it would make sense if we cut out the middle man. As map loading is now done engine side, there is no need for the games to be involved in the process of determining the lump offsets. From the games POV it should be enough to call:
<tt>P_LoadMap(char *mapidentifier)</tt> (eg "E1M1")
Furthermore, do we still need to fragment the process of setting up a map (using several calls in the games to <tt>the engine's R_SetupLevel</tt>)?
I understand this is due to polyobjects being managed game-side. Do you plan to move all polyobject mangement into the engine?
Comments
<blockquote>As map loading is now done engine side, there is no need for the games to be involved in the process of determining the lump offsets. From the games POV it should be enough to call:</blockquote>
I agree.
<blockquote>Furthermore, do we still need to fragment the process of setting up a map (using several calls in the games to the engine's R_SetupLevel)?</blockquote>
The reason why there are so many calls to R_SetupLevel is that the initialization of differents parts of the engine-side data had to be done at certain times during map setup. The alternative would have been to export all the individual engine-side map setup functions; I thought it best to use only one function but specify the task to do as an argument.
But if map loading is done on engine-side, there shouldn't be any calls to R_SetupLevel from the game?
<blockquote>Do you plan to move all polyobject mangement into the engine?</blockquote>
Not all, but enough so that any game can use them. IIRC, the current implementation in jHexen is somewhat dependent on ACS for controlling the polyobjs. We need to make it so that the low-level management functions reside in the engine (or Src/Common for starters), so that any game can use their own game-side logic to control polyobjs (e.g., ACS in Hexen's case).
BTW, we should probably do the same for the low-level sector manipulation functions. The engine needs to know about moving planes, their speeds and destination values, and is best suited to update the planes themselves and notify the game about changes (for crushing). This information is needed for netgames. Currently the games have to provide these parameters separately as sector properties.
The engine should have similar functionality as currently exists in T_MovePlane and the handling of activeceilings and activefloors. The game should only need to say that "move this plane to height X at speed Y".
I was thinking of the following that is used for jHexen currently:
<pre>// Server can't be initialized before PO_Init is done, but PO_Init
// can't be done until SetupLevel is called...
R_SetupLevel(levelId, setupflags | DDSLF_NO_SERVER);
// Initialize polyobjs.
Con_Message("PO initn");
PO_Init(lumpNumbers[0] + ML_THINGS); // Initialize the polyobjs
// Now we can init the server.
Con_Message("Init servern");
R_SetupLevel(levelId, DDSLF_SERVER_ONLY);</pre>
For the polyobject management I propose that we allow the engine to handle loading THINGS that it understands (ie polyobjects) by using the new map loading code to read (just) the <tt>type</tt> of a THING. If it is of an unknown type then ALL handling is done by the game using the property forwarding stuff.
This would also allow Doomsday to manage any (engine only) object types we may need, which could be placed via the maps' THINGS lump.
IIRC, that R_SetupLevel/PO_Init kludge was done because PO_Init required data that was calculated during R_SetupLevel, but the initial state of the map (which was recorded during the server init) included the state of the polyobjs.
A cleaner implementation would be to have a function that is called when the map setup has been completed, so that the initial state of the map can be saved at that time. Currently DDSLF_SERVER_ONLY only initializes the netgame server's map state tracking system (which will, apart from mobjs, be obsoleted thanks to DMU).
I agree that polyobj creation should be occuring as an engine-controlled operation. There has to be a way for the games to customize the process, though, since they may have custom map/polyobj formats.
Are you thinking of a full engine-managed, thinker system or something simpler?
<blockquote>I agree that polyobj creation should be occuring as an engine-controlled operation. There has to be a way for the games to customize the process, though, since they may have custom map/polyobj formats.</blockquote>
Ok. What functionality might the games require for customizing the polyobj creation process?
The games would have a thinker for opening and closing a door (which tracks the door's state), but the engine would actually do the work of moving the ceiling plane.
<blockquote>What functionality might the games require for customizing the polyobj creation process?</blockquote> I'm thinking something like relationships between several polyobjs that the engine cannot have any information about. The games have to have the freedom to use the polyobjs as they wish. This is something that should be discussed in greater detail later on, perhaps in a new post.
Makes sense to me. So perhaps "agent" would be a good term for these?
An agent would carry out it's orders (ie move plane 13 to height Y) unless interupted (eg collision with a mobj. Upon which point the engine would defer to the games' logic to decide the outcome), or the agent has completed it's orders (eg the plane has reached it's destination height. Upon which point the engine would inform the game of the agent's success).
<blockquote>I'm thinking something like relationships between several polyobjs that the engine cannot have any information about. The games have to have the freedom to use the polyobjs as they wish.</blockquote>
So although direct control of polyobjects is the task of the engine, it must be done by proxy, under the guidance of the games' logic. Another instance where an agent could be used?
<blockquote>This is something that should be discussed in greater detail later on, perhaps in a new post.</blockquote>
Agreed.
<blockquote>So although direct control of polyobjects is the task of the engine, it must be done by proxy, under the guidance of the games' logic. Another instance where an agent could be used?</blockquote> I think yes. In general, we should treat polyobjs just like all other map data is treated (sectors, lines, etc.).