[plugin] JSON (import/export/generate/edit/inspect/...)

0 favourites
From the Asset Store
The I18N (Translation) is a Construct plugin created to translate text in game.
  • my choise - using square brackets.or maybe rounded

  • Yann

    while i can work around this, i would be nice to check the length of an object / not array.length

    examplecode:

    var myObject = {'name':'Kasun', 'address':'columbo','age': '29'}

    var count = Object.keys(myObject).length

    console.log(count);

    about the brackets, to me it looks like rounded would fit better, it doesn't refer to an object or array

  • vtrix

    Thing is, even in javascript you have no property/function to get the number of properties in an object. An object has no length per se.

    The way you can answer this question is to usually count them manually

    var count = 0;
    for (var p in myObject) {
        if(myObject.hasOwnProperty(p) {
             count++;
        }
    }[/code:1eqcbou2]
    I could implement that, but I'm not sure if it's a good idea to blend the boundaries between array and object. If the user can get the property count (which shouldn't really be called length) they might be tempted to believe they could loop through properties using indices... well still thinking about it.
    
    Hmm, yeah I might add that as well as "isEmpty" and "Clear" function for array and object. We'll see. Maybe renaming "Length" to "ElementCount" or something more general to cover array and objects with the same function... 
    Hmm according to json.org, objects contain "members" whereas arrays contain "elements"... not sure how far I should stick to the vocabulary.
    Hmm... "Size" might be better then.
  • I was about to ask same question as

    And one more question, is there a way to rename objects or properties?

    If I have for example something like this:

    "Star1": {
        "name": "somename",
        "size": "somesize"
          }
    "Star2": {
        "name": "somename2",
        "size": "somesize2"
         }[/code:s40yz6be]
    
    I would like to change "Star2" (or any property)  name to something else. I'v been using a workaround simply creating new object  ie. "Star5" and setting it's all properties to "Star2" and deleteting "Star2". but it gets more complicated if I have more properties, objects and arrays belonging to Key I want to rename.
  • shinkan

    You can't do that kind of thing in any language I know of.

    JSON objects (a.k.a. dictionnary or hashtables) are values indexed using a key.

    The only way to change the key, for a given value, is, as you did, copying to another key and deleting the previous one.

    In javascript it wouldn't be a big deal because you would probably just swap objects references (the new key will point to the same object, hence no copy). But since, in construct2, you don't have access to any value type other than strings and number, it's not possible.

    To be clear, you would have that in javascript:

    // this creates an empty object
    // and put its reference in the variable root
    var root = {};
    
    // this creates an object with "name" and "size"
    // and  put its reference in the "Star1" property of root
    root["Star1"] = {"name":"somename","size":"somesize"};
    
    // "Star1" and "Star2" properties point to the same exact object
    root["Star2"] = root["Star1"];
    
    // for example:
    root["Star1"]["name"] = "plop";
    root["Star2"]["name"] == "plop"; // this will return true ("==" means "is equal?")
    
    // then to finish things up, in javascript you would do:
    delete root["Star1"];[/code:3clgjt1x]
    
    Now, the closest thing you can do with the current JSON plugin is:[code:3clgjt1x]-> JSON: Set Value at root["Star1"] to "{""name"":""somename"",""size"":""somesize""}"
    -> JSON: Load JSON JSON.ToJson(0,"Star1") at root["Star2"] // the copy
    -> JSON: delete root["Star1"][/code:3clgjt1x]
    as you notice it's almost the same
    The only difference is that after the copy (and before the delete) if you modify the object in "Star1", the one in "Star2" will be left untouched because it's not a reference but a copy.
    
    Modifying the key this way is totally fine, but you have to be carefull because copy is slower than just passing references. And going from an object to a JSON string to a new object is even slower than if you just copied each properties one by one. But it's a lot simpler (:
  • about the key adjust , maybe thats where json.stringify is used or parsing, not sure, would having a template object on first run be any good or will you still have the naming issue

    ----

    oh great isEmpty and clear would indeed be usefull! , and yes size or objectsize, would make a better distinction

    i also tested/used json.family and this works as expected, picking the json by uid and then working with it..

    parsing the data of an object to an array went pretty smooth, just needed some vars to count the objects and properties, then push x for objects and y for keys and values, i also did the keys, to make sure i get the values where i want, still working on the array to json,

    something i want to try later is querying by ID's, (within the json structure), still wondering how its best/could be done, by looping properties, or direct access, problem is that its not like an array, to get to the id, you must first get the right object, ... (thinking), i can name the object as the id,.. but not if its in an array.. damn,.. maybe later it comes to me..

  • vtrix

    You guessed right, when I do

    JSON.ToJson(0,"Star1")[/code:2v4ltxd4]in javascript I in fact do[code:2v4ltxd4]JSON.stringify(this.root["Star1"]);[/code:2v4ltxd4](well not exactly since I loop through the arguments provided to go through the path, but in a nutshell that's what I do)
    
    So yeah, if you already have the JSON string as a template, instead of copying one object into another with that[code:2v4ltxd4]-> JSON: Load JSON at root["Star2"] to JSON.ToJson(0,"Star1")[/code:2v4ltxd4]Doing that:[code:2v4ltxd4]-> JSON: Load JSON at root["Star2"] to myTemplate[/code:2v4ltxd4] (with myTemplate containing the JSON string for your... template) 
    would be slightly more efficient but you still will do a javascript JSON.parse(myTemplate) which can potentially be a bit slow as well (meaning slower than just passing references in javascript)
    
    If I rename the Length property I would probably not use ObjectSize but just Size, so you could use it for arrays or objects. (Note that your projects using Length will break when I'll make this change... or I can just set it to deprecated for a while to give you the opportunity to change it)
    
    Not sure I get your thing about ID. If you want to reference a JSON object using some kind of numbering, an array seems ok, you just need that numbering to be consecutive. (well in theory, javascript allows non consecutive indexing but when generating a JSON from that, in chrome at least, you get an array with the holes filled with null)
    For example you could do:[code:2v4ltxd4]-> JSON: Create new array at root[]
    -> JSON: Create new object at root[2]
    -> JSON: Create new object at root[4][/code:2v4ltxd4]but then if you want to get back the JSON you'll get something like[code:2v4ltxd4][null,null,{},null,{}][/code:2v4ltxd4]The other possibility would be to reference them in an object using the ID as a key.
  • Yann , ah ok i thought you keep the length for array and size for object, yes please if you could first deprecate it for a while, that would be great

    well the importing from array to json is working, and its also one way to create/modify keys , it was pretty complicated if you consider that the array can be larger ( if items are added) than the json, i had to check where the existing objects ended, and make sure, that new paths to objects existed, maybe i just was better of deleting all objects and remake them, o well... it is noticeable faster tho... i joke

    about id, its because i have worked alot with arrays recently, that it made sense to me to put my objects in indexes, put in fact, working with id's it doesn't make sense to have it in an array, (the reason i want to use id's is because ordering could potentially be changed by moving indexes, + i can simply reference the objects in multiple places,

    so a better workflow would be to have objects with id's (like youre saying), and then i can simply put those id's an ordered list if i need it

    making this all work will be another story ..

  • vtrix

    Not sure I understand all that you are saying, an example capx to illustrate your case would be better.

    Anyway, a simple capx showing how to simply go from array to the JSON plugin:

    arrayToJSONplugin.capx

  • Yann

    nice example, i think i just need to clear the current objects,

    will the clear function work like if you have object size 5, you clear this object, it will object size 0?

  • vtrix

    it will obviously (:

  • Yann

    i have some trouble resetting the current path, from certain paths (well thats what i think is happening)

    edit: i tried to change the path in a current loop, and continue the loop at this path, but this doesn't work

    i think i just need to call a new function

    no, i still have troubles..

    my only conclusion is that you cant switch path when in a for each current, its somehow stuck at that path,

    and my loop starts with a set path/reset, and runs one perfect, but is then stuck at end path

    its like "currentpath" has its own variable that isn't reset when set current path to root

  • Yann

    i made a capx of the problem,

    https://dl.dropboxusercontent.com/u/61666915/jsonProblem.capx

    use console to check the values, so i run the same function twice,

    at begin of the function i have a set path, but on second run, the path seems wrong, while it should been reset

  • vtrix

    Ok very interesting. At first I thought it was just a simple misuse, but it turned out there were a very peculiar issue.

    So first for the misuse, which is more of a design flaw for now, is that the foreach loop is actually modifying the current path to point to the property being foreached ( which doesn't work properly if you loop using an root based path (the loop will ignore the path <_<)). So, if you modify the current path inside the foreach loop, everything can get fucked up (:

    Here is one example case:

    considering this object:

    { "Wizard": {
          "stats":{
             "hp":100,
             "mp":80,
             "int":120,
             "dex":20,
             "str": 10
          },
          "buffs": {
             "hp":10,
             "mp":15,
             "int":10,
             "dex":3,
             "str": 2
          }
       }
    }[/code:2xof0hjw]
    
    Let say we want to loop through all the property and display their stats + buffs. It could be done like that:
    [code:2xof0hjw]
    -> System: set Current Path to root["Wizard","stats"]
    + JSON: foreach current[]  // using foreach root["Wizard","stats"] is broken
      Local text property = ""
      Local number value = 0
      -> System: set property to JSON.CurrentKey
      -> System: set value to JSON.Value(1,CurrentKey)
      -> System: set Current Path to root["Wizard","buffs"] // here you are modifying the looping path
      -> Text: Set text to property & ":" & value& " + " & JSON.Value(1) & " = " & value+ JSON.Value(1)[/code:2xof0hjw]
    
    Here is what will be output in the text object:
    [code:2xof0hjw]hp:100 + 10 = 110
    mp:15 + 15 = 30
    int:10 + 10 = 20
    dex:3 + 3 = 6
    str:2 + 2 = 4[/code:2xof0hjw]
    As you can see, after the first iteration, the loop is in fact looking into the buffs path
    and if you doesn't have the same properties in the two path you'll get some NaN or undefined values.
    
    I see two possible solutions to this problem:
     1. have a separated Current Path and Loop Path. As much as it makes sense now, I think it's a very confusing solution. What would be the current[]  in this situation? or maybe I should have root/current/loop... And what happens with nested loops? should I name those path like it's done with for loops and loopindex?... So yeah I'm not too sure about this idea
     2. have the loop reset the Current Path to the original path after each iterations. Good thing is, it's simple and straightforward to implement and use. Bad thing is, any change to the current path you do inside a loop will be lost at the end of the iteration (cannot be saved for later). But I think it's a very specific case and I can easily find a work around using an array in C2 and making a "savePath" and "buildPath" function.[code:2xof0hjw]// Function.Call("loadPath")
    + Function: On "loadPath"
       -> JSON: Set Current Path to root[]
       + Array: For each X element
          -> JSON: Set Current Path to current[Array.CurValue][/code:2xof0hjw][code:2xof0hjw]// Function.Call("savePath","path","you","want","to","save",...)
    + Function: On "savePath"
       -> Array: Set size to (0,1,1)
       + System: Repeat Function.ParamCount times
          -> Array: Push back Function.Param(loopindex) on X axis[/code:2xof0hjw]
    Though one weakness is that you can't dynamically save the path because you have no way, during a foreach loop, to know the entire path, you just know the CurrentKey. If you are recursively inspecting an entire unknown JSON it's harder to save a spacific path (probably doable if you save the path constantly during the recursion...)
    Maybe I could add a "foreach Node in the path"condition you could call in savePath instead of passing parameters.
    
    Anyway, now, for the real interesting stuff I discovered thanks to your capx:
    1. The list of parameters you pass in set Current Path to root["template","folder"], which is internally an array, is in fact built just once, and the same array object is passed over and over each time C2 reaches this action (at least during a given tick).
    And the plugin was using this very same array as a current path, and this array was modified when going through your two first foreach.
    That's why when you execute the run function a second time, you are already at root["template","folder","object1","path"] instead of root["template","folder"]. The array of argument was modified during the previous run.
    Hopefully this is easily solvable by using a copy of this array.
    2. A the end you logged properties (0, 1, 2, 3, 4 ,5 ,6)  that didn't really make sense since there were no array in your JSON. And the reason for that is that, in the second run, your first foreach was looping through the value at ["template","folder","object1","path"] which was actually the string "folder2". Javascript often consider strings as arrays of character, so you where looping through the 7 letters and was logging their indices. (which is more an unexpected feature than a bug )
  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • Yann , thanks for checking, yes a couple of things

    setting path and running thru current seems the most logical thing to do, if you know the correct way to do so, i dont think a root foreach would be that much use, setting the root outside the foreach loop is what i eventually did and works great.

    is also made the mistake that when importing a json file i didn't make a root object, this somehow also screws things up, not sure if thats also in my capx example, but the structure looks fine a first sight (there's also a root object) but i think its not recognised as such.

    as first time user, working with the json plugin (json for that matter), i found the 0 and 1 for value, the most confusing (at start) as you have the currentKey but not currentValue + the naming order, a path has to exist but a key doesn't, as in.. you set the key at a nonexistend name, you don't have to create it like an object (and this also creates a path) and an object you create and set

    edit: if you return an arrayProperty in for each, the arrayposition is a string, that can be confusing..

    as for path saving, i had the same idea, also if you could save the path, you probably are most likely to want to save a path to an array or object,

    you could create a json path "folder" filled with arrays at firstrun, and name them "key" & "path" , but indeed if you don't know the structure, indicating what the path is, would be harder i guess, on the other side json is very fast so iterating thru the structure is already fast and some shortcuts can always been made

    when im there, i will try those function out, i like the function.paramCount one

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)