Jump to content

NVOffset - A(nother) summary of how it works


Recommended Posts

If you use the NVOffset for a particular ROM then you MUST use it for all tables based on that ROM, if you want everything to work correctly.



First a quick thanks to koadic for actually coming up with the logic for NVOffset (11 years ago - wow!)
For reference koadic's original post regarding the NVOffset function can be found here:


So why this post? I have 2 Cyclones on my setup, the "normal" version by Sliderpoint, and a dark version (my go to version) by JPSalas.


After reading Jeffs comments on Cyclone, see the "Time for a change..." section here:


I decided to try out Jeff's alternative settings on the dark version, whilst leaving the "normal" version on the factory settings.


After quite a lot of reading of other posts regarding the use of the NVOffset function, that seemed to be what I needed, however there seems to be a lot of confusion regarding it's use, strange behaviour in some cases, and lots of guess work in how to get it to work properly.


In my case at first I appeared to have it working correctly when launching VPX first, but then I discovered it didn't work when run through a frontend (this turned out to be entirely my fault, I should have read koadics post more carefully in the first place). 


So, I decided to actually look at the NVOffset function (located in core.vbs) and see how it works and see what was going wrong.


I will continue to use Cyclone/cycln_l5 in my examples below.


So how does the NVOffset function actually work? It is all described accurately in koadic's original post but I'll document it here:


  1.  NVOffset works simply by using a combination of creating, copying and renaming files.
  2. VPinMame will only ever use the nvram file that is named "romname.nv" (e.g. for Cyclone this is cycln_l5.nv).
  3. When calling the NVOffset function, an offset number is passed in to it to indicate what "version" of the nvram you want to use, e.g. NVOffset(3).
  4. Regardless of what other posts might suggest, if 0 is passed into NVOffset it does absolutely NOTHING (not really sure why it was implemented like this).
  5. The first thing NVOffset does is try and determine the GameName (or RomName depending on BS2 server version), therefore it MUST be called after the controller.GameName = cGameName usually found in Table1_Init; in fact this is what threw me,  because you can get away with calling NVOffset before setting the name if you exit a table and then restart the table without exiting VPX, but it doesn't work from a clean launch of VPX (because controller.GameName won't be set in this case).  
  6. The NVOffset function then checks to see if there is a file present with any of the following filenames "gamename v<1 thru to 32>.txt", e.g. cycln_l5 v1.txt, cycln_l5 v2.txt, cycln_l5 v3.txt etc thru to cycln_l5 v32.txt
    This file has no content and can be thought of as breadcrumb to allow the NVOffset function to know what offset was used the previous time NVOffset was called for this gamename (this knowledge will be important later on). This previous time could have been five minutes ago while scripting a table, but it could also have been months ago with many reboots in between.
  7. If the breadcrumb indicates the previous offset was the same as the current, then NVOffset does ABSOLUTELY NOTHING.
  8. If no breadcrumb is found then a breadcrumb file is created with the appropriate filename (e.g. if 3 was passed into NVOffset then the breadcrumb will be called cycln_l5 v3.txt) and the function EXITS without doing anything else, i.e. there are ABSOLUTELY NO changes made to the existing  nvram files.
  9. And the only other scenario is a breadcrumb is found but it indicates a different offset was used last time compared to the current offset requested. It is important to note that this is in fact the ONLY scenario when anything actually happens to the nvram files.

In fact this is what happens:

  1. The current breadcrumb file is renamed to reflect the current offset number, e.g cycln_l5 v1.txt is renamed to cycln_l5 v3.txt
    the implication of this is hopefully obvious - there is at most ONLY ever 1 breadcrumb file.
  2. The current nvram as used by VPINMame (e.g. cycln_l5.nv WITH NO OFFSET NUMBER) is copied to a file with a filename that includes the breadcrumb number, e.g cycln_l5.nv is copied to cycln_l5 v1.nv, this can be thought of as backing up the previous nvram settings. 
  3. The nvram file with the current offset number (if it exists) is copied to a file with the VPinMame nvram filename (replacing the existing nvram file if present), e.g. , e.g cycln_l5 v3.nv is copied to cycln_l5.nv, this can be thought of as restoring the nvram settings. If the file doesn't exists then the current nvram file remains.


And that's it. 


Based on this functionality the following observations that can be made (and hopefully explains all of the shenanigans that people have observed in the past).


  1. Hopefully this should be obvious BUT it is extremely important; if NVOffset is not called ABSOLUTELY NOTHING happens. 
  2. If nothing happens then there are no changes made to the current nvram files and VPinMame will just use whatever the current nvram file is.
  3. If the offset passed in matches the breadcrumb (and therefore the same as the previous launch) then NOTHING happens (see step 7 above).
  4. If 0 is passed into NVOffset it does ABSOLUTELY NOTHING and VPinMame will just use whatever the current nvram file is (see step 4 above).
  5. NVOffset MUST be called after the gamename/romname has been set,  i.e. after the line controller.GameName = cGameName usually found in Table1_Init (see step 5 above)
  6. If you use the NVOffset for a particular ROM then you MUST use it in all tables based on that ROM if you want it to work correctly. This isn't so that all tables pick up the same nvram settings to start with as I seem to recall being described elsewhere. It is because if you don't call NVOffset for one particular table then that table will use whatever settings happen to be in the current nvram file. This will also cause any updates to that nvram file made by VPinMame itself to later on be copied into another nvram as indicated by the breadcrumb the next time NVOffset is called (see step 9.1 above). IMO this is the most important observation.
  7. There is no concept of a parent or default nvram settings used by new tables or tables where NVOffset is not called, if you add a new table and call NVOffset with a new offset, this will inherit the settings from whatever the previous offset launched was (due to step 8 above).
  8. If you only have 2 tables sharing a rom and only one calls NVOffset then ABSOLUTELY NOTHING will ever happen (apart from the one time creation of a breadcrumb file).
  9. Offsets do not need to be sequential, they just need to be unique (if you want independent settings) and be between 1-32 inclusive.
  10. The nvram file currently being used by VPinMame (e.g. cycln_l5.nv) will also be the most up to date nvram for the offset as indicated by the breadcrumb.
    e.g. if you have these files:
    cycln_l5.nv - the nvram used by VPinMame
    cycln_l5 v1.nv
    cycln_l5 v2.nv
    cycln_l5 v2.txt - the breadcrumb used by NVOffset
    In this case the most up to date version of the nvram for offset 2 is actually cycln_l5.nv NOT cycln_l5 v2.nv



Link to comment
Share on other sites

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...