[Solved] Ways to acquire an AssetKey for assets

Hey there,



I previously posted this in the MirrorMonkey thread, but I’d like some additional input on the subject, perhaps from people who don’t read that thread:



My issue was that even when adding the jME - Core and jME - Engine to projects in the jME SDK, it could not find the com.jme3.asset.Asset interface when compiling. I didn’t think about that any further and added jMonkeyEngine3.jar to my build path, which still contained the desired interface.



Now when running a batch of test cases, I noticed strange RuntimeExceptions that did not occur previously, only to discover that classes like Texture and the like no longer implement the Asset interface. Instead, they implement the interface com.jme3.asset.CloneableSmartAsset.



So, has CloneableSmartAsset replaced Asset? If so, is there any default / supposed way to obtain an AssetKey for assets that don’t implement CloneableSmartAsset other than creating an own interface to provide getKey methods and extending the asset classes that jME provides?

an asset is defined only by its name, you can just create any key you want or do i understand something wrong?

1 Like

@normen

Thanks for your response. Yeah, I can just create an AssetKey with the right path to load an asset from the asset manager. The problem is with MirrorMonkey’s asset injection system, which previously obtained an asset’s AssetKey by calling Asset.getKey on the server side and serialized the path. On the client side, it created a new AssetKey with the received path, fetched the asset from the local assetManager and injected the loaded asset into constructors, methods or fields.

This still works fine because the method in the server that will initiate a constructor call will also accept AssetKeys where the injected parameter on the client side will be an Asset.



However, so far it was also supported to pass the assets as they should be injected on the client side, not their AssetKeys. Now with the Asset interface gone, I’m stuck with no method to fetch the path from which to load the asset.

Just make your own locator and give it the info you need via some special characters, e.g. assetManager.loadModel(“ModelGenerator/@Man@Armor”);

1 Like

@normen

I appreciate your input. What you suggested is already supported, though yet undocumented, but I think I have not stated clearly enough what exactly the problem is:



Currently, it is possible to initiate a constructor call in some client by calling something similar on the server:



[java]

public class SomeEntity extends SyncEntity {



@ClientSideConstructor

public SomeEntity(Asset a) {



}



}

[/java]



[java]

Asset asset = […]

// The next getKey statement is not the problem

AssetKey key = asset.getKey();

SomeEntity entity = […]



// This worked previously, and it still works

coreModule.getData(entity).callConstr(someConnection, key);

// This worked previously, but not it doesn’t

coreModule.getData(entity).callConstr(someConnection, asset);

[/java]



The second statement will not work because there is no way to acquire the path to load asset when it no longer implements Asset. You could say that I should abolish that method of calling constructors alltogether, but in the future I would like to do something like this:



[java]

public class SomeEntity implements SyncEntity {



@AutoInit

public Material mat;



@ClientSideConstructor

public SomeEntity() {

}

}

[/java]



This way, users would not have to pass unnecessary arguments to constructors any longer, because fields can be transferred from server to client automatically. With no way to fetch paths for assets that don’t implement CloneableSmartAsset (and I have to admit that Material is a bad example for this), I would have to do some working arround the issue. In any case of working arround it that I can think of, there is no way to hide everything from the user, making the use of my library unnecessarily complex.

I don’t get why you have to do all this at the AssetKey level…? You have to create these keys in the first place so why do you have to handle their data?

1 Like

Huh, what exacly are you suggesting? I know I can load from the asset manager by using paths without encapsulating them in AssetKeys, but it doesn’t ease the need to fetch paths from assets that are already present. I previously used AssetKeys because that was the way to obtain an asset’s path from the asset.



Or are you suggesting something completely different that I’m not getting?

You have a key, you load an asset. There is your connection. You can design and save it any way you like, no need to hack the Asset system to reconstruct that connection…?

