Skip to content

Commit

Permalink
Merge pull request #3215 from EasyRPG-NewFeatures/jetrotal-jsonCMD
Browse files Browse the repository at this point in the history
New Command 2055 - Process JSON Code
  • Loading branch information
fdelapena authored Nov 22, 2024
2 parents 24930fd + 842c2a4 commit 24c5fa6
Show file tree
Hide file tree
Showing 8 changed files with 278 additions and 5 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,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
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ libeasyrpg_player_a_SOURCES = \
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
91 changes: 88 additions & 3 deletions src/game_interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,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 @@ -789,9 +790,11 @@ bool Game_Interpreter::ExecuteCommand(lcf::rpg::EventCommand const& com) {
return CommandManiacCallCommand(com);
case Cmd::EasyRpg_SetInterpreterFlag:
return CommandEasyRpgSetInterpreterFlag(com);
case static_cast<Cmd>(2056): //EasyRPG_CloneMapEvent
case Cmd::EasyRpg_ProcessJson:
return CommandEasyRpgProcessJson(com);
case Cmd::EasyRpg_CloneMapEvent:
return CommandEasyRpgCloneMapEvent(com);
case static_cast<Cmd>(2057): //EasyRPG_DestroyMapEvent
case Cmd::EasyRpg_DestroyMapEvent:
return CommandEasyRpgDestroyMapEvent(com);
default:
return true;
Expand Down Expand Up @@ -5055,13 +5058,95 @@ bool Game_Interpreter::CommandEasyRpgSetInterpreterFlag(lcf::rpg::EventCommand c
Player::game_config.patch_key_patch.Set(flag_value);
if (flag_name == "rpg2k3-cmds" || flag_name == "rpg2k3-commands")
Player::game_config.patch_rpg2k3_commands.Set(flag_value);

if (flag_name == "rpg2k-battle")
lcf::Data::system.easyrpg_use_rpg2k_battle_system = flag_value;

return true;
}

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

#ifndef HAVE_NLOHMANN_JSON
Output::Warning("CommandEasyRpgProcessJson: JSON not supported on this platform");
return true;
#else

int operation = ValueOrVariable(com.parameters[0], com.parameters[1]);
int source_var_id = ValueOrVariable(com.parameters[2], com.parameters[3]);
int target_var_type = ValueOrVariable(com.parameters[4], com.parameters[5]);
int target_var_id = ValueOrVariable(com.parameters[6], com.parameters[7]);

std::string json_path = ToString(CommandStringOrVariable(com, 8, 9));
auto* json_data = Main_Data::game_strings->ParseJson(source_var_id);

if (!json_data) {
Output::Warning("JSON Parse error for {}", Main_Data::game_strings->Get(source_var_id));
return true;
}

if (target_var_type == 2 && !Player::IsPatchManiac()) {
Output::Warning("CommandEasyRpgProcessJson: String operations require Maniac Patch support");
return true;
}

std::optional<std::string> result;

if (operation == 0) { // Get operation: Extract a value from JSON data
result = Json_Helper::GetValue(*json_data, json_path);

if (result) {
switch (target_var_type) {
case 0: // Switch
Main_Data::game_switches->Set(target_var_id, atoi(result->c_str()) != 0);
break;
case 1: // Variable
Main_Data::game_variables->Set(target_var_id, atoi(result->c_str()));
break;
case 2: // String
Main_Data::game_strings->Asg({ target_var_id }, *result);
break;
default:
Output::Warning("CommandEasyRpgProcessJson: Unsupported target_var_type {}", operation);
return true;
}
}
}
else if (operation == 1) { // Set operation: Update JSON data with a new value
std::string new_value;

switch (target_var_type) {
case 0: // Switch
new_value = std::to_string(Main_Data::game_switches->Get(target_var_id));
break;
case 1: // Variable
new_value = std::to_string(Main_Data::game_variables->Get(target_var_id));
break;
case 2: // String
new_value = ToString(Main_Data::game_strings->Get(target_var_id));
break;
default:
Output::Warning("CommandEasyRpgProcessJson: Unsupported target_var_type {}", operation);
return true;
}

result = Json_Helper::SetValue(*json_data, json_path, new_value);

if (result) {
Main_Data::game_strings->Asg({ source_var_id }, *result);
}
}
else {
Output::Warning("CommandEasyRpgProcessJson: Invalid Operation {}", operation);
}

return true;

#endif // !HAVE_NLOHMANN_JSON
}

