AssetManager & DLC

For adding a game DLC via the assetManager, I was thinking to do something like this:

assetManager.registerLocator("dlc/dlc.zip", ZipLocator.class);

Which works when the dlc is actually present. However, if the dlc is missing I get the exception

com.jme3.asset.AssetLoadException: Failed to open zip file: dlc/dlc.zip

so I think that before registering the location I should verify that the dlc is actually present. How should I do this test? The assetManager does not have a suitable API for that… and direct File access is not reccommended.

Maybe with a try-catch solution?

Why not?

if I remember correctly @pspeed said that AssetManager should be used over direct File access…

I’m pretty sure that the path you give to the zip locator is actually file system and not classpath specific.

The ZipLocator effectively just wraps it into a File object.

new ZipFile(new File(rootPath), ZipFile.OPEN_READ);

In which case you might as well do the same and verify it’s there first :smile:

We do something similar in our game for loading mods, we have the concept of PackedMod and UnpackedMod, one which is a zip and the other is just a folder on the file system somewhere.

We do this, but we always know the mod is there as we’ve ā€œpreloadedā€ it from the file system.

        if (mod instanceof PackedMod) {
            game.getAssetManager().registerLocator(mod.getPath().toString(), ZipLocator.class);
        } else {
            game.getAssetManager().registerLocator(mod.getPath().toString(), FileLocator.class);
        }
1 Like

Since my name was invoked… if you already know your content will be a file on the disk then it’s ok to use java.io.File to see if it’s there.

The general issue is when people think that their assets will be files on the disk and try to access them directly. Then they are disappointed when their load fails when the assets are not files on the disk.

3 Likes

IMO the try catch solution here is way easier than anything else…

I was going to say that as well, however I wasn’t sure when that exception was thrown. Is it at the point you register the locator or later when calling assetManager.loadAsset()?

later when calling assetManager.loadAsset().

Well then you should try to load a file right away when you register the locator…
If it fails, discard the DLC

…or just do:

if( new File("that-path.zip").exists() ) {
    // register the locator
}

…seems pretty clean to me.

2 Likes

Indeed. When I ā€˜liked’ your answer from 4 days ago I also implied that I was going to follow this route. The try/catch (plus loading) is slightly more verbose and convoluted, but that’s a matter of personal taste.

The try/catch is much worse because the error has already happened by the time it’s detected. If it happened when you registered the locator then that would be one thing… but if it waits until you load some asset then it’s too far removed.

Personal taste is preferring to query state rather than force an exception (expected exceptions are not exceptional to me)… and so I’d strongly agree there. But this particular case goes beyond that into creating fragile and confusing code.

2 Likes

To further elaborate on the topic: how to install the DLC? I give the download link of the DLC to my users and tell them: ā€œput file X inside folder Yā€.

Before reinventing the wheel, isn’t there some mechanism for cross-platform automagic install of files?

Maybe let them download a setup that extracts the files in user.dir/assets or so? Or you might choose a game specific folder such as Documents/My Games under windows (I don’t know about Mac OS and linux though).

Or you could even have a DLC browser inside your game and when they download / buy one, the game downloads it and puts it automatically inside the correct folder.

Why not simply request them to put the file (zip, jar) under a directory that is part of the classpath (eg app/dlc) ?

Yes, but this way each users on the same machine needs to download a copy of the DLC. %ALLUSERS% exist in windows, but how about Linux and Mac?

This might conflict with some stores (steam for example). Also, this requires an online service that somebody must run.

This is a viable option if you assume that your userbase is very small. Otherwise, be prepared to explain how to use the file manger to users. Many times… :frowning:

So I guess that the answer to my question is just ā€˜no’.

To the dev team: if I were to add an optional ā€œAdd DLCā€¦ā€ button wizard in the splash screen, and make a PR would you consider adding it to the master?

It would work like this: the AppSettings would contain another property (browse_dlc_enable with default false) that when enabled shows the ā€œAdd DLCā€¦ā€ button. When pressed, you see a file browser where you select your downloaded DLC which then gets moved in the right place.

No, I don’t think so because any solution you could provide would be extremely specific to your particular use-case. It wouldn’t work for Mythruna. It wouldn’t work for any game using normal DLC updates as part of their regular patch updates (for example getdown based projects and the like). Those are just off the top of my head.

It only handles the one tiny use case of ā€œI’m going to make my users do this manuallyā€ā€¦ which I hope is the smallest percent of the cases, personally.

Besides, you’ve just implied that they don’t know how to use a file browser and then you want them to use a file browser and somehow find where they stored the DLC? I’m not sure that makes sense but maybe I’ve missed something.

1 Like

Sorry, i guess I was not clear. if your ā€œdlcā€ directory is part of the classpath, you can search the content like any resources, so check for the content, read it and extract it.

About usage, 3 cases:

  • manual installation : yes user need to know how to download and save a file on local file system
  • steam,… : they place dlc in a predefined place choose by app or the shop, no issue (just need to be in configuration)
  • game include the download dlc (from url), then you take care of where you download

I don’t see the issue. What is your target use case and issue ?