Load file downloaded iOS app created in Unity - c#

I'm trying to load a json file downloaded and saved in the persistentDataPath of an iOS device. The download and save works great. However I think I have big issues to load the file. In fact when I try to compile the project in Xcode I have some errors messages.
First here is my C# code :
using UnityEngine;
using System.Collections;
using System.IO;
using System.Net;
using UnityEngine.UI;
public class ReadJson : MonoBehaviour
{
public Text City;
public Text Temperature;
public Image Weather;
public Text WeatherUrl;
[System.Serializable]
public class CityInfo
{
public string name;
}
[System.Serializable]
public class CurrentCondition
{
public string date;
public string hour;
public int tmp;
public int wnd_spd;
public int wnd_gust;
public string wnd_dir;
public double pressure;
public int humidity;
public string condition;
public string icon;
public string icon_big;
}
[System.Serializable]
public class RootObject
{
public CityInfo city_info;
public CurrentCondition current_condition;
}
void Start () {
WebClient client = new WebClient();
File.Delete(Path.Combine (Application.persistentDataPath, "myjson.json"));
client.DownloadFile ("http://www.myjsonurl", Path.Combine (Application.persistentDataPath, "myjson.json"));
TextAsset asset = Resources.Load (Path.Combine (Application.dataPath + "/Documents", "myjson")) as TextAsset;
RootObject m = JsonUtility.FromJson<RootObject> (asset.text);
City.text = m.city_info.name;
Temperature.text = (m.current_condition.tmp).ToString();
}
}
And now the xcode console :
2016-10-21 17:01:20.766001 json[1404:516674] [DYMTLInitPlatform] platform initialization successful
2016-10-21 17:01:20.929950 json[1404:516508] -> registered mono modules 0xb95f70
2016-10-21 17:01:21.356590 json[1404:516508] You've implemented -[<UIApplicationDelegate> application:didReceiveRemoteNotification:fetchCompletionHandler:], but you still need to add "remote-notification" to the list of your supported UIBackgroundModes in your Info.plist.
-> applicationDidFinishLaunching()
2016-10-21 17:01:21.452967 json[1404:516508] Metal GPU Frame Capture Enabled
2016-10-21 17:01:21.453369 json[1404:516508] Metal API Validation Enabled
-> applicationDidBecomeActive()
Init: screen size 750x1334
Initializing Metal device caps
Initialize engine version: 5.3.4f1 (fdbb5133b820)
UnloadTime: 1.705875 ms
Salut/var/mobile/Containers/Data/Application/51A2490E-94EB-4904-9F2E-112AD5632A98/Documents
(Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineDebugBindings.gen.cpp Line: 37)
NullReferenceException: A null value was found where an object instance was required.
(Filename: currently not available on il2cpp Line: -1)
Setting up 1 worker threads for Enlighten.
Thread -> id: 19f17000 -> priority: 1
If someone has an idea. Thanks a lot in advance.

The problem with your code is on this line:
TextAsset asset = Resources.Load(Path.Combine(Application.dataPath + "/Documents", "myjson")) as TextAsset;
I don't think you understand how and when to use Resources.Load. If you want to use the Resources.Load function, you must create a special folder from the Editor. This folder should be at <ProjectDirectory>/Assets/Resources. You can only put/write stuff into this folder from the Editor. You can't do it after build on iOS. It becomes read only after you build it. This special folder can then be read with the Resources.Load function.
Replacing:
TextAsset asset = Resources.Load(Path.Combine(Application.dataPath + "/Documents", "myjson")) as TextAsset;
with
string text = File.ReadAllText(Path.Combine(Application.persistentDataPath, "myjson.json"));
RootObject m = JsonUtility.FromJson<RootObject>(text);
City.text = m.city_info.name;
Temperature.text = (m.current_condition.tmp).ToString();
Should solve your problem.
Another API that should not be using is WebClient. Unless you have a good reason to use that, you shouldn't. You should either use the WWW or UnityWebRequest(newer and recommended) API.
This is what your code should look like without WebClient:
void Start()
{
StartCoroutine(DownloadAndloadJson());
}
IEnumerator DownloadAndloadJson()
{
string url = "http://www.myjsonurl";
UnityWebRequest www = UnityWebRequest.Get(url);
yield return www.Send();
if (www.isError)
{
Debug.Log(www.error);
}
else
{
//Sucessfully downloaded the Json File
Debug.Log("Json: " + www.downloadHandler.text);
string jsonFile = www.downloadHandler.text;
//Delete old json file. Don't know why but this was in your original code
File.Delete(Path.Combine(Application.persistentDataPath, "myjson.json"));
//Save the downloaded data as File
File.WriteAllText(Path.Combine(Application.persistentDataPath, "myjson.json"), jsonFile);
//Load the downloaded data
string text = File.ReadAllText(Path.Combine(Application.persistentDataPath, "myjson.json"));
Debug.Log(text);
RootObject m = JsonUtility.FromJson<RootObject>(text);
City.text = m.city_info.name;
Temperature.text = (m.current_condition.tmp).ToString();
}
}
If you have problems please update to Unity 5.4. The UnityWebRequest API should be used for this and it was introduced in 5.3 but bugs were fixed in 5.4. You need using UnityEngine.Networking; to use UnityWebRequest.

