ValveSoftware / halflife

Half-Life 1 engine based games
Other
3.68k stars 624 forks source link

[Request] New engine <->game interfaces #1739

Open SamVanheer opened 8 years ago

SamVanheer commented 8 years ago

I would like to request the addition of new interfaces for engine <-> game communication. The existing interfaces do not cover all necessary areas of game dev and can require ugly workarounds to achieve certain goals.

To that end, i have designed a proposal for a set of interfaces to allow communication between the server and the engine.

There are 2 interfaces in this proposal: IServerEngine: a new interface to the engine, this adds missing functionality, such as the ability to check what the highest entity index currently in use is, whether a model/sound/file has been precached, and whether a client has fully authenticated.

It can be found here: https://github.com/SamVanheer/HLEnhanced/blob/iface_proposal/shared/engine/server/IServerEngine.h

IServerGameLib: an interface that represents the server as a library and provides core callbacks needed to inform the server of map state changes in the engine. This is CRITICAL in order to write proper code, especially when it comes to initializing and cleaning up per-map data. It also provides a means to get any and all interfaces from any engine library, including the client, should it be a listen server.

It also includes the ability to handle entity creation on map start in the server, which allows for many improvements in map spawn logic. E.g. custom entities can be handled better than depending on global state to track when custom entities are being created.

The ability to handle game physics (excluding players, handled in pm_shared.cpp) also exists in it, allowing mods to implement completely custom physics.

Last but not least, a callback to notify when a client has fully authenticated also exists. Server operators have asked for this one specifically because getting a client's Steam ID can be difficult if authentication takes a while.

It can be found here: https://github.com/SamVanheer/HLEnhanced/blob/iface_proposal/shared/game/server/IServerGameLib.h

Should the documentation not adequately cover when callbacks should be invoked, i can with reasonable accuracy give you the function and location in that function to invoke them based on reverse engineered information.

I will be writing a version for the client side tomorrow to cover some things that are missing on that side, and probably refactor this code to deal with common issues.

SamVanheer commented 8 years ago

I've added interfaces for the client side. I opted to keep the server and client interfaces separate to prevent versioning issues if shared interfaces were ever modified.

As with the server, there are 2 interfaces: IClientEngine: a new interface to the engine, this covers much of IServerEngine's new additions, as well as the ability to play sounds by index. This is very important because it allows the server to send sound indices to clients instead of being forced to send sample names. In some cases, like the event system, there is no way to send strings at all, so there is no way to tell clients to play sounds that way. PlaySoundByIndex would allow you to pass an integer argument along to play it, which is very useful to have.

It can be found here: https://github.com/SamVanheer/HLEnhanced/blob/iface_proposal/shared/engine/client/IClientEngine.h

Ideally, an entirely new interface for sounds could be added where all current and new sound methods are centralized.

IClientGameLib: like IServerGameLib, this provides missing callbacks. The ability to connect with other libraries is present in LibInit, and callbacks at specific moments allows the client to initialize and clean itself up. The client gains the ability to detect to which server a connection has been established (currently impossible), as well as the ability to reject connections on its own if the server's info doesn't meet criteria (e.g. missing or present tags).

A callback to notify when a map is about to start loading allows it to initialize per-map data, for example parsing worldspawn's entity data to load a keyvalue from it. I'm using that to load a script on the client side to handle client side scripting operations. Currently this requires a hack which has timing issues, with server network messages arriving before my hack gets to run.

It can be found here: https://github.com/SamVanheer/HLEnhanced/blob/iface_proposal/shared/game/client/IClientGameLib.h

I am aware that the client already has the means to connect to other libraries in IClientVGUI. However, that interface is not included in the SDK. I would like to request the addition of this interface, as well as the entire GoldSource era VGUI2 library code so mods can use it as well. Additionally, utility code compatible with it (CUtlDict, CUtlVector, KeyValues, etc) would be greatly appreciated. If any documentation exists for this, that would also be appreciated.

Lastly, experimentation has shown that Steamworks is accessible in the game libraries. If possible, could Steamworks access be given to game code? This would allow direct access to query for data, like client Steam IDs, server tags, etc.

SamVanheer commented 8 years ago

I updated both engine interfaces with a method to convert Steam3 IDs (CSteamID) to Steam2 auth ID strings (which GoldSource uses and returns in enginefuncs_t::pfnGetPlayerAuthId).

SamVanheer commented 8 years ago

I've added an engine function to the server interface to get the first cvar pointer. This function is equivalent to cl_enginefunc_t::GetFirstCvarPtr. This will allow the server to implement cvar helpers, like a hash map to look up cvars faster or to implement a proper find command to find cvars using wildcards. I've also added a callback so the game is notified when a cvar changes.

SamVanheer commented 7 years ago

I've added a new interface called IEngineModel. This interface provides a safer and more complete way to access model data and use models: https://github.com/SamVanheer/HLEnhanced/blob/iface_proposal/shared/engine/IEngineModel.h

Basically it does what enginefuncs_t's model functions do, only without shutting the game down if anything goes wrong. It also allows direct access to an entity's model_t instance, which isn't possible on the server side.

SamVanheer commented 7 years ago

Added the OnFileSystemInit method to the client & server library interfaces for #1760.