Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Running external scripts?

Discussion in 'Scripting' started by Shykeas, Oct 2, 2016.

  1. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    I've looked around and found questions of the same name and didn't seem to have the same requested answer as myself.

    So I will explain:

    Sometimes in games there are (More popularly) .lua script that are accessible to the public in the games' files. And this outside of the game's compacted, secure source files.

    These .lua scripts usually are just references. How can I do this in Unity?

    So we can serialize variables and save it as a file then return them and assign them into our game externally. But is it possible to run SCRIPTS (Not just store variables and values, but entire scripts) in the same way as we would save data? (Serialization and stuff.) Here's an example:


    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System;
    4. using System.Runtime.Serialization.Formatters.Binary;
    5. using System.IO;
    6. public class savingToFile : MonoBehaviour {
    7.     public static int thisIsData;
    8. public void Save ()
    9.     {
    10.         BinaryFormatter bf = new BinaryFormatter ();
    11.         FileStream file = File.Create (Application.persistentDataPath + "/Location.file");
    12.         Data data = new Data ();
    13.         data.thisIsSavedData = thisIsData;
    14. file.Close();
    15. }
    16. public void Load()
    17.     {
    18.         if (File.Exists (Application.persistentDataPath + "/Location.file")) {
    19.             BinaryFormatter bf = new BinaryFormatter();
    20.             FileStream file = File.Open(Application.persistentDataPath + "/Location.file", FileMode.Open);
    21.             Data data  = (Data)bf.Deserialize(file);
    22.             file.Close();
    23.             thisIsData = data.thisIsSavedData;
    24. }
    25. }
    26. [Serializable]
    27.     class Data
    28.     {
    29.     public int thisIsSavedData;
    30. }
    So that is serializing an integer and saving it at the persistent data path as "Location.file". All that is in this file is simply a number.

    But here's what I am trying to do - a variant of the code above:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System;
    4. using System.Runtime.Serialization.Formatters.Binary;
    5. using System.IO;
    6. public class savingToFile : MonoBehaviour {
    7.     //????
    8. public void Save ()
    9.     {
    10.         BinaryFormatter bf = new BinaryFormatter ();
    11.         FileStream file = File.Create (Application.persistentDataPath + "/Location.file");
    12.         Data data = new Data ();
    13.         //Saves THIS script, or whichever script I want, to the Data Class.
    14. file.Close();
    15. }
    16. public void Load()
    17.     {
    18.         if (File.Exists (Application.persistentDataPath + "/Location.file")) {
    19.             BinaryFormatter bf = new BinaryFormatter();
    20.             FileStream file = File.Open(Application.persistentDataPath + "/Location.file", FileMode.Open);
    21.             Data data  = (Data)bf.Deserialize(file);
    22.             file.Close();
    23.             //Runs the script in Data Class.
    24. }
    25. }
    26. [Serializable]
    27.     class Data
    28.     {
    29.    //This is a script. Specifically: Instantiate script.
    30. }
    Been on this for months now... :( I just want to get by this now.


    For a more detailed description on what I want, I want to be able to instantiate something by running a script outside of the game's build. :(

    C#
     
    Last edited: Oct 2, 2016
  2. jimroberts

    jimroberts

    Joined:
    Sep 4, 2014
    Posts:
    560
    I would like to give you a resounding no due to obvious security issues. However, could you expand further on exactly what you're trying to accomplish?

    P.S. There are quite a few lua libraries that you could use...
     
    Last edited: Oct 2, 2016
  3. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    Ok, I'll explain a little more.
    (No, I don't want to use Lua. Just was an example.)

    I have a script that has a block follow the mouse. (Not really FOLLOW the mouse, but you get the idea) Then you click and it instantiates a block at that location. Simple. It has scripts attached to it, but not really relevant.
    Say I place a block. Instantiate it and stuff. And now it has NOTHING attached to it. Just a transform and now it's just there in the game.

    I place a bunch of blocks or whatever, fine. Problem is? I want to save the locations of these blocks. So if I quit the application, I can press load, and it reinstantiates all of the blocks in their respective locations. Obviously it has to be saved into an external file?

    I've been on this for MONTHS and thought "Ok, maybe I can have it when it loads the file, it just executes instantiations".

    So I'm just trying to get a block to save it's size, position and rotation and then reinstantiate it later.

    The problem I'm coming to is the fact that I can place as many as I want. when I press save, I want it to load the level I made. Just a bunch of blocks.
     
    Last edited: Oct 2, 2016
  4. Laperen

    Laperen

    Joined:
    Feb 1, 2016
    Posts:
    1,065
    You could have just mentioned saving and loading. Infact if you search those terms you probably can get results on how others have accomplished this. Playerprefs is the easiest to jump into and use by far, but it only saves basic data types and has a storage cap of 1mb. Other methods involve parsing of other file types, like XML which i think is by far the most popular for this purpose.
     
    passerbycmc and Kiwasi like this.
  5. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    I've been there. In a previous game I've created I've used saving with Serialization in the way I have in the cript I've given up there. I've never used PlayPrefs because I did not need to.
    I have looked, and all information is given. It's just what isn't given is how I can save WITHOUT KNOWING HOW MUCH I AM SAVING.
    Now I can easily, as I have up there, type in the position and such then put "new Vector3 (*Reference the stored value here*)" but it's not just one block. It's multiple blocks that I can't count because it depends on how many blocks were placed. I know how to save my data in games. But I don't know how to save, if what is being save dis always different.
     
  6. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    Is there nothing I can do?
    Anyone know anything on how this could be accomplished?

    A block is instantiated, and I need each blocks position and such to be saved. THEN referenced and instantiated accordingly. I can save a block's data. But there are so many ways to do this and all I have found have failed. :(
     
  7. jimroberts

    jimroberts

    Joined:
    Sep 4, 2014
    Posts:
    560
    Oh, so you just want to serialize and deserialize your data. I thought you were trying to execute external scripts for some reason. Are you using prefabs for your blocks?
     
  8. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    This is real basic collection stuff.

    Each time you create a block, add it to a collection. A List<Block> would work. Then at save time iterate over your collection and grab the save data for each block. Then write it all to a file with System.IO.

    Loading is the same thing. Read each line out of the file, then load each block.
     
  9. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    Ah, I've thought about that. But no. Just regular blocks. If I made them into prefabs then instantiated them, it requires Unity.Editor namespace which is only executed for Edit mode. :(
    And I do want to execute external script if it gets the job done.

    I'm thinking save the position + "Instantiate (Position data from above here)" in one generated script. Then I go load it and bam. One block. and have one script for all of the blocks the persons saved.

    Honestly, I don't care how I get it done, now. I just really want this done and I just can't seem to crack the code. :(
     
  10. jimroberts

    jimroberts

    Joined:
    Sep 4, 2014
    Posts:
    560
    Using prefabs does not require the UnityEditor namespace. I don't know where you came up with "executing external scripts" but that has nothing to do with what you want to accomplish. Could you please post your script that currently instantiates your blocks?
     
    Kiwasi likes this.
  11. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    I really think I'm doing a terrible job at explaining all of this. XD But I'll show you the script:


    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System;
    5. using System.IO;
    6. using System.Runtime.Serialization.Formatters.Binary;
    7. using System.Linq;
    8.  
    9. [Serializable]
    10. public class LevelDataSaving : MonoBehaviour {
    11.  
    12.     public static int sizeOfList;
    13.  
    14.     public List<Blocks> BlockDataList;
    15.     List<Blocks> lstBlocks = new List<Blocks>();
    16.     [Serializable]
    17.     public class Blocks
    18.         {
    19.      
    20.  
    21.         public static string NameData;
    22.  
    23.         public static float PositionXData;
    24.         public static float PositionYData;
    25.         public static float PositionZData;
    26.  
    27.         public static float SizeXData;
    28.         public static float SizeYData;
    29.         public static float SizeZData;
    30.          
    31.         public static float RotationXData;
    32.         public static float RotationYData;
    33.         public static float RotationZData;
    34.  
    35.  
    36.         public Blocks(string NewNameData,float NewPositionXData, float NewPositionYData, float NewPositionZData, float NewSizeXData, float NewSizeYData, float NewSizeZData, float NewRotationXData, float NewRotationYData,float NewRotationZData)
    37.         {
    38.          
    39.  
    40.             PositionXData = NewPositionXData;
    41.             PositionYData = NewPositionYData;
    42.             PositionZData = NewPositionZData;
    43.             SizeYData = NewSizeXData;
    44.             SizeYData = NewSizeYData;
    45.             SizeYData = NewSizeZData;
    46.             RotationXData = NewRotationXData;
    47.             RotationYData = NewRotationYData;
    48.             RotationZData = NewRotationZData;
    49.  
    50.  
    51.  
    52.         }
    53.     }
    54. }
    Note I am originally using a list.

    Now this goes on any empty object in the scene.(UP)
    This HERE goes on the blocks I am instantiation (Via a different script I have no problem with)(DOWN):


    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3. using System.Collections.Generic;
    4. using System.Collections;
    5. using System.Runtime.Serialization.Formatters.Binary;
    6. using System.IO;
    7.  
    8. [Serializable]
    9. public class BlocksSaving : MonoBehaviour {
    10.     public int BlockNum;
    11.             void Start()
    12.             {
    13.         BlockNum = GameObject.Find ("ToolController").GetComponent<ToolController> ().blockNum;
    14.         var BlockList = GameObject.Find("LevelData").GetComponent<LevelDataSaving>();
    15.          
    16.         BlockList.BlockDataList.Add (new LevelDataSaving.Blocks(BlockNum + "",
    17.             GetComponent<Transform>().position.x,
    18.             GetComponent<Transform>().position.y,
    19.             GetComponent<Transform>().position.z,
    20.             GetComponent<Transform>().localScale.x,
    21.             GetComponent<Transform>().localScale.y,
    22.             GetComponent<Transform>().localScale.z,
    23.             GetComponent<Transform>().rotation.x,
    24.             GetComponent<Transform>().rotation.y,
    25.             GetComponent<Transform>().rotation.z));
    26.  
    27.     }
    28. }
    That finds the empty object, adds it's position and etc. to a new list in the first script.
    That works fine. But how do I instantiate each element in the list with it's respective places?

    So here is where external scripts comes in at. I was thinking about doing this(DOWN):

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System;
    5. using System.IO;
    6. using System.Runtime.Serialization.Formatters.Binary;
    7. using System.Linq;
    8.  
    9. [Serializable]
    10. public class LevelDataSaving : MonoBehaviour {
    11.  
    12.     public static int sizeOfList;
    13.  
    14.     public List<Blocks> BlockDataList;
    15.     List<Blocks> lstBlocks = new List<Blocks>();
    16.     [Serializable]
    17.     public class Blocks
    18.         {
    19.      
    20.  
    21.         public static string NameData;
    22.  
    23.         public static float PositionXData;
    24.         public static float PositionYData;
    25.         public static float PositionZData;
    26.  
    27.         public static float SizeXData;
    28.         public static float SizeYData;
    29.         public static float SizeZData;
    30.          
    31.         public static float RotationXData;
    32.         public static float RotationYData;
    33.         public static float RotationZData;
    34.  
    35.  
    36.         public Blocks(string NewNameData,float NewPositionXData, float NewPositionYData, float NewPositionZData, float NewSizeXData, float NewSizeYData, float NewSizeZData, float NewRotationXData, float NewRotationYData,float NewRotationZData)
    37.         {
    38.          
    39.  
    40.             PositionXData = NewPositionXData;
    41.             PositionYData = NewPositionYData;
    42.             PositionZData = NewPositionZData;
    43.             SizeYData = NewSizeXData;
    44.             SizeYData = NewSizeYData;
    45.             SizeYData = NewSizeZData;
    46.             RotationXData = NewRotationXData;
    47.             RotationYData = NewRotationYData;
    48.             RotationZData = NewRotationZData;
    49.  
    50.             Instantiate (GameObject.Find("Cube(Clone)"), new Vector3(NewPositionXData,NewPositionYData,NewPositionZData), Quaternion.Euler (NewRotationXdata,NewRotationYData,NewRotationZData));
    51.  
    52.         }
    53.     }
    now notice that Instantiate line at the end. If I can get that entire class Blocks() to be a script on it's own saved elsewhere on runtime, I can just run the script, and it would do that final instantiate on it's own just like that and no real need for a list.
     
    Last edited: Oct 2, 2016
  12. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    P.S.: BoredMormon says I should use a list. And I am pretty sure I am. It's just it seems impossible to get the list in the way BoredMormon says since the list is being generated.

    And I know making prefabs alone doesn't require any namespace or scripting. But remember, let's just say it's a regular block. So no need for a prefab. If I wanted to create a prefab via scripting, (Of the ENTIRE level that was made, just create a prefab of the empty object parent the blocks are children of) then yeah. Easy. Save the prefab and load it. But it doesn't work that way since that can't be done outside of Unity. I want it to be done in BUILD mode. So I can't make prefabs of it before it's packed in. I asked that awhile ago thinking that was the answer and it isn't. :(
     
  13. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    8,986
    I believe you are over complicating this.

    Can you explain why you believe the script needs to be external? So far everything you have described shows that you just need to save values.
     
    Kiwasi likes this.
  14. Laperen

    Laperen

    Joined:
    Feb 1, 2016
    Posts:
    1,065
    Kiwasi likes this.
  15. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    Yeah, I agree. I am over complicating it. Hard to explain. First I want to make it a file. Then I want to run it FROM a different file... Ugh, it's so complicated, I know. I'll start from the very beginning. Hold on:
     
  16. Laperen

    Laperen

    Joined:
    Feb 1, 2016
    Posts:
    1,065
    what are you trying to ACHIEVE! Not what you THINK how what you are trying to achieve is gonna work.
     
  17. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    This.

    Describe the in game effect that you want to see. Forget files or external scripts. Just start with the plain English description.
     
  18. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    Forget running it from a file. It was an idea I THOUGHT would work. Scratch that. The name of this post should change.

    So you've seen my script. On this first image, when I click, a block instantiates. It add a script that gives it's position, data and etc. and then adds it as an element to the list I have. So now that list has block type, position and stuff. (Can't see the data in editor because all of that is static. But it's there.)

    So on the next image, I put this in the script:

    if(Input.GetKeyDown(KeyCode.P)){
    Instantiate(GameObject.Find("Cube(Clone)"),newVector3(Blocks.PositionXData,Blocks.PositionYData,Blocks.PositionZData),Quaternion.Euler(0,0,0));
    }


    SECTION 1
    Now you remember "Blocks.PositionXData" and etc from the Blocks Class? (In my script up there) It's just the data that is in the elements of the list. So when I press P three times, it instantiates at that location. So in that image it shows I have 4 blocks now. (Or four added to the list) They are all in the same spot, because they were instantiated with the data. However... If I add a block elsewhere then press P, only one block comes. (Hence why I press it 3 times, and 8 didn't come instead of 3) And to make it even worse? Only one block is instantiated.. Taking the data from the last given element data.

    Example of one of the problems:

    I add a block. Say this is Joe.
    Joe is at position 5.
    I press P.
    Joe Clone is made at position 5.
    -THAT IS SAVING AND LOADING-
    I delete the clone and add Jim at position 6.
    Jim and Joe are now there.
    I press P
    Jim Clone is made at position 6.

    Get it? No Joe clone even though he's there at position 5?
    I want all of the blocks to save, which they are (Hence the elements in the list) and when I press P, they all load up. Not Just one in one location. So here is how it should look:

    Example of how it should look:

    I add a block. Say this is Joe.
    Joe is at position 5.
    I press P.
    Joe Clone is made at position 5.
    I delete Joe Clone.
    I add Jim at position 6.
    Jim and Joe are now there. At positions 5 and 6.
    I press P.
    Jim Clone AND Joe Clone appear. Jim appears at 6 and Joe appears at 5.
    So if I press P again,
    Jim, Joe, Joe Clone and Jim Clone should be cloned.
    So now there should be 8 on the scene. 4 in each spot.
    If I press it again, the 8 get cloned in the same spot and now there are 16 in the same spot and etc.

    You get how the saving works?
    There is a picture of a block. Just so you get the point. There is a grid and etc. You click and the block appears there. Can make a bunch of blocks to form a block creation or whatever.
    I just want each block to be added as an element to the list with their position, name, size and rotation. And there is a picture of all of the hidden blocks on the scene that is being instantiated. (I know now that it's better to use a prefab, I'll change it later) Notice how Grass Block is not hidden, because that block is selected to be used to make your creation with. I can make a block creation with all different blocks. But that is why I need the name to be saved in the element list as well so I know which type of block goes where in each place.

    Now that is half of my problem. Each time I instantiate, it doesn't instantiate correctly. EXCLUDING THE LOADING FROM A SAVE FILE. (Have to make sure saving works by the press of a button before testing it out on a separate file of course.)


    SECTION 2

    The second problem I am facing is saving the element list. Now I have used serializations before to save integers and other data for save data and all. But I've never saved a list. And how do I even reference the list if the list is always changing?


    These are my problems. Forget the stupid loading scripts from a different file and all of the stupid stuff I was thinking would work. I hope I explained it well enough.

    EDIT: OOPS! Forgot that you wouldn't know which image is first. o_O

    Image 1: The image with element.
    Image 2: 4 elements in image.
    Image 3: Cube
    Image 4: Bunch of block names.

    Now I feel like the answer is so simple and stupid that I'm just an idiot that has been on it forever for no reason at all. XD And forgive my lack of cooperation. Just freaking out, skipping information, this and that. >~< Please forgive me.
     

    Attached Files:

    Last edited: Oct 2, 2016
  19. Laperen

    Laperen

    Joined:
    Feb 1, 2016
    Posts:
    1,065
    Within 2 sentences or less with no commas, describe what you want the player to see and/or do.
     
    Kiwasi likes this.
  20. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    I want the player to place a bunch of regular cubes. They will eventually press the save button and leave and come back and reload the cubes they placed.
     
  21. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    So what's wrong with the save method presented in the learn section?

    https://unity3d.com/learn/tutorials/topics/scripting/persistence-saving-and-loading-data

    Saving is a three step process.
    1. Collect the data to be saved from the game world
    2. Convert the data to text (serialisation)
    3. Save the text to storage
    Loading is the reverse
    1. Load the text from storage
    2. Convert the text to data (deserialisation)
    3. Apply the data to the game world
    Which step are you having problems with?
     
  22. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    That method works. But how do I save lists? :( And then instantiate the list data? That's where I'm stuck on.
     
  23. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Read my post again. You don't save a list. You convert a list to text, then save the string.

    So, can you convert your list to a string for saving?
     
  24. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    As a string? How would I convert it from a string? I've always wondered that. Again, appreciate this help.
    I've had strings. But if I had a string "2 + 3 = 5" it would be a string and won't actually calculate anything. How would I do that?
     
  25. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    8,986
    You don't save logic in a string, just data. The script contains the logic. Stay focused on the goal, "1+2=3" is irrelevant, there is never a need to store and parse something like that. You would just store "3" or "1,2", or "1,add,2" or whatever. But you are storing vector3s, so it would be "1,1,1". or something like "1,1,1|1,1,1|1,1,1" for full transform. A while back I wrote a simple storage for flat files that looked something like this:
    Code (CSharp):
    1. 125:0,0,0|0,0,0|1,1,1
    2. 199:0,0,0|0,0,0|1,1,1
    3. 175:0,0,0|0,0,0|1,1,1
    4. 912:0,0,0|0,0,0|1,1,1
    it was a simple text file that stored the transform data by object id. Regex or string.split by line gets the id, position, rotation and scale. It was fast and dirty. If it had wider scope, I would have used json instead.

    You only need to store values and a way to reference them, you don't need to store logic, that is what the parsing script or other logic in game should handle.
     
    Kiwasi likes this.
  26. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    It has no storage cap. That was only for the webplayer, which isn't supported any more. (Not that it's a good idea to dump gigabytes into it or anything....)

    --Eric
     
    Kiwasi and RavenOfCode like this.
  27. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145

    Ok, appreciated. I will look into splitting strings. I don't want to keep bugging you guys, I know I came off as incompetent and insolence.
    Would using string.split by line void using lists altogether? And how would I serialize this?
     
  28. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    8,986
    Unrelated. It is just one way to parse strings, it is a type of serialization. (for more/complex data you would want to use something like json/bson/xml) You will still need a list or array to store the data/objects on the client side.
    See BoredMormon's post:
    They are different steps in the process. How you manage the elements in the game is a separate step from store/retrieving the attributes.
     
    Kiwasi likes this.
  29. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    So lets break down the steps.

    This is where your list comes in. Since you are only interested in positions, I would expect this to come as a List<Vector3>. You have several options on how to populate this list, but the simplest would be to just add to it immediately after you Instantiate a block.

    Code (CSharp):
    1. List<Vector3> blockPositions;
    2.  
    3. void CreateBlock (){
    4.     GameObject newBlock = Instantiate <GameObject>(blockPrefab);
    5.     blockPositions.Add (newBlock.transform.position);
    6. }
    There are several options for this. You can use a binary formatter. You can use JSON or XML libraries. Or you can just parse it yourself. For our purposes we will just manually parse it.

    Code (CSharp):
    1. string saveData;
    2.  
    3. void GenerateTextFromList (){
    4.     saveData = "";
    5.     foreach (Vector3 vector in blockPositions){
    6.         saveData += vector.x + "," + vector.y + "," + vector.z + "\n";
    7.     }
    8. }
    Again there are multiple options. You can send the data to a cloud server. You can display it on the screen. You can write it to a file. Or you can dump it in player prefs. We will use playerprefs for now.

    Code (CSharp):
    1. void SaveDataToDisk (){
    2.     PlayerPrefs.SetString ("savedBlocks",saveData);
    3.     PlayerPrefs.Save();
    4. }
    And now your data is saved. When you can get this working, follow the process in reverse to recreate your blocks. There are a few tricks for this, but that can be saved for another post.

    Before anyone comments this is the simplest way to save, not the most performant. We can talk performance later after it is working.
     
  30. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    Thanks 2 million! Now I have one last question. What if I am saving more than one block's positions and etc.? Would it go to a single file, or just overwrite it? Or would it be added to this file with this script?

    I want it all to go to a single file then load all of the positions and stuff with one file.
     
  31. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    You do understand the concept of a List and a for loop right? If not then it might be better to give up on this and go back to the learn section tutorials for a while.
     
  32. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    I know loop and List. XD I just never used Loop to loop through the list, but that's a good idea! ^.^ Thanks for all of you guy's help. I'm going to go accomplish this. Can't wait to just get this done. My stresses can finally cease.
     
    Kiwasi likes this.
  33. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    Hey. Ive run into another problem.

    I can't seem to get other lists to combine with this first list.
    I want it to save the block numbers as well. (IDs)
    I can only get it to do this:
    #, #, # | #, #, # | #, #, #

    Then if I try to add anything else the same way I add that, such as a block number, it overwrites it for all of them.
    Example:

    Block 1 has ID 1.
    *Save*
    1 | 1, 1, 1 | 1, 1, 1

    The last three set of integers are transform data.
    The first one that is alone is ID.

    So I add Block 1 AND THEN Block 2 with IDs 1 and 2.
    *Save*
    Comes out like this:
    2 | 1, 1, 1 | 1, 1, 1 | 1, 1, 1
    2 | 3, 4, 5 | 2, 2, 2 | 3, 4, 1
    instead of
    1 | 1, 1, 1 | 1, 1, 1 | 1, 1, 1
    2 | 3, 4, 5 | 2, 2, 2 | 3, 4, 1

    I get the Transform to list correctly, but not the ID.
    Not sure how to add an integer, using the code BoredMormon gave, without overwriting it. :(
     
  34. Kalladystine

    Kalladystine

    Joined:
    Jan 12, 2015
    Posts:
    227
    Please show the code that you used.
     
  35. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    Code (CSharp):
    1.     public GameObject blockPrefab;
    2.         public List<Transform> blockPositions;
    3.  
    4.        
    5.     public string saveData;
    6.     public int blockNumber;
    7.     public void GenerateTextFromList (){
    8.         saveData = "";
    9.         foreach (Transform state in blockPositions){
    10.             saveData += "|" + transform.position + "|" + transform.rotation + "|" + transform.localScale + "\n";
    11.         }
    12.     }
    13. void Update()
    14.     {
    15.         Debug.Log (blockPositions);
    16.  
    17.         if (Input.GetKeyDown (KeyCode.L)) {
    18.             GenerateTextFromList ();
    19.             Debug.Log (saveData);
    20.  
    21.         }
    Code saves the block transforms. ^


    Code (CSharp):
    1. public int BlockNum;
    2.  
    3.  
    4.     void Update()
    5.     {
    6.         if (Input.GetKeyDown (KeyCode.P)) {  
    7.             GameObject.Find ("LevelData").GetComponent<LevelDataSaving>().saveData += BlockNum + "|";
    8.             GameObject.Find ("LevelData").GetComponent<LevelDataSaving> ().blockPositions.Add (transform);
    9.  
    10.  
    11.         }
    12.     }
    13.  
    That one goes on the block IDs. That is what BockNum is. A different script assigns the BlockNumber when it is placed.
    On the first row, I added saveData += BlockNum + "|" so is can add it to SaveData, THEN on the next line it adds the rest of the data. (Transform.) That is when I press P. I press that first.
    So now on the first script, I press L and it should compile all of the data. Instead of overwriting, it says "+=" so it would just add. Sadly with this code it doesn't add the BlockNum AT ALL.
    I changed the code up and played around and the closest I could get is it adding it to the line... But each time I press L it would overwrite each line's Block Number with one specific, instead of just adding a new one.
     
  36. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    No thoughts? D:
     
  37. Kalladystine

    Kalladystine

    Joined:
    Jan 12, 2015
    Posts:
    227
    You are overcomplicating this.

    The example provided by BoredMormon works, because all you care about then is the position. If you want to save complex data, generate it where it is.

    To keep it simple:
    (sidenote: there are other methods to do it, it's just an example)

    Inside your Block class (where you have the blockID stored of that individual block object) add a method to generate saveData like this:
    Code (CSharp):
    1. public string GenerateMyUniqueSaveData()
    2.     {
    3.         saveData += blockID + "|" + transform.position + "|" + transform.rotation + "|" + transform.localScale + "\n";
    4.     }
    Now the saving object:
    The list you need to iterate is not List<Transform>, since you don't want only transform. It should be a List<Block> (or however you named the class).
    When you create a new block, you add it to the list.
    Now when you want to save, just call this method:
    Code (CSharp):
    1. public List<Block> myBlocks;
    2.  
    3. void SaveBlockData()
    4. {
    5.       string saveData = "";
    6.       foreach (Block block in myBlocks)
    7.       {
    8.             saveData += block.GenerateMyUniqueSaveData();
    9.       }
    10.       // save saveData somewhere
    11. }
    This is a common serialization method - each object controls himself what will be saved from it. That way if you later want to also save, let's say, a int bounceCount (which stores how many times something bounced on the block), you change it only inside the Block class and all the rest of the saving stays exactly the same. (loading changes, but that's self explanatory - you need to "load" additional data from the string into the object, which btw a Block factory should do)
     
  38. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    Thanks for the help. I'll try that out. And I didn't meant to make it seem I'm over complicating it, I was just giving an example so you'd know what I wanted. I'll see about this a little later. If I run into something, I'll drop by. :)
     
  39. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    I'm getting this error:
    Not all code paths return a value.

    I looked it up and it's because GenerateMyUniqueSaveData is string instead of void. I change it.. And th erest becomes obsolete. Why is this and what can I do about it?
     
  40. Kalladystine

    Kalladystine

    Joined:
    Jan 12, 2015
    Posts:
    227
    It was my error in the function (this is what you get when you write directly in the post, copy pasting from previous posts, instead committing 1 minute more and opening a IDE...).

    It should've been:
    Code (CSharp):
    1. public string GenerateMyUniqueSaveData()
    2.     {
    3.         saveData = blockID + "|" + transform.position + "|" + transform.rotation + "|" + transform.localScale + "\n";
    4.         return saveData;
    5.     }
    So the error was completely correct - compiler was expecting the function to return a string, while it didn't have a return statement.
    Conclusion - I messed up. Sorry for that.

    For future reference:
    When you see this kind of error and you're not sure if this method should return something or was the error in the method declaration (tip: it usually isn't):
    - check how it's named.
    If it's named like an action, it usually should either return something or mutate something (change the state or values). Here we can see that it is named like an action, but the name doesn't tell us which of the options it is. A more descriptive name might've been "GetMyUniqueSaveData", because Get is explicit - return it to me. Generate is less explicit (it's a matter of style - I prefer to use Generate in these situations because it shows from the name that it involves some "calculations" and not just get some that is already there, like an int from a field).

    - check how it's used.
    In this topic, it was used from here:
    Code (CSharp):
    1. public List<Block> myBlocks;
    2. void SaveBlockData()
    3. {
    4.       string saveData = "";
    5.       foreach (Block block in myBlocks)
    6.       {
    7.             saveData += block.GenerateMyUniqueSaveData();
    8.       }
    9.       // save saveData somewhere
    10. }
    In this code block, we have a list, declare a string and iterate over the list while adding to that string. Also there is a comment below the loop to "save saveData somewhere", so clearly the method should produce some output into that string, otherwise it would remain empty and, as you've noted, the whole code becomes obsolete.

    Once again sorry for a stupid mistake like this, I should've paid more attention. Hopefully I can make it up with a short write up like this on how to debug this error in the future.
     
  41. Shykeas

    Shykeas

    Joined:
    Apr 11, 2015
    Posts:
    145
    Hey. I really appreciate this. The answers I found online just basically said "Don't make it look like it's returning something if it isn't. So make it not look like that." Instead of explaining that it's looking for the return that isn't there and how to make it be there.
    It's fine with the goofs. You've all been very helpful. I'm eventually going to need a step-by-step on how to make the integers in the string actually be integers in a bunch of different places. I still don't see a solution to that. DX Googling hasn't been helping much lately like it used it.
    Now I haven't tried this yet and I will definitely get back to you if I run into anything.