Related

"The name "Asset Database" does not exist in the current context" error while building unity game [duplicate]

This question already has answers here:
UNITY - The name `AssetDatabase' does not exist in the current context
(3 answers)
Closed 2 years ago.
My teacher gave me a challenge in unity (c#) where I have to load prefabs into an array (as a GameObject[] function). The code I have works in the editor, but when I build the game, it gives me the error The name "Asset Database" does not exist in the curernt context. The code I have currently is:
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEditor;
using System;
public class FindCards : MonoBehaviour
{
public string directoryName;
public List<GameObject> foundGameObjects;
public GameObject[] ListOfCards()
{
// get the directory and the files in them
DirectoryInfo dirInfo = new DirectoryInfo(Application.dataPath + directoryName);
FileInfo[] fileInfo = dirInfo.GetFiles("*.prefab");
// loop through the files
foreach(FileInfo file in fileInfo)
{
// get the path to the directory again (with proper formatting)
string fullPath = file.FullName.Replace(#"\","/");
string assetPath = "Assets" + fullPath.Replace(Application.dataPath, "");
GameObject _asset;
// load the asset from the direcotry
_asset = AssetDatabase.LoadAssetAtPath(assetPath, typeof(GameObject)) as GameObject;
// add it to the list
foundGameObjects.Add(_asset);
Debug.Log(_asset.name);
}
// return the list as an array
return(foundGameObjects.ToArray());
}
public void SetCardProperties(string cardName, Card card)
{
// get the first string, and the int
// from the card's name
string[] sub = cardName.Split('_');
// (if the name was Diamond_07, // string name
// there would be an int = 07 and // name[0]
// a string = Diamond) // name[1]
card.suit = sub[0];
Int32.TryParse(sub[1], out card.number);
}
}
The code that is calling this function looks like this (note that this is in a different script):
private void Start()
{
canScore = true;
gameIsGoing = true;
// set up cards
cards = findCards.ListOfCards();
for (int i = 0; i < cards.Length; i++)
{
Card card = cards[i].GetComponent<Card>();
findCards.SetCardProperties(cards[i].name, card);
}
// set up deck
ResetDeck();
}
The directory here:
Prefabs in the directory
Errors here:
Errors unity gives me
I have been pulling my hair out, because there was nothing online I could find that would help me. My teacher gave this to me as challenge because he also did not know how to do it which is why I'm asking this question...
Thanks in advance!
AssetsDatabase it seems that works only in Editor. Check this thread for more info:
https://answers.unity.com/questions/1068055/assetdatabase.html
Edit:
`Resources.Load()´ search in the path: "Assets/Resources".
Look what documentation says:
If an asset can be found at path, it is returned with type T, otherwise returns null. If the file at path is of a type that cannot be converted to T, also returns null. The path is relative to any folder named Resources inside the Assets folder of your project. More than one Resources folder can be used. For example, a project may have Resources folders called Assets/Resources and ##AssetsAssetsResources##. The path does not need to include Assets and Resources in the string, for example loading a GameObject at ##AssetspathShotgun.prefab## would only require Shotgun as the path. Also, if ##AssetspathMissiles/PlasmaGun.prefab exists it can be loaded using GunspathPlasmaGun## as the path string. If you have multiple Resources folders you cannot duplicate the use of an asset name.

Error deserialising string into JSON object

