Updating a Hash inside a module inside of array

Discussion in 'RGSSx Script Support' started by Yuuta Kirishima, May 12, 2016.

  1. Yuuta Kirishima

    Yuuta Kirishima Software Engineer/Professional Mayonnaise Player Veteran

    Messages:
    550
    Likes Received:
    131
    Location:
    North Carolina
    First Language:
    Engilsh
    Primarily Uses:
    RMMV
    From the title, you may be confused, Basically I have something like this:


    module Example
    ExampleArray = Array.new

    ExampleArray[0] = {
    "ExampleKey" => ["Stuff", "Stuff"]
    }

    ExampleArray[1] = {
    "ExampleKey2" => ["Things", "Things"]
    }
    end



    How do I go about changing the value of the keys, things i've tried:


    ExampleArray[0]["ExampleKey"] = ["new", "value"]


    Didn't work


    I even tried changing the value of the key to a global variable, and editing that variable, didn't work.


    Any help will be appreciated
     
    Last edited by a moderator: May 12, 2016
    #1
  2. chaucer

    chaucer Veteran Veteran

    Messages:
    236
    Likes Received:
    354
    Location:
    Lost at sea
    First Language:
    English
    Primarily Uses:
    RMMV
    my knowledge of ruby's alittle bit rusty, but iirc, it's not possible to update anything inside of a module, you'll either have to create the variable outside the module, or create an instance of the hash outside of the module, and modify that instance of the module.
     
    #2
  3. Sixth

    Sixth Veteran Veteran

    Messages:
    2,130
    Likes Received:
    800
    First Language:
    Hungarian
    Primarily Uses:
    RMVXA
    Those are module "constants" that you are trying to change, which is not really something you should do normally, because every time you restart your game, they will be reset to their original value.


    If you want to store your changes (and I guess you do, why else would you want to change them, right?), you must first save this module constant in a variable/object which is saved with your game. You can put it into many places, in Game_System, Game_Party, and so on, any class which gets saved is good for it. 


    To check which classes are saved by default, take a look at the DataManager module. 


    Now, because you use nested hashes and arrays, you should Marshal dump/load your module constant when you initialize it in your chosen class. This ensures that the correct values will be loaded on new game, and that you only modify the "clone" (people call these things "deep copies", or so I heard) of your module constant and not the constant itself.


    An example code would look like this:

    ExampleModule

    ExampleData = []

    ExampleData[0] = {
    "ExampleKey1" => ["stuffA","stuffB"],
    "ExampleKey2" => ["stuffC","AndSoOn"],
    }

    ExampleData[1] = {
    "ExampleA" => ["okay!","wut?"],
    }

    end

    class Game_System

    attr_accessor :example_data

    def example_data
    @example_data = Marshal.load(Marshal.dump(ExampleModule::ExampleData)) if @example_data.nil?
    return @example_data
    end

    end



    So, the above code creates that example module, same as yours. That will be the setting area, and that will be the initial value of your data later in the game.


    Basically, the module and it's constants are only used for initializing the data, it got no other purpose here (or if you don't need to change these the data in the module at all during run-time, you can use it to read the data directly from there).


    After that, we choose a class which is saved already with the game, this time, it will be Game_System. Anything inside this class is saved with your game by default.


    We define the accessor method, so that we can change the data later on from anywhere (from any other class/module).


    After that we define the method which will do 1 thing from the following:

    1. If the instance variable named @example_data is not yet defined, it will be initialized using the values from the ExampleModule's data. This means that this operation will only happen once, and never again!
    2. If we already got @example_data defined, it will simply return the value of that instance variable, which will be either the un-modified content of the ExampleData constant from the module (if you did not change the data of this variable yet in the game), or it will return the modified data (if you already modified the instance variable). Any change made to this instance variable will be saved!

    Some things to note:


    - I used the same name for the instance variable and the method name. This means that if you want to access this instance variable from outside of it's class, you can simply use the class object + the method name, in this case it would be $game_system.example_data. You would do this normally anyway with any instance variable. But if you want to access this variable inside it's own class, you will need to use self + the method name (which would look like: self.example_data) instead of simply using the name of the instance variable, because this way, it will go through the method and will initialize the variable if needed. If you would simply use the variable name, it is possible to get a NoMethodError, if you managed to call that variable before it is actually initialized.


    - I used the Marshal load/dump methods to ensure that the values of the module constant remain unchanged. If I would have used a simple clone or an even simpler direct reference to the module constant, the values of the constant would have been changed too along with our new variable in the Game_System class upon changing this new variable. This is how arrays, hashes, strings and bitmaps work (and possibly some other, less used classes as well). If you don't clone or "marshal" them, their original "self" will be changed as well if you make a change to the other reference. There is a special thing with nested arrays and hashes. Simply cloning or duping them will only clone or dup the highest level of the nest, any deeper nests inside of that will still use their original "self", so modifying them will still modify their original value. In short, just marshal them when you have these nested arrays/hashes, and you will be fine. The point of saving the original value is to ensure that, if the player exited to the title screen and started a new game, the correct values will be loaded. If you would not have marshal dump/load your data, in this case, the modified values would be loaded on the new game instead of their original values, since the original values (if changed) in a module will only be reset after a full game restart (closing the client and reopening it). 


    Okay, so now you got your data saved. To access it, you can simply use:

    • $game_system.example_data[array_index] - to get an element from your array.
    • $game_system.example_data[array_index][key_name] - to get a specific value from your hash inside the array.
    • $game_system.example_data[array_index][key_name][array_index] - to get a specific value from your array inside your hash inside the array (ouch! :p).
    • $game_system.example_data[array_index] = value - to change the value of the entire element in your array.
    • $game_system.example_data[array_index][key_name] = value - to change a specific value in your hash inside the array.
    • $game_system.example_data[array_index][key_name][array_index] = value - to change the value of the element in your array inside your hash inside the array.
    • And so on...

    And you can use these script calls from anywhere you want.


    As you can see, you were on the right track getting and changing these values (by using array indexes and key names), but depending on when you did it and when you checked it, the values could have been reset (any change will be reset when the game is restarted, because you modified the module constant and read the data from there).


    Lotsa text right? :p


    I hope it will help, my entire coffee break is gone now! :D
     
    #3
  4. Yuuta Kirishima

    Yuuta Kirishima Software Engineer/Professional Mayonnaise Player Veteran

    Messages:
    550
    Likes Received:
    131
    Location:
    North Carolina
    First Language:
    Engilsh
    Primarily Uses:
    RMMV
    You just saved me many lines of code, and it's fate that you answered this because I needed this for a  feature I queried you about almost a year ago.
     
    Last edited by a moderator: May 12, 2016
    #4

Share This Page