Skip to content

Commit

Permalink
New Command 2055 - Process JSON Code
Browse files Browse the repository at this point in the history
  • Loading branch information
jetrotal committed May 3, 2024
1 parent b313163 commit 3484dbb
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ add_library(${PROJECT_NAME} OBJECT
src/input_source.h
src/instrumentation.cpp
src/instrumentation.h
src/json_helper.cpp
src/json_helper.h
src/keys.h
src/main_data.cpp
src/main_data.h
Expand Down
42 changes: 42 additions & 0 deletions src/game_interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "game_screen.h"
#include "game_interpreter_control_variables.h"
#include "game_windows.h"
#include "json_helper.h"
#include "maniac_patch.h"
#include "spriteset_map.h"
#include "sprite_character.h"
Expand Down Expand Up @@ -826,6 +827,8 @@ bool Game_Interpreter::ExecuteCommand(lcf::rpg::EventCommand const& com) {
return CommandManiacControlStrings(com);
case Cmd::Maniac_CallCommand:
return CommandManiacCallCommand(com);
case static_cast<Cmd>(2055): //EasyRPG_ProcessJson
return CommandProcessJson(com);
default:
return true;
}
Expand Down Expand Up @@ -5108,6 +5111,45 @@ bool Game_Interpreter::CommandManiacCallCommand(lcf::rpg::EventCommand const& co
return true;
}

bool Game_Interpreter::CommandProcessJson(lcf::rpg::EventCommand const& com) {
if (!Player::IsPatchManiac()) {
return true;
}

int operation = ValueOrVariable(com.parameters[0], com.parameters[1]);
int sourceVarId = ValueOrVariable(com.parameters[2], com.parameters[3]);
int targetVarId = ValueOrVariable(com.parameters[4], com.parameters[5]);

std::string jsonPath = ToString(CommandStringOrVariable(com, 6, 7));
std::string jsonData = ToString(Main_Data::game_strings->Get(sourceVarId));

int assignVarId = 0;
std::string result;
std::string newValue;

switch (operation) {
case 0: // Get operation: Extract a value from JSON data
result = Json_Helper::GetValue(jsonData, jsonPath);
assignVarId = targetVarId;
break;

case 1: // Set operation: Update JSON data with a new value
newValue = ToString(Main_Data::game_strings->Get(targetVarId));
result = Json_Helper::SetValue(jsonData, jsonPath, newValue);
assignVarId = sourceVarId;
break;

default:
Output::Warning("Process JSON - Invalid Operation: {}", operation);
result = "<<INVALID_OUTPUT>>";
break;
}

if (result != "<<INVALID_OUTPUT>>") Main_Data::game_strings->Asg({ assignVarId }, result);

return true;
}

Game_Interpreter& Game_Interpreter::GetForegroundInterpreter() {
return Game_Battle::IsBattleRunning()
? Game_Battle::GetInterpreter()
Expand Down
1 change: 1 addition & 0 deletions src/game_interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ class Game_Interpreter
bool CommandManiacSetGameOption(lcf::rpg::EventCommand const& com);
bool CommandManiacControlStrings(lcf::rpg::EventCommand const& com);
bool CommandManiacCallCommand(lcf::rpg::EventCommand const& com);
bool CommandProcessJson(lcf::rpg::EventCommand const& com);

int DecodeInt(lcf::DBArray<int32_t>::const_iterator& it);
const std::string DecodeString(lcf::DBArray<int32_t>::const_iterator& it);
Expand Down
159 changes: 159 additions & 0 deletions src/json_helper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#include "json_helper.h"
#include "external/picojson.h"
#include "output.h"
#include <vector>

namespace Json_Helper {
const std::string kInvalidOutput = "<<INVALID_OUTPUT>>";

std::vector<std::string> SplitPath(const std::string& jsonPath) {
std::istringstream iss(jsonPath);
std::vector<std::string> pathParts;
std::string part;
while (std::getline(iss, part, '.')) {
pathParts.push_back(part);
}
return pathParts;
}

picojson::value* GetValuePointer(picojson::value& jsonValue, const std::vector<std::string>& pathParts, bool allowCreation) {
picojson::value* currentValue = &jsonValue;

for (const auto& part : pathParts) {
std::string arrayName;
int arrayIndex = -1;
bool inArray = false;

for (char c : part) {
if (!inArray) {
if (c == '[') {
inArray = true;
arrayIndex = 0;
}
else {
arrayName += c;
}
}
else {
if (c == ']') {
break;
}
else {
arrayIndex = arrayIndex * 10 + (c - '0');
}
}
}

if (inArray) {
if (!currentValue->is<picojson::object>()) {
if (allowCreation) {
*currentValue = picojson::value(picojson::object());
}
else {
Output::Warning("JSON_ERROR - Invalid JSON type for array: {}", arrayName);
return nullptr;
}
}

auto& obj = currentValue->get<picojson::object>();
auto arrayIt = obj.find(arrayName);

if (arrayIt == obj.end()) {
if (allowCreation) {
obj.emplace(arrayName, picojson::value(picojson::array()));
arrayIt = obj.find(arrayName);
}
else {
Output::Warning("JSON_ERROR - Array not found: {}", arrayName);
return nullptr;
}
}

auto& arr = arrayIt->second.get<picojson::array>();

if (arrayIndex >= static_cast<int>(arr.size())) {
if (allowCreation) {
arr.resize(arrayIndex + 1);
}
else {
Output::Warning("JSON_ERROR - Array index out of bounds: {}", part);
return nullptr;
}
}

currentValue = &arr[arrayIndex];
}
else {
if (!currentValue->is<picojson::object>()) {
if (allowCreation) {
*currentValue = picojson::value(picojson::object());
}
else {
Output::Warning("JSON_ERROR - Invalid JSON type for path: {}", part);
return nullptr;
}
}

auto& obj = currentValue->get<picojson::object>();
auto objIt = obj.find(arrayName);

if (objIt == obj.end()) {
if (allowCreation) {
obj.emplace(arrayName, picojson::value(picojson::object()));
objIt = obj.find(arrayName);
}
else {
Output::Warning("JSON_ERROR - Object key not found: {}", part);
return nullptr;
}
}

currentValue = &objIt->second;
}
}

return currentValue;
}

std::string GetValue(const std::string& jsonData, const std::string& jsonPath) {
picojson::value jsonValue;
std::string err = picojson::parse(jsonValue, jsonData);

if (!err.empty()) {
Output::Warning("JSON_ERROR - JSON parsing error: {}", err);
return kInvalidOutput;
}

auto pathParts = SplitPath(jsonPath);
auto valuePtr = GetValuePointer(jsonValue, pathParts, false);

if (valuePtr == nullptr || !valuePtr->is<std::string>()) {
Output::Warning("JSON_ERROR - Value not found or not a string");
return kInvalidOutput;
}

return valuePtr->get<std::string>();
}

std::string SetValue(const std::string& jsonData, const std::string& jsonPath, const std::string& value) {
picojson::value jsonValue;
std::string err = picojson::parse(jsonValue, jsonData);

if (!err.empty()) {
Output::Warning("JSON_ERROR - JSON parsing error: {}", err);
return kInvalidOutput;
}

auto pathParts = SplitPath(jsonPath);
auto valuePtr = GetValuePointer(jsonValue, pathParts, true);

if (valuePtr == nullptr) {
Output::Warning("JSON_ERROR - Unable to create value");
return kInvalidOutput;
}

*valuePtr = picojson::value(value);

return picojson::value(jsonValue).serialize();
}
}
11 changes: 11 additions & 0 deletions src/json_helper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef JSON_HELPER_H
#define JSON_HELPER_H

#include <string>

namespace Json_Helper {
std::string GetValue(const std::string& jsonData, const std::string& jsonPath);
std::string SetValue(const std::string& jsonData, const std::string& jsonPath, const std::string& value);
}

#endif // JSON_HELPER_H

0 comments on commit 3484dbb

Please sign in to comment.