The following function (or part of it, I will only add the part that is relevant to the problem) is supposed to load a UI configuration from a .json
file for a simple game engine I am making (this is all custom). I am using the Nlohmann JSON library for modern C++.
void UIManager::loadUiConfig(SceneManager& sceneManager){
std::ifstream uiFile("..\\resources\\ui\\ui.json");
if(!uiFile.is_open()){
std::cerr << "Failed to load ui configuration file" << std::endl;
exit(EXIT_FAILURE);
}
json uiConfig;
try{
uiFile >> uiConfig;
}catch(const json::parse_error& e){
std::cerr << e.what() << std::endl;
exit(EXIT_FAILURE);
}
StructScenes scenesData;
try{
if(!uiConfig.contains("scenes")) throw std::runtime_error("scenes is not found");
if(uiConfig["scenes"].is_null()) throw std::runtime_error("scenes is empty/null");
scenesData = uiConfig.template get<StructScenes>();
} catch (const std::runtime_error& e) {
std::cerr << "Runtime Error: " << e.what() << std::endl;
exit(EXIT_FAILURE);
}catch(const json::type_error& e){
std::cerr << "Error parsing JSON: " << e.what() << std::endl;
exit(EXIT_FAILURE);
}
//rest of function
}
These are the structs I defined to hold the data from the .json
file:
#ifndef SERIALIZER_CLASS_H
#define SERIALIZER_CLASS_H
#include <glad/glad.h>
#include <vector>
#include <string>
#include <unordered_map>
#include <EventHandler/EventType.h>
#include <Json/json.hpp>
#include <ui/ui.h>
struct StructAppearance{
GLfloat posX, posY;
GLfloat width, height;
GLfloat color[4];
GLfloat texturePosX, texturePosY;
std::string textureImagePath;
int renderType;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(StructAppearance, posX, posY, width, height, color, texturePosX, texturePosY, textureImagePath, renderType);
};
struct StructButton{
std::string name;
std::vector<std::pair<EventType, std::string>> events;
StructAppearance appearance;
Shapes shape;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(StructButton, name, events, appearance, shape);
};
struct StructScene {
std::string name;
std::vector<StructButton> sceneMembers;
std::string vertexShaderPath;
std::string fragmentShaderPath;
GLfloat backgroundColor[4];
int posSize, colorSize, texSize;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(StructScene, sceneMembers, vertexShaderPath, fragmentShaderPath, backgroundColor, posSize, colorSize, texSize);
};
struct StructScenes{
std::vector<StructScene> scenes;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(StructScenes, scenes);
};
#endif
The entry structure (or root structure) is StructScenes
, which just holds a std::vector<StructScene>
of all the scenes available (this is just a method I am using to create menus in my game).
The problem is at the part where I want to de-serialize my .json
data into the StructScenes
. It keeps displaying this error:
Error parsing JSON: [json.exception.type_error.302] type must be array, but is object
To be specific, the error is occuring on this line:
scenesData = uiConfig.template get<StructScenes>();
I tried to instead make a direct std::vector<StructScene>
but the same issue happened where I got the aforementioned error, instead of actually creating the scenes and filling them with the respective buttons.
EDIT:since people are asking for the ui.json file, here is the sample one I am using:
{
"scenes": [
{
"name": "Main Menu",
"sceneMembers": [
{
"name": "Play",
"events": [
{
"type": "onclick",
"action": "settings"
}
],
"appearance": {
"posX": -0.9,
"posY": 0.1,
"width": 0.4,
"height": 0.3,
"color": [0, 0, 0, 0],
"texturePosX": 0,
"texturePosY": 0,
"textureImagePath": "..\\resources\\textures\\play.png",
"renderType": 1
},
"shape": "rectangle"
}
],
"vertexShaderPath": "..\\resources\\Shaders\\default.vert",
"fragmentShaderPath": "..\\resources\\Shaders\\default.frag",
"backgroundColor": [1.0, 1.0, 1.0, 1.0],
"posSize": 2,
"colorSize": 4,
"texSize": 2
}
]
}
Based on your provided json file, the events
field should be an Array of Object
"events": [
{
"type": "onclick",
"action": "settings"
}
],
Therefore the events
member of this struct is not correct
struct StructButton {
std::string name;
std::vector<std::pair<EventType, std::string>> events;
StructAppearance appearance;
Shapes shape;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(StructButton, name, events, appearance, shape);
};
It should be another struct which will be an json object
struct StructEvent {
std::string type;
std::string action;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(StructEvent, type, action);
};
then you would update the Button member
struct StructButton {
std::string name;
std::vector<StructEvent> events;
StructAppearance appearance;
Shapes shape;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(StructButton, name, events, appearance, shape);
};