[SOLVED] Question about updatable asset structure


#1

Hey guys

Sorry if this has been asked before.

In default JME gradle project setup, all assets are published in one jar along with application.
For my game I need more flexible structure. I want to be able to add new assets (say new character) to game later without client needing to re download that big asset jar.
So I thought to separate my assets as packs of jars, ex character-pack, nature-pack, texture-pack, sound-pack. This time if a new character added client now only need to re download character pack (Getdown can do this automatically). But I am not happy with this approach.

Maybe it would be better to put all assets in form of one zipped file and use some form of versioning on files inside the zip, and register it to AssetManager with ZipLocator, and when there is a new update (or if player wants to buy a new character) , client application auto fetch only the new files from server, then unzip assets file in client and add new file to it and rezip it again ? Is this possible ? Anybody have better idea ?


#2

you’re trying to avoid downloading an entire pack that only updated some of its contents.

A “difference” comparator is what you’re describing, which will receive a currentVer and return a list of changed files. Then your client will download those changes and “update” a zip. Most zip utilities allow you to just overwrite without unzip, etc so there’s no need for all of that. Just give the zip the new files and it will do the rest.


#3

Thanks @jayfella, I am going to use this approach.

By any chance, do you know of any library can do this between client and server ? (probably using http/ftp protocol)

Or I better to just manually write the list of modified/added files in a change log every time I edit assets in server ?


#4

Something like this should work fine. It should be pretty easy for you to get a path and time in milliseconds of the creation date from any filesystem, so you can construct the maps automatically.

Note: it compiles but I haven’t checked it. It might be slightly off. You get the idea, I’m sure.

// <asset, time>
Map<String, Long> assets_v_1 = new HashMap<>();

assets_v_1.put("/models/tree_3.j3o", 1231243L);
assets_v_1.put("/models/tree_7.j3o", 1231243L);

Map<String, Long> assets_v_2 = new HashMap<>();
assets_v_2.put("/models/tree_3.j3o", 2231243L);
assets_v_2.put("/models/tree_8.j3o", 2231243L);

// assets that were added
Map<String, Long> additions = assets_v_2.entrySet().stream()
        .filter(entry -> !assets_v_1.containsKey(entry.getKey()))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

// assets that were removed
Map<String, Long> removals = assets_v_1.entrySet().stream()
        .filter(entry -> !assets_v_2.containsKey(entry.getKey()))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

// assets that were updated
Map<String, Long> updates = assets_v_2.entrySet().stream()
        .filter(entry -> entry.getValue() > assets_v_1.get(entry.getKey()))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));


#5

Ah, yes, I got the idea.
Thank you so much friend. :slightly_smiling_face:


#6

@Ali_RS we built a system in house for this. I would recommend having a file server (we used http). The client request a list of assets from the server which that account has access to. In the list is the asset name, the last timestamp when the asset was updated, and the md5 hash for the asset. The client then checks what it has in its repo. It keeps a list of those properties for each asset is has. Then decided if it wants to download the new asset. The server checks if the account has access to each asset that is requested. That way we can do DLC downloads (or other custom paid content) Our client also verifies files it has using the md5 to make sure the user has not modified any files.

Hope that gives you some ideas.