Good Day Community,
Im Working on a silly drinking game since a few weeks. Its all fine and dandy. Worked my way through all my ideas and got it done. I was pretty proud of my self. Now hereĀ“s the kicker. The game downloads a Json file from my Nextcloud using www in Unity. The Json Holds all the Game_Cards. It worked Really well in Unity, But after i build the game, Its just doing nothing. Im pretty Sure im missing something here. But i have no Clue how to Debug it. And to be frank, i think i have Workblindness on this one. I hope its a simple fix.
What i think is going on Maybe:
Download works Fine but Json file is saved to wrong or inaccesible Path
Download is not Working at all.
Card Path:
cardPath = Application.dataPath + "/Saves/cards.json";
Download Method
IEnumerator Cards()
{
UnityWebRequest www = new UnityWebRequest("https://my.link.wich/nobody/should/know");
www.downloadHandler = new DownloadHandlerBuffer();
yield return www.SendWebRequest();
if (www.isNetworkError || www.isHttpError)
{
Debug.LogError(www.error);
}
else
{
string downloadedText = www.downloadHandler.text;
File.WriteAllText(cardPath, downloadedText);
ReadCards();
}
}
Reading Cards from Json
public void ReadCards()
{
string cardFile = File.ReadAllText(cardPath);
cardDatabase = JsonUtility.FromJson<CardListObject>(cardFile);
}
First time using StackOverflow an actually posting something. Be kind on me :D
Update
Got it Working!
I had to create the Folder first.
cardPath = Application.persistentDataPath + "/Saves/cards.json";
if (!System.IO.Directory.Exists(Application.persistentDataPath + "/Saves"))
{
System.IO.Directory.CreateDirectory(Application.persistentDataPath + "/Saves");
}
In build, you need to use Application.persistentDataPath not Application.dataPath
UPD: My bad, you are reading only if downloading. So you can ignore next part.
You need to do something in your ReadCards method in case the file does not exists, because you can have a download error and file will not be created.
For example:
public void ReadCards()
{
if (!System.IO.File.Exists(cardPath) return;
string cardFile = File.ReadAllText(cardPath);
cardDatabase = JsonUtility.FromJson<CardListObject>(cardFile);
}
Then your cardDatabase will stay with default values and you will not have a FileNotFoundException.
Related
I am attempting to get the metadata from a few music files and failing miserably. Online, there seems to be absolutely NO HOPE in finding an answer; no matter what I google. I thought it would be a great time to come and ask here because of this.
The specific error I got was: Error HRESULT E_FAIL has been returned from a call to a COM component. I really wish I could elaborate on this issue, but I'm simply getting nothing back from the COMException object. The error code was -2147467259, and it in hex is -0x7FFFBFFB, and Microsoft have not documented this specific error.
I 70% sure that its not the file's fault. My code will run through a directory full of music and convert the file into a song, hence the ConvertFileToSong name. The function would not be running if the file were to not exist is what I'm trying to say.
The only thing I can really say is that I'm using Dotnet 6, and have a massive headache.
Well, I guess I could also share another problem I had before this error showed up. Dotnet6 has top level code or whatever its called, this means that I can't add the [STAThread] attribute. To solve this, I simply added the code bellow to the top. Not sure why I have to set it to unknown, but that's what I (someone else on Stack Overflow) have to do. That solved that previous problem that the Shell32 could not start, but could that be causing my current problem? Who knows... definitely not me.
Thread.CurrentThread.SetApartmentState(ApartmentState.Unknown);
Thread.CurrentThread.SetApartmentState(ApartmentState.STA);
Here is the code:
// Help from: https://stackoverflow.com/questions/37869388/how-to-read-extended-file-properties-file-metadata
public static Song ConvertFileToSong(FileInfo file)
{
Song song = new Song();
List<string> headers = new List<string>();
// initialise the windows shell to parse attributes from
Shell32.Shell shell = new Shell32.Shell();
Shell32.Folder objFolder = null;
try
{
objFolder = shell.NameSpace(file.FullName);
}
catch (COMException e)
{
int code = e.ErrorCode;
string hex = code.ToString();
Console.WriteLine("MESSAGE: " + e.Message + ", CODE: " + hex);
return null;
}
Shell32.FolderItem folderItem = objFolder.ParseName(file.Name);
// the rest of the code is not important, but I'll leave it there anyway
// pretty much loop infinetly with a counter better than
// while loop because we don't have to declare an int on a new
// line
for (int i = 0; i < short.MaxValue; i++)
{
string header = objFolder.GetDetailsOf(null, i);
// the header does not exist, so we must exit
if (String.IsNullOrEmpty(header)) break;
headers.Add(header);
}
// Once the code works, I'll try and get this to work
song.Title = objFolder.GetDetailsOf(folderItem, 0);
return song;
}
Good night,
Diseased Finger
Ok, so the solution isn't that hard. I used file.FullName which includes the file's name, but Shell32.NameSpace ONLY requires the directory name (discluding the file name).
This is the code that fixed it:
public static Song ConvertFileToSong(FileInfo file)
{
// .....
Shell32.Shell shell = new Shell32.Shell();
Shell32.Folder objFolder = file.DirectoryName;
Shell32.FolderItem folderItem = objFolder.ParseName(file.Name);
// .....
return something;
}
So I have been trying to make it possible for users to load a .obj file and read it as an AssetBundle, but I can't figure it out.
I have figured out how to get the path of the file, but I can't load it as an asset bundle, it just returns null.
Here is my code :
WWW bundleRequest = new WWW(#"file://" + pathName);
while (!bundleRequest.isDone)
{
yield return null;
}
AssetBundle bundle = null;
if (bundleRequest.bytesDownloaded > 0)
{
AssetBundleCreateRequest myRequest = AssetBundle.LoadFromMemoryAsync(bundleRequest.bytes);
while (!myRequest.isDone)
{
Debug.Log("loading....");
yield return null;
}
if (myRequest.assetBundle != null)
{
bundle = myRequest.assetBundle;
GameObject model = null;
if (bundle != null)
{
AssetBundleRequest newRequest = bundle.LoadAssetAsync<GameObject>("Test");
while (!newRequest.isDone)
{
Debug.Log("loading ASSET....");
yield return null;
}
model = (GameObject)newRequest.asset;
bundle.Unload(false);
}
}
else
{
Debug.LogError("COULDN'T DOWNLOAD ASSET BUNDLE FROM URL");
}
}
else
{
Debug.LogError("COULDN'T DOWNLOAD ASSET BUNDLE FROM URL");
}
pathName here is: "C:\\Users\\mySuperCoolName\\OneDrive\\Documents\\Fun\\Programming\\Ungoing projects\\ThiefCop\\Unity Mobile\\Assets\\Prefabs\\TestOBJ.obj". Everything seems to work until AssetBundleCreateRequest when AssetBundle.LoadFromMemoryAsync() is called, where myRequest.assetBundle == null even if the file was downloaded correctly.
I also get an error which probably is linked with my problem : I have searched for what it meant but I couldn't find...
It is really hard to explain what I mean, but I really hope you can find an answer to this, I've been searching for hours and between us, I don't understand much of File loadind and Reading... Don't hesitate to ask if you didn't understand my bad english... Thank you in advance :)
https://docs.unity3d.com/ScriptReference/BuildPipeline.BuildAssetBundles.html
To be short :
Import your object in Unity
Give it a AssetBundle name (click on it then on bottom of the inspector view)
Call this function
for load obj files directly to you project, you need todo code what unpacks object file and then converts it to the Unity engine.
in assert store look at the Runtime OBJ Importer,
this should be right direction for your issue.
https://assetstore.unity.com/packages/tools/modeling/runtime-obj-importer-49547
I'm working on a Unity app right now, and the client wants to be able to allow the user to click a button and have a PDF open on the phone (iOS and Android), but in whatever app they use for reading PDFs and not inside of the Unity app.
I've tried Application.OpenURL("file:///[...]"), and that works in the editor on my Windows desktop (opens PDF in Edge)... but it doesn't open the file on Android (nothing happens to open the file).
Here's what I'm doing:
public string FileName = string.Empty;
public string FileExtension = string.Empty;
private string FilePath = string.Empty;
void Start()
{
FilePath = string.Format("{0}/{1}.{2}", Application.persistentDataPath, FileName, FileExtension);
}
public void OpenFile()
{
if (!File.Exists(FilePath))
{
var pathRoot = Application.streamingAssetsPath;
#if UNITY_ANDROID && !UNITY_EDITOR
pathRoot = Application.dataPath + "!/assets";
#endif
StartCoroutine(FetchFile(string.Format("{0}/{1}.{2}", pathRoot, FileName, FileExtension)));
return;
}
Application.OpenURL(FilePath);
}
private IEnumerator FetchFile(string path)
{
path = "file://" + path;
#if UNITY_ANDROID && !UNITY_EDITOR
path = "jar:" + path;
#endif
var fetcher = new WWW(path);
yield return fetcher;
File.WriteAllBytes(FilePath, fetcher.bytes);
Application.OpenURL("file:///" + FilePath);
}
So I'm checking if the file exists on the device in storage, and if not I am 'extracting' it from the app and writing it to storage. Then I try to open the local 'URL' with the file:/// standard (this Application.OpenURL("https://www.google.com"); does work successfully to open that URL in my mobile browser).
Is there a way in Unity to create an Intent or something to trigger this? The FilePath works on Windows, and is the same path I am writing the bytes to, so that should be correct... or am I missing something?
NOTE: this is also not working in iOS, but I thought I read in the Unity forums (can't find the link now) to Android being the only exception to the paths/URL thing... can anyone help me out with that, too?
If you are trying to open any document using Application.OpenURL then it won't work. Unity removed that support in latest versions. You can use AndroidOpenUrl.OpenUrl(documentUrl, dataType) to resolve this issue.
public void Example()
{
string dataType = "application/pdf";
string documentUrl = "/storage/emulated/0/Downloads/template.pdf";
AndroidOpenUrl.OpenUrl(documentUrl, dataType); // you can specify any MIME type when opening a file by explicitly specifying the dataType parameter
}
You will get a demo and installation steps of the package from the following repository.
https://github.com/codemaker2015/Unity-Android-Files-Opener
Android permissions changed in Nougat (v.7)
you won't be able to open by path only, the sistem was blocking it.
Just lower the target API level to 23 (Android 6.0 'Marshmallow').
you could just use this code as per this reference URL:
How to Open a PDF in an Android-Unity3D App?
void openPDF(){
string namePDF = "test";
TextAsset pdfTem = Resources.Load("PDFs/"+namePDF, typeof(TextAsset)) as TextAsset;
System.IO.File.WriteAllBytes(Application.persistentDataPath + "/"+namePDF+".pdf", pdfTem.bytes);
Application.OpenURL(Application.persistentDataPath+"/"+namePDF+".pdf");
}
I am trying to allow the user to Import a song using a file browser Add on from the unity store. Currently I am trying to just play the song in the menu, just to see if I have loaded it correctly but it seems I cannot get past this stage. The WWW function makes no sense to me and I will need someone to explain it very simply. In my eyes this should open the file browser, the user then selects that file, then the selected file should be loaded into the audio clip. then the debug play button should play that audio clip, but from pausing the game I can see that the file browser finds the file and has the correct string but the audio is never assigned to the clip correctly. I am using .wav and .ogg files so no problem with formats.
public FileBrowser fb = new FileBrowser();
public bool toggleBrowser = true;
public string userAudio;
public AudioSource aSource;
public AudioListener aListener;
public AudioClip aClip;
void Start()
{
if (aSource == null)
{
aSource = gameObject.AddComponent<AudioSource>();
aListener = gameObject.AddComponent<AudioListener>();
}
}
void OnGUI()
{
// File browser, cancel returns to menu and select chooses music file to load
if (fb.draw())
{
if (fb.outputFile == null)
{
Application.LoadLevel("_WaveRider_Menu");
}
else
{
Debug.Log("Ouput File = \"" + fb.outputFile.ToString() + "\"");
// Taking the selected file and assigning it a string
userAudio = fb.outputFile.ToString();
}
}
}
public void playTrack()
{
//assigns the clip to the audio source and plays it
aSource.clip = aClip;
aSource.Play();
}
IEnumerator LoadFilePC(string filePath)
{
filePath = userAudio;
print("loading " + filePath);
//Loading the string file from the File browser
WWW www = new WWW("file:///" + filePath);
//create audio clip from the www
aClip = www.GetAudioClip(false);
while (!aClip.isReadyToPlay)
{
yield return www;
}
}
}
There are a few things that may be causing you some trouble.
I'm not sure how exactly the file browser add-on works, but in the code you posted the PlayTrack() function is never called, and the LoadFilePC coroutine is never started. Even if you're loading the file correctly, it's never being assigned to the AudioSource or playing.
Try adding "playTrack();" at the end of your coroutine, and starting it using the MonoBehaviour.StartCoroutine() function after the file is selected.
Firstly I must point out that I am very new to C#.
I am developing an application using Unity3D, and part of the application requires that I parse a JSON file stored on my server.
The problem that I am having is that sometimes everything works perfectly, and other times the app hangs on the downloading the JSON. I don't receive any errors, the script just never reaches 100% on the progress.
Here is my code:
public IEnumerator DownloadJSONFile(string url)
{
Debug.Log("JSON URL: "+ url);
mJsonInfo = new WWW(url);
yield return mJsonInfo;
mIsJSONRequested = true;
}
private void LoadJSONData(string jsonUrl)
{
Debug.LogWarning("LoadJSONData, url= "+jsonUrl);
if(!mIsJSONRequested){
StartCoroutine(DownloadJSONFile(jsonUrl));
} else {
if(mJsonInfo.progress >= 1)
{
if(mJsonInfo.error == null )
{
//** PARSE THE JSON HERE **//
}else
{
Debug.LogError("Error downloading JSON");
mIsLoadingData = false;
}
} else {
Debug.LogWarning("!! ### JSON DOWNLOADING: "+mJsonInfo.progress+"%");
if(mJsonInfo.error != null )
{
Debug.LogError("Error downloading JSON");
Debug.LogError("JSON Error:"+mJsonInfo.error);
mIsLoadingData = false;
}
}
}
}
Like I said, 50% of the time the JSON data gets loaded nearly instantly, and 50% of the time the progress never reaches 1. I never receive an error in form the mJsonInfo.error variable.
Any suggestions as to what I am doing wrong would be greatly appreciated!
You need to wait until the download is complete.
As stated in the documentation you need to:
var www = new WWW(...);
yield return www;
So you need to modify the return type of your method from void to IEnumerator.
private IEnumerator LoadJSONData(string jsonUrl)
{
Debug.LogWarning("LoadJSONData, url= "+jsonUrl);
if(!mIsJSONRequested)
{
// Gets the json book info from the url
mJsonInfo = new WWW(jsonUrl);
yield return mJsonInfo; //Wait for download to complete
mIsJSONRequested = true;
}
else
{
...
}
}
isDone is that you need,
WWW lWWW = new WWW(...)
if(lWWW.isDone)
then parse it
I found the problem, I thought I would post my solution for anyone else experiencing the same problem.
The solution in the end was the JSON file on the server. I was using PHP (CakePHP) to generate the JSON, when opening the PHP generated file via the browser the response time was instant, but from my mobile app for some reason it would hang. So I changed my server side code to actually create and updated an actual JSON file, and now everything works fine.