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!
Related
I am using Uno Platform to make an app which access a specific folder inside the user's Documents library from a game (BeamNG.drive). I want the app to read all the mod files inside this folder to be able to edit and display them to users on startup. I installed the Nito.Mvvm.Async Package to help me bind everything to the UI.
Here's part of the method that loads the mod files from the Documents folder:
public static async Task<List<Mod>> GetModList()
{
StorageFolder documents = await KnownFolders.DocumentsLibrary.GetFolderAsync("BeamNG.drive");
IReadOnlyList<StorageFile> fileList = await documents.GetFilesAsync();
List<Mod> foundModsList = new();
foreach (StorageFile file in fileList)
{
//...
}
return foundModsList;
}
Here's the code on MainPage.xaml.cs inside the Shared project in my solution, based on code from this answer
public NotifyTask<ObservableCollection<Mod>> ModsData { get; }
public MainPage()
{
InitializeComponent();
ModsData = NotifyTask.Create(InitModData());
}
private static async Task<ObservableCollection<Mod>> InitModData()
{
return new(await ModManager.GetModList());
}
The GetModList() method is called, but the GetFolderAsync("BeamNG.drive") method never returns, and the app keeps running normally (not UI freezes or anything). If I add a breakpoint in that line, Visual Studio stops there normally. But if I press "Step Over", instead of continuing on that method, VS jumps to this line...
return new(await ModManager.GetModList());
...then this one:
ModsData = NotifyTask.Create(InitModData());
Using ConfigureAwait(false) in any of the calls using await doesn't help anything. I'm really not sure what is going on and I suspect that Nito.Mvvm.Async might have something to do with it (considering its last update was in 2017) but I'm really not sure.
From your question it seems this problem occurs under .NET 5 - meaning targeting WebAssembly or Skia targets of Uno Platform. Under Uno, the KnownFolders type is not yet supported, so accessing DocumentLibrary is not possible. If you want to have this supported, please file an issue on Uno Platform GitHub.
In case of UWP, to access the Documents library, you need to declare a special capability in app manifest (see Docs). However, it is a restricted capability and it is quite likely that if you utilize it, the app will not pass Microsoft Store certification. Instead, it is recommended to use FolderPicker instead and let the user decide on the location when files are stored, or to use ApplicationData.Current.LocalFolder to store the data for the app privately.
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);
I'm using addressable assets to remote download a new scene from server, What I'm trying to do is to activate a play button if the addressable scene is already downloaded and in cache, and a download button if it is not in cache so that the player won't download the addressable from server every time he wants to play the scene.
I tried using Caching. IsVersionCached to check the bundle is in the cache using the bundle name but the problem here is that the name is not a good reference since in the addressable system I load the scene using Addressable. loadscene which loads the scene directly without giving any reference to the asset bundle. so the question is how to check if the scene is cached?
Here is what I tried with but it is not working since I already know that the asset bundle name won't be the good reference at least in this example.
private IEnumerator LoadRoutine()
{
var lastHash = PlayerPrefs.GetString(LAST_HASH);
if (Caching.IsVersionCached(AssetBundleHavingTheScene.name, Hash128.Parse(lastHash)))
{
Debug.Log("The Bundle is Cached i'll launch it");
Addressables.LoadScene(AddressableScene);
}
else
{
Debug.Log("Not Cached I'm going to download it");
var async = Addressables.LoadScene(AddressableScene);
while (!async.IsDone)
{
ProgressNumber.text = (async.PercentComplete * 100f).ToString("F0") + ("%");
ProgressSlider.value = async.PercentComplete;
Debug.Log(async.PercentComplete);
yield return null;
}
// At this point the scene is loaded and referenced in async.Result
Debug.Log("LOADED!");
Scene myScene = async.Result;
}
}
As far as I know, Addressable assets are automatically cached by unity and will not be downloaded twice. But you have to make sure that when you build the addressables in the unity editor, you select 'update existing build' (or similar) rather than a clean build.
But if you still want to check manually, you could use the method "Addressables.GetDownloadSizeAsync()". (Please read more about it in unity docs).
I hope it helps you a little bit.
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.
I have a c# program which open *.postfix file.
If a user runs a (.lnk)shortcut which points to my type of file, my program will open the target.
So, how could my program know it is started by a (.lnk)shortcut (and get it's file path)?
In some circumstances,i need to replace the .lnk file.
Thanks!
Edited
First, thanks to guys who answered my question.
By following #Anders answer, i find out my problem lays here.
I made some changes to windows registry, so browser knows to throw customized protocol string to certain program.
some thing like this..
[InternetShortcut]
URL=myProtocol://abcdefg.....
That's maybe why i lost lpTitle. :(
I'm going to try this way:
Whenever my program invoked, of course fed with %1, program checks current opened explorer(Window), and try to get it's current path with IWebBrowserApp. With that path and desktop of course, scan and analyze *.lnk to determine which one to replace.
I think this will probably work, but not be sure. I will try.
continued
In native code you can call GetStartupInfo, if the STARTF_TITLEISLINKNAME bit is set in STARTUPINFO.dwFlags then the path to the .lnk is in STARTUPINFO.lpTitle. I don't know if there is a .NET way to get this info, you probably have to P/Invoke...
You don't. There's no way to do it. End of story.
So this has been brought to my attention due to a recent downvote. There's an accepted answer showing an idea that gets the path to the launching shortcut most of the time. However my answer is to the whole. OP wants the link to the shortcut so he can change it. That is what can't be done most of the time.
Most likely case is the shortcut file exists in the start menu but is unwritable. However other cases involve the shortcut coming from another launching application that didn't even read it from a disk but from a database (I've seen a lot of corporate level restricted application launch tools). I also have a program that launches programs from shortcuts not via IShellLink but by parsing the .lnk file (because it must not start COM for reasons) and launching the program contained. It doesn't pass STARTF_TITLEISLINKNAME because it's passing an actual title.
If you're using Visual Studio Setup Project to build an installer and do the file type association, you should follow these instructions http://www.dreamincode.net/forums/topic/58005-file-associations-in-visual-studio/
Open up your solution in Visual studio.
Add a Setup Project to your solution by file , add project,New project, Setup & Deployment projects,Setup project
Right-click on your setup project in the "Solution Explorer" window,Select view,then select file types.
you'll see the "file types" window displayed in Visual studio.At the top of the window will be "File types on target machine"
Right-click on "File types on target machine".the menu will pop up with Add "file type" Click on this.
you'll see "New document Type#1" added,and "&open"underneath it.
The "new document type#1" can be anything you want - change it to something descriptive.although the user never sees this,never use something common- be as unique as possible,Because you can overlay current file associations without even realizing it.For example,you might think"pngfile" might be a useful name- but using that will now send all"*.png" files to your application,instead of to an image viewer.A good practice maybe "YourCompantName.Filetype",where your company name is your name of your company's name, and "Filetype" is a descriptive text of your file.
In the "properties" window for your new type,you will need to change a few properties.:
Command:Change to the application that you want to run.If you click on the "..." and you will proberly want to locate and use the "primary Output..." File
Description: This is the description of the file type(if it doesn't describe it's self"
Extensions:This your list of extensions for you chosen Program.Separate each one with a ","
Icon:This will associate the icon with your file type,This shows up in the window explorer.
Now we move to that "&open ".This is an action that is available if your right-click on the file.The default action("&Open" is currently set as the default) is what happens when you double click on the file.Right click on your "New document type#1" to add actions,but for the moment,lets define our "&open" action
Click on "&Open".You will see in the properties window "Name","Arguments","Verbs". Verb is hidden from the user,but is the key that is stored in the registry.Leave it same as the name,But without the "&".The default for"Arguments" is "%1",Which means to pass the full path and filename to your application.You can add other stuff here as well,if you need to pass flags to your application to do special stuff.All this infomaton is getting passed to your application on the command line,so you'll need to be familiar with the "Environment.CommandLine" object.
If you need to set a different action as your default,just right click on the action and "set as default"
Basically, you'll pass the file path as an argument to your program. Then if it's a console application or Windows Forms , you should check the arguments in Program.Main
static void Main(string[] args)
{
//if file association done with Arguments %1 as per forum post above
//you file path should be in args[0]
string filePath = null;
if(args != null && args.Length > 0)
filePath = args[0];
}
For a WPF application you'll need to handle that in the StartUp event for your Application
void App_Startup(object sender, StartupEventArgs e)
{
string filePath = null;
if ((e.Args != null) && (e.Args.Length > 0))
{
filePath = e.Args[0];
}
}