I've already asked this in Answers but no one has responded and I usually come here to post or answer things so I'm posting here too. I'm just trying to save keybinings to json file and allow the user to change and save them. It works totally fine in the editor but not when the game is built. Yes, I am using persistantDataPath. I'll post my scripts and maybe someone can see something I'm missing. I've been struggling with this since last night. I will say it does load the file just fine in the build, it just won't save changes like it does in the editor. here's the code: (Sorry for the commented out stuff. I've just been trying everything and leaving things there so I know I've tried them) Code (CSharp): using UnityEngine; using System.IO; using System.Text; public class JsonFileUtility { public static string LoadJsonFromFile(string path, bool isResource) { if (isResource) { return LoadJsonAsResource(path); } else { return LoadJsonAsExternalResource(path); } } public static string LoadJsonAsResource(string path) { string JsonFilePath = path.Replace(".json", ""); TextAsset loadedJsonFile = Resources.Load<TextAsset>(JsonFilePath); return loadedJsonFile.text; } public static string LoadJsonAsExternalResource(string path) { path = Application.persistentDataPath + "/" + path; if (!File.Exists(path)) { return string.Empty; } StreamReader reader = new StreamReader(path); string response = ""; while (!reader.EndOfStream) { response += reader.ReadLine(); } reader.Close(); return response; } public static void WriteJsontoExternalResource(string path, string content) { path = Application.persistentDataPath + "/" + path; //using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) //{ // byte[] contentBytes = new UTF8Encoding(true).GetBytes(content); //stream.Write(contentBytes, 0, contentBytes.Length); //} //File.Delete(path); if (!File.Exists(path)) { FileStream stream = File.Create(path); byte[] contentBytes = new UTF8Encoding(true).GetBytes(content); // ********** File.WriteAllBytes(path, contentBytes); stream.Write(contentBytes, 0, contentBytes.Length); stream.Close(); } else { File.Delete(path); byte[] contentBytes = new UTF8Encoding(true).GetBytes(content); FileStream stream = File.OpenWrite(path); stream.Write(contentBytes, 0, contentBytes.Length); stream.Close(); } } } using System.Collections.Generic; using UnityEngine; using TMPro; using UnityEngine.UI; using System.Reflection; using System.IO; public class PlayerKeys : MonoBehaviour { // private Dictionary<string, KeyCode> tokens = new Dictionary<string, KeyCode>(); [HideInInspector] public TextMeshProUGUI up, down, left, right, jump, attack1, attack2, cast1, cast2, cast3, block, toggle_run, health_pot, mana_pot, target, untarget, settings, inv, spellbook, journal; [HideInInspector] public GameObject currentKey; private Color normal = Color.black; private Color selectedColor = Color.blue; private KeyCode playerKeyCode; private string EntryString; [System.Serializable] public struct Token { public string varName; public KeyCode keyCode; } [System.Serializable] public struct TokenCollection { public List<Token> tokens; } public Dictionary<string, Token> tokens; private void Start() { up = GameObject.Find("bindings_up").GetComponent<TextMeshProUGUI>(); down = GameObject.Find("bindings_down").GetComponent<TextMeshProUGUI>(); left = GameObject.Find("bindings_left").GetComponent<TextMeshProUGUI>(); right = GameObject.Find("bindings_right").GetComponent<TextMeshProUGUI>(); jump = GameObject.Find("bindings_jump").GetComponent<TextMeshProUGUI>(); attack1 = GameObject.Find("bindings_attack1").GetComponent<TextMeshProUGUI>(); attack2 = GameObject.Find("bindings_attack2").GetComponent<TextMeshProUGUI>(); cast1 = GameObject.Find("bindings_cast1").GetComponent<TextMeshProUGUI>(); cast2 = GameObject.Find("bindings_cast2").GetComponent<TextMeshProUGUI>(); cast3 = GameObject.Find("bindings_cast3").GetComponent<TextMeshProUGUI>(); block = GameObject.Find("bindings_block").GetComponent<TextMeshProUGUI>(); toggle_run = GameObject.Find("bindings_run_toggle").GetComponent<TextMeshProUGUI>(); health_pot = GameObject.Find("bindings_health_pot").GetComponent<TextMeshProUGUI>(); mana_pot = GameObject.Find("bindings_mana_pot").GetComponent<TextMeshProUGUI>(); target = GameObject.Find("bindings_target").GetComponent<TextMeshProUGUI>(); untarget = GameObject.Find("bindings_untarget").GetComponent<TextMeshProUGUI>(); settings = GameObject.Find("bindings_settings").GetComponent<TextMeshProUGUI>(); inv = GameObject.Find("bindings_inventory").GetComponent<TextMeshProUGUI>(); spellbook = GameObject.Find("bindings_spellbook").GetComponent<TextMeshProUGUI>(); journal = GameObject.Find("bindings_journal").GetComponent<TextMeshProUGUI>(); tokens = new Dictionary<string, Token>(); ManagerSupp.instance.playerKeys = this; LoadToken(); List<string> tokenKeys = new List<string>(tokens.Keys); if (tokenKeys.Count > 0) { foreach (string key in tokenKeys) { SetKeyBind(key); } } else { tokens.Add("K_Up", new Token() { varName = "K_Up", keyCode = KeyCode.UpArrow }); //0 (KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_Down", KeyCode.DownArrow.ToString()))); //KeyCode.DownArrow); tokens.Add("K_Down", new Token() { varName = "K_Down", keyCode = KeyCode.DownArrow }); //1 (KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_Down", KeyCode.DownArrow.ToString()))); //KeyCode.DownArrow); tokens.Add("K_Left", new Token() { varName = "K_Left", keyCode = KeyCode.LeftArrow }); //2(KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_Left", KeyCode.LeftArrow.ToString()))); //KeyCode.LeftArrow); tokens.Add("K_Right", new Token() { varName = "K_Right", keyCode = KeyCode.RightArrow }); //3(KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_Right", KeyCode.RightArrow.ToString()))); //KeyCode.RightArrow); tokens.Add("K_Jump", new Token() { varName = "K_Jump", keyCode = KeyCode.Space }); //4 (KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_Jump", KeyCode.Space.ToString()))); //KeyCode.Space); tokens.Add("K_Attack1", new Token() { varName = "K_Attack1", keyCode = KeyCode.F}); //5(KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_Attack1", KeyCode.F.ToString()))); tokens.Add("K_Attack2", new Token() { varName = "K_Attack2", keyCode = KeyCode.G }); //6(KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_Attack2", "G"))); //KeyCode.G); tokens.Add("K_Cast1", new Token() { varName = "K_Cast1", keyCode = KeyCode.Alpha1 }); //7(KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_Cast1", KeyCode.Alpha1.ToString()))); tokens.Add("K_Cast2", new Token() { varName = "K_Cast2", keyCode = KeyCode.Alpha2 }); //8(KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_Cast2", KeyCode.Alpha2.ToString()))); //KeyCode.Alpha2); tokens.Add("K_Cast3", new Token() { varName = "K_Cast3", keyCode = KeyCode.Alpha3 }); //9(KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_Cast3", KeyCode.Alpha3.ToString()))); //KeyCode.Alpha3); tokens.Add("K_Block", new Token() { varName = "K_Block", keyCode = KeyCode.B }); //10(KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_Block", "V")));//KeyCode.V); tokens.Add("K_ToggleRun", new Token() { varName = "K_ToggleRun", keyCode = KeyCode.R }); //11(KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_ToggleRun", "R"))); //KeyCode.R); tokens.Add("K_HealthPot", new Token() { varName = "K_HealthPot", keyCode = KeyCode.N }); //12(KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_HealthPot", "N")));//KeyCode.N); tokens.Add("K_ManaPot", new Token() { varName = "K_ManaPot", keyCode = KeyCode.M}); //13(KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_ManaPot", "M"))); //KeyCode.M); tokens.Add("K_Target", new Token() { varName = "K_Target", keyCode = KeyCode.T }); //14(KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_Target", "T"))); //KeyCode.T); tokens.Add("K_Untarget", new Token() { varName = "K_Untarget", keyCode = KeyCode.U }); //15(KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_Untarget", "U"))); //KeyCode.U); tokens.Add("K_Settings", new Token() { varName = "K_Settings", keyCode = KeyCode.O }); //16(KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_Settings", "H"))); //KeyCode.H); tokens.Add("K_Inventory", new Token() { varName = "K_Inventory", keyCode = KeyCode.I }); //17(KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_Inventory", "I"))); //KeyCode.I); tokens.Add("K_Spellbook", new Token() { varName = "K_Spellbook", keyCode = KeyCode.K}); //18(KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_Spellbook", "K"))); //KeyCode.K); tokens.Add("K_Journal", new Token() { varName = "K_Journal", keyCode = KeyCode.J }); //19 (KeyCode)System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("K_Journal", "J"))); //KeyCode.J); SaveKeys(); SetKeyBind("K_Up"); SetKeyBind("K_Down"); SetKeyBind("K_Left"); SetKeyBind("K_Right"); SetKeyBind("K_Jump"); SetKeyBind("K_Attack1"); SetKeyBind("K_Attack2"); SetKeyBind("K_Cast1"); SetKeyBind("K_Cast2"); SetKeyBind("K_Cast3"); SetKeyBind("K_Block"); SetKeyBind("K_ToggleRun"); SetKeyBind("K_HealthPot"); SetKeyBind("K_ManaPot"); SetKeyBind("K_Target"); SetKeyBind("K_Untarget"); SetKeyBind("K_Settings"); SetKeyBind("K_Inventory"); SetKeyBind("K_Spellbook"); SetKeyBind("K_Journal"); } up.text = GetEntry("K_Up"); //keys["K_Up"].ToString(); down.text = GetEntry("K_Down"); //keys["K_Down"].ToString(); left.text = GetEntry("K_Left"); //keys["K_Left"].ToString(); right.text = GetEntry("K_Right"); //keys["K_Right"].ToString(); jump.text = GetEntry("K_Jump"); //keys["K_Jump"].ToString(); attack1.text = GetEntry("K_Attack1"); //keys["K_Attack1"].ToString(); attack2.text = GetEntry("K_Attack2"); //keys["K_Attack2"].ToString(); cast1.text = GetEntry("K_Cast1"); //keys["K_Cast1"].ToString(); cast2.text = GetEntry("K_Cast2"); //keys["K_Cast2"].ToString(); cast3.text = GetEntry("K_Cast3"); //keys["K_Cast3"].ToString(); block.text = GetEntry("K_Block"); //keys["K_Block"].ToString(); toggle_run.text = GetEntry("K_ToggleRun"); //keys["K_ToggleRun"].ToString(); health_pot.text = GetEntry("K_HealthPot"); //keys["K_HealthPot"].ToString(); mana_pot.text = GetEntry("K_ManaPot"); //keys["K_ManaPot"].ToString(); target.text = GetEntry("K_Target"); //keys["K_Target"].ToString(); untarget.text = GetEntry("K_Untarget"); //keys["K_Untarget"].ToString(); settings.text = GetEntry("K_Settings"); //keys["K_"].ToString(); inv.text = GetEntry("K_Inventory"); // keys["K_Inventory"].ToString(); spellbook.text = GetEntry("K_Spellbook"); //keys["K_Spellbook"].ToString(); journal.text = GetEntry("K_Journal"); //keys["K_Journal"].ToString(); } private void OnGUI() { if(currentKey != null) { Event e = Event.current; if (e.isKey) { Token tmp = new Token() { varName = currentKey.name, keyCode = e.keyCode }; tokens[currentKey.name] = tmp; //new Token() { varName = currentKey.name, keyCode = e.keyCode }; currentKey.transform.GetChild(1).GetComponent<TextMeshProUGUI>().text = GetEntry(currentKey.name); //e.keyCode.ToString(); currentKey.GetComponent<Image>().color = normal; FieldInfo tmpKey = (FieldInfo)Manager.instance.playerContoller.GetType().GetField(currentKey.name); Component comp = Manager.instance.playerContoller; tmpKey.SetValue(comp, tokens[currentKey.name].keyCode); //SaveKey(currentKey.name); currentKey = null; } } } private string GetEntry(string key) { EntryString = tokens[key].keyCode.ToString(); for(int i = 0; i < 10; i++) { if(EntryString == "Alpha" + i.ToString()) { EntryString = i.ToString(); } } return EntryString; } public void ChangeKey(GameObject clicked) { if(currentKey != null) { currentKey.GetComponent<Image>().color = normal; } currentKey = clicked; currentKey.GetComponent<Image>().color = selectedColor; } public void SetKeyBind(string key) { FieldInfo tmpKey = (FieldInfo)Manager.instance.playerContoller.GetType().GetField(key); Component comp = Manager.instance.playerContoller; tmpKey.SetValue(comp, tokens[key].keyCode); } public void ClosePlayerKeys() { SaveKeys(); if (currentKey != null) { currentKey.GetComponent<Image>().color = normal; currentKey = null; } } public void SaveKeys() { SaveToken(); } // public void SaveKey(string key) //{ // PlayerPrefs.SetString(key, tokens[key].ToString()); //PlayerPrefs.Save(); //} public void LoadToken() { if (!File.Exists(Application.persistentDataPath + "/tokenCollection.json")) return; tokens.Clear(); TokenCollection tmpCollection = JsonUtility.FromJson<TokenCollection>(JsonFileUtility.LoadJsonFromFile("tokenCollection.json", false)); // JsonUtility.FromJsonOverwrite(JsonFileUtility.LoadJsonFromFile("tokenCollection.json", false), tmpCollection); foreach (Token tok in tmpCollection.tokens) { tokens.Add(tok.varName, tok); } } public void SaveToken() { List<string> tokenKeys = new List<string>(tokens.Keys); List<Token> toSaveCollection = new List<Token>(); foreach (string key in tokenKeys) { toSaveCollection.Add(tokens[key]); } TokenCollection saveCollection = new TokenCollection() { tokens = toSaveCollection }; string jsonString = JsonUtility.ToJson(saveCollection); JsonFileUtility.WriteJsontoExternalResource("tokenCollection.json", jsonString); } }
i have used this for json: saveJson = JsonUtility.ToJson(gameSave); File.WriteAllText(Directory.GetCurrentDirectory() + "/save.txt", saveJson); saveJson = File.ReadAllText(Directory.GetCurrentDirectory() + "/save.txt"); gameSave = JsonUtility.FromJson<GameSave>(saveJson);
maybe this string patch = Directory.GetCurrentDirectory() + "/something.txt"; sorry, I am just useless with C# InputOutput
Unfortunately, that's not even saving in the editor. Which really doesn't make sense. However, I can still save it as bytes[] into a text file. Using your way gives me a file with nothing but "{ }" I dunno. This is one of those frustrating situations we all get.
did you replace the line: 322 JsonFileUtility.WriteJsontoExternalResource("tokenCollection.json", jsonString); with File.WriteAllText(Directory.GetCurrentDirectory() + "/save.txt", jsonString); the line should create txt file in the game folder
maybe you can try with dataPath https://docs.unity3d.com/ScriptReference/Application-dataPath.html and I hope someone other can help here I think, this is the half way. Nothing just means that the string was empty. And did you tried to build the game and start it from its folder and not over the button "Build and Play" ?
Yes, that's how I normally do it. I added a UI window to get some debug info. Since, I have since added a File.Delete before saving I know that it is actually saving the file with my method. But it is not saving the changed the keys in build mode. They get saved as the original. That sounds to me like there is some reason that the changes are taking effect in the editor but not in build. Like the variables are not being fully changed. I'm going to do a few tests and see what they tell me about why my KeyCode changes are only being saved in the inspector. It's a weird sort of bug that must be from something I have coded wrong that I can't figure out.
I've narrowed it down to something. When I change a key bind in game the panel shows that the dictionary contains the updated key. When I close the settings window (which also saves) the key reverts back to the old one. So something is going on there.
where are you calling the function public void ClosePlayerKeys() (try to Debug.Log("saved"); its execution)?
I'd have to search for where I'm calling it when I close the window. I likely put it in the close window button. But it's the same function that's called from the save button so it's nothing to do with the close button calling it. ie. it's doing nothing more than the save button in the keybings menu is doing.
OK, looking at the json file. I can see that it is indeed saving the keycode when I click save, but reverts back to the original when I close the window. How in the world does that make any sense? It should be saving the exact same thing again...
well, it's working now without the saving automatically, but it doesn't make sense to me. There's something somewhere that is causing it to do so, but there's no need for a save button if it's automatic or vice versa. Therefore, I will keep the save button and move on and hope it doesn't bite me in the deriere later.
Thanks for tagging along with me and giving me the idea to look at the close button. Whatever the reason I'm putting it behind me and moving on unless it becomes an issue later.
Lol, I have no idea what is going on here, still it is good if it works in some way and you have found where to look later
working beautifully now. I must say, I'm completely dumbfounded. It makes no sense to me, like I said many times already but now my blood pressure will go down and I can enjoy football tomorrow knowing it's working : )
OMG Vakabaka! I just discovered what the issue was. When I first started making this I for some reason put a copy of the script on my player and forgot about it. This whole time the script was updating from the player and the UI window. When the UI window closed it overwrote what the player script had done with the default setting from the UI window script.... God I hate when I do stupid crap like that. Cheese and Rice. 2 days work for being a bonehead. I'm laughing outside but crying inside.
You have made a problem and solved it by yourself. Well done Ah, something like this was happened to me too