Access item inside Unity sharedassets.assets file programmatically in C# Mono - c#

I'm working on a Cities: Skylines mod and I want to access the sharedassets.assets file(s) the game has in the Data folder programmatically to get a mesh/prefab.
I've found a tool called Unity Assets Bundle Extractor (UABE) and it is able to open up these files and extract the mesh.
Is there a way to extract a mesh from the sharedassets programmatically with C# code like UABE does?
I've looked in the Unity documentation but so far only have seen this page (not sure if relevant): https://docs.unity3d.com/ScriptReference/AssetBundle.LoadFromFile.html
I tried adapting the code from there but I haven't had any success so far, only have had not found error messages
var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.dataPath, "sharedassets11"));
Is there a way to achieve this? Thanks

Look at the API for AssetBundle.LoadFromFile.
There is a second method AssetBundle.LoadAsset (or alternatively also maybe AssetBundle.LoadAllAssets) you will need:
var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.dataPath, "sharedassets11"));
if (myLoadedAssetBundle == null)
{
Debug.Log("Failed to load AssetBundle!");
return;
}
var prefab = myLoadedAssetBundle.LoadAsset<GameObject>("NameOfTheAccordingObject");
Instantiate(prefab);
myLoadedAssetBundle.Unload(false);

Related

I cannot get Xamarin to play small media files

Using an android scanner device, running KitKat.
Using Xamarin in Visual Studio Enterprise 2017, 15.9.9.
I need to generate a "Success" or "Error" sound, based on the content of the scanned barcode.
I have two files: "Success.mp3" and "Error.wav", neither of which will play.
Since this should be a very simple process, I am trying to use Android's MediaPlayer class, rather than add some NuGet package.
I am using Dependency Injection to properly run the Android code, since Xamarin does not have any sort or media API.
I instantiate Android's MediaPlayer as variable "player", and it does successfully instantiate, but as soon as I attempt to do anything with it, it throws a Null Exception error and the value of "player" displays as Null.
I have been experimenting with different ways to do this and have copies of the sound files stored both in the Assets folder, and the Resources/Raw folder (see below).
Here is my method:
public void PlaySound(string soundType) {
var filename =
global::Android.App.Application.Context.Assets.OpenFd(soundType);
if (player == null) {
MediaPlayer player = new MediaPlayer();
}
//This is where the error happens
player.SetDataSource(filename);
player.Prepare();
player.Start();
}
I have also tried the last three lines as the following, with the same result:
player.Prepared += (s, e) => {
player.Start();
};
player.SetDataSource(filename.FileDescriptor, filename.StartOffset,
filename.Length);
player.Prepare();
I have also attempted to utilize what so many people demonstrate as the way to do this, but it does not work for me. This is where the file must be stored in Resources/Raw:
player = MediaPlayer.Create(global::Android.App.Application.Context,
Resource.Raw.someFileName);
Whatever value that you use for "someFileName", all Visual Studio gives you is "'Resource.Raw' does not contain a definition for 'someFileName'".
Resource.designer.CS does contain entries for both files:
public const int Error = 2131230720;
public const int Success = 2131230721;
Expected results: sound, or some meaningful error message that puts me on the right path.
I am still relatively new to Xamarin and am probably missing something that would be obvious to veteran eyes. I have tried so many other things, most of which are not mentioned here, grasping for some straw. This should be simple, but is proving otherwise. Thank you for any help that you can provide.

GameObject.Find() works in editor, but returns null in build

I'm currently using GameObject.Find() to retrieve an object generated by the Mapbox Unity SDK. The code works fine in the editor, but when I build the project it returns null. The offending code is the following:
GameObject go = GameObject.Find ("16/32699/21126");
if(go != null) {
//do the thing
} else {
Debug.Log("the tile doesn't exist");
}
I've tried building in both WebGL and Native OSX, both with the same result.
in the editor, the exact name of the object I'm looking for in the scene hierarchy is 16/32699/21126. I appreciate that using the forward slash is how you search for sub-children in unity, but it seemed to work fine in the editor.
below is a screenshot of the scene hierarchy.
The behaviour script is attached to the Map object.
Do you know what could be causing this, or if there is another way of searching for the object I'm after?
You can directly access the tile through the map visualises..
example code.
UnwrappedTileId unwrappedTileId = Conversions.LatitudeLongitudeToTileId(latLon.x, latLon.y, (int)_mapManager.Zoom); //either use lat,lon or other way to get unwraptileid
var tile = _mapManager.MapVisualizer.ActiveTiles[unwrappedTileId];//_mapManager is your abstract map
//active tiles is the dictionary created by mapbox sdk to track which tiles are active
if(null!= tile)
{
myModel.transform.SetParent(tile.transform, true);
}
else
{
Debug.Log("Map tile is null");
}

