Jump to content

(OpenJK SP) Adding savegame values to the client and playerstate?


Recommended Posts

Posted

I've made a topic or two about this in the past and I still don't understand it very well, not to mention OpenJK has made some changes.

 

Is there anything coders should know about where to place new fields for save games? I still personally don't understand the entire client/playerstate networking and save game system even as it was in the base game, I usually just stick to copying code from other parts of the source and trying to get it to work.

 

Is there any explanation anywhere of this or of OpenJK's new system? Specifically as it pertains to the save game reading and writing, playerstate and client information contained in g_shared.h and q_shared.h?

Posted

The savegame code can be simplified down to two operations: read and write. The reason OpenJK modified the savegame code is so that the values serialize correctly on different platforms. Mac and Windows games can use the same savegames now, and so can 32bit/64bit games. How they're serialized is a complicated process that is really outside the scope of your question.

 

Savegames contain the following, in order:

  • Internal Name (COMM) - The name of the savegame
  • Screenshot (CMTM) - The screenshot of the savegame (*)
  • Gamestate (multiple) - The save file name, whether it was an autosave, ammo, health, inventory, and whether First Person Lightsaber is enabled
  • (At this point, if we are reading the savegame, the map gets loaded)
  • sv.time (TIME) (**)
  • sv.residualTime (TIMR) (**)
  • Configstrings (multiple) - Value of configstrings (**)
  • Portal State (PRTS) - Information about which areaportals are currently flagged as open, closed, etc (**)
  • (Everything past this point is modcode information, handled via ReadLevel and WriteLevel in g_savegame.cpp)

* = Only present in JK2 saves

** = Not present in autosaves

 

Savegames are always terminated with a DONE block.

 

You don't need to interact with OpenJK's specific stuff to add things to the savegame. Rather, this is what you need to edit. Add things to that table, and they'll appear in the savegame.

As you'll note, the playerstate doesn't actually show up in that table, it uses some cvars to pass around values as part of the Gamestate portion. (search for "ReadGame"/"WriteGame")

Smoo likes this
Posted

What about sg_import, sg_export, and the values declared before those functions, that are in both g_shared.h (client values) and q_shared.h (playerstate values)? What is the significance of those parts of the code?

Posted

sg_import/sg_export just describe to the serializer how the field is supposed to be handled. You need sg_import and sg_export functions on every struct/class that is in the savegame and they act like their names imply: sg_import describes how this struct gets read, and sg_export describes how this struct gets written.

Posted

So, is there any particular reason I should add a field to the playerstate instead of the client? Or vice versa? I assume it is easier to add to the client fields rather than the playerstate, but do I lose anything by doing this?

Posted

So, is there any particular reason I should add a field to the playerstate instead of the client? Or vice versa? I assume it is easier to add to the client fields rather than the playerstate, but do I lose anything by doing this?

There is no real reason, honestly. You're probably better off putting stuff in gclient_t instead of the playerstate.
Posted

So I see that in the savefields_x tables that no numeric types are directly saved, but generally only strings and pointers to structs like the client or gentity. I was wondering what the exact reason is for that? Are these values generally stored/saved under some larger structure? If so, it seems kind of hacky for me to just throw some integers in there, and I'm not sure exactly how to do that since there's no F_INT type (it's commented out in fields.h).

Posted

So I see that in the savefields_x tables that no numeric types are directly saved, but generally only strings and pointers to structs like the client or gentity. I was wondering what the exact reason is for that? Are these values generally stored/saved under some larger structure? If so, it seems kind of hacky for me to just throw some integers in there, and I'm not sure exactly how to do that since there's no F_INT type (it's commented out in fields.h).

Because those fields are the only ones that must be handled specially at least in the original code. Now the rest of the structures are handled by the new functions which were discussed above but I'm not really sure how they work. Not enough documentation was given. Look for the author of the changes maybe.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...