Edit: If you see no other option, just set the asset key name as userData on the object after loading, e.g. spatial.setUserData(“assetKeyName”, assetKey.getName()); and later String key = spatial.getUserData(“assetKeyName”);

1 Like

@normen

But I don’t have the key, that’s the whole point. A user could load any self-defined asset or even self-defined asset classes and asset key classes and want to do asset injection on them, I don’t have any control over the user’s design other than specifying entry points, annotations and maybe a little bit of glue.

The only options I can think of at the moment are these:



[java]

public class SomeEntity {

@AssetInjection

public Material mat;



@PathForAsset(“mat”)

public String matPath;

}

[/java]

This is horrible, because it is not covered by refactoring tools and requires a lot of user-level glue.



[java]

public class SomeEntity {

@AssetInjection("/path/to/asset")

public Material mat;

}

[/java]

This would not allow users to dynamically change the asset.



[java]

public class CommonEntity {

@AssetInjection

public Material mat;

}



public class ServerEntity extends CommonEntity {

@BindFieldType(Material.class)

@BindFieldName(“mat”)

public AssetKey matKey;

}

[/java]

This would actually be possible with my current codebase, but it has the same drawbacks as the first option.



Then there is always the option of creating my own interface with something like a getAssetPath or getAssetKey method, but then again, jME’s asset loaders would not return compatible asset classes by default.



Then there’s the option of letting users register assets and their paths or keys to my framework, but that seems too complicated, especially if you keep in mind that they already loaded the asset and specified the path for jME’s AssetManager.



The option in your edit seems viable, but it only covers objects that provide a setUserData method and would still require users to set the key names themselves while still manually loading and setting the assets on the server side.



I’m sorry to throw all that stuff at you here, especially since you are not involved with the development and this is not in any way part of your responsibility, but I’ve been on and off chewing on this problem for the past few days and really feel like I have hit a dead end. I really, really appreciate your input.

1 Like

An asset can be fully recognized by the AssetManager by its path. You have to have the key at some point, else you wouldn’t have an asset. As said I think you make a mistake by trying to “hack” the asset key in the first place, just let the user specify the asset name if it can be loaded on the other side and doesn’t have to be transferred or something.

1 Like

@normen

The user has the key at some point, I don’t. Currently, it pretty much goes like this:



  • user creates asset key

  • user loads asset

  • user initializes server-local instance with loaded asset

  • user registers server-local instance by calling one of the framework's methods, creating a client-local instance on some client



I never get a hold of the AssetKey or the asset's path in the first place if I don't require the user to pass the AssetKey or its path to the framework's method. My initial intention was to erase the need to pass unnecessary parameters to the framework's method - where unnecessary parameters are parameters that would be the same for every single client that are already known as fields in the server-local instance. So if I got you right, this is not possible without either creating a hack for jME's asset system or requiring the users to call additional framework methods to register all assets that they use, thus breaking the locality principle. Is the previous sentence correct?
2 Likes
@mirrormonkey said:So if I got you right, this is not possible without either creating a hack for jME's asset system or requiring the users to call additional framework methods to register all assets that they use, thus breaking the locality principle. Is the previous sentence correct?

Yeah but if the framework is that "invasive" then doing myNetworkSyncSystem.getSyncedModel(myname); instead of assetManager.loadModel(myname); would probably be best anyway. The issue is that you try to assign this data from an arbitrary location. Generally if the system is that extensive it should right away manage the data so you first register e.g. templates with the model name, sync type etc. and then just instantiate synced instances through the system. I mean they would appear because the server said they should and the server should know the name by then. How the actual mesh/model name is defined in the first place is secondary.
2 Likes

@normen

Great idea, and it also solves some other issues with stuff I had planned for future development. Thanks a lot for your input, and most of all, for the time you invested helping me.

2 Likes

Thanks for your persistence in explaining your point without branching into personal attacks or unnecessary “education” :smiley: I now see I missed you actually mentioned basically this solution already :slight_smile:

1 Like