Json file was not found in Android - c#

I am developing a game for mobile and can't create a normal save system because when playing on the phone the error is logged: Could not find the file.
I use the persistent data path as it was recommended in many answers and this method works well in Editor and Windows but not in Android.
Is there something I can do about it? Additional info: I am using IL2CPP as backend. Heard that it might create problem with serialization.
Full code:
using System;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
public class JsonFileWriter : MonoBehaviour
{
public string path;
public JsonData data;
string jsonDataString;
void Awake(){
path = Path.Combine(Application.persistentDataPath, "savegames", "data.json");
FileInfo file = new FileInfo(path);
if(!Directory.Exists(path)){
file.Directory.Create();
}
CheckFileExistance(path);
DeserializeData();
SerializeData();
}
public void SerializeData()
{
CheckFileExistance(path);
jsonDataString = JsonUtility.ToJson(data, true);
File.WriteAllText(path, jsonDataString);
Debug.Log("JSon data "+ jsonDataString);
}
public void DeserializeData()
{
string loadedJsonDataString = File.ReadAllText(path);
data = JsonUtility.FromJson<JsonData>(loadedJsonDataString);
Debug.Log("health: " + data.healthBoostAmt.ToString() + "secondChar: " + data.secondCharacterUnlocked.ToString());
}
public void WriteData(int hp,int money,int score,int damage, bool secondChar,int moneyAmt,int charSelected){
data = new JsonData(hp,money,score,damage,secondChar,moneyAmt,charSelected);
SerializeData();
}
#region Getters and seters
public int GetHealthBoosterAmt(){
DeserializeData();
return data.healthBoostAmt;
}
public int GetMoneyBoosterAmt(){
DeserializeData();
return data.moneyBoostAmt;
}
public int GetScoreBoostAmt(){
DeserializeData();
return data.scoreBoostAmt;
}
public int GetDamageBoostAmt(){
DeserializeData();
return data.damageBoostAmt;
}
public bool GetSecondCharBought(){
DeserializeData();
return data.secondCharacterUnlocked;
}
public int GetMoneyAmt(){
DeserializeData();
return data.moneyAmt;
}
public int GetSelectedCharID(){
DeserializeData();
return data.charSelected;
}
public string GetJsonDataString(){
return jsonDataString;
}
public void SetJsonDataString(string newValue){
//int hp,int money,int score,int damage, bool secondChar
data = JsonUtility.FromJson<JsonData>(newValue);
WriteData(data.healthBoostAmt,data.moneyBoostAmt,data.scoreBoostAmt,data.damageBoostAmt,data.secondCharacterUnlocked,data.moneyAmt,data.charSelected);
}
#endregion
void CheckFileExistance(string filePath){
if (!File.Exists(filePath)){
File.Create(filePath).Close();
}
}
}
[Serializable]
public class JsonData
{
public int healthBoostAmt;
public int moneyBoostAmt;
public int scoreBoostAmt;
public int damageBoostAmt;
public bool secondCharacterUnlocked;
public int moneyAmt;
public int charSelected;
public JsonData (int healthBoostAmt,int moneyBoostAmt,int scoreBoostAmt,int damageBoostAmt,bool secondCharacterUnlocked,int moneyAmt,int charSelected)
{
this.healthBoostAmt = healthBoostAmt;
this.moneyBoostAmt = moneyBoostAmt;
this.scoreBoostAmt = scoreBoostAmt;
this.damageBoostAmt = damageBoostAmt;
this.secondCharacterUnlocked = secondCharacterUnlocked;
this.moneyAmt = moneyAmt;
this.charSelected = charSelected;
}
public JsonData (){}
}

Related

Unity3d - IntemDatabase.cs gives an error (FormatException: Input string was not in the correct format)