How to change audio output device using VLC.Net

I am able to create media player like app using VLC.Net library. I am now trying to add a feature to be able to select the output device to play the media through. So far no luck.
Has anyone ever done it?
From reading the source code I would try the following. I assume you have a VlcMediaPlayer at hand and created somewhere:
void DoAudio(VlcMediaPlayer player)
{
IAudioManagement audioMgt = player.Audio;
foreach(AudioOutputDescriptions descriptions in audioMgt.Outputs.All){
foreach(AudioOutputDevice device in description.Devices){
//enumerate them for display
string audioName = device.LongName;
// Or set it as output
device.SetAsCurrent();
}
}

How to create a new save and load it?

What I'm trying to do:
When I press the play button appears the panel with +. I made a simple script for the + button
public void addSave()
{
if (i != 0)
{
File.Delete("Assets/Game1.unity");//If there is already a save then delete it
i = 0;
}
if (i == 0)
{
File.Copy("Assets/Game.unity", "Assets/Game1.unity");//And copy the scene to make the new one.
OpenSave.SetActive(true);
i++;
}
}
When I press on it has to load the Game1.unity but it says: "Scene 'Game1' couldn't be loaded because it has not been added to the build settings or the AssetBundle has not been loaded." So how do I add it to the build settings in the script?
I've found this but how do I make a new scene before the gameplay?
Edit: I've added the Game1.unity to build settings manually so the + button just resets the game. But maybe there is a better way to do this?
Or maybe there is a better way to do this?
You shouldn't be using scenes to save and load your game. Actually it is better to use just a master scene for everything (Unity scene system is ugly and slow).
You can use any serialization method depending on your needs such as xml, json,protocol buffers or the ones in the Asset Store. Serialization is much more flexible and manageable for these kind of things.

Untiy List.Add prevents a sprite update on Android

I have a method that gets called when a button is pressed,
private List<Page> _pages = new List<Page>();
public void LoadKern(int requestedKern)
{
TextAsset pages = Resources.Load("kern" + requestedKern) as TextAsset;
JSONArray jsonPages = JSON.Parse(pages.text)["pages"].AsArray;
foreach (JSONNode page in jsonPages)
{
_pages.Add(new Page(page["image"], page["text"]));
}
ImageSpriteRenderer.sprite = Resources.Load<Sprite>(_pages[currentPage].image);
TextSpriteRenderer.sprite = Resources.Load<Sprite>(_pages[currentPage].text);
}
The code works perfect when running it in the simulator but whenever I deploy it to an android device or use the Untiy Remote 4 it no longer updates the sprites.
Whenever I remove this line and set the resource manually, it does update when the button is pressed.
_pages.Add(new Page(page["image"], page["text"]));
It seems very odd that it does work on a desktop but not on Android, is there something I am missing?
I think it difficult to put it in the comment, so I write it as an answer here.
The simplest approach to verify this a problem due to the Resource.Load<>, is to add below code:
TextAsset pages = Resources.Load("kern" + requestedKern) as TextAsset;
Debug.Load(pages + "are Loading"); // to see if it is really loaded successfully
Connect your device and open the adb log, filter the message with "are loading".
If you see pages are null, then it is clear that Resource.Load<> is the culprit.
If it is Resource.Load<> problem, you can consider using StreamingAssets:
Any files placed in a folder called StreamingAssets in a Unity project will be copied verbatim to a particular folder on the target machine. You can retrieve the folder using the Application.streamingAssetsPath property. It’s always best to use Application.streamingAssetsPath to get the location of the StreamingAssets folder, it will always point to the correct location on the platform where the application is running.
On Android, you should use:
path = "jar:file://" + Application.dataPath + "!/assets/";
I suspect that your loading the text assets is carried out at runtime, when you package the app, the text assets are not read, and it might be excluded from the project, as Unity considers this "not used". When you run the app on Android, it is natural that it fails.
Using StreamingAssets approach, you force Unity to copy the text assets "verbatim" which assures it is accessible at runtime!

Categories

Resources