Storing self-switches in a global variable

● ARCHIVED · READ-ONLY
Started by Tsukihime 18 posts View original ↗
  1. RPG Maker stores self-switches in global variables.


    This is likely because events are not saved, and so the next time you load an event, that information will be lost.


    Self-switches are considered "local" data simply because access them requires a map ID and an event ID (along with the actual switch ID).


    If you were designing self-switches (or any sort of event-local data), how would you do it?


    For example, would you store them with the events themselves?


    Something of interest to me is why they don't just store the event data somewhere.
  2. Tsukihime said:
    Something of interest to me is why they don't just store the event data somewhere.
    Because then they won't update if, say, the event is updated in the editor after a save is initially created. You could get around that my caching them all up at the boot of the game, but even then, what if you manipulate the events somehow with a script? The current way means event data referenced is always up to date.
  3. If we're just looking into the finished game with no plans of updating events and so on, we could do save the events somewhere. Saving them makes sense, not saving them makes sense too though.
  4. Galenmereth said:
    Because then they won't update if, say, the event is updated in the editor after a save is initially created. You could get around that my caching them all up at the boot of the game, but even then, what if you manipulate the events somehow with a script? The current way means event data referenced is always up to date.
    You could selectively choose what to save, such as the things that are stored by the "character" rather than strictly the event that the character represents like position or something.


    But then I guess that's what they did with self-switches.
  5. yeah, if anything, I wonder why they didn't at least save positions... or at least allowed a checkbox to do that...
  6. If you wanted to store them on the actual events, then that means you'd have to ensure every event is saved in the save file. That's going to be a HUGE save file. I think the way the program does it now is probably the most efficient as far as keeping save file size small while keeping track of the status of every event in the game.
  7. Here's how it goes for save file size. Setting a self-switch to an array containing ["Test", 1, 7, 6, 2] 100,000 times...

    Starting save size: 12,758 bytes
    Ending save size: 1,212,861 bytes

    For a simple array with true 100,000 times...

    Starting: 12,797 bytes

    Ending:  112,828 bytes

    That isn't too bad, all things considered. I guess you could always try to stick them in a separate instance variable in Game_Map and check against a hash that way but I don't really see any advantages from doing it that way. For one thing, you'd need to figure out a way to save the local data for every map and reload it every time you change maps. By default, RM seems to load the data file for the specific map from your hard drive every time you change areas and you don't want to overwrite *that* bit of information. To make it work in a more localized fashion you'd need to rework the handling of game maps in addition to the switches, then you're coming across the next bit that isn't written to use all localized data and the next, and the next... Before you know it, you've refactored the entire RM product.
  8. To make it work in a more localized fashion you'd need to rework the handling of game maps in addition to the switches
    Your only tapping point is the part where it initializes the events for that map and make it such that if saved events exist, load those saved events rather than initializing them again from the rvdata2 file. Other than that, everything will proceed in the same way as default.
  9. Shaz said:
    If you wanted to store them on the actual events, then that means you'd have to ensure every event is saved in the save file. That's going to be a HUGE save file. I think the way the program does it now is probably the most efficient as far as keeping save file size small while keeping track of the status of every event in the game.
    Not really.

    You may of course be right in that is the reason for a premature optimization. Personally I think rather the global variable for self-switches was made following the structure of variables and normal switches. That events are not saved along probably also guiding the design. Let me show you why I call considering the save file size a premature optimization.

    I made a little experiment where I read all *.rxdata except Scripts.rxdata and put them all into a single save file. (*.rvdata2 for RPG Maker VX Ace)

    Spoiler
    Ugly code, I know.all_files = Dir['data/*']ignore_files = ['data/Scripts.rxdata']output_file = 'output/save.data' # Create 'output' folder firstfiles = all_files - ignore_filesfile_map = {}for filename in files  File.open(filename, 'rb') {|file|    file_map[filename] = file.read  }endraw_data = Marshal.dump(file_map)compressed_data = Zlib::Deflate.deflate(raw_data)p 'Raw dump size', raw_data.sizep 'Compressed size', compressed_data.sizesave_data(compressed_data, output_file)# Test that we can load the filetest_data = load_data(output_file)test_raw_data = Zlib::Inflate.inflate(test_data)test_map = Marshal.load(test_raw_data)p 'Test data', test_data.sizep 'Test raw data', test_raw_data.sizep 'Test map', test_map.keysexit
    For an example, I tried using this script on The Book of Legends, a fairly big game by Aldorlea games.

    The compressed data printed out a string of size 1037618. Yup, only a little above 1 MB. Sure, the marshalling of the string that save_data does adds a couple of bytes, but that does not change the big picture.

    Remember that this is all of the static game data, not just events. Simply saving the event locations will not cause your save to suddenly become humongous.

    *hugs*

     - Zeriab
  10. haha - I guess I am used to tiny save files.  1MB is a HUGE save file imo.  This comes from having multiple people send me their save files via email, forum attachment, etc, when testing & debugging games.

    One thing I do like about the way self switches are currently saved is that, although you've got to do it via a script call, you can change self switches on events that are on other maps.  I've never had to do that - I've only changed self switches from other events on the same map.  But it's a nice thing to be able to do if the need was there (adding the disclaimer that self switches are much more difficult to understand than regular switches and variables because they're not named, so if you're not careful, don't know what you're doing, or come back to the project after a lengthy period, you could be in for a bit of trouble).
  11. considering RM save files, yeah 1MB could pass as big. But if you compare it with like a save file for Sims 3, it's still small.

    One thing I do like about the way self switches are currently saved is that, although you've got to do it via a script call, you can change self switches on events that are on other maps.
    If we would be making events actually saved into something, then we would also be allowing to do that for anything event related. :)
  12. I think I've seen games go as high as a couple hundred MB on saves. My old Neverwinter Nights 2 saves weigh in just under 50MB a piece. The biggest files in the save folder even appear to be compressed into some type of archive. If you wanted to modify everything event related as is, couldn't you stick an autorun event that triggers every time you load the map and set it up to fire off a custom method that will then alter the $game_map.events hash according to your wishes? You could even hijack event pages and command lists regardless of setting conditions if you really wanted to. Lots of accessor methods on events in the map's hash and tons of data on every entry. Even stores the hash with event IDs as keys, it's pretty handy.

    Edit: That 1.2 million byte save size had an array a thousand times larger than I'd ever be likely to add. Each array index in that test corresponds to $game_player.reserve_transfer data along with a string to put in a choice list so the player can identify where they're selecting. Even 100 destinations would be extreme for a list of cities and dungeons you can magically teleport between. You'll need to use a *lot* of scripts storing a lot of data in saves to hit that number in practice.
  13. Your case is why I am using actual game data. Compression works really nice on such artificial structures.

    h =  []100000.times {h << ["Test", 1, 7, 6, 2]}raw_data = Marshal.dump(h)compressed_data = Zlib::Deflate.deflate(raw_data)p raw_data.size, compressed_data.sizeYup, a whooping 3153 bytes!

    Shaz said:
    haha - I guess I am used to tiny save files.  1MB is a HUGE save file imo.  This comes from having multiple people send me their save files via email, forum attachment, etc, when testing & debugging games.
    Remember that I included everything, which is way way more than just the event positions.

    So I for testing that I filled in a map point from map_id, event_id to the event's x- and y-coordinates.

    For 5422 events the resulting file did manage to crop up to a whole 28 KB. I know, I was wrong. My gut feeling was that the actualy size would be around 10-15 KB, but ah well...

    *hugs*

     - Zeriab
  14. Engr. Adiktuzmiko said:
    If we would be making events actually saved into something, then we would also be allowing to do that for anything event related. :)
    Depends on what you're saving them into. Are you saving them into a hash that's somehow keyed by map? Isn't that still going to be a global variable that contains all events for all maps? How is it different/better than a global variable just for the self switches?
  15. Exactly... What I mean is that since you're saving the events themselves, then everything else about that event is also saved and hence, you can also edit them the same way we can edit "Self Switches" right now
  16. I know it's a little off topic as a side thing, but I did just do a rather ridiculous save size test with the code Zeriab kindly provided. I calculated the first 200,000 numbers in the Fibonacci sequence and saved them. Resulted in a file that was 1,737,883,327 bytes (1.61GB). After compressing it down, the save is only 172,696 bytes (168KB). That's pretty extreme. I just want to thank Zeriab for opening my eyes to the true importance of it, going to be very useful in the future.

    As for saving the events, it may not actually be that difficult to achieve. I've been looking through events and the game interpreter a bit more. Most of the difficulty would probably come from making sure you track down every way in which events are checked or activated in various methods in order to refer it to the correct map ID in the new database. On that note, I haven't quite figured out the @starting boolean in events. It seems like all the action happens from an interpreter.setup command. Does @starting have some hidden significance I missed or is it just a value RM uses as a failsafe in various other classes?
  17. Balrogic said:
    I haven't quite figured out the @starting boolean in events. It seems like all the action happens from an interpreter.setup command. Does @starting have some hidden significance I missed or is it just a value RM uses as a failsafe in various other classes?
    Events that don't use their own interpreter but instead have the map execute the commands don't immediately start when they are able to run, especially given that the map only supports running one event at any given time, and any number of other factors that prevent an event from executing ASAP.


    The starting flag indicates that the event is ready to run, and whenever the map gets around to checking for events to run, it grabs an event with a starting flag and sets up its own interpreter with it.
  18. Gotcha! I did work out that it runs one event at a time in the map's interpreter. In order to get around it I wound up making a method that gives each affected event an interpreter, started them that way. When I tested @starting it seemed to hang my game every time I tried to start another event, whether I did it with $game_map.events[id].start or an accessor method. I didn't try it from a different interpreter until I thought of it halfway through posting this, seemed to work just fine when I did it that way. It must be some sort of problem that only happens when the map's interpreter is already running.

    Seems like it stopped hanging once I changed the setup_starting_map_event method so it doesn't do anything until the interpreter stops running.

    Edit: For conciseness.

    Edit 3: But now I can't reproduce my original problem even if I take the fix off. Grr. This could take a while. Wish I knew how I managed to break that, exactly. I don't seem to have the problematic script calls from yesterday. Giving each event it's own interpreter executes large event batches much faster, so at least it wasn't a total waste of time.