G'day,
I am currently working on a Unity3d project and get this error while working on the ItemDatabase.cs file. The code looks fine to me but I get the error for some reason. Could I please get some help with fixing the error.
Thanks,
https://i.stack.imgur.com/xUETY.png
ItemDatabase.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
[System.Serializable]
public struct Item
{
public int ID;
public string Name;
public bool Stackable;
public string Slug;
public Item(int id, string name, bool stackable, string slug){
ID = id;
Name = name;
Stackable = stackable;
Slug = slug;
}
}
public class ItemDatabase : MonoBehaviour {
public List<Item> itemDatabase = new List<Item>();
// Use this for initialization
void Start () {
GetDatabase("Assets/Resources/ItemData.txt");
}
// Update is called once per frame
void Update () {
}
void GetDatabase(string path)
{
StreamReader sr = new StreamReader(path);
AddItem:
itemDatabase.Add(new Item(
int.Parse(sr.ReadLine().Replace("id", "")),
sr.ReadLine().Replace("name: ",""),
bool.Parse(sr.ReadLine().Replace("stackable: ","")),
sr.ReadLine().Replace("slug: ","")
));
string c = sr.ReadLine();
if(c == ",")
{
goto AddItem;
}
else if(c == ";")
{
sr.Close();
}
}
}
The error message here is quite explicit in what it's telling you - you're calling int.Parse() on a string that it can't recognise as an integer value here:
itemDatabase.Add(new Item(
int.Parse(sr.ReadLine().Replace("id", "")),
sr.ReadLine().Replace("name: ",""),
bool.Parse(sr.ReadLine().Replace("stackable: ","")),
sr.ReadLine().Replace("slug: ","")
));
You're going to need to double-check what input you are passing to GetDatabase and go from there.

Unity json data from server returns null

I have a problem, where Json data is taken from server and then called out, but always outputs NULL. You can test code if you want to, Url is public.
This is Json data that I get from server
[{"id":"3","question":"Cik ir 4 + 4 = ?","answer1":"3","answer2":"13","answer3":"7","answer4c":"8"}]
How do I fix this, so Json data outputs correctly?
Thank you.
using System.Collections;
using System.Collections.Generic;
using System.Net.Mime;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System;
public class Code : MonoBehaviour
{
public Text first;
public const string URLBase = "http://91.200.67.104:8080/test/json.php";
[System.Serializable]
public class Results
{
public string id;
public string question;
public string answer1;
public string answer2;
public string answer3;
public string answer4c;
}
void Start()
{
StartCoroutine(Run());
}
IEnumerator Run()
{
var req = CreateReturnPlayerDataRequest();
yield return req.SendWebRequest();
var results = HandleReturnPlayerDataRequest(req);
first.text = results.id + " dasdasdas " + results.question;
}
public static UnityWebRequest CreateReturnPlayerDataRequest()
{
var req = UnityWebRequest.Get(URLBase);
return req;
}
public static Results HandleReturnPlayerDataRequest(UnityWebRequest req)
{
if (req.isNetworkError)
{
Debug.LogError("Failed to POST /player/register");
return new Results();
}
// Debug izvada datus console
Debug.Log("{\"Results\":" + req.downloadHandler.text + "}");
Results results = JsonUtility.FromJson<Results>("{\"Results\":" + req.downloadHandler.text + "}");
Debug.Log("ID:" + results.id + " ;question: " + results.question + " ; " + results.answer1);
Debug.Log(results.id);
Debug.Log(results.question);
Debug.Log(results.answer1);
return results;
}
}
Your deserialization class structure is incorrect.
Firstly, the json data you are receiving from the server is an array/collection (it is surrounded by square brackets "[ ]").
Secondly, you are placing it in the "Results" field of a parent object.
Therefore, this would be the correct structure:
[System.Serializable]
public class RootObject
{
public List<Results> Results;
}
[System.Serializable]
public class Results
{
public string id;
public string question;
public string answer1;
public string answer2;
public string answer3;
public string answer4c;
}
Usage:
var obj = JsonUtility.FromJson<RootObject>("{\"Results\":" + req.downloadHandler.text + "}");
Results serverData = obj.Results[0];

