Skip to content

Commit

Permalink
Refactor|libdoomsday|Plugins: Game exports queried individually
Browse files Browse the repository at this point in the history
Instead of GetGameAPI returning a struct with the exported game
functions, GetGameAPI now takes the name of the function and returns
a pointer to that particular function.

This is more flexible and future-proof, and allows using C++ types in
the arguments and return values. The exports from libcommon are
also handled in one place.
  • Loading branch information
skyjake committed Oct 2, 2017
1 parent 786f04d commit 5c8d7ec
Show file tree
Hide file tree
Showing 26 changed files with 403 additions and 453 deletions.
2 changes: 1 addition & 1 deletion doomsday/apps/client/include/world/p_object.h
Expand Up @@ -44,7 +44,7 @@ class Subsector;
}
class Plane;

#define MOBJ_SIZE gx.mobjSize
#define MOBJ_SIZE gx.GetInteger(DD_MOBJ_SIZE)

class MobjThinker : public ThinkerT<mobj_t>
{
Expand Down
22 changes: 7 additions & 15 deletions doomsday/apps/client/src/world/base/map.cpp
Expand Up @@ -3116,16 +3116,14 @@ String Map::objectsDescription() const
String str;
QTextStream os(&str);

if (auto *descPtr = gx.GetPointer(DD_FUNC_OBJECT_STATE_INFO_STR))
if (gx.MobjStateAsInfoText)
{
auto const descFunc = de::function_cast<de::String (*)(mobj_t const *)>(descPtr);

// Print out a state description for each thinker.
thinkers().forAll(0x3, [&os, &descFunc] (thinker_t *th)
thinkers().forAll(0x3, [&os] (thinker_t *th)
{
if (Thinker_IsMobj(th))
{
os << descFunc(reinterpret_cast<mobj_t const *>(th));
os << gx.MobjStateAsInfoText(reinterpret_cast<mobj_t const *>(th));
}
return LoopContinue;
});
Expand All @@ -3138,13 +3136,7 @@ void Map::restoreObjects(Info const &objState, IThinkerMapping const &thinkerMap
{
/// @todo Generalize from mobjs to all thinkers?

auto *descPtr = gx.GetPointer(DD_FUNC_OBJECT_STATE_INFO_STR);
auto *restorePtr = gx.GetPointer(DD_FUNC_RESTORE_OBJECT_STATE);

if (!descPtr || !restorePtr) return;

auto const descFunc = de::function_cast<de::String (*)(mobj_t const *)>(descPtr);
auto const restoreFunc = de::function_cast<void (*)(mobj_t *, Info::BlockElement const &)>(restorePtr);
if (!gx.MobjStateAsInfoText || !gx.MobjRestoreState) return;

// Look up all the mobjs.
QList<thinker_t const *> mobjs;
Expand Down Expand Up @@ -3178,12 +3170,12 @@ void Map::restoreObjects(Info const &objState, IThinkerMapping const &thinkerMap
DENG2_ASSERT(&found->thinker() == th);

// Restore the state according to the serialized info.
restoreFunc(found->as<MobjThinkerData>().mobj(), state);
gx.MobjRestoreState(found->as<MobjThinkerData>().mobj(), state);

#if defined (DENG2_DEBUG)
{
// Verify that the state is now correct.
Info const currentDesc(descFunc(found->as<MobjThinkerData>().mobj()));
Info const currentDesc(gx.MobjStateAsInfoText(found->as<MobjThinkerData>().mobj()));
Info::BlockElement const &currentState = currentDesc.root().contentsInOrder()
.first()->as<Info::BlockElement>();
DENG2_ASSERT(currentState.name() == state.name());
Expand Down Expand Up @@ -4117,7 +4109,7 @@ Polyobj *Map::createPolyobj(Vector2d const &origin)
/// @throw EditError Attempted when not editing.
throw EditError("Map::createPolyobj", "Editing is not enabled");

void *region = M_Calloc(POLYOBJ_SIZE);
void *region = M_Calloc(gx.GetInteger(DD_POLYOBJ_SIZE));
auto *pob = new (region) Polyobj(origin);
d->editable.polyobjs.append(pob);

Expand Down
141 changes: 4 additions & 137 deletions doomsday/apps/libdoomsday/include/doomsday/gameapi.h
Expand Up @@ -65,9 +65,11 @@ enum {

DD_ACTION_LINK = 0x500, ///< State action routine addresses.
DD_XGFUNC_LINK, ///< XG line classes
DD_MOBJ_SIZE,
DD_POLYOBJ_SIZE,

DD_FUNC_OBJECT_STATE_INFO_STR, ///< Information about mobjs in plain text Info format.
DD_FUNC_RESTORE_OBJECT_STATE, ///< Restore object state according to a parsed Info block.
//DD_FUNC_OBJECT_STATE_INFO_STR, ///< Information about mobjs in plain text Info format.
//DD_FUNC_RESTORE_OBJECT_STATE, ///< Restore object state according to a parsed Info block.

DD_TM_FLOOR_Z = 0x600, ///< output from P_CheckPosition
DD_TM_CEILING_Z, ///< output from P_CheckPosition
Expand All @@ -78,141 +80,6 @@ enum {
DD_RENDER_RESTART_POST
};

/**
* The routines/data exported from the game plugin. @ingroup game
*
* @todo Get rid of this struct in favor of individually queried entrypoints.
*/
typedef struct {
size_t apiSize; ///< sizeof(game_export_t)

// Base-level.
void (*PreInit) (char const *gameId);
void (*PostInit) (void);
dd_bool (*TryShutdown) (void);
void (*Shutdown) (void);
void (*UpdateState) (int step);
int (*GetInteger) (int id);
void *(*GetPointer) (int id);

// Networking.
int (*NetServerStart) (int before);
int (*NetServerStop) (int before);
int (*NetConnect) (int before);
int (*NetDisconnect) (int before);
long int (*NetPlayerEvent) (int playernum, int type, void *data);
int (*NetWorldEvent) (int type, int parm, void *data);
void (*HandlePacket) (int fromplayer, int type, void *data,
size_t length);

// Tickers.
void (*Ticker) (timespan_t ticLength);

// Responders.
int (*FinaleResponder) (void const *ddev);
int (*PrivilegedResponder) (struct event_s *ev);
int (*Responder) (struct event_s *ev);
int (*FallbackResponder) (struct event_s *ev);

// Refresh.
void (*BeginFrame) (void);

/**
* Called at the end of a refresh frame. This is the last chance the game
* will have at updating the engine state before rendering of the frame
* begins. Once rendering begins, the viewer can still be updated however
* any changes will not take effect until the subsequent frame. Therefore
* this is the place where games should strive to update the viewer to
* ensure latency-free world refresh.
*/
void (*EndFrame) (void);

/**
* Draw the view port display of the identified console @a player.
* The engine will configure a orthographic GL projection in real pixel
* dimensions prior to calling this.
*
* Example subdivision of the game window into four view ports:
* <pre>
* (0,0)-----------------------. X
* | .--------. | |
* | | window | | |
* | '--------' | |
* | port #0 | port #1 |
* |-------------------------|
* | | |
* | | |
* | | |
* | port #2 | port #3 |
* '--------------------(xn-1, yn-1)
* Y Game Window
* </pre>
*
* @param port Logical number of this view port.
* @param portGeometry Geometry of the view port in real screen pixels.
* @param windowGeometry Geometry of the view window within the port, in
* real screen pixels.
*
* @param player Console player number associated with the view port.
* @param layer Logical layer identifier for the content to be drawn:
* - 0: The bottom-most layer and the one which generally contains the
* call to R_RenderPlayerView.
* - 1: Displays to be drawn on top of view window (after bordering),
* such as the player HUD.
*/
void (*DrawViewPort) (int port, RectRaw const *portGeometry,
RectRaw const *windowGeometry, int player, int layer);

/**
* Draw over-viewport displays covering the whole game window. Typically
* graphical user interfaces such as game menus are done here.
*
* @param windowSize Dimensions of the game window in real screen pixels.
*/
void (*DrawWindow) (Size2Raw const *windowSize);

// Miscellaneous.
void (*MobjThinker) (void *mobj);
coord_t (*MobjFriction) (struct mobj_s const *mobj); // Returns a friction factor.
dd_bool (*MobjCheckPositionXYZ) (struct mobj_s *mobj, coord_t x, coord_t y, coord_t z);
dd_bool (*MobjTryMoveXYZ) (struct mobj_s *mobj, coord_t x, coord_t y, coord_t z);
void (*SectorHeightChangeNotification)(int sectorIdx); // Applies necessary checks on objects.

// Main structure sizes.
size_t mobjSize; ///< sizeof(mobj_t)
size_t polyobjSize; ///< sizeof(Polyobj)

// Map setup

/**
* Called once a map change (i.e., P_MapChange()) has completed to allow the
* game to do any post change finalization it needs to do at this time.
*/
void (*FinalizeMapChange) (void const *uri);

/**
* Called when trying to assign a value read from the map data (to a
* property known to us) that we don't know what to do with.
*
* (eg the side->toptexture field contains a text string that
* we don't understand but the game might).
*
* @return The action code returned by the game depends on the context.
*/
int (*HandleMapDataPropertyValue) (uint id, int dtype, int prop,
valuetype_t type, void *data);
// Post map setup
/**
* The engine calls this to inform the game of any changes it is
* making to map data object to which the game might want to
* take further action.
*/
int (*HandleMapObjectStatusReport) (int code, uint id, int dtype, void *data);
} game_export_t;

/// Function pointer for @c GetGameAPI() (exported by game plugin). @ingroup game
typedef game_export_t *(*GETGAMEAPI) (void);

#ifdef __cplusplus
} // extern "C"
#endif
Expand Down
134 changes: 133 additions & 1 deletion doomsday/apps/libdoomsday/include/doomsday/plugins.h
Expand Up @@ -22,6 +22,7 @@

#include <de/str.h>
#include <de/rect.h>
#include "world/valuetype.h"

/**
* Unique identifier assigned to each plugin during initial startup.
Expand Down Expand Up @@ -107,10 +108,141 @@ typedef struct {
#ifdef __cplusplus

#include <de/Observers>
#include <de/Info>
#include "libdoomsday.h"
#include "library.h"
#include "gameapi.h"

/**
* Routines exported from a game plugin. @ingroup game
*
* Note that this struct is not part of the game plugin ABI any longer (since 2.1).
*/
struct GameExports
{
// Base-level.
void (*PreInit) (char const *gameId);
void (*PostInit) (void);
dd_bool (*TryShutdown) (void);
void (*Shutdown) (void);
void (*UpdateState) (int step);
int (*GetInteger) (int id);
void *(*GetPointer) (int id);

// Networking.
int (*NetServerStart) (int before);
int (*NetServerStop) (int before);
int (*NetConnect) (int before);
int (*NetDisconnect) (int before);
long int (*NetPlayerEvent) (int playernum, int type, void *data);
int (*NetWorldEvent) (int type, int parm, void *data);
void (*HandlePacket) (int fromplayer, int type, void *data,
size_t length);

// Tickers.
void (*Ticker) (timespan_t ticLength);

// Responders.
int (*FinaleResponder) (void const *ddev);
int (*PrivilegedResponder) (struct event_s *ev);
int (*Responder) (struct event_s *ev);
int (*FallbackResponder) (struct event_s *ev);

// Refresh.
void (*BeginFrame) (void);

/**
* Called at the end of a refresh frame. This is the last chance the game
* will have at updating the engine state before rendering of the frame
* begins. Once rendering begins, the viewer can still be updated however
* any changes will not take effect until the subsequent frame. Therefore
* this is the place where games should strive to update the viewer to
* ensure latency-free world refresh.
*/
void (*EndFrame) (void);

/**
* Draw the view port display of the identified console @a player.
* The engine will configure a orthographic GL projection in real pixel
* dimensions prior to calling this.
*
* Example subdivision of the game window into four view ports:
* <pre>
* (0,0)-----------------------. X
* | .--------. | |
* | | window | | |
* | '--------' | |
* | port #0 | port #1 |
* |-------------------------|
* | | |
* | | |
* | | |
* | port #2 | port #3 |
* '--------------------(xn-1, yn-1)
* Y Game Window
* </pre>
*
* @param port Logical number of this view port.
* @param portGeometry Geometry of the view port in real screen pixels.
* @param windowGeometry Geometry of the view window within the port, in
* real screen pixels.
*
* @param player Console player number associated with the view port.
* @param layer Logical layer identifier for the content to be drawn:
* - 0: The bottom-most layer and the one which generally contains the
* call to R_RenderPlayerView.
* - 1: Displays to be drawn on top of view window (after bordering),
* such as the player HUD.
*/
void (*DrawViewPort) (int port, RectRaw const *portGeometry,
RectRaw const *windowGeometry, int player, int layer);

/**
* Draw over-viewport displays covering the whole game window. Typically
* graphical user interfaces such as game menus are done here.
*
* @param windowSize Dimensions of the game window in real screen pixels.
*/
void (*DrawWindow) (Size2Raw const *windowSize);

// Miscellaneous.
void (*MobjThinker) (void *mobj);
coord_t (*MobjFriction) (struct mobj_s const *mobj); // Returns a friction factor.
dd_bool (*MobjCheckPositionXYZ) (struct mobj_s *mobj, coord_t x, coord_t y, coord_t z);
dd_bool (*MobjTryMoveXYZ) (struct mobj_s *mobj, coord_t x, coord_t y, coord_t z);
de::String (*MobjStateAsInfoText) (struct mobj_s const *);
void (*MobjRestoreState) (struct mobj_s *, de::Info::BlockElement const &stateInfoBlockElement);

void (*SectorHeightChangeNotification)(int sectorIdx); // Applies necessary checks on objects.

// Map setup

/**
* Called once a map change (i.e., P_MapChange()) has completed to allow the
* game to do any post change finalization it needs to do at this time.
*/
void (*FinalizeMapChange) (void const *uri);

/**
* Called when trying to assign a value read from the map data (to a
* property known to us) that we don't know what to do with.
*
* (eg the side->toptexture field contains a text string that
* we don't understand but the game might).
*
* @return The action code returned by the game depends on the context.
*/
int (*HandleMapDataPropertyValue) (uint id, int dtype, int prop,
valuetype_t type, void *data);
// Post map setup
/**
* The engine calls this to inform the game of any changes it is
* making to map data object to which the game might want to
* take further action.
*/
int (*HandleMapObjectStatusReport) (int code, uint id, int dtype, void *data);
};

/**
* Plugin loader.
*/
Expand Down Expand Up @@ -167,7 +299,7 @@ class LIBDOOMSDAY_PUBLIC Plugins
/**
* Returns the current game plugin's entrypoints.
*/
game_export_t &gameExports() const;
GameExports &gameExports() const;

public: // Function hooks: ----------------------------------------------------------

Expand Down

0 comments on commit 5c8d7ec

Please sign in to comment.