bool Game_Interpreter::CommandEasyRpgCloneMapEvent(lcf::rpg::EventCommand const& com) {
if (!Player::HasEasyRpgExtensions()) {
return true;
Expand Down
1 change: 1 addition & 0 deletions src/game_interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ class Game_Interpreter : public Game_BaseInterpreterContext
bool CommandManiacControlStrings(lcf::rpg::EventCommand const& com);
bool CommandManiacCallCommand(lcf::rpg::EventCommand const& com);
bool CommandEasyRpgSetInterpreterFlag(lcf::rpg::EventCommand const& com);
bool CommandEasyRpgProcessJson(lcf::rpg::EventCommand const& com);
bool CommandEasyRpgCloneMapEvent(lcf::rpg::EventCommand const& com);
bool CommandEasyRpgDestroyMapEvent(lcf::rpg::EventCommand const& com);

Expand Down
23 changes: 23 additions & 0 deletions src/game_strings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,34 @@
#include "player.h"
#include "utils.h"

#ifdef HAVE_NLOHMANN_JSON
#include "json_helper.h"
#endif

void Game_Strings::WarnGet(int id) const {
Output::Debug("Invalid read strvar[{}]!", id);
--_warnings;
}

#ifdef HAVE_NLOHMANN_JSON
nlohmann::json* Game_Strings::ParseJson(int id) {
auto it = _json_cache.find(id);
if (it != _json_cache.end()) {
return &(it->second);
}

auto str = ToString(Get(id));
auto res = Json_Helper::Parse(str);

if (!res) {
return nullptr;
} else {
_json_cache[id] = *res;
return &_json_cache[id];
}
}
#endif

StringView Game_Strings::Asg(Str_Params params, StringView string) {
Set(params, string);
return Get(params.string_id);
Expand Down
28 changes: 26 additions & 2 deletions src/game_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
* along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.
*/

// Headers
// Headers
#include "system.h"
#include <cstdint>
#include <string>
#include <lcf/data.h>
Expand All @@ -27,6 +28,10 @@
#include "player.h"
#include "string_view.h"

#ifdef HAVE_NLOHMANN_JSON
#include <nlohmann/json.hpp>
#endif

/**
* Game_Strings class.
*/
Expand Down Expand Up @@ -59,6 +64,10 @@ class Game_Strings {
StringView GetWithMode(StringView str_data, int mode, int arg, const Game_Variables& variables) const;
StringView GetWithModeAndPos(StringView str_data, int mode, int arg, int* pos, const Game_Variables& variables);

#ifdef HAVE_NLOHMANN_JSON
nlohmann::json* ParseJson(int id);
#endif

StringView Asg(Str_Params params, StringView string);
StringView Cat(Str_Params params, StringView string);
int ToNum(Str_Params params, int var_id, Game_Variables& variables);
Expand All @@ -85,8 +94,11 @@ class Game_Strings {

Strings_t _strings;
mutable int _warnings = max_warnings;
};

#ifdef HAVE_NLOHMANN_JSON
std::unordered_map<int, nlohmann::json> _json_cache;
#endif
};

inline void Game_Strings::Set(Str_Params params, StringView string) {
if (params.string_id <= 0) {
Expand All @@ -108,10 +120,18 @@ inline void Game_Strings::Set(Str_Params params, StringView string) {
} else {
it->second = ins_string;
}

#ifdef HAVE_NLOHMANN_JSON
_json_cache.erase(params.string_id);
#endif
}

inline void Game_Strings::SetData(Strings_t s) {
_strings = std::move(s);

#ifdef HAVE_NLOHMANN_JSON
_json_cache.clear();
#endif
}

inline void Game_Strings::SetData(const std::vector<lcf::DBString>& s) {
Expand All @@ -122,6 +142,10 @@ inline void Game_Strings::SetData(const std::vector<lcf::DBString>& s) {
}
++i;
}

#ifdef HAVE_NLOHMANN_JSON
_json_cache.clear();
#endif
}

inline const Game_Strings::Strings_t& Game_Strings::GetData() const {
Expand Down
100 changes: 100 additions & 0 deletions src/json_helper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* This file is part of EasyRPG Player.
*
* EasyRPG Player is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EasyRPG Player is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.
*/

#include "json_helper.h"

#ifdef HAVE_NLOHMANN_JSON

#include "output.h"
#include <nlohmann/json.hpp>
#include <sstream>
#include <unordered_map>
#include "string_view.h"

using json = nlohmann::json;

namespace {
std::string GetValueAsString(const json& json_obj) {
std::string result;

if (json_obj.is_string()) {
result = json_obj.get<std::string>();
}
else if (json_obj.is_number_integer()) {
result = std::to_string(json_obj.get<int>());
}
else if (json_obj.is_number_float()) {
result = std::to_string(json_obj.get<float>());
}
else if (json_obj.is_boolean()) {
result = json_obj.get<bool>() ? "true" : "false";
}
else {
result = json_obj.dump();
}

return result;
}
}

namespace Json_Helper {
std::optional<nlohmann::json> Parse(std::string_view json_data) {
json json_obj = json::parse(json_data, nullptr, false);
if (json_obj.is_discarded()) {
return {};
}

return json_obj;
}

std::optional<std::string> GetValue(nlohmann::json& json_obj, std::string_view json_path) {
json::json_pointer ptr((std::string(json_path)));

if (ptr.empty()) {
Output::Warning("JSON: Bad json pointer {}", json_path);
return {};
}

if (!json_obj.contains(ptr)) {
return "";
}

return GetValueAsString(json_obj[ptr]);
}

std::string SetValue(nlohmann::json& json_obj, std::string_view json_path, std::string_view value) {
json::json_pointer ptr((std::string(json_path)));

if (ptr.empty()) {
Output::Warning("JSON: Bad json pointer {}", json_path);
return {};
}

json obj_value = json::parse(value, nullptr, false);

if (obj_value.is_discarded()) {
// If parsing fails, treat it as a string value
json_obj[ptr] = std::string(value);
} else {
json_obj[ptr] = obj_value;
}

return json_obj.dump();
}
}

#endif // HAVE_NLOHMANN_JSON
36 changes: 36 additions & 0 deletions src/json_helper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* This file is part of EasyRPG Player.
*
* EasyRPG Player is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EasyRPG Player is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef JSON_HELPER_H
#define JSON_HELPER_H

#include "system.h"

#ifdef HAVE_NLOHMANN_JSON

#include <optional>
#include <string_view>
#include <nlohmann/json.hpp>

namespace Json_Helper {
std::optional<nlohmann::json> Parse(std::string_view json_data);
std::optional<std::string> GetValue(nlohmann::json& json_obj, std::string_view json_path);
std::string SetValue(nlohmann::json& json_obj, std::string_view json_path, std::string_view value);
}

#endif // HAVE_NLOHMANN_JSON
#endif // JSON_HELPER_H

0 comments on commit 24c5fa6

Please sign in to comment.