Marshalling objects work around

Okay so i have a map with hexes on it. My game is a strategy game so you add point values to each hex to display the size of your army on the hex. Think exactly risk the board game.

Now theres a few other blends i need to go to and come back from. When i do i need to pick up where i left off on each hex and how many points they have and who owns them.

So being a n00b i made a bge.globalDict and added every hex and those two values into it.

For hex in all_hexes:
Bge.logic.globalDict[hex] = hex[‘owner’], hex[‘points’]

I was delighted with myself until i found out game objects apparantly cant be marshalled.

Now im at a loss.
How would you do it instead?

Only store data that can be marshalled.

Python docs:

Not all Python object types are supported; in general, only objects whose value is independent from a particular invocation of Python can be written and read by this module. The following types are supported: booleans, integers, long integers, floating point numbers, complex numbers, strings, Unicode objects, tuples, lists, sets, frozensets, dictionaries, and code objects, where it should be understood that tuples, lists, sets, frozensets and dictionaries are only supported as long as the values contained therein are themselves supported; and recursive lists, sets and dictionaries should not be written (they will cause infinite loops). The singletons None, Ellipsis and StopIteration can also be marshalled and unmarshalled.

It does not include own classes or BGE objects.

You could use pickle to save/store. It supports more formats.

(be aware you will never be able to save and load game objects. This is because they are no Python objects and Python can’t create them. But you can apply stored data to an existing game object with your own Python code.)

So, I know I can apply stored data. but where would I store that data?

/uploads/default/original/4X/8/0/8/8086820e7fcf199cd958fe3b7a20d5c05cae7800.jpgstc=1

for I need to let every one of these countries know every time I come back to this map from another blend;

  1. how many points were on it last time I was in this blend.
  2. who’s ownership the country was under last time I was in this blend.

The map I’m using have somewhere near 2000 hexagon shaped territories and so I would like to be able to run a ‘for loop’ to get those two pieces of info and then run another loop to retrieve those pieces of info. Now since I can’t just jam it into a dictionary. I’m kind of at a loss.

P.S. what is pickle?

Attachments


okay so editing isn’t working for me :confused:

200, not 2000.

This point has been made elsewhere recently, but I’ll outline it again for simplicity.

You need to separate your “what” from your “how”. The BGE does many things, including rendering your models. As a user, you don’t care exactly how it does this, you just give it the colour you want, and mesh data. Apply the same logic to your game state.

The easiest way of thinking about this is to have your game state expressed some data object (class / dictionaries, whatever), and pass those to a draw_game method. This draw game method will take your “generic” gamestate data and make it interactive and visual inside the BGE.

For some games this can be taken too far, but if it’s a long term project, keeping some separation between the BGE types and your own gamestate really helps.

So, what to do…

  1. Represent your game as some combination of Python types where your tiles are stored by some ID. This ID could be their position (in some coordinate system that doesn’t rely on floating point precision), or a generic random number, or sequential number. Each tile has a position, and other data that the game relies on for the game mechanics (like who owns it, for example). You can read/write this to disk easily with JSON (which is a better suggestion than pickle for most applications).

  2. Design some specific systems to represent the game-state in the BGE. You can imagine that you’re keeping things really generic so you could easily port your game to another Python-based game engine, that helps you to keep the separation you need.
    These systems accept the gamestate (which could be a list of Tile objects (which might be simple dictionaries if you’re using a more functional programming style (which is common with people writing games in the BGE))), and generate / find the game objects associated with them and move them if they move, or update their colours etc. You can make this more performant and have your game code keep track of changes and only update the tiles with those changes, or just do things naively and update every tile every frame (expensive).

This is a sweeping overview, but you’ll be able to find out more yourself.

In short - don’t loop over gameobjects. Loop over data. If you design the map in Blender, then loop over the game objects once at the start of the game, to produce your generic gamestate data.

This is based upon the MVC (model view controller) design pattern

I use pickle to send data between scenes and to store stuff, but only in situations that are a single frame situation, not every frame*

The globaldict can be used for this, you can save anything you like really, its just a matter of setting it up correctly.

Here this script saves: name of object, points and owner(as you posted) from objects with the property ‘hex_data’.

from bge import logic

def save_hex():
    
    scene_objects   = logic.getCurrentScene().objects
    
    GD = logic.globalDict
    
    objects_array = []


    for obj in [obj for obj in scene_objects if 'hex_data' in obj]:
        
        obj_data = {}
        
        obj_data['name']    = obj.name
        obj_data['owner']   = obj['owner']
        obj_data['points']  = obj['points']
              
        objects_array.append(obj_data)


    if not 'hex' in GD:         
        GD['hex'] = {}
        
    GD['hex'] = objects_array
      
    logic.saveGlobalDict()
    
    
def load_hex():
    
    logic.loadGlobalDict()
    
    GD = logic.globalDict 
    
    if not 'hex' in GD:       
        print('*** NO SAVEGAME FOUND! ***')        
        return
    
    scene_objects = logic.getCurrentScene().objects
    saved_hexes = GD['hex']
    
    for obj in saved_hexes:
        hex_obj = scene_objects[obj['name']]
        
        hex_obj['owner']    = obj['owner'] 
        hex_obj['points']   = obj['points']

Here is a working blend:
test hex.blend (461 KB)

S to save
L to load (once saved)

#edit
i duplicated the planes, so the logic is on all 3 of em, only 1 object (doesnt matter what object) needs the logic bricks.

I suggest to search the resource forum for save/load solutions.

oooh that actually looks legit. I’mma try it. thank you.

Cotax you rock. Totally saved my bacon. Now i know how to save object dictionaries between scenes etc.

I use pickle, because I still need to save the game at some point*

I make many little lists that contain only 1 type of systems information
enemies, lamps, components etc, it makes it much easier to get your hooks into stuff, (at least for me) and you can itterate through the smaller lists without blowing up logic usage*.

You do not need pickle unless you save your data to a file. (You could use it to verify that your data is pickle-able - but if it is not you have a design problem already.)

I pickle the actor data (one actor) and send that to the inventory overylay by pickeling it, it seems to work pretty well, and speed is not a problem at all,

I save, open overlay, load pickle, and effectively sent a very large list as a message kinda, I don’t ever really use global dictionary, as most systems that store data also need to have logic to operate on the data*

In nearly all cases, pickling increases the size of the data. It doesn’t really make sense to send non-string data in a message.

Ultimately what I’m really trying to build is a proof of concept for a kickstarter or something like that so being able to legitimately save your game will have to come later. I just need to show full iterations are possible.