Guest User

HUNTERZ

a guest
Aug 21st, 2020
40
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 24.15 KB | None | 0 0
  1. Introduction
  2. Hunter’z Persistency Module is a framework designed for mission-makers looking to run campaignlike scenarios ranging from multi-session operations (MSO or similar), to survival and role-play
  3. missions, or anything that you feel would be enhanced by persistency. It is a fully customisable,
  4. offline persistency framework. In other words, it does not need complex infrastructure like SQL
  5. servers and databases. It works based on file read/writes on server machine and stores full
  6. information on vehicles and items, and player units for persistent missions. It offers reconnect
  7. persistency for players, and is especially made compatible with ACE and ACRE. It accurately restores
  8. the state of vehicles and players down to ammo count upon server restart.
  9. This module doesn’t work by just saving every vehicle/soldier existing on the battlefield. In most
  10. cases, that’s not what mission makers are after, and it’s highly inefficient. Instead, it saves whatever
  11. you want it to save. This is best described as the vehicles, ammo crates and objects (ranging from
  12. fortifications, to lamps and campfires – basically could be anything you want) that you “own”, or
  13. otherwise want to save. You achieve this by setting these objects as “persistent” through the calling
  14. of API functions described in this manual. Once you set an object as persistent, it will stay as
  15. persistent throughout your campaign, until the point it is destroyed or deleted.
  16. In addition, you are able to configure variables as persistent. Variables can be in global (aka mission
  17. namespace) or object namespace, and each will have their own API function to easily configure them
  18. as persistent. Persistent global variables can be used to store gameplay/campaign information, such
  19. as how many civilians have been killed in total, or how much money your side has, while object
  20. namespace variables can be made persistent to store “getvariable/setvariable” values together with
  21. the persistent vehicles/objects themselves, allowing you to store further information specific to
  22. different objects.
  23. Player persistency works automatically. Upon reconnecting, your character’s state will be fully
  24. restored, down to how many rounds you have left in your magazines, and your medical state if you
  25. enable ACE medical persistency through the module settings.
  26. As this is a persistency framework, it is designed for complex dynamic missions in mind. Anything
  27. you want to save, is expected to be dynamically spawned during mission execution, and not placed
  28. into the mission using the editor. For example, it’s sensible to save vehicles that you spawn or “buy”
  29. using a vehicle spawner/store, but not a vehicle that you place in the editor that always re-appears
  30. when you restart the server anyway.
  31. A Note on Persistency for User-placed Map Markers
  32. Hunter’z Persistency Module is also able to save user-placed map markers. Due to the limitations of
  33. the Arma 3 engine, only actual markers (and not lines) are able to be saved. However, since a subtle
  34. change in the Arma 3 netcode in one of the recent game updates (v1.80 if I remember right…), the
  35. server is only able to retrieve user-placed marker information from the Global Channel. It is advised
  36. to brief players on this matter, so they adjust themselves to using the Global Channel when placing
  37. markers. Any marker placed in the global channel will become automatically persistent, with no
  38. need to adjust any settings. You can also make things easier for players by disabling other channels
  39. from description.ext within your mission. For more info:
  40. https://community.bistudio.com/wiki/Description.ext#disableChannels
  41. How it Works
  42. Hunter’z Persistency Module should have no performance impact. The only time it uses resources is
  43. when it is saving to file (how often that happens is configured by you), which is a near-instant
  44. process, or when dealing with player persistency, which is also well optimised and uses server-side
  45. Disconnect/Connect eventhandlers to store and retrieve the information. Currently the only
  46. drawback is the pause-menu delay, which you see when you hit the Esc button to open your game
  47. menu while in multiplayer. This occurs because the module is configured to send any local variables
  48. from your player’s side that you configured as persistent to the server, thinking that you might be
  49. attempting to disconnect when you hit the menu. This is a very efficient way of handling the
  50. updating on the server of players’ local variables, but is a bit annoying if you for whatever reason
  51. constantly want to access your game menu while playing.
  52. In terms of how the saving works, the module uses the Debug Console Extension by Killzonekid,
  53. which is already included in this package and you don’t need to obtain it separately. This is a dll
  54. extension and allows the game to create a text file on the server’s hard-drive which effectively
  55. becomes your “save file”. The principle of saving is by autosaving like in other games. You configure
  56. how often the module conducts an autosave, and it will create a new save file every time, while
  57. keeping any older files in case they’re needed by you later.
  58. Save files will be created inside the Arma 3 installation folder on the server. The name of these files
  59. will be in the following format "debug_console(_x64)_xxxx-xx-xx_xx-xx-xx". This is a bit awkward,
  60. but it’s because that’s how the debug console names its files. The good thing is that you get a
  61. timestamp in the file name. The part with all the "x"s will be the date & time. In order to make things
  62. easier, when you restart your server, you should rename the latest save file to a name that can be
  63. recognised by the module as the save file to load from. You can also move it to another folder inside
  64. the Arma 3 installation folder to keep it separated from everything else. This is all explained in the
  65. Setup section of the manual. There is also a batch file provided in the Tools folder to allow you to
  66. automate this process, with instructions.
  67. Vehicles, Objects and Crates
  68. When you look at the API functions, you’ll realise the module defines different types of objects that
  69. you can set persistent. These go under 3 categories: vehicles, objects and crates. Essentially, there
  70. isn’t much of a difference between them, but it still helps to keep them separate. So what you have
  71. to watch out for is to use the correct function for the correct type of object. It’s simple: use vehicle
  72. functions for vehicles, use crate functions for crates or boxes that you use to hold weapons, ammo
  73. or any other items inside, and for everything else like fortifications or miscellaneous items use object
  74. functions. You need to be aware that unless you specifically set some object to be persistent by
  75. using the appropriate API function, it won’t be persistent. So if you have a vehicle spawner in your
  76. mission, for example, and you want all vehicles spawned by it to be persistent, you have to make
  77. that happen by calling Hz_pers_API_addVehicle for each new vehicle that it spawns. The same goes
  78. for a crate spawner, an object spawner, or some object that your team captures after completing a
  79. task. All of this needs to be scripted by you, as the module can’t guess what you want to achieve.
  80. Persistent Object Namespace Variables
  81. For true persistency, it’s indeed not enough to just save a bunch of objects and vehicles. While doing
  82. so will save their physical state and some other intrinsic information such as ammo content, fuel,
  83. etc., in many cases you’ll also want to save some more information along with each object. If you
  84. have a lot of custom scripts running, chances are they will be storing variables in object namespace,
  85. such as perhaps a vehicle access script that determines who is allowed to drive a particular car, using
  86. a variable called “vehicle_access” which might point to an array with names of different players. You
  87. wouldn’t want a server restart to wipe this information. The module is able to handle all of this, by
  88. letting you set any object namespace variables such as the one in the example as persistent. Object
  89. namespace variables are set globally for all persistent objects, which means when you set such a
  90. variable as persistent, it will check the existence of that variable for each persistent object. So you
  91. only need to set it once, and not for each and every object individually. It doesn’t matter if not all
  92. objects have this variable defined. It will not affect the correct functioning of the module or your
  93. scripts in any way. So to go along with the previous example, it doesn’t matter if only one of my cars
  94. has restricted access and has the variable “vehicle_access” defined. However, if I later make another
  95. one of my persistent cars have restricted access, I don’t need to redefine the “vehicle_access”
  96. variable as persistent, since it already is on the persistency list. When the module conducts a save, it
  97. will pick this up and store the information if suddenly this new vehicle also has this variable defined.
  98. So that’s how object namespace variables are made persistent. You have these kinds of variables
  99. divided into the same categories as in the previous section, with vehicles, crates and objects keeping
  100. a different list of persistent variables. In addition, you also have player variables which are object
  101. namespace variables specific to players. They work in exactly the same way, storing further
  102. information on player units if needed. All of these have their respective API commands.
  103. Persistent Mission Namespace Variables
  104. The module is also able to save any global variables, which are sometimes called “mission
  105. namespace variables”. An API command exists to configure global variables as persistent.
  106. A word of caution!
  107. Although object namespace variables don’t need to be defined for all objects (or any object for that
  108. matter), mission namespace variables that you set as persistent should always be defined! If the
  109. module attempts to save, and you previously added a global variable to be persistent, and that
  110. variable does not exist (or is nil) at the time of saving, the behaviour of the module is undefined. You
  111. will most likely get errors and the save may be unsuccessful, or even corrupted. It is your
  112. responsibility to ensure any global variables you make persistent are defined and “known” by the
  113. server at the time of saving.
  114. Undefined Variable in Logs
  115. It is advisable to check the logs for testing after you set up the module for the first time. Even if
  116. things appear to be working, there might easily be one or two things you haven’t noticed and are
  117. causing problems. However, one important thing to be aware of is that the module by default will
  118. log some errors in the RPT during loading from a save file, warning you repeatedly of an undefined
  119. return value from some array parsing functions. This is because those functions are configured to
  120. pass nil values as part of their normal operation. Those aren’t errors, so you can ignore them, but be
  121. on the lookout for any other errors mixed up in between that might be caused by your setup.
  122. Setup
  123. Setting Up the Environment
  124. Because saving is done through a dll extension, you have to make sure your server has the required
  125. C++ runtime libraries installed. The extension uses Microsoft Visual C++ 2013 Redistributable
  126. Libraries. You can obtain this from here: https://www.microsoft.com/engb/download/details.aspx?id=40784. You need to make sure both the x86 and x64 versions are
  127. installed, so be sure to download and install both of them from the link provided. You might find
  128. that you already have them installed, but it’s good to verify.
  129. One more thing to note, to get the module to work correctly, is to make sure your server has
  130. “filepatching” enabled. This is to ensure that your server is allowed to read from files outside of the
  131. mission folder, i.e. from directly inside the Arma 3 installation folder. Filepatching is disabled by
  132. default, and you must enable it manually on the server. If you don’t, your server will give you an
  133. error telling you it can’t find the save file, since it’s not allowed to look in there. To enable
  134. filepatching, use the “-filepatching” startup parameter for your server. If you have no idea what
  135. startup parameters are, then it’s time to read the wiki
  136. https://community.bistudio.com/wiki/Arma_3_Startup_Parameters.
  137. Note that if you want to conduct tests with the module in singleplayer or in the editor, you need to
  138. enable filepatching for your game too, from the Arma 3 Launcher parameters tab, since in that case
  139. you are also considered to be a “server”.
  140. Configuring Module Parameters Through the Editor
  141. Setting up the module is done through the configuration of parameters through the mission editor.
  142. To enable the module in your mission, find it in the editor modules list under the “Hz” title, and
  143. deploy it. You will see a few options here, which need to be configured correctly for the module to
  144. work.
  145. First Time Launch Handler Function
  146. The first item you see when you open up the module options is the First Time Launch Handler
  147. Function. This is the name of a function you must write and define in global namespace inside your
  148. mission. The name comes from the idea that you’re launching your persistent mission for the very
  149. first time. It is basically the main thing that will allow you to suit the module for your mission’s
  150. needs, during the mission’s first launch. This function will only be called by the module on the server
  151. the first time you run your mission, or when the module does not find a save file and assumes you
  152. want to start fresh. If it finds a save file, it will instead load your progress from there, and not call
  153. this function. You don’t have to worry about the module being too early to check for the existence of
  154. the function. In fact, the module will keep waiting and won’t proceed until this function is defined
  155. during your mission’s first launch.
  156. So what is this function really about, and what is it supposed to contain? It is inside this function that
  157. you can put your API calls to set up your persistent variables during your first launch. This function
  158. can contain any number of calls to set mission, object, crate, vehicle or player variables as persistent.
  159. These API functions are described later in this manual, and you can understand better how this all
  160. works by checking out the example mission provided. If you are reading this for the first time, I
  161. advise you to go and check out the example mission provided right now and see what the First Time
  162. Launch Handler Function is about. You can find explanations to what the API calls inside do in the
  163. later part of this manual.
  164. Important Note
  165. If you want to set more variables persistent later as your campaign progresses, changing the
  166. contents of your First Time Launch Handler Function will have no effect, since as mentioned above
  167. this function is only called at first launch of your mission, or when no save file is found. So if you
  168. want to both keep your progress, and add some new variables that should be saved, you need to be
  169. able to execute code in real-time on the server during runtime, for example by logging in as admin
  170. and using the debug console. The API functions can still be called while the mission is loaded in and
  171. running, and it will influence the next autosave. So, let’s say you have a new variable called
  172. “captured_outposts”, which you added into your mission in your latest version, and you didn’t have
  173. this in your First Time Launch Handler Function during your first launch. If you want to set this to be
  174. a persistent variable, you will have to start up your server, wait for it to load, and then use the ingame debug console, or otherwise, and execute the appropriate API call at runtime. You will notice
  175. that the next time the server saves to file, you will have this variable stored.
  176. Autosaving
  177. It is possible to set the frequency of autosaving through the module options. By default, this is 1
  178. hour. Remember that each autosave will create a new save file, without overwriting the old one. It is
  179. advisable to keep some old save files handy, in case something goes wrong down the line and you
  180. can revert your progress without losing everything and starting again.
  181. Autoloading from save file
  182. Loading is done automatically at mission start after you restart your server. As mentioned earlier,
  183. the server will attempt to load from a save file when starting up, assuming that it exists. If it can’t be
  184. found, it will run the First Time Launch Handler Function instead. You can set the delay after mission
  185. start for the autoloading to take place through the module options. It might be useful to include a
  186. relatively longer delay, if your mission has many initialisations that it needs to go through, that you
  187. want to be finished before the save file is loaded.
  188. You will have to configure the module correctly such that it finds the save file you want to load,
  189. which will in most cases be the latest save file. Since all the old saves will also be kept, you will
  190. normally have a list of save files in the Arma 3 folder after a session, each created after an autosave.
  191. The normal procedure is to take the latest save file that your last session created (the "
  192. debug_console(_x64)_xxxx-xx-xx_xx-xx-xx” thingy), rename it to something more sensible, like
  193. “lastSave” or whatever, and if you want, move it to another folder (which still should be inside the
  194. Arma 3 root folder). The critical thing here, is to make the module “know” what your save file name
  195. is and where it can be found, so that it can load it. This is done through the configuration of the
  196. parameter “Path to Save File”. A batch program exists in the tools folder of this addon, which will
  197. allow you to automate this procedure. Instructions on how to use it can also be found there.
  198. Client Loading on Reconnect
  199. Client loading describes how a player loads their saved state upon reconnecting to the server. This
  200. can be done in 2 different ways. The first mode works similarly to how the server autoloads game
  201. progress from a save file, i.e. using a delay. You configure this delay in seconds through the module
  202. options, which defines how long your game will wait after joining the game, for it to load your
  203. previous state. Again, longer delays are useful if you have loads of scripts initialising when you join in
  204. and you want them to finish initialising before loading.
  205. The second method you can use is an optimised version of the above explained method. Instead of
  206. waiting for a set amount time, the game waits for a variable on the client to become true before
  207. loading. This is useful if you don’t want to guesstimate the delay, and just want manual control over
  208. when to let it load. If you want to use this method instead, simply tick “Enable Client Manual Load”
  209. in the module options. This will override your delay setting and instead wait for you to set the
  210. variable “Hz_pers_clientReadyForLoad = true;”. You can use this at the end of your mission init
  211. script, for example, to make loading happen without any unnecessary delay, while also ensuring
  212. everything that should happen before loading has already finished.
  213. /////////////////////////////////////////////////////////////////////////////////////////////
  214. /////////////////////////////////////////////////////////////////////////////////////////////
  215. /////////////////////////////////////////////////////////////////////////////////////////////
  216. /////////////////////////////////////////////////////////////////////////////////////////////
  217. /////////////////////////////////////////////////////////////////////////////////////////////
  218. /////////////////////////////////////////////////////////////////////////////////////////////
  219. API Functions
  220. Hz_pers_API_addVehicle
  221. Use: Turns an existing vehicle persistent.
  222. Argument(s): _this: reference to object type -> object
  223. Example: _car call Hz_pers_API_ addVehicle;
  224. Hz_pers_API_addVehicleVariable
  225. Use: Makes an object namespace variable persistent for all of your persistent vehicles. Can only be
  226. called by the server. The variable does not have to be defined for all vehicles.
  227. Argument(s): _this select 0: name of variable type -> string
  228. _this select 1: variable is publicvariabled type-> bool
  229. Example: [“isLocked”, false] call Hz_pers_API_ addVehicleVariable;
  230. Hz_pers_API_addCrate
  231. Use: Turns an existing ammo crate persistent.
  232. Argument(s): _this: reference to object type -> object
  233. Example: _crate call Hz_pers_API_addCrate;
  234. Hz_pers_API_addCrateVariable
  235. Use: Makes an object namespace variable persistent for all of your persistent ammo crates. Can only
  236. be called by the server. The variable does not have to be defined for all crates.
  237. Argument(s): _this select 0: name of variable type -> string
  238. _this select 1: variable is publicvariabled type-> bool
  239. Example: [“canBeMoved”, true] call Hz_pers_API_ addCrateVariable;
  240. Hz_pers_API_addObject
  241. Use: Turns an existing object persistent.
  242. Argument(s): _this: reference to object type -> object
  243. Example: _obj call Hz_pers_API_addCrate;
  244. Hz_pers_API_addObjectVariable
  245. Use: Makes an object namespace variable persistent for persistent objects added using the
  246. Hz_pers_API_addObject function. Can only be called by the server. The variable does not have to be
  247. defined for all objects.
  248. Argument(s): _this select 0: name of variable type -> string
  249. _this select 1: variable is publicvariabled type-> bool
  250. Example: [“canBeCarried”, true] call Hz_pers_API_ addCrateVariable;
  251. Hz_pers_API_addPlayerVariable
  252. Use: Makes an object namespace variable persistent for all player units. Can only be called by the
  253. server. The variable does not have to be defined for all units.
  254. Argument(s): _this select 0: name of variable type -> string
  255. _this select 1: variable is publicvariabled type-> bool
  256. Example: [“isMedic”, false] call Hz_pers_API_ addPlayerVariable;
  257. Hz_pers_API_addMissionVariable
  258. Use: Makes a global variable persistent. Can only be called by the server. This variable must have
  259. been defined before the server attempts to save.
  260.  
  261. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  262. /////////////////////////////////////////////////////////////////////////////////////////////
  263. /////////////////////////////////////////////////////////////////////////////////////////////
  264. Argument(s): _this select 0: name of variable type -> string
  265. _this select 1: parsing descriptor type -> number
  266. _this select 2: variable is publicvariabled type -> bool
  267. The parsing descriptor is a number between 0 to 3 that is needed for the module to understand
  268. what kind of variable this is.
  269. Use 0 for anything that is not an array.
  270. If it’s an array, depending on its dimension you need to use either:
  271. 1 if it’s a one-dimensional array
  272. 2 if it’s a multidimensional array in the form [ [ ],[ ],[ ],… ]
  273. Or 3 if it’s an array of multidimensional arrays, as in [ [ [ ],[ ],[ ],… ] , [ [ ],[ ],[ ],… ], … ]
  274. It’s unlikely that you’ll have to store any data form this complex, so you’ll most likely be using either
  275. 0 or 1. However, if you don’t use the correct number, you can corrupt your save file! For example, if
  276. you put “0” there and you’ve actually got an array, it might work, but if that array grows to become
  277. very large, you’ll eventually corrupt your save file.
  278. Example: [“numberOfTasksCompleted”, 0, false] call Hz_pers_API_ addMissionVariable;
  279. [“adminNames”, 1, true] call Hz_pers_API_ addMissionVariable;
  280. Hz_pers_API_disablePlayerSaveStateOnDisconnect
  281. Use: Allows you to disable saving for a particular player. This is a useful measure to take against
  282. possible exploits related to using persistency, or in case you don’t want a player to benefit from it.
  283. Must be called from the player’s side.
  284. Argument(s): None
  285. Example: call Hz_pers_API_disablePlayerSaveStateOnDisconnect;
  286. Hz_pers_API_enablePlayerSaveStateOnDisconnect
  287. Use: Allows you to re-enable saving for a player after having disabled it using the previous function.
  288. Must be called from the player’s side.
  289. Argument(s): None
  290. Example: call Hz_pers_API_enablePlayerSaveStateOnDisconnect;
Add Comment
Please, Sign In to add comment