I have a php file which reads a .txt file and sends it via a php server to a c# unity script. Below is a snippet of the text file showing the first 3 lines:
{ "lemma" : "aljotta", "gloss" : "Fisħ soup" }
{ "lemma" : "arguzin", "gloss" : "Slave driver" }
{ "lemma" : "armunjaka", "gloss" : "Armunjaka" }
This is the php script:
<?php
$file = fopen("lemmas.txt", "r");
echo fread($file, filesize("lemmas.txt"));
fclose($file);
?>
In a c# script, the text is returned and each line is separated into an array (string[] lines) slot as seen below:
IEnumerator GetTextFromFile()
{
bool succcessful = true;
WWWForm form = new WWWForm();
WWW www = new WWW("http://localhost:9000/tounity.php", form);
yield return www;
if(www.error != null)
{
succcessful = false;
}
else
{
succcessful = true;
}
if (succcessful)
{
populateWordList(www.text);
}
}
void populateWordList(string text)
{
string[] textArray = text.Split('\n');
wordsList = gameDatabase.GetWords(textArray);
}
The array is then passed to a method which deserializes each line into an object of class GameDatabase as seen in the image below:
public string lemma { get; set; }
public string gloss { get; set; }
public GameDatabase(string lemma, string gloss)
{
this.lemma = lemma;
this.gloss = gloss;
}
public ArrayList GetWords(string[] lines)
{
foreach (string line in lines)
{
GameDatabase gd = JsonConvert.DeserializeObject<GameDatabase>(line);
lemmasAndGlossesList.Add(new GameDatabase(gd.lemma, gd.gloss));
}
foreach(GameDatabase line in lemmasAndGlossesList)
{
Debug.Log(line.lemma + "------" + line.gloss);
}
return lemmasAndGlossesList;
}
The error occurs in GameDatabase gd = JsonConvert.DeserializeObject<GameDatabase>(line); and returns
JsonReaderException: Unexpected character encountered while parsing value: . Path '', line 0, position 0.
I have searched extensively, however, haven't found anything that works. Any help would be greatly appreciated. It is worth noting that this problem doesn't happen when loading the text file directly into unity without using php.
EDIT
When using the vs debugger this is the value in the line to be deserialized:
The JSON visualiser of Visual Studio 2019 however reports this:
Thanks to Jonathon K's comment and your reply we can see the data returned by the PHP script starts with a BOM: the first three bytes. This nice article explains how to handle such data properly. In short: use a StreamReader to read the data.
This little program demonstrates how it could work with your data:
using System;
using Newtonsoft.Json;
using System.IO;
public class Program
{
public static void Main()
{
var bytes = new byte[] {
0xEF,0xBB,0xBF,0x7B,0x20,0x22,0x6C,0x65,0x6D,0x6D,0x61,0x22,
0x20,0x3A,0x20,0x22,0x61,0x72,0x67,0x75,0x7A,0x69,0x6E,0x22,
0x2C,0x20,0x22,0x67,0x6C,0x6F,0x73,0x73,0x22,0x20,0x3A,0x20,
0x22,0x53,0x6C,0x61,0x76,0x65,0x20,0x64,0x72,0x69,0x76,0x65,
0x72,0x22,0x20,0x7D};
string json;
using(var ms = new MemoryStream(bytes))
using(var sr = new StreamReader(ms))
{
json = sr.ReadToEnd();
Console.WriteLine(json);
}
// I'm using dynamic here. In your case you can use GameDatabase
dynamic obj = JsonConvert.DeserializeObject(json);
Console.WriteLine(obj.lemma);
}
}
Output:
{ "lemma" : "arguzin", "gloss" : "Slave driver" }
arguzin
I dont know the c# sintax but this will work.
change your JSON file.
[
{ "lemma" : "aljotta", "gloss" : "Fisħ soup" },
{ "lemma" : "arguzin", "gloss" : "Slave driver" },
{ "lemma" : "armunjaka", "gloss" : "Armunjaka" }
]
apply JsonConvert.DeserializeObject to www.text
for (GameDatabase line in JsonConvert.DeserializeObject<GameDatabase[]>(www.text)){
Debug.Log(line.lemma + "------" + line.gloss);
}
Maybe my c# syntax is wrong but i would that u understand my idea
I think it's possible that you're going about deserialization wrong by using JsonConvert.
Instead, read up on this documentation and try to use the Unity functions:
https://docs.unity3d.com/Manual/JSONSerialization.html
For starters, you're defining lemma and gloss incorrectly if you're looking to use them for deserializing JSON in Unity. See this answer for more info:
Serialize and Deserialize Json and Json Array in Unity

Unity 3D: Loading FBX dynamically using AssetBundle

i am trying to load an already created FBX object into the scene at runtime, i searched around and found that assetbundle can be used to do so. I tried this code but it doesnt seem to instantiate the object in the scene and neither does it pop an error.
Here is the code
using System;
using UnityEngine;
using System.Collections;
public class CachingLoadExample : MonoBehaviour {
public string BundleURL;
public string AssetName;
public int version;
void Start() {
StartCoroutine (DownloadAndCache());
}
IEnumerator DownloadAndCache (){
// Wait for the Caching system to be ready
while (!Caching.ready)
yield return null;
// Load the AssetBundle file from Cache if it exists with the same version or download and store it in the cache
using(WWW www = WWW.LoadFromCacheOrDownload (BundleURL, version)){
yield return www;
if (www.error != null)
throw new Exception("WWW download had an error:" + www.error);
AssetBundle bundle = www.assetBundle;
if (AssetName == "")
Instantiate(bundle.mainAsset);
else
Instantiate(bundle.Load(AssetName));
// Unload the AssetBundles compressed contents to conserve memory
bundle.Unload(false);
} // memory is freed from the web stream (www.Dispose() gets called implicitly)
}
}
I added a new empty game object, dragged the C# code to that game object, supplied the asset bundle link "file://C:/Users/Sahibzada/Documents/New Unity Project/Assets/100777102370.FBX" but no luck
Can someone please guide me, whats wrong with the code, i am totally new with scripting in Unity, Thanks
Create a folder named AssetBundles inside your Assets folder, then
you need to create the AssetBundle of your FBX with an Editor script as show in: http://docs.unity3d.com/Manual/BuildingAssetBundles.html
using UnityEditor;
public class CreateAssetBundles
{
[MenuItem ("Assets/Build AssetBundles")]
static void BuildAllAssetBundles ()
{
BuildPipeline.BuildAssetBundles ("Assets/AssetBundles");
}
}
Lastly you need to introduce, in the BundleURL the URL to the new AssetsBundle:
"file://C:/Users/Sahibzada/Documents/New Unity Project/Assets/AssetsBundles/yourassetbundle"
and on the AssetName you need to introduce "yourassetbundle"
I also recommend not having paths with spaces, this can also be an issue.