Loading XML document loads the same group twice

Some classes to start, I'm writing them all so you can reproduce my problem:
public class PermissionObject
{
public string permissionName;
public string permissionObject;
public bool permissionGranted;
public PermissionObject()
{
permissionName = "";
permissionObject = "";
permissionGranted = true;
}
public PermissionObject(string name, string obj, bool granted)
{
permissionName = name;
permissionObject = obj;
permissionGranted = granted;
}
}
public class Config
{
public string cmsDataPath = "";
public string cmsIP = "";
public List<UserClass> usersCMS = new List<UserClass>();
static public string pathToConfig = #"E:\testconpcms.xml";
public string cardServerAddress = "";
public void Save()
{
XmlSerializer serializer = new XmlSerializer(typeof(Config));
using (Stream fileStream = new FileStream(pathToConfig, FileMode.Create))
{
serializer.Serialize(fileStream, this);
}
}
public static Config Load()
{
if (File.Exists(pathToConfig))
{
XmlSerializer serializer = new XmlSerializer(typeof(Config));
try
{
using (Stream fileStream = new FileStream(pathToConfig, FileMode.Open))
{
return (Config)serializer.Deserialize(fileStream);
}
}
catch (Exception ex)
{
return new Config();
}
}
else
{
return null;
}
}
}
public class UserClass
{
public string Name;
public string Login;
public string Password;
public PCMS2 PermissionsList; // OR new PCMS1, as I will explain in a bit
public UserClass()
{
this.Name = "Admin";
this.Login = "61-64-6D-69-6E";
this.Password = "61-64-6D-69-6E";
this.PermissionsList = new PCMS2(); // OR new PCMS1, as I will explain in a bit
}
}
The problematic bit: consider two implementations of PCMS class, PCMS1 and PCMS2:
public class PCMS1
{
public PermissionObject p1, p2;
public PCMS1()
{
p1 = new PermissionObject("ImportConfigCMS", "tsmiImportCMSConfigFile", true);
p2 = new PermissionObject("ExportConfigCMS", "tsmiExportCMSConfigFile", true);
}
}
public class PCMS2
{
public List<PermissionObject> listOfPermissions = new List<PermissionObject>();
public PCMS2()
{
listOfPermissions.Add(new PermissionObject("ImportConfigCMS", "tsmiImportCMSConfigFile", true));
listOfPermissions.Add(new PermissionObject("ExportConfigCMS", "tsmiExportCMSConfigFile", true));
}
}
And finally main class:
public partial class Form1 : Form
{
private Config Con;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Con = Config.Load();
if (Con == null)
{
Con = new Config();
Con.cmsDataPath = #"E:\testconpcms.xml";
Con.Save();
}
if (Con.usersCMS.Count == 0)
{
UserClass adminDefault = new UserClass();
Con.usersCMS.Add(adminDefault);
Con.Save();
}
}
}
Now, using either PCMS1 or PCMS2, the config file generates properly - one user with 2 permissions.
However, when config file is present, calling Con = Config.Load() in the main class gives different results.
Using PCMS1, the Con object is as expected - 1 user with 2 permissions.
However, using PCMS2, the Con object is 1 user with 4 (four) permissions. It doubles that field (it's basically p1, p2, p1, p2). Put a BP to see Con after Load().
I guess the list (PCMS2) implementation is doing something wonky during load which I'm not aware of, but I can't seem to find the issue.
You creates your permission objects in constructor of PMCS2 you do it in the constructor of PMCS1 too, but there you do have two properties that will be overwritten by serializer.
In case of of PMCS2 your constructor adds two items to List and than serializer adds the items it has deserilized to the same list.
I don't know exactly your usecase but i would suggest to move init of the permissions to separated method:
public class PCMS1
{
public PermissionObject p1, p2;
public void Init()
{
p1 = new PermissionObject("ImportConfigCMS", "tsmiImportCMSConfigFile", true);
p2 = new PermissionObject("ExportConfigCMS", "tsmiExportCMSConfigFile", true);
}
}
public class PCMS2
{
public List<PermissionObject> listOfPermissions = new List<PermissionObject>();
public void Init()
{
listOfPermissions.Add(new PermissionObject("ImportConfigCMS", "tsmiImportCMSConfigFile", true));
listOfPermissions.Add(new PermissionObject("ExportConfigCMS", "tsmiExportCMSConfigFile", true));
}
}
after that you could call it, if you want to get initial settings:
if (Con.usersCMS.Count == 0)
{
UserClass adminDefault = new UserClass();
adminDefault.PermissionsList.Init();
Con.usersCMS.Add(adminDefault);
Con.Save();
}

"InvalidCastException: Cannot cast from source type to destination type." when loading serialized data

I'd sincerely appreciate if you looked through some of my code as I can't seem to be able to fix it myself, and this will also hopefully help others understand serialization better.
I have four pieces of related code here, with anything seemingly irrelevant cut out. I'm trying to create a user profile in a set up where the user then chooses from a range of games to play. Only options/settings for the chosen games, in this case something to do with a fish, are saved.
The error in the title occurs in the 4th section [feel free to skip to that] which is the OptionsController.LoadOptions() function at
FishData.Store data = (FishData.Store)bf.Deserialize(fileOpt);
I have this at the top of all following sections:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
1) Profile data structure:
public class Profile { //Profile variables
public static string id;
public static string name;
public static string dob;
public static bool fishEnabled;
public static bool birdEnabled;
public static string stringTest;
[System.Serializable]
public class Store { //Profile variables
public string id;
public string name;
public string dob;
public bool fishEnabled;
public bool birdEnabled;
public string stringTest;
}
}
2) Fish data structure:
public class FishData { //static Fish variables to be used in game
public static bool sizeInc;
public static bool speedInc;
public static int level;
public static bool toxic;
public static bool handLeft;
public static bool timer;
public static int timerVal;
public static int percentReq;
public static int successReq;
public static string testStringTwo;
public static List<StatController.Session> sessions = new List<StatController.Session>();
[System.Serializable]
public class Store { //non static variable set for serialization
public bool sizeInc;
public bool speedInc;
public int level;
public bool toxic;
public bool handLeft;
public bool timer;
public int timerVal;
public int percentReq;
public int successReq;
public string testStringTwo;
public List<StatController.Session> sessions = new List<StatController.Session>();
}
}
3) The script where the data file was initially created and where there didn't seem to be problems:
public class ProfileController : MonoBehaviour {
public static string currentID;
//create ----
public InputField idField;
public InputField nameField;
public InputField dobField;
public Toggle fishToggle;
public Toggle birdToggle;
//open ------
public Button idTitleButton;
public Text nameText;
public Text dobText;
public Text testText;
public InputField numField;
void Save() { //saves new ID and declares required variables based on game choice
Debug.Log("id =" + idField.text + ", name = " + nameField.text + ", save");
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Create(Application.persistentDataPath + "/" + idField.text + ".dat");
Profile.Store data = new Profile.Store(); //sets Profile variables
currentID = idField.text;
data.id = idField.text;
data.name = nameField.text;
data.dob = dobField.text;
data.fishEnabled = fishToggle.isOn;
data.birdEnabled = birdToggle.isOn;
Profile.id = idField.text;
Profile.name = nameField.text;
Profile.dob = dobField.text;
Profile.fishEnabled = fishToggle.isOn;
Profile.birdEnabled = birdToggle.isOn;
bf.Serialize(file, data); //saves Profile variables
if (fishToggle.isOn) {
FishData.Store dataFish = new FishData.Store(); //sets default Fish variables
dataFish.sizeInc = false;
dataFish.speedInc = false;
dataFish.level = 5;
dataFish.toxic = true;
dataFish.handLeft = false;
dataFish.timer = false;
dataFish.timerVal = 240;
dataFish.percentReq = 0;
dataFish.successReq = 0;
bf.Serialize(file, dataFish); //saves default Fish variables
Debug.Log("level = " + dataFish.level);
}
file.Close(); //closes save file
idSelectField.text = idField.text; //ensures current ID is used as selected ID where needed
EnableOpenProfile(); //loads new profile
}
void Load() {
if (File.Exists(Application.persistentDataPath + "/" + idField.text + ".dat")) { //loads save file
currentID = idField.text;
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + "/" + idField.text + ".dat", FileMode.Open);
Profile.Store data = (Profile.Store)bf.Deserialize(file);
nameField.text = data.name; //loads saved Profile details and settings
fishToggle.isOn = data.fishEnabled;
birdToggle.isOn = data.birdEnabled;
fishPlayButton.enabled = data.fishEnabled;
birdPlayButton.enabled = data.birdEnabled;
FishData.Store dataFish = (FishData.Store)bf.Deserialize(file); //loads saved Fish settings
FishData.sizeInc = dataFish.sizeInc;
FishData.speedInc = dataFish.speedInc;
FishData.toxic = dataFish.toxic;
FishData.timer = dataFish.timer;
FishData.level = dataFish.level;
FishData.timerVal = dataFish.timerVal;
FishData.percentReq = dataFish.percentReq;
FishData.successReq = dataFish.successReq;
FishData.handLeft = dataFish.handLeft;
file.Close(); //closes save file
nameText.text = "Name : " + data.name + " ID : " + data.id; //displays profile details
dobText.text = "DOB : " + data.dob;
}
else return;
}
}
4) The main script that produces the error when trying to load what was saved in the previous script:
public class OptionsController : MonoBehaviour {
public static bool handLeft = false;
public Toggle sizeIncToggle;
public Toggle speedIncToggle;
public Toggle toxicToggle;
public Toggle timerToggle;
public Toggle leftToggle;
public Toggle rightToggle;
public InputField levelField;
public InputField timerValField;
public InputField percentReqField;
public InputField successReqField;
void LoadOptions() {
if (File.Exists(Application.persistentDataPath + "/" + ProfileController.currentID + ".dat")) {
BinaryFormatter bf = new BinaryFormatter();
FileStream fileOpt = File.Open(Application.persistentDataPath + "/" + ProfileController.currentID + ".dat", FileMode.Open);
FishData.Store data = (FishData.Store)bf.Deserialize(fileOpt); //[[ERROR HERE]]
sizeIncToggle.isOn = data.sizeInc;
speedIncToggle.isOn = data.speedInc;
toxicToggle.isOn = data.toxic;
timerToggle.isOn = data.timer;
levelField.text = data.level.ToString();
timerValField.text = data.timerVal.ToString();
percentReqField.text = data.percentReq.ToString();
successReqField.text = data.successReq.ToString();
fileOpt.Close();
}
}
public void SaveOptions() {
Debug.Log("name = " + ProfileController.currentID + ", save");
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Create(Application.persistentDataPath + "/" + ProfileController.currentID + ".dat");
FishData.Store data = new FishData.Store();
data.sizeInc = FishData.sizeInc;
data.speedInc = FishData.speedInc;
data.toxic = FishData.toxic;
data.timer = FishData.timer;
data.level = FishData.level;
data.timerVal = FishData.timerVal;
data.percentReq = FishData.percentReq;
data.successReq = FishData.successReq;
data.handLeft = FishData.handLeft;
bf.Serialize(file, data);
Debug.Log("level = " + FishData.level);
file.Close();
}
}
Thank you.
To ensure you are serializing/deserializing in the correct order it is best that you create a "holding" class which contains both a Fish.Store variable and Profile.Store variable. If you serialize and deserilize in different orders you will run into issues like trying to deserialize a Fish.Store object to Profile.Store.
Try creating another class with public variables of Fish.Store and Profile.Store, like:
public class ExampleClass
{
public Fish.Store FishStore;
public Profile.Store ProfileStore;
public ExampleClass()
{
}
}
Then do:
ExampleClass example = new ExampleClass();
example.ProfileStore = data;
example.FishStore = dataFish;
//File Create stuff, etc
bf.Serialize(file, example);
//File close stuff, etc
And to deserialize:
ExampleClass e = (ExampleClass)bf.Deserialize(fileOpt);
data = e.ProfileStore;
dataFish = e.FishStore;
If you only wish to serialize/deserialize one class at a time, it is best practice to read/write to/from one file per serialized class.
Correct me if I'm wrong but it seems you first save Profile.Store
and then you save FishData.Store.
Then on the load you try to retreive the FishData.Store when the Profile.Store is first in the file.
(I'm assuming you use the load from script 4 and the save in script 3.)

itunes listening to

within windows live messenger, it is possible to share the song you are currently listening to. what would i need to do to get this working within c# like libarys etc cannot find the correct documentation on google.
You'll need to use the iTunes SDK to interact with iTunes from .NET. So there's your Google search term. :)
Here's a start:
http://blogs.msdn.com/b/noahc/archive/2006/07/06/automating-itunes-with-c-in-net.aspx
http://blogs.msdn.com/b/dancre/archive/2004/05/08/128645.aspx
Here is a script for LinqPad in C# which does as requested. (see LinqPad.com)
Bonus! Artwork view.
It looks like this:
<Query Kind="Program">
<Namespace>iTunesLib</Namespace>
<Namespace>System.Security.Cryptography</Namespace>
</Query>
void Main()
{
var track = new iTunesApp().CurrentTrack;
if (track == null)
"nothing playing".Dump();
else
new Viewer(track,true).Dump();
}
public class Viewer
{
const string PREFIX = "itlps-";
private IITFileOrCDTrack store;
private bool materialize;
public string album { get { return store.Album; } }
public string band { get { return store.Artist; } }
public string song { get { return store.Name; } }
public string desc { get { return store.Description; } }
public int? artCnt { get {
if (store.Artwork == null) return null;
else return store.Artwork.Count; }
}
public IEnumerable<ImageViewer> art { get {
if (materialize)
{
foreach(var artT in store.Artwork)
{
var art = artT as IITArtwork;
string ext = ".tmp";
switch(art.Format)
{
case ITArtworkFormat.ITArtworkFormatBMP:
ext = ".BMP";
break;
case ITArtworkFormat.ITArtworkFormatJPEG:
ext = ".JPG";
break;
case ITArtworkFormat.ITArtworkFormatPNG:
ext = ".PNG";
break;
}
string path = Path.Combine(Path.GetTempPath(),PREFIX+Path.GetRandomFileName()+ext);
art.SaveArtworkToFile(path);
yield return new ImageViewer(path);
}
}
yield break; }
}
public Viewer(IITFileOrCDTrack t,bool materializeArt = false)
{
store = t;
materialize = materializeArt;
}
public Viewer(IITTrack t,bool materializeArt = false)
{
store = t as IITFileOrCDTrack;
materialize = materializeArt;
}
}
public class ImageViewer
{
public string hash { get { return _hash.Value; } }
static private string _path { get; set; }
public object image { get { return _image.Value; } }
static private SHA1Managed sha = new SHA1Managed();
private Lazy<object> _image = new Lazy<object>(() => {return Util.Image(_path);});
private Lazy<string> _hash = new Lazy<string>(() =>
{
string hash = string.Empty;
using (FileStream stream = File.OpenRead(_path))
{
byte [] checksum = sha.ComputeHash(stream);
hash = BitConverter.ToString(checksum).Replace("-", string.Empty);
}
return hash;
});
public ImageViewer(string path)
{
_path = path;
}
}
last i checked this functionality is included out of the box all you need is to have itunes and windows live messenger installed and activate "what im listening to" and it shows this in your messenger status. if you are looking to create a bot that messages this out to a contact that is a different story tho that you will need to write a script for

Categories