FWGS / xash3d-fwgs

Xash3D FWGS engine
1.56k stars 236 forks source link

Export additional server data and functions #330

Closed a1batross closed 8 months ago

a1batross commented 3 years ago

@StevenKal comment from #164


Well, exporting some global variables like "svs", "sv", and some others (cvar_vars, host...), also try to "not break" related structures (server_static, server...), I know we discussed that before and I heard your opinion about, but the fact it is not "public" is not a solid argument to break them without caring, there are a bunch of them which can be very useful for programmers and extend current possibilities, not all of the members can really be useful, but there are, like on the "sv_client_t", we can use the "pViewEntity" to get in-live the current view entity ID attached to a client (as a camera, etc.), same thing for some members of "server_t" (as checking resources...), etc..
Just to say that I do not ask you to "do not touch them", just add new members at the suite if you have to, on the previous v0.19.* you changed (even "fucked up"!!) a tons of things regarding this (this sounded like a complete rebuild of the Uncle Mike's Xash3D), while the latest v0.20 version seem more "clean", I mean, I have not looked compared in details, but it seems you kept some original parts but "extend" a lot by adding your features the right way. So seems better at first view at least.
However, if you have to change the size of an existing member (like if it is an array and you redefine it) and can not do otherwise, so be it, but for new additions, add them at the suite. I know I insist a bit, but this is because this reduce my work for the future things I have plans to do & release, which might partially use such structures.

About the functions, well, a bunch can be exported, just if I look at "server.h" and at some other files, I see a bunch of them which could be exported, like:
Cvar_DirectSet
SV_DropClient
SV_GetEntityClass (like "GetEntityInit" from that I recall)
SV_FreeEdict
SV_UpdateMovevars
SV_*Index
SV_SendResource[List]
SV_ActivateServer
SV_SpawnServer
SV_ModelHandle
SV_DeactivateServer
SV_ClientPrintf
Con_Printf
Some related to commands (SV_Kick_f, SV_Status_f, etc.)
Cbuf_Execute
Cmd_ExecuteString
Cmd_Exists
Cmd_TokenizeString
Host_Error
SV_GetClientIDString
SV_ClientBy<Id|Name>
SV_FullClientUpdate
SV_ExecuteClientMessage
SV_UpdateServerInfo
SV_RejectConnection
SV_AddToResourceList
SV_SendResources
SV_SpawnEntities
SV_StartSound

And maybe more of them...

Also, I remember seeing some kind of "partial API" for the file system, as Xash3D is not using exact original GoldSrc system, there were some kind of API at the end of "filesystem.c" file (g_fsapi exported via "FS_GetAPI" function). You could redo it like it was but fully filled, and properly export it. VALVe's file system searching at through other games paths (fallback & original "valve" directory) is good for various files (as precached files such as models, sounds, etc.).

Despite this could look "long", adding "EXPORT" label to all of those previous variables & functions I listed will probably take you like one hour, and once done it is done! You will not need to go back! Hehehe!
You could also build a structure with a functions list, a bit like guys behind Re* binaries did, and export it, but in my opinion and for my needs, adding that "EXPORT" label in order to see it via IDA in "exports" tab and find the address easily in a reliable way via "symbols", is very enough and I even prefer like this.
And about "providing hooks", well, while you do not fuck up your engine with "shitty compilers" like ReHLDS is victim, we can "memhack" those functions with ease and without troubles and I like that too.
Of course this could stil be broken if in case you change like, the format (parameters) of a function, but well, this will be the same for an "hardcoded API" where major should be changed in such case so...

But after that, for the rest, I think you can "think yourself" about which functions could be useful for third-party addons, then export them yourself, as this can be done quickly for you.

Thanks in advance.```
a1batross commented 3 years ago

@StevenKal if you don't mind, I created a new issue just for discussing new possible exports.

I'm kinda fine with that list, but how the exact function signature should look though? I remember some of them were defined differently from GoldSrc so I had to fix them.

About "svs", "sv" structures. I can't guarantee that they will not be touched at all, or new members added strictly to the end and there is serious reason for that.

For example, svgame_static_t depends on several structures that can change in the future, like Xash3D's Physic Interface. By the way, some of listed functions can be reached from that interface. (and probably listed functions can be just added to that API)

Other than that, I think I can provide a header with those structures, so you won't have to calculate offsets and just use them in code as is, so AMXMod can be just recompiled with them.

By the way, is AMXMod and modules for it opensource?

StevenKal commented 3 years ago

P1: Yeah, no problem, a new topic for API exports requests is good, so other people can also perform submissions if needed. It could even be as "pinned".

P2: Well, for the signatures, I do not know exactly, probably that depends on the compiler used and its settings, but the goal is to have reliable symbols which are not changed on update (except if you change the format of the related function, obviously, but normally even with that normal symbols matching exactly to the function name can be exported and whatever the format of the function it should remain the same. The ideal might be to have exact function name as string, like for the "PM_*" functions under the games, and with guarantee there is no "conflict" with that name used elsewhere (as string for X reason in a print, etc.), but like on recent versions of VALVe's games (from 2013 updates start by Alfred), symbols like "AddAccount__11CBasePlayerib" have changed into "_ZN11CBasePlayer10AddAccountEib". But I have to admit that having a symbol like "_Z15SV_LoadEntitiesv" instead of "SV_LoadEntities" is not a problem, and maybe even better against the conflict I talked above, and while this symbol does not change on updates, no problem neither, I am good with that.

P3: For "svs" & "sv", well, I understand, but new additions can be added at the end everytime, like for an API listing, to avoid breaking it. Because except in order to maintain a "logical order", there is no problem at adding them in the end.

P4: Yeah I looked at "svgame_static_t", where I can find for example "physics_interface_t" which point to a list of functions, this way can be good too (at least for me), but the offset of "physFuncs" needs to be "reliable" for an easy use.

P5: What do you mean about header? A public .h file with those structs? Or something else? About a header file, well, I am not much in favor of compiling AMX with those "private structures", because I attempt to provide support for all known engines, and most of them have different structures, GoldSrc has his own "server_static/server", Svengine (Sven Co-op v5. engine) has a similar one, but changed/extended, Xash3D has its own, and your old v0.19. had its own too... So I am much more in favor of having "offsets" in a file, and I have coded a data where I can handle multiple engines with ease & simplicity. So, the ideal for me, I would like I will like to have a function like: int API_GetOffset(const char szMembershipName, const char szDataName); Then I will just do: int iOffset_svgstatic_physFuncs = API_GetOffset("svgame_static_t", "physFuncs") int iOffset_svgstatic_physFuncs = API_GetOffset("server_static_t", "currentPlayer") And this returns -1 on failure (if not listed in the API), or the offset of the structure. etc. So I could push them to my data in order to guarantee reliability, and use them later with the base global variable catched via export... Also, a similar exported function could be made, which just return (void ) (function address), like: void API_GetAddress(const char szVariableOrFunctionName); Then we do: void pSVSAddress = API_GetAddress("svs"); void *pCVarDirectSetAddress = API_GetAddress("Cvar_DirectSet"); ... as alternative to an API listing we catch differently, just another method, the advantage is against possible symbols name change.

P6: Old AMX Mod versions are "open source", but I have no plans to release the one of the futures versions for multiple reasons, like I did not for my own ReAPI module I made one year ago. But I am basically interested by Xash3D [FWGS] engine since I have plans to provide an addon which could handle all different versions of the engine & games without problems in order to make the users "less afraid to put it on their server without risking to have major issues/incompatibilities/bugs/crashs..." But this is a very hard work, & a lot of tests & time. I am also interested by those Xash3D engines since I consider them more "beautiful, powerful, & extended" (about that they can handle compared to GoldSrc, like water effect HL² style, less resources limits [models, sounds...], etc.), and I almost always play the singleplayer games I discover (some on ModDB) under them, but I personnaly regret Uncle Mike did not make a Linux version, neither seems to care about improving the "multiplayer" part like you do, because I would like to see multiple servers with Xash3D and under different games... maybe it is my nostalgic side of the old-days under WON & CS v1.5! Haha! Except that, I do not care at all about Android support (no offense), I think this is for kids at school at the recreation with their 5cmX10cm cellphones! Or maybe for adults who are in waiting room for their coronashit analyzes! I know there are not only cellphones, bigger things like tablets exists under Android of course, but this still remains "small screens which kill your eyes faster", and for some reasons I do not want to be a part of it (I am not "pro-modernism", I like simplicity usually), and do not help people to be more addicted with those items everywhere they go, I want to radically separate real life & virtual one. Additionnaly to the fact I have no idea about that should I touch to AMX Mod to make it compatible with Android, I will have to figure out via some research or help and I am too lazy & busy for that! But if people like to have Xash3D + their favorites games on their cellphones, I guess this is good there is someone like you who work on that.

mittorn commented 3 years ago

The best way to export engine structures is single GET_PARM export with enums like it done in render/ref API So if we break internal structures it will not break anything But i prefer extending physic api and adding admin/security API. Check if all features already exist in physics api. It may be very useful for amxmodx. For example, it allows to pass linkents without dlsym hacking. Existing APIs really missing some functions. For example, i cannot enable pause or playersonly from server in GravGunMod and need to hack physics by increasing time to pause game in coop. Also i cannot force-enable save in multiplayer and need to add this to engine fearures. Also there are no admin-related APIs except of hlsdk apis, but i sure we need something. Using kick from cbuf to kick client does not look like very good idea

StevenKal commented 3 years ago

"The best way to export engine structures is single GET_PARM export with enums like it done in render/ref API So if we break internal structures it will not break anything..."

This way can be good too, but I personnaly see two problems: First one: I am afraid you might be like "too lazy", to implement the whole structure(s) as enum list, but only add the ones you consider useful. Second one: If those "<GET|SET>_PARAMETER" only allow coders to retrieve/alter data without having members offsets or even address of "base global variable + member" returned (so I can substract from the base global variable to get the offset myself), this annoy me and this is less interesting for me. The main reason is that I should use in my codes (C++ or even in plugins), two different methods, one using members offsets for other engines, and this one for yours, and even in plugins I should add some natives which calls those functions directly, while I could just deal with an all-in-one supporting members and with some size I could get from an API function.

So my preference really goes to a function as I suggested, which could return the offset, despite as inconvenient compared to your function, is having in the future the size of a member (or type, or name), changed, which can lead to some issues. Like if you have (on a structure): int m_iValue1[4] float m_flValue1; Changed into: int m_iValue1[8]; char szValue1[32]; float m_flValue1;

Here I can still get the size (offset difference between the two) from "m_iValue1" to "m_flValue1", but this new "szValue1" added in the middle will lead to issues for backward, one more reason why I recommend new members to always be added at the end of the list. Another problem is that if the type is changed, like: int m_iValue[4]; Into: long long m_iValue[4]; ... Not a problem for the base offset I will get via the function I suggested above, but if I check the "m_iValue[1]", I will need +4 bytes to get/set its value...

So at the end, it is clear that functions like you suggested are reliable and do not have such troubles I have explained, and are better in case of you change the structure like in the examples I specified, but if you do not touch the existing content, but only add new members at the end, I personnaly prefer having a "GetOffset" function for my needs.

However, to "fix" the issues I have specified, the function I suggested should be upgraded into something like: int API_GetOffset(const char szMembershipName, const char szDataName, const char * pszDataName, int iSizesList, int iSizesListNum, int * iSizesNumWhenArray); And we could even add a "bIsDataPointer" via reference after "pszDataName" to specify it is a member at à pointer format.

So I can push the right values to my own data without troubles, example with svgame_static_t's "msg_realsize" member: int iSizesList[10], iSizesNumWhenArray; const char * pszDataName = ""; int iOffset_svgstatic_msg_realsize = API_GetOffset("svgame_static_t", "msg_realsize", &pszDataName, iSizesList, arraysize(iSizesList), &iSizesNumWhenArray); Here I will get the base value of the offset of "svgame_static_t's "msg_realsize" member, and, in the "iSizesList[0]" the size in bytes of "int", then "iSizesNumWhenArray" returning 0 as the member is not an array.

Other example with svgame_static_t's "interp" member: int iOffset_svgstatic_interp = API_GetOffset("svgame_static_t", "interp",, &pszDataName, iSizesList, arraysize(iSizesList), &iSizesNumWhenArray); Here I will get the base value of the offset of "svgame_static_t's "interp" member, and, in the "iSizesList[0]" the size int bytes of the "sv_interp_t" structure, and in the "iSizesList[1]" the value of "MAX_CLIENTS" (as this is an array), then "iSizesNumWhenArray" returning 1 as the member is an array.

For "pszDataName", this should return as string the type of the member (used for me as information, to update my own datas properly for a later use with the right fields without problems), like "byte", "int", "float", "pointer", "structure", etc., or an enum with a list can be made too instead, there are not too much C++ types (bool, byte/char (signed/unsigned), short (signed/unsigned), integer (signed/unsigned), long long (signed/unsigned), float, double, long double) + some extras you can put like (vector, charptr, ptr, structure, edict. entvars, sv_client, etc.), as information for us about the member.

Do you get it?

But to achieve this you will probably need to build some kind of "separated board" with strings matching to the members & their informations. So maybe too much work & pain for you despite this is feasible & once done & updated too when the structures are there should not be any problem.

Maybe I am asking too much, I do not know, but well, I am just suggesting & recommending that I think should be the, at least "best for me & my needs", but that does not mean this is the best for the others or in general, and I am far to know everything in programming, so feel free to do as you prefer. Hehehe!

a1batross commented 3 years ago

tl;dr

At first, I want to recommend you opensource your work, it's the only way to give a chance to someone to fix their problems. I'm not sure who you are but there will be always different circumstances that will force you (or us) to stop working on our code.

How to make your code future-proof? Make it easy to maintain. That's why my decision on offsets and signatures is still no.

You're free to calculate offsets for your own work but we have interfaces and will work on them. But I don't I want to provide anything that will make the situation with proprietary code around the GNU GPL licensed engine worse.

a1batross commented 3 years ago

Moreover, I don't think you actually have any rights to close AMXMod source code, as it's GPL licensed. :)

StevenKal commented 3 years ago

Well, adding global variables & functions exports is already a good start, if you do it for the next "public release".

For the offsets, if you are not O.K. to provide some kind of function like the one I suggested, I will "personnaly" keep dealing the way I am get use to it for simplicity and make "all-in-one & unique" codes for my needs (so, with offsets updated when needed), or/and will wait for an API like "<GET|SET>_PARAMETER" as suggested mittorn, which will do the job but I might need to provide more API functions (usually, natives for plugins) in order to call those last as replicate. But as I said above, I am afraid to do not have all of that I might need (despite we usually do not need to use all members, because not everything can be interested for third-party addons goals), this is for example, the case on ReHLDS, for the server's interfaces structures in "public/rehlds/rehlds_interfaces.h" file.

With the members, if I have all the values, I can deal with ALL! Hehe!

a1batross commented 8 months ago

If any modders need additional data from engine, they are free to send their suggestions in pull requests and/or create new issues.