How to play sounds loaded on the fly

I trying to make a tool for the sound designer of my group that would allow him to hear his sound file played in Unity.
Check if it's loadable
Check if the volume is right
Check if loops properly
and so on ...
My issue is to find how Unity can manage loading audio files laying somewhere in a folder.
I found a lot of topics speaking about it but no real solutions to how you can make Unity load external files dynamically.
If you want to load files from the same directory as the .exe / .app you can use this :
Using the System.IO DirectoryInfo() to get all files names
Using the WWW class to stream/load the files found
Here the code :
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
public class SoundPlayer : MonoBehaviour {
string absolutePath = "./"; // relative path to where the app is running
AudioSource src;
List<AudioClip> clips = new List<AudioClip>();
int soundIndex = 0;
//compatible file extensions
string[] fileTypes = {"ogg","wav"};
FileInfo[] files;
void Start () {
//being able to test in unity
if(Application.isEditor) absolutePath = "Assets/";
if(src == null) src = gameObject.AddComponent<AudioSource>();
reloadSounds();
}
void reloadSounds() {
DirectoryInfo info = new DirectoryInfo(absolutePath);
files = info.GetFiles();
//check if the file is valid and load it
foreach(FileInfo f in files) {
if(validFileType(f.FullName)) {
//Debug.Log("Start loading "+f.FullName);
StartCoroutine(loadFile(f.FullName));
}
}
}
bool validFileType(string filename) {
foreach(string ext in fileTypes) {
if(filename.IndexOf(ext) > -1) return true;
}
return false;
}
IEnumerator loadFile(string path) {
WWW www = new WWW("file://"+path);
AudioClip myAudioClip = www.audioClip;
while (!myAudioClip.isReadyToPlay)
yield return www;
AudioClip clip = www.GetAudioClip(false);
string[] parts = path.Split('\\');
clip.name = parts[parts.Length - 1];
clips.Add(clip);
}
}
[EDIT]
If people wants to improve on the file management I recommend this link

Disable vs2010 XNA Content Pipeline warning

I am building a game with XNA, and I have a custom file format for my game's levels. I want to load them and parse them myself, without using XNA's content pipeline. I have this much working, and by adding the files to the Content project I can even edit them in Visual Studio (which I also want).
The Problem: I get a warning stating "Project item 'item.lvl' was not built with the XNA Framework Content Pipeline. Set its Build Action property to Compile to build it."
I do not want XNA to Compile it, since I am doing my own parsing. How can I disable the warning?
Set the file's Build Action to None, and then set it to Copy if newer. That will cause the file to be written to the proper output directory without putting it through the Content Pipeline.
The solution could be create a custom content importer as explained here: Creating a Custom Importer and Processor. To create a simple content importer you have to inherit your class from the ContentImporter<T> (abstract class) and override the Import() method.
Here is a simple example from the msdn:
//...
using Microsoft.Xna.Framework.Content.Pipeline;
class PSSourceCode
{
const string techniqueCode = "{ pass p0 { PixelShader = compile ps_2_0 main(); } }";
public PSSourceCode(string sourceCode, string techniqueName)
{
this.sourceCode = sourceCode + "\ntechnique " + techniqueName + techniqueCode;
}
private string sourceCode;
public string SourceCode { get { return sourceCode; } }
}
[ContentImporter(".psh", DefaultProcessor = "PSProcessor", DisplayName = "Pixel Shader Importer")]
class PSImporter : ContentImporter<PSSourceCode>
{
public override PSSourceCode Import(string filename,
ContentImporterContext context)
{
string sourceCode = System.IO.File.ReadAllText(filename);
return new PSSourceCode(sourceCode, System.IO.Path.GetFileNameWithoutExtension(filename));
}
}

Categories

Resources