clugg / sm-json

A pure SourcePawn JSON encoder/decoder.
GNU General Public License v3.0
82 stars 8 forks source link

[Feature Req] Sort order of keys of the second level depth #19

Closed mage-ua closed 2 years ago

mage-ua commented 3 years ago

Hello! Thanks for the great library.

Is there any sort order?

This code gives a randomly sorted values on the second level object (paramsJson):

JSON_Object outputJson = new JSON_Object();
JSON_Object paramsJson = new JSON_Object();

char output[1024];

outputJson.SetString("matchid", g_sMatchID);

paramsJson.SetString("team", teamString);
paramsJson.SetString("name", name);

paramsJson.SetInt(STAT_KILLS, kv.GetNum(STAT_KILLS));
paramsJson.SetInt(STAT_DEATHS, kv.GetNum(STAT_DEATHS));
paramsJson.SetInt(STAT_ASSISTS, kv.GetNum(STAT_ASSISTS));
paramsJson.SetInt(STAT_FLASHBANG_ASSISTS, kv.GetNum(STAT_FLASHBANG_ASSISTS));
paramsJson.SetInt(STAT_TEAMKILLS, kv.GetNum(STAT_TEAMKILLS));
paramsJson.SetInt(STAT_SUICIDES, kv.GetNum(STAT_SUICIDES));
paramsJson.SetInt(STAT_DAMAGE, kv.GetNum(STAT_DAMAGE));
paramsJson.SetInt(STAT_HEADSHOT_KILLS, kv.GetNum(STAT_HEADSHOT_KILLS));
paramsJson.SetInt(STAT_ROUNDSPLAYED, kv.GetNum(STAT_ROUNDSPLAYED));
paramsJson.SetInt(STAT_BOMBDEFUSES, kv.GetNum(STAT_BOMBDEFUSES));
paramsJson.SetInt(STAT_BOMBPLANTS, kv.GetNum(STAT_BOMBPLANTS));
paramsJson.SetInt(STAT_1K, kv.GetNum(STAT_1K));
paramsJson.SetInt(STAT_2K, kv.GetNum(STAT_2K));
paramsJson.SetInt(STAT_3K, kv.GetNum(STAT_3K));
paramsJson.SetInt(STAT_4K, kv.GetNum(STAT_4K));
paramsJson.SetInt(STAT_5K, kv.GetNum(STAT_5K));
paramsJson.SetInt(STAT_V1, kv.GetNum(STAT_V1));
paramsJson.SetInt(STAT_V2, kv.GetNum(STAT_V2));
paramsJson.SetInt(STAT_V3, kv.GetNum(STAT_V3));
paramsJson.SetInt(STAT_V4, kv.GetNum(STAT_V4));
paramsJson.SetInt(STAT_V5, kv.GetNum(STAT_V5));
paramsJson.SetInt(STAT_FIRSTKILL_T, kv.GetNum(STAT_FIRSTKILL_T));
paramsJson.SetInt(STAT_FIRSTKILL_CT, kv.GetNum(STAT_FIRSTKILL_CT));
paramsJson.SetInt(STAT_FIRSTDEATH_T, kv.GetNum(STAT_FIRSTDEATH_T));
paramsJson.SetInt(STAT_FIRSTDEATH_CT, kv.GetNum(STAT_FIRSTDEATH_CT));
paramsJson.SetInt(STAT_TRADEKILL, kv.GetNum(STAT_TRADEKILL));
paramsJson.SetInt(STAT_KAST, kv.GetNum(STAT_KAST));
paramsJson.SetInt(STAT_CONTRIBUTION_SCORE, kv.GetNum(STAT_CONTRIBUTION_SCORE));

outputJson.SetObject("params", paramsJson);

outputJson.Encode(output, sizeof(output));

delete outputJson;
delete paramsJson;

Output:

{
  matchid: 'mage_match',
  params: {
    v5: 0,
    '1kill_rounds': 0,
    name: 'Bender',
    team: 'team2',
    roundsplayed: 1,
    '2kill_rounds': 0,
    assists: 0,
    '3kill_rounds': 0,
    v3: 0,
    suicides: 0,
    tradekill: 0,
    '4kill_rounds': 0,
    v1: 0,
    deaths: 1,
    '5kill_rounds': 0,
    firstkill_t: 0,
    firstdeath_ct: 0,
    bomb_defuses: 0,
    damage: 0,
    contribution_score: 0,
    kills: 0,
    v4: 0,
    headshot_kills: 0,
    v2: 0,
    mvp: 0,
    firstkill_ct: 0,
    firstdeath_t: 1,
    teamkills: 0,
    flashbang_assists: 0,
    bomb_plants: 0,
    kast: 0
  }
}
MAGNAT2645 commented 3 years ago

There's no order since JSON_Object is based on StringMap.

mage-ua commented 3 years ago

So I don't understand why in output keys appears out of order...

Expect:

kills,
deaths,
assists,
.
.
.
contribution_score

Result:

v5,
1kill_rounds,
.
.
.
kast
clugg commented 3 years ago

Hey there, As @MAGNAT2645 stated, this library is built on top of StringMap which is inherently unordered. This is not a technical problem because JSON objects don't need to be ordered for anything other than human readability, but I'd be happy to implement an optional "lock order of inserted keys" which tracks the keys in a separate array if you like. Will look into this over the next week. Cheers!

EDIT: Just an update here, I am still working on this - I've found some nice underlying quality of life changes that can be made in relation to this feature so there are quite a few changes in the works. Will keep you updated on the status.

deibeljc commented 2 years ago

Hey there, As @MAGNAT2645 stated, this library is built on top of StringMap which is inherently unordered. This is not a technical problem because JSON objects don't need to be ordered for anything other than human readability, but I'd be happy to implement an optional "lock order of inserted keys" which tracks the keys in a separate array if you like. Will look into this over the next week. Cheers!

EDIT: Just an update here, I am still working on this - I've found some nice underlying quality of life changes that can be made in relation to this feature so there are quite a few changes in the works. Will keep you updated on the status.

Hey @clugg I was wondering if you were still working on this? We are facing a bug when using get5 for our CS league where the captains are always random. Get5 will always pick the first item out of the players array as the captain who bans and picks for their team, but because the schema they expect is a Json object, the order is random and not what we specified. Your fix would allow us to fix this issue completely!

See https://github.com/splewis/get5/blob/master/configs/get5/example_match.json

clugg commented 2 years ago

I've just released v4.0.0. You can enable this functionality using obj.EnableOrderedKeys() or by passing JSON_DECODE_ORDERED_KEYS as an option to json_decode.

Thanks for your suggestion!