From ed8eacc7195e60150f9c66b2d77df9e42945e3c3 Mon Sep 17 00:00:00 2001 From: mrq Date: Mon, 9 Nov 2020 00:00:00 -0600 Subject: [PATCH] Commit for 2020.11.09.7z --- Makefile | 21 +- .../shaders/display.rendertarget.frag.glsl | 1 - bin/data/shaders/gui.text.frag.glsl | 2 - client/client/ext.cpp | 46 +- debug.sh | 7 +- engine/inc/{json => json-old}/allocator.h | 0 engine/inc/{json => json-old}/assertions.h | 0 engine/inc/{json => json-old}/autolink.h | 0 engine/inc/{json => json-old}/config.h | 0 engine/inc/{json => json-old}/features.h | 0 engine/inc/{json => json-old}/forwards.h | 0 engine/inc/json-old/json.h | 15 + engine/inc/{json => json-old}/reader.h | 0 engine/inc/{json => json-old}/value.h | 0 engine/inc/{json => json-old}/version.h | 0 engine/inc/{json => json-old}/writer.h | 0 engine/inc/json/json-forwards.h | 446 ++ engine/inc/json/json.h | 2341 +++++++- engine/inc/sol/sol.hpp | 25 + engine/inc/uf/engine/asset/asset.h | 28 +- engine/inc/uf/engine/behavior/behavior.h | 8 +- engine/inc/uf/engine/behavior/macros.inl | 30 +- engine/inc/uf/engine/entity/entity.h | 4 +- .../inc/uf/engine/instantiator/instantiator.h | 4 + engine/inc/uf/engine/instantiator/macros.inl | 45 +- engine/inc/uf/ext/json/json.h | 32 + engine/inc/uf/ext/json/json.inl | 0 engine/inc/uf/ext/lua/lua.h | 20 +- engine/inc/uf/ext/lua/lua.inl | 66 +- engine/inc/uf/ext/oal/oal.h | 2 + engine/inc/uf/ext/vulkan.h | 19 +- engine/inc/uf/ext/vulkan/buffer.h | 18 +- engine/inc/uf/ext/vulkan/graphic.h | 2 +- engine/inc/uf/utils/audio/audio.h | 2 + engine/inc/uf/utils/component/component.h | 2 + engine/inc/uf/utils/hook/hook.h | 4 +- engine/inc/uf/utils/math/vector.h | 2 + engine/inc/uf/utils/math/vector/pod.inl | 2 + engine/inc/uf/utils/serialize/serializer.h | 28 +- engine/inc/uf/utils/userdata/userdata.h | 2 + engine/inc/uf/utils/userdata/userdata.inl | 10 +- engine/src/engine/asset/asset.cpp | 28 +- engine/src/engine/behavior/behavior.cpp | 59 +- engine/src/engine/entity/behavior.cpp | 10 +- engine/src/engine/entity/entity.cpp | 2 + .../src/engine/instantiator/instantiator.cpp | 43 + engine/src/engine/object/behavior.cpp | 71 +- engine/src/engine/object/behaviors/gltf.cpp | 32 +- .../src/engine/object/behaviors/loading.cpp | 24 +- engine/src/engine/object/behaviors/lua.cpp | 8 +- engine/src/engine/object/behaviors/render.cpp | 2 +- engine/src/engine/object/object.cpp | 214 +- engine/src/engine/scene/behavior.cpp | 8 +- engine/src/engine/scene/scene.cpp | 34 +- engine/src/ext/discord/discord.cpp | 26 +- .../ext/json/{jsoncpp.cpp2 => jsoncpp.cpp} | 2689 +++++---- engine/src/ext/json/jsoncpp.cpp1 | 5139 ----------------- engine/src/ext/lua/lua.cpp | 317 +- engine/src/ext/lua/usertypes/asset.cpp | 19 + engine/src/ext/lua/usertypes/audio.cpp | 33 + engine/src/ext/lua/usertypes/camera.cpp | 7 + engine/src/ext/lua/usertypes/matrix.cpp | 9 + engine/src/ext/lua/usertypes/object.cpp | 163 + engine/src/ext/lua/usertypes/quaternion.cpp | 35 + engine/src/ext/lua/usertypes/timer.cpp | 14 + engine/src/ext/lua/usertypes/transform.cpp | 35 + engine/src/ext/lua/usertypes/vector.cpp | 59 + engine/src/ext/oal/oal.cpp | 25 +- engine/src/ext/openvr/openvr.cpp | 6 +- engine/src/ext/vulkan/buffer.cpp | 9 +- engine/src/ext/vulkan/device.cpp | 22 +- engine/src/ext/vulkan/graphic.cpp | 294 +- engine/src/ext/vulkan/rendermode.cpp | 4 +- engine/src/ext/vulkan/rendermodes/compute.cpp | 2 +- .../src/ext/vulkan/rendermodes/deferred.cpp | 32 +- .../multiview_stereoscopic_deferred.cpp | 12 +- .../ext/vulkan/rendermodes/rendertarget.cpp | 10 +- .../rendermodes/stereoscopic_deferred.cpp | 14 +- engine/src/ext/vulkan/rendertarget.cpp | 24 + engine/src/ext/vulkan/vulkan.cpp | 16 +- engine/src/spec/window/universal.cpp | 4 +- engine/src/utils/audio/audio.cpp | 59 +- engine/src/utils/component/component.cpp | 12 +- engine/src/utils/hook/hook.cpp | 55 +- engine/src/utils/serialize/serializer.cpp | 84 +- engine/src/utils/string/ext.cpp | 22 +- engine/src/utils/userdata/userdata.cpp | 15 +- ext/behaviors/craeture/behavior.cpp | 52 +- ext/behaviors/hands/behavior.cpp | 124 +- ext/behaviors/light/behavior.cpp | 88 +- ext/behaviors/player/behavior.cpp | 200 +- ext/behaviors/portal/behavior.cpp | 10 +- ext/behaviors/scene/behavior.cpp | 101 +- ext/behaviors/scene/collision/behavior.cpp | 35 +- ext/behaviors/soundemitter/behavior.cpp | 24 +- ext/behaviors/sprite/behavior.cpp | 24 +- ext/behaviors/staticemitter/behavior.cpp | 74 - ext/behaviors/staticemitter/behavior.h | 17 - ext/gui/behavior.cpp | 342 +- ext/gui/manager/behavior.cpp | 64 +- ext/inits/persistence.inl | 6 +- ext/main.cpp | 205 +- ext/scenes/raytrace/behavior.cpp | 52 +- ext/scenes/start/behavior.cpp | 111 - ext/scenes/start/behavior.h | 17 - ext/scenes/worldscape/behavior.cpp | 13 +- ext/scenes/worldscape/gui/battle.cpp | 222 +- ext/scenes/worldscape/gui/dialogue.cpp | 40 +- ext/scenes/worldscape/gui/pause.cpp | 578 -- ext/scenes/worldscape/gui/pause.h | 13 - ext/scenes/worldscape/gui/pause/behavior.cpp | 590 -- ext/scenes/worldscape/gui/pause/behavior.h | 17 - ext/scenes/worldscape/housamo/battle.cpp | 554 +- ext/scenes/worldscape/housamo/dialogue.cpp | 38 +- ext/scenes/worldscape/housamo/housamo.cpp | 64 +- ext/scenes/worldscape/terrain/behavior.cpp | 60 +- ext/scenes/worldscape/terrain/generator.cpp | 36 +- ext/scenes/worldscape/terrain/region.cpp | 110 +- ext/scenes/worldscape/terrain/terrain.cpp | 60 +- makefiles/win64.gcc.make | 2 +- makefiles/win64.gcc10.make | 2 +- program.sh | 3 +- 122 files changed, 7024 insertions(+), 9959 deletions(-) rename engine/inc/{json => json-old}/allocator.h (100%) rename engine/inc/{json => json-old}/assertions.h (100%) rename engine/inc/{json => json-old}/autolink.h (100%) rename engine/inc/{json => json-old}/config.h (100%) rename engine/inc/{json => json-old}/features.h (100%) rename engine/inc/{json => json-old}/forwards.h (100%) create mode 100644 engine/inc/json-old/json.h rename engine/inc/{json => json-old}/reader.h (100%) rename engine/inc/{json => json-old}/value.h (100%) rename engine/inc/{json => json-old}/version.h (100%) rename engine/inc/{json => json-old}/writer.h (100%) create mode 100644 engine/inc/json/json-forwards.h create mode 100644 engine/inc/uf/ext/json/json.h create mode 100644 engine/inc/uf/ext/json/json.inl rename engine/src/ext/json/{jsoncpp.cpp2 => jsoncpp.cpp} (67%) delete mode 100644 engine/src/ext/json/jsoncpp.cpp1 create mode 100644 engine/src/ext/lua/usertypes/asset.cpp create mode 100644 engine/src/ext/lua/usertypes/audio.cpp create mode 100644 engine/src/ext/lua/usertypes/camera.cpp create mode 100644 engine/src/ext/lua/usertypes/matrix.cpp create mode 100644 engine/src/ext/lua/usertypes/object.cpp create mode 100644 engine/src/ext/lua/usertypes/quaternion.cpp create mode 100644 engine/src/ext/lua/usertypes/timer.cpp create mode 100644 engine/src/ext/lua/usertypes/transform.cpp create mode 100644 engine/src/ext/lua/usertypes/vector.cpp delete mode 100644 ext/behaviors/staticemitter/behavior.cpp delete mode 100644 ext/behaviors/staticemitter/behavior.h delete mode 100644 ext/scenes/start/behavior.cpp delete mode 100644 ext/scenes/start/behavior.h delete mode 100644 ext/scenes/worldscape/gui/pause.cpp delete mode 100644 ext/scenes/worldscape/gui/pause.h delete mode 100644 ext/scenes/worldscape/gui/pause/behavior.cpp delete mode 100644 ext/scenes/worldscape/gui/pause/behavior.h diff --git a/Makefile b/Makefile index 36d02a70..e1a7cc50 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -DEFAULT_PREFIX = gcc -include makefiles/win64.$(DEFAULT_PREFIX).make +PREFIX = gcc +include makefiles/win64.$(PREFIX).make .PHONY: $(ARCH)-$(PREFIX) @@ -15,15 +15,15 @@ CLIENT_SRC_DIR += ./client UF_LIBS += EXT_LIBS += -FLAGS += -std=c++17 -DVK_USE_PLATFORM_WIN32_KHR -DUF_USE_VULKAN -DGLM_ENABLE_EXPERIMENTAL -DUF_USE_JSON -DUF_USE_NCURSES -DUF_USE_OPENAL -DUF_USE_VORBIS -DUF_USE_FREETYPE -DUSE_OPENVR_MINGW +FLAGS += -Wno-unknown-pragmas -std=c++17 -g -DVK_USE_PLATFORM_WIN32_KHR -DUF_USE_VULKAN -DGLM_ENABLE_EXPERIMENTAL -DUF_USE_JSON -DUF_USE_NCURSES -DUF_USE_OPENAL -DUF_USE_VORBIS -DUF_USE_FREETYPE -DUSE_OPENVR_MINGW LIB_NAME += uf EXT_LIB_NAME += ext #VULKAN_SDK_PATH += /c/VulkanSDK/1.1.101.0/ #VULKAN_SDK_PATH += /c/VulkanSDK/1.1.108.0/ #VULKAN_SDK_PATH += /c/VulkanSDK/1.1.114.0/ -VULKAN_SDK_PATH += /c/VulkanSDK/1.2.141.2/ -#VULKAN_SDK_PATH += /c/VulkanSDK/1.2.154.0/ +#VULKAN_SDK_PATH += /c/VulkanSDK/1.2.141.2/ +VULKAN_SDK_PATH += /c/VulkanSDK/1.2.154.0/ GLSL_VALIDATOR += $(VULKAN_SDK_PATH)/Bin32/glslangValidator # Base Engine's DLL INC_DIR += $(ENGINE_INC_DIR)/$(ARCH)/$(PREFIX) @@ -41,13 +41,12 @@ SRCS_DLL += $(wildcard $(ENGINE_SRC_DIR)/*.cpp) $(wildcard $(ENGINE_SRC_DIR) OBJS_DLL += $(patsubst %.cpp,%.$(ARCH).$(PREFIX).o,$(SRCS_DLL)) BASE_DLL += lib$(LIB_NAME) IM_DLL += $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_DLL).dll.a -EX_DLL += $(BIN_DIR)/lib/$(ARCH)/$(PREFIX)/$(BASE_DLL).dll +EX_DLL += $(BIN_DIR)/exe/lib/$(ARCH)/$(PREFIX)/$(BASE_DLL).dll # External Engine's DLL EXT_INC_DIR += $(INC_DIR) EXT_LB_FLAGS += $(LIB_DIR) EXT_DEPS += -l$(LIB_NAME) $(DEPS) EXT_LINKS += $(UF_LIBS) $(EXT_LIBS) $(EXT_DEPS) -EXT_FLAGS += $(FLAGS) #-Wl,-subsystem,windows EXT_LIB_DIR += $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/ @@ -58,11 +57,11 @@ SRCS_EXT_DLL += $(wildcard $(EXT_SRC_DIR)/*.cpp) $(wildcard $(EXT_SRC_DIR)/*/ OBJS_EXT_DLL += $(patsubst %.cpp,%.$(ARCH).$(PREFIX).o,$(SRCS_EXT_DLL)) BASE_EXT_DLL += lib$(EXT_LIB_NAME) EXT_IM_DLL += $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_EXT_DLL).dll.a -EXT_EX_DLL += $(BIN_DIR)/lib/$(ARCH)/$(PREFIX)/$(BASE_EXT_DLL).dll +EXT_EX_DLL += $(BIN_DIR)/exe/lib/$(ARCH)/$(PREFIX)/$(BASE_EXT_DLL).dll # Client EXE SRCS += $(wildcard $(CLIENT_SRC_DIR)/*.cpp) $(wildcard $(CLIENT_SRC_DIR)/*/*.cpp) OBJS += $(patsubst %.cpp,%.$(ARCH).$(PREFIX).o,$(SRCS)) -TARGET += $(BIN_DIR)/$(TARGET_NAME).$(PREFIX).exe +TARGET += $(BIN_DIR)/exe/$(TARGET_NAME).$(PREFIX).exe # Shaders SRCS_SHADERS += $(wildcard bin/data/shaders/*.glsl) TARGET_SHADERS += $(patsubst %.glsl,%.spv,$(SRCS_SHADERS)) @@ -78,12 +77,12 @@ rm-exe64: %.$(ARCH).$(PREFIX).o: %.cpp $(CC) $(FLAGS) $(INCS) -c $< -o $@ -$(EX_DLL): FLAGS += -DUF_EXPORTS +$(EX_DLL): FLAGS += -DUF_EXPORTS -DJSON_DLL_BUILD $(EX_DLL): $(OBJS_DLL) $(CC) -shared -o $(EX_DLL) -g -Wl,--out-implib=$(IM_DLL) $(OBJS_DLL) $(LIBS) $(INCS) $(LINKS) cp $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_DLL).dll.a $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_DLL).a -$(EXT_EX_DLL): FLAGS += -DEXT_EXPORTS +$(EXT_EX_DLL): FLAGS += -DEXT_EXPORTS -DJSON_DLL_BUILD $(EXT_EX_DLL): $(OBJS_EXT_DLL) $(CC) -shared -o $(EXT_EX_DLL) -g -Wl,--out-implib=$(EXT_IM_DLL) $(OBJS_EXT_DLL) $(EXT_LIBS) $(EXT_INCS) $(EXT_LINKS) cp $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_EXT_DLL).dll.a $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_EXT_DLL).a diff --git a/bin/data/shaders/display.rendertarget.frag.glsl b/bin/data/shaders/display.rendertarget.frag.glsl index f817f3d0..88efa001 100644 --- a/bin/data/shaders/display.rendertarget.frag.glsl +++ b/bin/data/shaders/display.rendertarget.frag.glsl @@ -26,7 +26,6 @@ void main() { outAlbedoSpecular = texture(sampler2D(albedoTexture, samp), uv); outNormal = texture(sampler2D(normalTexture, samp), uv); outPosition = texture(sampler2D(positionTexture, samp), uv); - // if ( outAlbedoSpecular.a < 0.01f ) outAlbedoSpecular = vec4(0,0,0,1); return; } diff --git a/bin/data/shaders/gui.text.frag.glsl b/bin/data/shaders/gui.text.frag.glsl index ba599489..84f6b603 100644 --- a/bin/data/shaders/gui.text.frag.glsl +++ b/bin/data/shaders/gui.text.frag.glsl @@ -31,8 +31,6 @@ void main() { return; } float dist = texture(samplerColor, inUv).r; -// outFragColor = mix(vec4(inGui.color) * dist, vec4(1.0f, 0.0f, 1.0f, 0.5f), 0.9); - if ( inGui.sdf == 1 ) { float smoothing = ( inGui.spread > 0 && inGui.scale > 0 ) ? 0.25 / (inGui.spread * inGui.scale) : 0.25 / (4 * 1.5); float outlining = smoothstep(0.5 - smoothing, 0.5 + smoothing, dist); diff --git a/client/client/ext.cpp b/client/client/ext.cpp index ab5947e4..b51e6dd2 100644 --- a/client/client/ext.cpp +++ b/client/client/ext.cpp @@ -34,8 +34,8 @@ void client::initialize() { /* Initialize window */ { // Window size pod::Vector2i size; { - size.x = client::config["window"]["size"]["x"].asUInt(); - size.y = client::config["window"]["size"]["y"].asUInt(); + size.x = client::config["window"]["size"]["x"].as(); + size.y = client::config["window"]["size"]["y"].as(); // request system size if ( size.x <= 0 && size.y <= 0 ) { auto resolution = client::window.getResolution(); @@ -45,12 +45,12 @@ void client::initialize() { } // Window title uf::String title; { - title = client::config["window"]["title"].asString(); + title = client::config["window"]["title"].as(); } // Terminal window; - spec::terminal.setVisible( client::config["window"]["terminal"]["visible"].asBool() ); + spec::terminal.setVisible( client::config["window"]["terminal"]["visible"].as() ); // Ncurses - uf::IoStream::ncurses = client::config["window"]["terminal"]["ncurses"].asBool(); + uf::IoStream::ncurses = client::config["window"]["terminal"]["ncurses"].as(); // Window's context settings uf::renderer::settings::width = size.x; @@ -58,16 +58,16 @@ void client::initialize() { client::window.create( size, title ); // Miscellaneous - client::window.setVisible(client::config["window"]["visible"].asBool()); - client::window.setCursorVisible(client::config["window"]["cursor"]["visible"].asBool()); - client::window.setKeyRepeatEnabled(client::config["window"]["keyboard"]["repeat"].asBool()); + client::window.setVisible(client::config["window"]["visible"].as()); + client::window.setCursorVisible(client::config["window"]["cursor"]["visible"].as()); + client::window.setKeyRepeatEnabled(client::config["window"]["keyboard"]["repeat"].as()); // client::window.centerWindow(); // client::window.setPosition({0, 0}); // client::window.setMouseGrabbed(true); - /* Set Icon */ if ( client::config["window"]["icon"].isString() ) { + /* Set Icon */ if ( client::config["window"]["icon"].is() ) { uf::Image icon; - icon.open(client::config["window"]["icon"].asString()); + icon.open(client::config["window"]["icon"].as()); client::window.setIcon({(int) icon.getDimensions().x, (int) icon.getDimensions().y}, ((uint8_t*)icon.getPixelsPtr())); } client::window.setTitle(title); { @@ -94,10 +94,10 @@ void client::initialize() { if ( client::config["engine"]["hook"]["mode"] == "Both" || client::config["engine"]["hook"]["mode"] == "Readable" ) { uf::hooks.addHook( "window:Mouse.CursorVisibility", [&](const std::string& event)->std::string{ uf::Serializer json = event; - client::window.setCursorVisible(json["state"].asBool()); - client::window.setMouseGrabbed(!json["state"].asBool()); - client::config["mouse"]["visible"] = json["state"].asBool(); - client::config["window"]["mouse"]["center"] = !json["state"].asBool(); + client::window.setCursorVisible(json["state"].as()); + client::window.setMouseGrabbed(!json["state"].as()); + client::config["mouse"]["visible"] = json["state"].as(); + client::config["window"]["mouse"]["center"] = !json["state"].as(); return "true"; }); uf::hooks.addHook( "window:Mouse.Lock", [&](const std::string& event)->std::string{ @@ -115,8 +115,8 @@ void client::initialize() { uf::hooks.addHook( "window:Title.Changed", [&](const std::string& event)->std::string{ uf::Serializer json = event; if ( json["invoker"] != "os" ) { - if ( !json["window"].isObject() ) return "false"; - uf::String title = json["window"]["title"].asString(); + if ( !ext::json::isObject( json["window"] ) ) return "false"; + uf::String title = json["window"]["title"].as(); client::window.setTitle(title); } return "true"; @@ -124,15 +124,15 @@ void client::initialize() { uf::hooks.addHook( "window:Resized", [&](const std::string& event)->std::string{ uf::Serializer json = event; pod::Vector2i size; { - size.x = json["window"]["size"]["x"].asUInt64(); - size.y = json["window"]["size"]["y"].asUInt64(); + size.x = json["window"]["size"]["x"].as(); + size.y = json["window"]["size"]["y"].as(); } if ( json["invoker"] != "os" ) { client::window.setSize(size); } // Update viewport - if ( !client::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"].isArray() ) { - float scale = client::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"].isNumeric() ? client::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"].asFloat() : 1; + if ( !ext::json::isArray( client::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"] ) ) { + float scale = client::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"].is() ? client::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"].as() : 1; uf::renderer::settings::width = size.x * scale; uf::renderer::settings::height = size.y * scale; } @@ -182,8 +182,8 @@ void client::initialize() { } ); } } - if ( client::config["window"]["mode"].asString() == "fullscreen" ) client::window.switchToFullscreen(); - if ( client::config["window"]["mode"].asString() == "borderless" ) client::window.switchToFullscreen( true ); + if ( client::config["window"]["mode"].as() == "fullscreen" ) client::window.switchToFullscreen(); + if ( client::config["window"]["mode"].as() == "borderless" ) client::window.switchToFullscreen( true ); client::ready = true; } void client::tick() { @@ -191,7 +191,7 @@ void client::tick() { client::window.pollEvents(); // call mouse move // query lock - if ( client::window.hasFocus() && client::config["window"]["mouse"]["center"].asBool() ) { + if ( client::window.hasFocus() && client::config["window"]["mouse"]["center"].as() ) { auto previous = client::window.getMousePosition(); client::window.setMousePosition(client::window.getSize()/2); auto current = client::window.getMousePosition(); diff --git a/debug.sh b/debug.sh index a9c80213..97c9cd78 100644 --- a/debug.sh +++ b/debug.sh @@ -1,8 +1,7 @@ #!/bin/bash -PREFIX=gcc - cd bin -cp lib/win64/$PREFIX/*.dll . -gdb program.$PREFIX.exe +PREFIX=$(cat ./exe/default.config) +cp ./exe/lib/win64/$PREFIX/*.dll . +gdb ./exe/program.$PREFIX.exe rm *.dll diff --git a/engine/inc/json/allocator.h b/engine/inc/json-old/allocator.h similarity index 100% rename from engine/inc/json/allocator.h rename to engine/inc/json-old/allocator.h diff --git a/engine/inc/json/assertions.h b/engine/inc/json-old/assertions.h similarity index 100% rename from engine/inc/json/assertions.h rename to engine/inc/json-old/assertions.h diff --git a/engine/inc/json/autolink.h b/engine/inc/json-old/autolink.h similarity index 100% rename from engine/inc/json/autolink.h rename to engine/inc/json-old/autolink.h diff --git a/engine/inc/json/config.h b/engine/inc/json-old/config.h similarity index 100% rename from engine/inc/json/config.h rename to engine/inc/json-old/config.h diff --git a/engine/inc/json/features.h b/engine/inc/json-old/features.h similarity index 100% rename from engine/inc/json/features.h rename to engine/inc/json-old/features.h diff --git a/engine/inc/json/forwards.h b/engine/inc/json-old/forwards.h similarity index 100% rename from engine/inc/json/forwards.h rename to engine/inc/json-old/forwards.h diff --git a/engine/inc/json-old/json.h b/engine/inc/json-old/json.h new file mode 100644 index 00000000..3d2798a6 --- /dev/null +++ b/engine/inc/json-old/json.h @@ -0,0 +1,15 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_JSON_H_INCLUDED +#define JSON_JSON_H_INCLUDED + +#include "autolink.h" +#include "value.h" +#include "reader.h" +#include "writer.h" +#include "features.h" + +#endif // JSON_JSON_H_INCLUDED diff --git a/engine/inc/json/reader.h b/engine/inc/json-old/reader.h similarity index 100% rename from engine/inc/json/reader.h rename to engine/inc/json-old/reader.h diff --git a/engine/inc/json/value.h b/engine/inc/json-old/value.h similarity index 100% rename from engine/inc/json/value.h rename to engine/inc/json-old/value.h diff --git a/engine/inc/json/version.h b/engine/inc/json-old/version.h similarity index 100% rename from engine/inc/json/version.h rename to engine/inc/json-old/version.h diff --git a/engine/inc/json/writer.h b/engine/inc/json-old/writer.h similarity index 100% rename from engine/inc/json/writer.h rename to engine/inc/json-old/writer.h diff --git a/engine/inc/json/json-forwards.h b/engine/inc/json/json-forwards.h new file mode 100644 index 00000000..9330e4e6 --- /dev/null +++ b/engine/inc/json/json-forwards.h @@ -0,0 +1,446 @@ +/// Json-cpp amalgamated forward header (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json-forwards.h" +/// This header provides forward declaration for all JsonCpp types. + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and +The JsonCpp Authors, and is released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + +#ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED +# define JSON_FORWARD_AMALGAMATED_H_INCLUDED +/// If defined, indicates that the source file is amalgamated +/// to prevent private header inclusion. +#define JSON_IS_AMALGAMATION + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/version.h +// ////////////////////////////////////////////////////////////////////// + +#ifndef JSON_VERSION_H_INCLUDED +#define JSON_VERSION_H_INCLUDED + +// Note: version must be updated in three places when doing a release. This +// annoying process ensures that amalgamate, CMake, and meson all report the +// correct version. +// 1. /meson.build +// 2. /include/json/version.h +// 3. /CMakeLists.txt +// IMPORTANT: also update the SOVERSION!! + +#define JSONCPP_VERSION_STRING "1.9.4" +#define JSONCPP_VERSION_MAJOR 1 +#define JSONCPP_VERSION_MINOR 9 +#define JSONCPP_VERSION_PATCH 4 +#define JSONCPP_VERSION_QUALIFIER +#define JSONCPP_VERSION_HEXA \ + ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ + (JSONCPP_VERSION_PATCH << 8)) + +#ifdef JSONCPP_USING_SECURE_MEMORY +#undef JSONCPP_USING_SECURE_MEMORY +#endif +#define JSONCPP_USING_SECURE_MEMORY 0 +// If non-zero, the library zeroes any memory that it has allocated before +// it frees its memory. + +#endif // JSON_VERSION_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/version.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/allocator.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_ALLOCATOR_H_INCLUDED +#define JSON_ALLOCATOR_H_INCLUDED + +#include +#include + +#pragma pack(push, 8) + +namespace Json { +template class SecureAllocator { +public: + // Type definitions + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + /** + * Allocate memory for N items using the standard allocator. + */ + pointer allocate(size_type n) { + // allocate using "global operator new" + return static_cast(::operator new(n * sizeof(T))); + } + + /** + * Release memory which was allocated for N items at pointer P. + * + * The memory block is filled with zeroes before being released. + */ + void deallocate(pointer p, size_type n) { + // memset_s is used because memset may be optimized away by the compiler + memset_s(p, n * sizeof(T), 0, n * sizeof(T)); + // free using "global operator delete" + ::operator delete(p); + } + + /** + * Construct an item in-place at pointer P. + */ + template void construct(pointer p, Args&&... args) { + // construct using "placement new" and "perfect forwarding" + ::new (static_cast(p)) T(std::forward(args)...); + } + + size_type max_size() const { return size_t(-1) / sizeof(T); } + + pointer address(reference x) const { return std::addressof(x); } + + const_pointer address(const_reference x) const { return std::addressof(x); } + + /** + * Destroy an item in-place at pointer P. + */ + void destroy(pointer p) { + // destroy using "explicit destructor" + p->~T(); + } + + // Boilerplate + SecureAllocator() {} + template SecureAllocator(const SecureAllocator&) {} + template struct rebind { using other = SecureAllocator; }; +}; + +template +bool operator==(const SecureAllocator&, const SecureAllocator&) { + return true; +} + +template +bool operator!=(const SecureAllocator&, const SecureAllocator&) { + return false; +} + +} // namespace Json + +#pragma pack(pop) + +#endif // JSON_ALLOCATOR_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/allocator.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +#define JSON_CONFIG_H_INCLUDED +#include +#include +#include +#include +#include +#include +#include +#include + +// If non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +// Temporary, tracked for removal with issue #982. +#ifndef JSON_USE_NULLREF +#define JSON_USE_NULLREF 1 +#endif + +/// If defined, indicates that the source file is amalgamated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgamated header. +// #define JSON_IS_AMALGAMATION + +// Export macros for DLL visibility +#if defined(JSON_DLL_BUILD) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#elif defined(__GNUC__) || defined(__clang__) +#define JSON_API __attribute__((visibility("default"))) +#endif // if defined(_MSC_VER) + +#elif defined(JSON_DLL) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_DLL_BUILD + +#if !defined(JSON_API) +#define JSON_API +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1800 +#error \ + "ERROR: Visual Studio 12 (2013) with _MSC_VER=1800 is the oldest supported compiler with sufficient C++11 capabilities" +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1900 +// As recommended at +// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 +extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size, + const char* format, ...); +#define jsoncpp_snprintf msvc_pre1900_c99_snprintf +#else +#define jsoncpp_snprintf std::snprintf +#endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for +// integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools. +// C++11 should be used directly in JSONCPP. +#define JSONCPP_OVERRIDE override + +#ifdef __clang__ +#if __has_extension(attribute_deprecated_with_message) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#endif +#elif defined(__GNUC__) // not clang (gcc comes later since clang emulates gcc) +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +#endif // GNUC version +#elif defined(_MSC_VER) // MSVC (after clang because clang on Windows emulates + // MSVC) +#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#endif // __clang__ || __GNUC__ || _MSC_VER + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 6)) +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +#include "allocator.h" +#include "version.h" + +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { +using Int = int; +using UInt = unsigned int; +#if defined(JSON_NO_INT64) +using LargestInt = int; +using LargestUInt = unsigned int; +#undef JSON_HAS_INT64 +#else // if defined(JSON_NO_INT64) +// For Microsoft Visual use specific types as long long is not supported +#if defined(_MSC_VER) // Microsoft Visual Studio +using Int64 = __int64; +using UInt64 = unsigned __int64; +#else // if defined(_MSC_VER) // Other platforms, use long long +using Int64 = int64_t; +using UInt64 = uint64_t; +#endif // if defined(_MSC_VER) +using LargestInt = Int64; +using LargestUInt = UInt64; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) + +template +using Allocator = + typename std::conditional, + std::allocator>::type; +using String = std::basic_string, Allocator>; +using IStringStream = + std::basic_istringstream; +using OStringStream = + std::basic_ostringstream; +using IStream = std::istream; +using OStream = std::ostream; +} // namespace Json + +// Legacy names (formerly macros). +using JSONCPP_STRING = Json::String; +using JSONCPP_ISTRINGSTREAM = Json::IStringStream; +using JSONCPP_OSTRINGSTREAM = Json::OStringStream; +using JSONCPP_ISTREAM = Json::IStream; +using JSONCPP_OSTREAM = Json::OStream; + +#endif // JSON_CONFIG_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +#define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +// writer.h +class StreamWriter; +class StreamWriterBuilder; +class Writer; +class FastWriter; +class StyledWriter; +class StyledStreamWriter; + +// reader.h +class Reader; +class CharReader; +class CharReaderBuilder; + +// json_features.h +class Features; + +// value.h +using ArrayIndex = unsigned int; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED diff --git a/engine/inc/json/json.h b/engine/inc/json/json.h index 3d2798a6..60cf0ca6 100644 --- a/engine/inc/json/json.h +++ b/engine/inc/json/json.h @@ -1,15 +1,2342 @@ +/// Json-cpp amalgamated header (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json.h" + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and +The JsonCpp Authors, and is released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + +#ifndef JSON_AMALGAMATED_H_INCLUDED +# define JSON_AMALGAMATED_H_INCLUDED +/// If defined, indicates that the source file is amalgamated +/// to prevent private header inclusion. +#define JSON_IS_AMALGAMATION + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/version.h +// ////////////////////////////////////////////////////////////////////// + +#ifndef JSON_VERSION_H_INCLUDED +#define JSON_VERSION_H_INCLUDED + +// Note: version must be updated in three places when doing a release. This +// annoying process ensures that amalgamate, CMake, and meson all report the +// correct version. +// 1. /meson.build +// 2. /include/json/version.h +// 3. /CMakeLists.txt +// IMPORTANT: also update the SOVERSION!! + +#define JSONCPP_VERSION_STRING "1.9.4" +#define JSONCPP_VERSION_MAJOR 1 +#define JSONCPP_VERSION_MINOR 9 +#define JSONCPP_VERSION_PATCH 4 +#define JSONCPP_VERSION_QUALIFIER +#define JSONCPP_VERSION_HEXA \ + ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ + (JSONCPP_VERSION_PATCH << 8)) + +#ifdef JSONCPP_USING_SECURE_MEMORY +#undef JSONCPP_USING_SECURE_MEMORY +#endif +#define JSONCPP_USING_SECURE_MEMORY 0 +// If non-zero, the library zeroes any memory that it has allocated before +// it frees its memory. + +#endif // JSON_VERSION_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/version.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/allocator.h +// ////////////////////////////////////////////////////////////////////// + // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE -#ifndef JSON_JSON_H_INCLUDED -#define JSON_JSON_H_INCLUDED +#ifndef JSON_ALLOCATOR_H_INCLUDED +#define JSON_ALLOCATOR_H_INCLUDED -#include "autolink.h" +#include +#include + +#pragma pack(push, 8) + +namespace Json { +template class SecureAllocator { +public: + // Type definitions + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + /** + * Allocate memory for N items using the standard allocator. + */ + pointer allocate(size_type n) { + // allocate using "global operator new" + return static_cast(::operator new(n * sizeof(T))); + } + + /** + * Release memory which was allocated for N items at pointer P. + * + * The memory block is filled with zeroes before being released. + */ + void deallocate(pointer p, size_type n) { + // memset_s is used because memset may be optimized away by the compiler + memset_s(p, n * sizeof(T), 0, n * sizeof(T)); + // free using "global operator delete" + ::operator delete(p); + } + + /** + * Construct an item in-place at pointer P. + */ + template void construct(pointer p, Args&&... args) { + // construct using "placement new" and "perfect forwarding" + ::new (static_cast(p)) T(std::forward(args)...); + } + + size_type max_size() const { return size_t(-1) / sizeof(T); } + + pointer address(reference x) const { return std::addressof(x); } + + const_pointer address(const_reference x) const { return std::addressof(x); } + + /** + * Destroy an item in-place at pointer P. + */ + void destroy(pointer p) { + // destroy using "explicit destructor" + p->~T(); + } + + // Boilerplate + SecureAllocator() {} + template SecureAllocator(const SecureAllocator&) {} + template struct rebind { using other = SecureAllocator; }; +}; + +template +bool operator==(const SecureAllocator&, const SecureAllocator&) { + return true; +} + +template +bool operator!=(const SecureAllocator&, const SecureAllocator&) { + return false; +} + +} // namespace Json + +#pragma pack(pop) + +#endif // JSON_ALLOCATOR_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/allocator.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +#define JSON_CONFIG_H_INCLUDED +#include +#include +#include +#include +#include +#include +#include +#include + +// If non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +// Temporary, tracked for removal with issue #982. +#ifndef JSON_USE_NULLREF +#define JSON_USE_NULLREF 1 +#endif + +/// If defined, indicates that the source file is amalgamated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgamated header. +// #define JSON_IS_AMALGAMATION + +// Export macros for DLL visibility +#if defined(JSON_DLL_BUILD) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#elif defined(__GNUC__) || defined(__clang__) +#define JSON_API __attribute__((visibility("default"))) +#endif // if defined(_MSC_VER) + +#elif defined(JSON_DLL) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_DLL_BUILD + +#if !defined(JSON_API) +#define JSON_API +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1800 +#error \ + "ERROR: Visual Studio 12 (2013) with _MSC_VER=1800 is the oldest supported compiler with sufficient C++11 capabilities" +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1900 +// As recommended at +// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 +extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size, + const char* format, ...); +#define jsoncpp_snprintf msvc_pre1900_c99_snprintf +#else +#define jsoncpp_snprintf std::snprintf +#endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for +// integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools. +// C++11 should be used directly in JSONCPP. +#define JSONCPP_OVERRIDE override + +#ifdef __clang__ +#if __has_extension(attribute_deprecated_with_message) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#endif +#elif defined(__GNUC__) // not clang (gcc comes later since clang emulates gcc) +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +#endif // GNUC version +#elif defined(_MSC_VER) // MSVC (after clang because clang on Windows emulates + // MSVC) +#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#endif // __clang__ || __GNUC__ || _MSC_VER + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 6)) +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +#include "allocator.h" +#include "version.h" + +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { +using Int = int; +using UInt = unsigned int; +#if defined(JSON_NO_INT64) +using LargestInt = int; +using LargestUInt = unsigned int; +#undef JSON_HAS_INT64 +#else // if defined(JSON_NO_INT64) +// For Microsoft Visual use specific types as long long is not supported +#if defined(_MSC_VER) // Microsoft Visual Studio +using Int64 = __int64; +using UInt64 = unsigned __int64; +#else // if defined(_MSC_VER) // Other platforms, use long long +using Int64 = int64_t; +using UInt64 = uint64_t; +#endif // if defined(_MSC_VER) +using LargestInt = Int64; +using LargestUInt = UInt64; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) + +template +using Allocator = + typename std::conditional, + std::allocator>::type; +using String = std::basic_string, Allocator>; +using IStringStream = + std::basic_istringstream; +using OStringStream = + std::basic_ostringstream; +using IStream = std::istream; +using OStream = std::ostream; +} // namespace Json + +// Legacy names (formerly macros). +using JSONCPP_STRING = Json::String; +using JSONCPP_ISTRINGSTREAM = Json::IStringStream; +using JSONCPP_OSTRINGSTREAM = Json::OStringStream; +using JSONCPP_ISTREAM = Json::IStream; +using JSONCPP_OSTREAM = Json::OStream; + +#endif // JSON_CONFIG_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +#define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +// writer.h +class StreamWriter; +class StreamWriterBuilder; +class Writer; +class FastWriter; +class StyledWriter; +class StyledStreamWriter; + +// reader.h +class Reader; +class CharReader; +class CharReaderBuilder; + +// json_features.h +class Features; + +// value.h +using ArrayIndex = unsigned int; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/json_features.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FEATURES_H_INCLUDED +#define JSON_FEATURES_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +#pragma pack(push, 8) + +namespace Json { + +/** \brief Configuration passed to reader and writer. + * This configuration object can be used to force the Reader or Writer + * to behave in a standard conforming way. + */ +class JSON_API Features { +public: + /** \brief A configuration that allows all features and assumes all strings + * are UTF-8. + * - C & C++ comments are allowed + * - Root object can be any JSON value + * - Assumes Value strings are encoded in UTF-8 + */ + static Features all(); + + /** \brief A configuration that is strictly compatible with the JSON + * specification. + * - Comments are forbidden. + * - Root object must be either an array or an object value. + * - Assumes Value strings are encoded in UTF-8 + */ + static Features strictMode(); + + /** \brief Initialize the configuration like JsonConfig::allFeatures; + */ + Features(); + + /// \c true if comments are allowed. Default: \c true. + bool allowComments_{true}; + + /// \c true if root must be either an array or an object value. Default: \c + /// false. + bool strictRoot_{false}; + + /// \c true if dropped null placeholders are allowed. Default: \c false. + bool allowDroppedNullPlaceholders_{false}; + + /// \c true if numeric object key are allowed. Default: \c false. + bool allowNumericKeys_{false}; +}; + +} // namespace Json + +#pragma pack(pop) + +#endif // JSON_FEATURES_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/json_features.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/value.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_H_INCLUDED +#define JSON_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +// Conditional NORETURN attribute on the throw functions would: +// a) suppress false positives from static code analysis +// b) possibly improve optimization opportunities. +#if !defined(JSONCPP_NORETURN) +#if defined(_MSC_VER) && _MSC_VER == 1800 +#define JSONCPP_NORETURN __declspec(noreturn) +#else +#define JSONCPP_NORETURN [[noreturn]] +#endif +#endif + +// Support for '= delete' with template declarations was a late addition +// to the c++11 standard and is rejected by clang 3.8 and Apple clang 8.2 +// even though these declare themselves to be c++11 compilers. +#if !defined(JSONCPP_TEMPLATE_DELETE) +#if defined(__clang__) && defined(__apple_build_version__) +#if __apple_build_version__ <= 8000042 +#define JSONCPP_TEMPLATE_DELETE +#endif +#elif defined(__clang__) +#if __clang_major__ == 3 && __clang_minor__ <= 8 +#define JSONCPP_TEMPLATE_DELETE +#endif +#endif +#if !defined(JSONCPP_TEMPLATE_DELETE) +#define JSONCPP_TEMPLATE_DELETE = delete +#endif +#endif + +#include +#include +#include +#include +#include +#include + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push, 8) + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + +#if JSON_USE_EXCEPTION +/** Base class for all exceptions we throw. + * + * We use nothing but these internally. Of course, STL can throw others. + */ +class JSON_API Exception : public std::exception { +public: + Exception(String msg); + ~Exception() noexcept override; + char const* what() const noexcept override; + +protected: + String msg_; +}; + +/** Exceptions which the user cannot easily avoid. + * + * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input + * + * \remark derived from Json::Exception + */ +class JSON_API RuntimeError : public Exception { +public: + RuntimeError(String const& msg); +}; + +/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. + * + * These are precondition-violations (user bugs) and internal errors (our bugs). + * + * \remark derived from Json::Exception + */ +class JSON_API LogicError : public Exception { +public: + LogicError(String const& msg); +}; +#endif + +/// used internally +JSONCPP_NORETURN void throwRuntimeError(String const& msg); +/// used internally +JSONCPP_NORETURN void throwLogicError(String const& msg); + +/** \brief Type of the value held by a Value object. + */ +enum ValueType { + nullValue = 0, ///< 'null' value + intValue, ///< signed integer value + uintValue, ///< unsigned integer value + realValue, ///< double value + stringValue, ///< UTF-8 string value + booleanValue, ///< bool value + arrayValue, ///< array value (ordered list) + objectValue ///< object value (collection of name/value pairs). +}; + +enum CommentPlacement { + commentBefore = 0, ///< a comment placed on the line before a value + commentAfterOnSameLine, ///< a comment just after a value on the same line + commentAfter, ///< a comment on the line after a value (only make sense for + /// root value) + numberOfCommentPlacement +}; + +/** \brief Type of precision for formatting of real values. + */ +enum PrecisionType { + significantDigits = 0, ///< we set max number of significant digits in string + decimalPlaces ///< we set max number of digits after "." in string +}; + +/** \brief Lightweight wrapper to tag static string. + * + * Value constructor and objectValue member assignment takes advantage of the + * StaticString and avoid the cost of string duplication when storing the + * string or the member name. + * + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ +class JSON_API StaticString { +public: + explicit StaticString(const char* czstring) : c_str_(czstring) {} + + operator const char*() const { return c_str_; } + + const char* c_str() const { return c_str_; } + +private: + const char* c_str_; +}; + +/** \brief Represents a JSON value. + * + * This class is a discriminated union wrapper that can represents a: + * - signed integer [range: Value::minInt - Value::maxInt] + * - unsigned integer (range: 0 - Value::maxUInt) + * - double + * - UTF-8 string + * - boolean + * - 'null' + * - an ordered list of Value + * - collection of name/value pairs (javascript object) + * + * The type of the held value is represented by a #ValueType and + * can be obtained using type(). + * + * Values of an #objectValue or #arrayValue can be accessed using operator[]() + * methods. + * Non-const methods will automatically create the a #nullValue element + * if it does not exist. + * The sequence of an #arrayValue will be automatically resized and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtain default value in the case the + * required element does not exist. + * + * It is possible to iterate over the list of member keys of an object using + * the getMemberNames() method. + * + * \note #Value string-length fit in size_t, but keys must be < 2^30. + * (The reason is an implementation detail.) A #CharReader will raise an + * exception if a bound is exceeded to avoid security holes in your app, + * but the Value API does *not* check bounds. That is the responsibility + * of the caller. + */ +class JSON_API Value { + friend class ValueIteratorBase; + +public: + using Members = std::vector; + using iterator = ValueIterator; + using const_iterator = ValueConstIterator; + using UInt = Json::UInt; + using Int = Json::Int; +#if defined(JSON_HAS_INT64) + using UInt64 = Json::UInt64; + using Int64 = Json::Int64; +#endif // defined(JSON_HAS_INT64) + using LargestInt = Json::LargestInt; + using LargestUInt = Json::LargestUInt; + using ArrayIndex = Json::ArrayIndex; + + // Required for boost integration, e. g. BOOST_TEST + using value_type = std::string; + +#if JSON_USE_NULLREF + // Binary compatibility kludges, do not use. + static const Value& null; + static const Value& nullRef; +#endif + + // null and nullRef are deprecated, use this instead. + static Value const& nullSingleton(); + + /// Minimum signed integer value that can be stored in a Json::Value. + static constexpr LargestInt minLargestInt = + LargestInt(~(LargestUInt(-1) / 2)); + /// Maximum signed integer value that can be stored in a Json::Value. + static constexpr LargestInt maxLargestInt = LargestInt(LargestUInt(-1) / 2); + /// Maximum unsigned integer value that can be stored in a Json::Value. + static constexpr LargestUInt maxLargestUInt = LargestUInt(-1); + + /// Minimum signed int value that can be stored in a Json::Value. + static constexpr Int minInt = Int(~(UInt(-1) / 2)); + /// Maximum signed int value that can be stored in a Json::Value. + static constexpr Int maxInt = Int(UInt(-1) / 2); + /// Maximum unsigned int value that can be stored in a Json::Value. + static constexpr UInt maxUInt = UInt(-1); + +#if defined(JSON_HAS_INT64) + /// Minimum signed 64 bits int value that can be stored in a Json::Value. + static constexpr Int64 minInt64 = Int64(~(UInt64(-1) / 2)); + /// Maximum signed 64 bits int value that can be stored in a Json::Value. + static constexpr Int64 maxInt64 = Int64(UInt64(-1) / 2); + /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. + static constexpr UInt64 maxUInt64 = UInt64(-1); +#endif // defined(JSON_HAS_INT64) + /// Default precision for real value for string representation. + static constexpr UInt defaultRealPrecision = 17; + // The constant is hard-coded because some compiler have trouble + // converting Value::maxUInt64 to a double correctly (AIX/xlC). + // Assumes that UInt64 is a 64 bits integer. + static constexpr double maxUInt64AsDouble = 18446744073709551615.0; +// Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler +// when using gcc and clang backend compilers. CZString +// cannot be defined as private. See issue #486 +#ifdef __NVCC__ +public: +#else +private: +#endif +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + class CZString { + public: + enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy }; + CZString(ArrayIndex index); + CZString(char const* str, unsigned length, DuplicationPolicy allocate); + CZString(CZString const& other); + CZString(CZString&& other) noexcept; + ~CZString(); + CZString& operator=(const CZString& other); + CZString& operator=(CZString&& other) noexcept; + + bool operator<(CZString const& other) const; + bool operator==(CZString const& other) const; + ArrayIndex index() const; + // const char* c_str() const; ///< \deprecated + char const* data() const; + unsigned length() const; + bool isStaticString() const; + + private: + void swap(CZString& other); + + struct StringStorage { + unsigned policy_ : 2; + unsigned length_ : 30; // 1GB max + }; + + char const* cstr_; // actually, a prefixed string, unless policy is noDup + union { + ArrayIndex index_; + StringStorage storage_; + }; + }; + +public: + typedef std::map ObjectValues; +#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + +public: + /** + * \brief Create a default Value of the given type. + * + * This is a very useful constructor. + * To create an empty array, pass arrayValue. + * To create an empty object, pass objectValue. + * Another Value can then be set to this one by assignment. + * This is useful since clear() and resize() will not alter types. + * + * Examples: + * \code + * Json::Value null_value; // null + * Json::Value arr_value(Json::arrayValue); // [] + * Json::Value obj_value(Json::objectValue); // {} + * \endcode + */ + Value(ValueType type = nullValue); + Value(Int value); + Value(UInt value); +#if defined(JSON_HAS_INT64) + Value(Int64 value); + Value(UInt64 value); +#endif // if defined(JSON_HAS_INT64) + Value(double value); + Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.) + Value(const char* begin, const char* end); ///< Copy all, incl zeroes. + /** + * \brief Constructs a value from a static string. + * + * Like other value string constructor but do not duplicate the string for + * internal storage. The given string must remain alive after the call to + * this constructor. + * + * \note This works only for null-terminated strings. (We cannot change the + * size of this class, so we have nowhere to store the length, which might be + * computed later for various operations.) + * + * Example of usage: + * \code + * static StaticString foo("some text"); + * Json::Value aValue(foo); + * \endcode + */ + Value(const StaticString& value); + Value(const String& value); + Value(bool value); + Value(std::nullptr_t ptr) = delete; + Value(const Value& other); + Value(Value&& other) noexcept; + ~Value(); + + /// \note Overwrite existing comments. To preserve comments, use + /// #swapPayload(). + Value& operator=(const Value& other); + Value& operator=(Value&& other) noexcept; + + /// Swap everything. + void swap(Value& other); + /// Swap values but leave comments and source offsets in place. + void swapPayload(Value& other); + + /// copy everything. + void copy(const Value& other); + /// copy values but leave comments and source offsets in place. + void copyPayload(const Value& other); + + ValueType type() const; + + /// Compare payload only, not comments etc. + bool operator<(const Value& other) const; + bool operator<=(const Value& other) const; + bool operator>=(const Value& other) const; + bool operator>(const Value& other) const; + bool operator==(const Value& other) const; + bool operator!=(const Value& other) const; + int compare(const Value& other) const; + + const char* asCString() const; ///< Embedded zeroes could cause you trouble! +#if JSONCPP_USING_SECURE_MEMORY + unsigned getCStringLength() const; // Allows you to understand the length of + // the CString +#endif + String asString() const; ///< Embedded zeroes are possible. + /** Get raw char* of string-value. + * \return false if !string. (Seg-fault if str or end are NULL.) + */ + bool getString(char const** begin, char const** end) const; + Int asInt() const; + UInt asUInt() const; +#if defined(JSON_HAS_INT64) + Int64 asInt64() const; + UInt64 asUInt64() const; +#endif // if defined(JSON_HAS_INT64) + LargestInt asLargestInt() const; + LargestUInt asLargestUInt() const; + float asFloat() const; + double asDouble() const; + bool asBool() const; + + bool isNull() const; + bool isBool() const; + bool isInt() const; + bool isInt64() const; + bool isUInt() const; + bool isUInt64() const; + bool isIntegral() const; + bool isDouble() const; + bool isNumeric() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + + /// The `as` and `is` member function templates and specializations. + template T as() const JSONCPP_TEMPLATE_DELETE; + template bool is() const JSONCPP_TEMPLATE_DELETE; + + bool isConvertibleTo(ValueType other) const; + + /// Number of values in array or object + ArrayIndex size() const; + + /// \brief Return true if empty array, empty object, or null; + /// otherwise, false. + bool empty() const; + + /// Return !isNull() + explicit operator bool() const; + + /// Remove all object members and array elements. + /// \pre type() is arrayValue, objectValue, or nullValue + /// \post type() is unchanged + void clear(); + + /// Resize the array to newSize elements. + /// New elements are initialized to null. + /// May only be called on nullValue or arrayValue. + /// \pre type() is arrayValue or nullValue + /// \post type() is arrayValue + void resize(ArrayIndex newSize); + + //@{ + /// Access an array element (zero based index). If the array contains less + /// than index element, then null value are inserted in the array so that + /// its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value& operator[](ArrayIndex index); + Value& operator[](int index); + //@} + + //@{ + /// Access an array element (zero based index). + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value& operator[](ArrayIndex index) const; + const Value& operator[](int index) const; + //@} + + /// If the array contains at least index+1 elements, returns the element + /// value, otherwise returns defaultValue. + Value get(ArrayIndex index, const Value& defaultValue) const; + /// Return true if index < size(). + bool isValidIndex(ArrayIndex index) const; + /// \brief Append value to array at the end. + /// + /// Equivalent to jsonvalue[jsonvalue.size()] = value; + Value& append(const Value& value); + Value& append(Value&& value); + + /// \brief Insert value in array at specific index + bool insert(ArrayIndex index, const Value& newValue); + bool insert(ArrayIndex index, Value&& newValue); + + /// Access an object value by name, create a null member if it does not exist. + /// \note Because of our implementation, keys are limited to 2^30 -1 chars. + /// Exceeding that will cause an exception. + Value& operator[](const char* key); + /// Access an object value by name, returns null if there is no member with + /// that name. + const Value& operator[](const char* key) const; + /// Access an object value by name, create a null member if it does not exist. + /// \param key may contain embedded nulls. + Value& operator[](const String& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + /// \param key may contain embedded nulls. + const Value& operator[](const String& key) const; + /** \brief Access an object value by name, create a null member if it does not + * exist. + * + * If the object has no entry for that name, then the member name used to + * store the new entry is not duplicated. + * Example of use: + * \code + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + Value& operator[](const StaticString& key); + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const char* key, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \note key may contain embedded nulls. + Value get(const char* begin, const char* end, + const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \param key may contain embedded nulls. + Value get(const String& key, const Value& defaultValue) const; + /// Most general and efficient version of isMember()const, get()const, + /// and operator[]const + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + Value const* find(char const* begin, char const* end) const; + /// Most general and efficient version of object-mutators. + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. + Value* demand(char const* begin, char const* end); + /// \brief Remove and return the named member. + /// + /// Do nothing if it did not exist. + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + void removeMember(const char* key); + /// Same as removeMember(const char*) + /// \param key may contain embedded nulls. + void removeMember(const String& key); + /// Same as removeMember(const char* begin, const char* end, Value* removed), + /// but 'key' is null-terminated. + bool removeMember(const char* key, Value* removed); + /** \brief Remove the named map member. + * + * Update 'removed' iff removed. + * \param key may contain embedded nulls. + * \return true iff removed (no exceptions) + */ + bool removeMember(String const& key, Value* removed); + /// Same as removeMember(String const& key, Value* removed) + bool removeMember(const char* begin, const char* end, Value* removed); + /** \brief Remove the indexed array element. + * + * O(n) expensive operations. + * Update 'removed' iff removed. + * \return true if removed (no exceptions) + */ + bool removeIndex(ArrayIndex index, Value* removed); + + /// Return true if the object has a member named key. + /// \note 'key' must be null-terminated. + bool isMember(const char* key) const; + /// Return true if the object has a member named key. + /// \param key may contain embedded nulls. + bool isMember(const String& key) const; + /// Same as isMember(String const& key)const + bool isMember(const char* begin, const char* end) const; + + /// \brief Return a list of the member names. + /// + /// If null, return an empty list. + /// \pre type() is objectValue or nullValue + /// \post if type() was nullValue, it remains nullValue + Members getMemberNames() const; + + /// \deprecated Always pass len. + JSONCPP_DEPRECATED("Use setComment(String const&) instead.") + void setComment(const char* comment, CommentPlacement placement) { + setComment(String(comment, strlen(comment)), placement); + } + /// Comments must be //... or /* ... */ + void setComment(const char* comment, size_t len, CommentPlacement placement) { + setComment(String(comment, len), placement); + } + /// Comments must be //... or /* ... */ + void setComment(String comment, CommentPlacement placement); + bool hasComment(CommentPlacement placement) const; + /// Include delimiters and embedded newlines. + String getComment(CommentPlacement placement) const; + + String toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + + // Accessors for the [start, limit) range of bytes within the JSON text from + // which this value was parsed, if any. + void setOffsetStart(ptrdiff_t start); + void setOffsetLimit(ptrdiff_t limit); + ptrdiff_t getOffsetStart() const; + ptrdiff_t getOffsetLimit() const; + +private: + void setType(ValueType v) { + bits_.value_type_ = static_cast(v); + } + bool isAllocated() const { return bits_.allocated_; } + void setIsAllocated(bool v) { bits_.allocated_ = v; } + + void initBasic(ValueType type, bool allocated = false); + void dupPayload(const Value& other); + void releasePayload(); + void dupMeta(const Value& other); + + Value& resolveReference(const char* key); + Value& resolveReference(const char* key, const char* end); + + // struct MemberNamesTransform + //{ + // typedef const char *result_type; + // const char *operator()( const CZString &name ) const + // { + // return name.c_str(); + // } + //}; + + union ValueHolder { + LargestInt int_; + LargestUInt uint_; + double real_; + bool bool_; + char* string_; // if allocated_, ptr to { unsigned, char[] }. + ObjectValues* map_; + } value_; + + struct { + // Really a ValueType, but types should agree for bitfield packing. + unsigned int value_type_ : 8; + // Unless allocated_, string_ must be null-terminated. + unsigned int allocated_ : 1; + } bits_; + + class Comments { + public: + Comments() = default; + Comments(const Comments& that); + Comments(Comments&& that) noexcept; + Comments& operator=(const Comments& that); + Comments& operator=(Comments&& that) noexcept; + bool has(CommentPlacement slot) const; + String get(CommentPlacement slot) const; + void set(CommentPlacement slot, String comment); + + private: + using Array = std::array; + std::unique_ptr ptr_; + }; + Comments comments_; + + // [start, limit) byte offsets in the source JSON text from which this Value + // was extracted. + ptrdiff_t start_; + ptrdiff_t limit_; +}; + +template <> inline bool Value::as() const { return asBool(); } +template <> inline bool Value::is() const { return isBool(); } + +template <> inline Int Value::as() const { return asInt(); } +template <> inline bool Value::is() const { return isInt(); } + +template <> inline UInt Value::as() const { return asUInt(); } +template <> inline bool Value::is() const { return isUInt(); } + +#if defined(JSON_HAS_INT64) +template <> inline Int64 Value::as() const { return asInt64(); } +template <> inline bool Value::is() const { return isInt64(); } + +template <> inline UInt64 Value::as() const { return asUInt64(); } +template <> inline bool Value::is() const { return isUInt64(); } +#endif + +template <> inline double Value::as() const { return asDouble(); } +template <> inline bool Value::is() const { return isDouble(); } + +template <> inline String Value::as() const { return asString(); } +template <> inline bool Value::is() const { return isString(); } + +/// These `as` specializations are type conversions, and do not have a +/// corresponding `is`. +template <> inline float Value::as() const { return asFloat(); } +template <> inline const char* Value::as() const { + return asCString(); +} + +/** \brief Experimental and untested: represents an element of the "path" to + * access a node. + */ +class JSON_API PathArgument { +public: + friend class Path; + + PathArgument(); + PathArgument(ArrayIndex index); + PathArgument(const char* key); + PathArgument(String key); + +private: + enum Kind { kindNone = 0, kindIndex, kindKey }; + String key_; + ArrayIndex index_{}; + Kind kind_{kindNone}; +}; + +/** \brief Experimental and untested: represents a "path" to access a node. + * + * Syntax: + * - "." => root node + * - ".[n]" => elements at index 'n' of root node (an array value) + * - ".name" => member named 'name' of root node (an object value) + * - ".name1.name2.name3" + * - ".[0][1][2].name1[3]" + * - ".%" => member name is provided as parameter + * - ".[%]" => index is provided as parameter + */ +class JSON_API Path { +public: + Path(const String& path, const PathArgument& a1 = PathArgument(), + const PathArgument& a2 = PathArgument(), + const PathArgument& a3 = PathArgument(), + const PathArgument& a4 = PathArgument(), + const PathArgument& a5 = PathArgument()); + + const Value& resolve(const Value& root) const; + Value resolve(const Value& root, const Value& defaultValue) const; + /// Creates the "path" to access the specified node and returns a reference on + /// the node. + Value& make(Value& root) const; + +private: + using InArgs = std::vector; + using Args = std::vector; + + void makePath(const String& path, const InArgs& in); + void addPathInArg(const String& path, const InArgs& in, + InArgs::const_iterator& itInArg, PathArgument::Kind kind); + static void invalidPath(const String& path, int location); + + Args args_; +}; + +/** \brief base class for Value iterators. + * + */ +class JSON_API ValueIteratorBase { +public: + using iterator_category = std::bidirectional_iterator_tag; + using size_t = unsigned int; + using difference_type = int; + using SelfType = ValueIteratorBase; + + bool operator==(const SelfType& other) const { return isEqual(other); } + + bool operator!=(const SelfType& other) const { return !isEqual(other); } + + difference_type operator-(const SelfType& other) const { + return other.computeDistance(*this); + } + + /// Return either the index or the member name of the referenced value as a + /// Value. + Value key() const; + + /// Return the index of the referenced Value, or -1 if it is not an + /// arrayValue. + UInt index() const; + + /// Return the member name of the referenced Value, or "" if it is not an + /// objectValue. + /// \note Avoid `c_str()` on result, as embedded zeroes are possible. + String name() const; + + /// Return the member name of the referenced Value. "" if it is not an + /// objectValue. + /// \deprecated This cannot be used for UTF-8 strings, since there can be + /// embedded nulls. + JSONCPP_DEPRECATED("Use `key = name();` instead.") + char const* memberName() const; + /// Return the member name of the referenced Value, or NULL if it is not an + /// objectValue. + /// \note Better version than memberName(). Allows embedded nulls. + char const* memberName(char const** end) const; + +protected: + /*! Internal utility functions to assist with implementing + * other iterator functions. The const and non-const versions + * of the "deref" protected methods expose the protected + * current_ member variable in a way that can often be + * optimized away by the compiler. + */ + const Value& deref() const; + Value& deref(); + + void increment(); + + void decrement(); + + difference_type computeDistance(const SelfType& other) const; + + bool isEqual(const SelfType& other) const; + + void copy(const SelfType& other); + +private: + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_{true}; + +public: + // For some reason, BORLAND needs these at the end, rather + // than earlier. No idea why. + ValueIteratorBase(); + explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); +}; + +/** \brief const iterator for object and array value. + * + */ +class JSON_API ValueConstIterator : public ValueIteratorBase { + friend class Value; + +public: + using value_type = const Value; + // typedef unsigned int size_t; + // typedef int difference_type; + using reference = const Value&; + using pointer = const Value*; + using SelfType = ValueConstIterator; + + ValueConstIterator(); + ValueConstIterator(ValueIterator const& other); + +private: + /*! \internal Use by Value to create an iterator. + */ + explicit ValueConstIterator(const Value::ObjectValues::iterator& current); + +public: + SelfType& operator=(const ValueIteratorBase& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + reference operator*() const { return deref(); } + + pointer operator->() const { return &deref(); } +}; + +/** \brief Iterator for object and array value. + */ +class JSON_API ValueIterator : public ValueIteratorBase { + friend class Value; + +public: + using value_type = Value; + using size_t = unsigned int; + using difference_type = int; + using reference = Value&; + using pointer = Value*; + using SelfType = ValueIterator; + + ValueIterator(); + explicit ValueIterator(const ValueConstIterator& other); + ValueIterator(const ValueIterator& other); + +private: + /*! \internal Use by Value to create an iterator. + */ + explicit ValueIterator(const Value::ObjectValues::iterator& current); + +public: + SelfType& operator=(const SelfType& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + /*! The return value of non-const iterators can be + * changed, so the these functions are not const + * because the returned references/pointers can be used + * to change state of the base class. + */ + reference operator*() { return deref(); } + pointer operator->() { return &deref(); } +}; + +inline void swap(Value& a, Value& b) { a.swap(b); } + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/value.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/reader.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_READER_H_INCLUDED +#define JSON_READER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "json_features.h" #include "value.h" -#include "reader.h" -#include "writer.h" -#include "features.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include -#endif // JSON_JSON_H_INCLUDED +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push, 8) + +namespace Json { + +/** \brief Unserialize a JSON document into a + * Value. + * + * \deprecated Use CharReader and CharReaderBuilder. + */ + +class JSONCPP_DEPRECATED( + "Use CharReader and CharReaderBuilder instead.") JSON_API Reader { +public: + using Char = char; + using Location = const Char*; + + /** \brief An error tagged with where in the JSON text it was encountered. + * + * The offsets give the [start, limit) range of bytes within the text. Note + * that this is bytes, not codepoints. + */ + struct StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + String message; + }; + + /** \brief Constructs a Reader allowing all features for parsing. + */ + JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead") + Reader(); + + /** \brief Constructs a Reader allowing the specified feature set for parsing. + */ + JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead") + Reader(const Features& features); + + /** \brief Read a Value from a JSON + * document. + * + * \param document UTF-8 encoded string containing the document + * to read. + * \param[out] root Contains the root value of the document if it + * was successfully parsed. + * \param collectComments \c true to collect comment and allow writing + * them back during serialization, \c false to + * discard comments. This parameter is ignored + * if Features::allowComments_ is \c false. + * \return \c true if the document was successfully parsed, \c false if an + * error occurred. + */ + bool parse(const std::string& document, Value& root, + bool collectComments = true); + + /** \brief Read a Value from a JSON + * document. + * + * \param beginDoc Pointer on the beginning of the UTF-8 encoded + * string of the document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string + * of the document to read. Must be >= beginDoc. + * \param[out] root Contains the root value of the document if it + * was successfully parsed. + * \param collectComments \c true to collect comment and allow writing + * them back during serialization, \c false to + * discard comments. This parameter is ignored + * if Features::allowComments_ is \c false. + * \return \c true if the document was successfully parsed, \c false if an + * error occurred. + */ + bool parse(const char* beginDoc, const char* endDoc, Value& root, + bool collectComments = true); + + /// \brief Parse from input stream. + /// \see Json::operator>>(std::istream&, Json::Value&). + bool parse(IStream& is, Value& root, bool collectComments = true); + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * + * \return Formatted error message with the list of errors with their + * location in the parsed document. An empty string is returned if no error + * occurred during parsing. + * \deprecated Use getFormattedErrorMessages() instead (typo fix). + */ + JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") + String getFormatedErrorMessages() const; + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * + * \return Formatted error message with the list of errors with their + * location in the parsed document. An empty string is returned if no error + * occurred during parsing. + */ + String getFormattedErrorMessages() const; + + /** \brief Returns a vector of structured errors encountered while parsing. + * + * \return A (possibly empty) vector of StructuredError objects. Currently + * only one error can be returned, but the caller should tolerate multiple + * errors. This can occur if the parser recovers from a non-fatal parse + * error and then encounters additional errors. + */ + std::vector getStructuredErrors() const; + + /** \brief Add a semantic error message. + * + * \param value JSON Value location associated with the error + * \param message The error message. + * \return \c true if the error was successfully added, \c false if the Value + * offset exceeds the document size. + */ + bool pushError(const Value& value, const String& message); + + /** \brief Add a semantic error message with extra context. + * + * \param value JSON Value location associated with the error + * \param message The error message. + * \param extra Additional JSON Value location to contextualize the error + * \return \c true if the error was successfully added, \c false if either + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, const String& message, const Value& extra); + + /** \brief Return whether there are any errors. + * + * \return \c true if there are no errors to report \c false if errors have + * occurred. + */ + bool good() const; + +private: + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + String message_; + Location extra_; + }; + + using Errors = std::deque; + + bool readToken(Token& token); + void skipSpaces(); + bool match(const Char* pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + void readNumber(); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, String& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, Location& current, Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, Location& current, + Location end, unsigned int& unicode); + bool addError(const String& message, Token& token, Location extra = nullptr); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const String& message, Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void getLocationLineAndColumn(Location location, int& line, + int& column) const; + String getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + static bool containsNewLine(Location begin, Location end); + static String normalizeEOL(Location begin, Location end); + + using Nodes = std::stack; + Nodes nodes_; + Errors errors_; + String document_; + Location begin_{}; + Location end_{}; + Location current_{}; + Location lastValueEnd_{}; + Value* lastValue_{}; + String commentsBefore_; + Features features_; + bool collectComments_{}; +}; // Reader + +/** Interface for reading JSON from a char array. + */ +class JSON_API CharReader { +public: + virtual ~CharReader() = default; + /** \brief Read a Value from a JSON + * document. The document must be a UTF-8 encoded string containing the + * document to read. + * + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string + * of the document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the + * document to read. Must be >= beginDoc. + * \param[out] root Contains the root value of the document if it was + * successfully parsed. + * \param[out] errs Formatted error messages (if not NULL) a user + * friendly string that lists errors in the parsed + * document. + * \return \c true if the document was successfully parsed, \c false if an + * error occurred. + */ + virtual bool parse(char const* beginDoc, char const* endDoc, Value* root, + String* errs) = 0; + + class JSON_API Factory { + public: + virtual ~Factory() = default; + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual CharReader* newCharReader() const = 0; + }; // Factory +}; // CharReader + +/** \brief Build a CharReader implementation. + * + * Usage: + * \code + * using namespace Json; + * CharReaderBuilder builder; + * builder["collectComments"] = false; + * Value value; + * String errs; + * bool ok = parseFromStream(builder, std::cin, &value, &errs); + * \endcode + */ +class JSON_API CharReaderBuilder : public CharReader::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + * These are case-sensitive. + * Available settings (case-sensitive): + * - `"collectComments": false or true` + * - true to collect comment and allow writing them back during + * serialization, false to discard comments. This parameter is ignored + * if allowComments is false. + * - `"allowComments": false or true` + * - true if comments are allowed. + * - `"allowTrailingCommas": false or true` + * - true if trailing commas in objects and arrays are allowed. + * - `"strictRoot": false or true` + * - true if root must be either an array or an object value + * - `"allowDroppedNullPlaceholders": false or true` + * - true if dropped null placeholders are allowed. (See + * StreamWriterBuilder.) + * - `"allowNumericKeys": false or true` + * - true if numeric object keys are allowed. + * - `"allowSingleQuotes": false or true` + * - true if '' are allowed for strings (both keys and values) + * - `"stackLimit": integer` + * - Exceeding stackLimit (recursive depth of `readValue()`) will cause an + * exception. + * - This is a security issue (seg-faults caused by deeply nested JSON), so + * the default is low. + * - `"failIfExtra": false or true` + * - If true, `parse()` returns false when extra non-whitespace trails the + * JSON value in the input string. + * - `"rejectDupKeys": false or true` + * - If true, `parse()` returns false when a key is duplicated within an + * object. + * - `"allowSpecialFloats": false or true` + * - If true, special float values (NaNs and infinities) are allowed and + * their values are lossfree restorable. + * + * You can examine 'settings_` yourself to see the defaults. You can also + * write and read them just like any JSON Value. + * \sa setDefaults() + */ + Json::Value settings_; + + CharReaderBuilder(); + ~CharReaderBuilder() override; + + CharReader* newCharReader() const override; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + + /** A simple way to update a specific setting. + */ + Value& operator[](const String& key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults + */ + static void setDefaults(Json::Value* settings); + /** Same as old Features::strictMode(). + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode + */ + static void strictMode(Json::Value* settings); +}; + +/** Consume entire stream and use its begin/end. + * Someday we might have a real StreamReader, but for now this + * is convenient. + */ +bool JSON_API parseFromStream(CharReader::Factory const&, IStream&, Value* root, + String* errs); + +/** \brief Read from 'sin' into 'root'. + * + * Always keep comments from the input JSON. + * + * This can be used to read a file into a particular sub-object. + * For example: + * \code + * Json::Value root; + * cin >> root["dir"]["file"]; + * cout << root; + * \endcode + * Result: + * \verbatim + * { + * "dir": { + * "file": { + * // The input stream JSON would be nested here. + * } + * } + * } + * \endverbatim + * \throw std::exception on parse error. + * \see Json::operator<<() + */ +JSON_API IStream& operator>>(IStream&, Value&); + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_READER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/reader.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_WRITER_H_INCLUDED +#define JSON_WRITER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) && defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push, 8) + +namespace Json { + +class Value; + +/** + * + * Usage: + * \code + * using namespace Json; + * void writeToStdout(StreamWriter::Factory const& factory, Value const& value) + * { std::unique_ptr const writer( factory.newStreamWriter()); + * writer->write(value, &std::cout); + * std::cout << std::endl; // add lf and flush + * } + * \endcode + */ +class JSON_API StreamWriter { +protected: + OStream* sout_; // not owned; will not delete +public: + StreamWriter(); + virtual ~StreamWriter(); + /** Write Value into document as configured in sub-class. + * Do not take ownership of sout, but maintain a reference during function. + * \pre sout != NULL + * \return zero on success (For now, we always return zero, so check the + * stream instead.) \throw std::exception possibly, depending on + * configuration + */ + virtual int write(Value const& root, OStream* sout) = 0; + + /** \brief A simple abstract factory. + */ + class JSON_API Factory { + public: + virtual ~Factory(); + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual StreamWriter* newStreamWriter() const = 0; + }; // Factory +}; // StreamWriter + +/** \brief Write into stringstream, then return string, for convenience. + * A StreamWriter will be created from the factory, used, and then deleted. + */ +String JSON_API writeString(StreamWriter::Factory const& factory, + Value const& root); + +/** \brief Build a StreamWriter implementation. + +* Usage: +* \code +* using namespace Json; +* Value value = ...; +* StreamWriterBuilder builder; +* builder["commentStyle"] = "None"; +* builder["indentation"] = " "; // or whatever you like +* std::unique_ptr writer( +* builder.newStreamWriter()); +* writer->write(value, &std::cout); +* std::cout << std::endl; // add lf and flush +* \endcode +*/ +class JSON_API StreamWriterBuilder : public StreamWriter::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + * Available settings (case-sensitive): + * - "commentStyle": "None" or "All" + * - "indentation": "". + * - Setting this to an empty string also omits newline characters. + * - "enableYAMLCompatibility": false or true + * - slightly change the whitespace around colons + * - "dropNullPlaceholders": false or true + * - Drop the "null" string from the writer's output for nullValues. + * Strictly speaking, this is not valid JSON. But when the output is being + * fed to a browser's JavaScript, it makes for smaller output and the + * browser can handle the output just fine. + * - "useSpecialFloats": false or true + * - If true, outputs non-finite floating point values in the following way: + * NaN values as "NaN", positive infinity as "Infinity", and negative + * infinity as "-Infinity". + * - "precision": int + * - Number of precision digits for formatting of real values. + * - "precisionType": "significant"(default) or "decimal" + * - Type of precision for formatting of real values. + + * You can examine 'settings_` yourself + * to see the defaults. You can also write and read them just like any + * JSON Value. + * \sa setDefaults() + */ + Json::Value settings_; + + StreamWriterBuilder(); + ~StreamWriterBuilder() override; + + /** + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + StreamWriter* newStreamWriter() const override; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + /** A simple way to update a specific setting. + */ + Value& operator[](const String& key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults + */ + static void setDefaults(Json::Value* settings); +}; + +/** \brief Abstract class for writers. + * \deprecated Use StreamWriter. (And really, this is an implementation detail.) + */ +class JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer { +public: + virtual ~Writer(); + + virtual String write(const Value& root) = 0; +}; + +/** \brief Outputs a Value in JSON format + *without formatting (not human friendly). + * + * The JSON document is written in a single line. It is not intended for 'human' + *consumption, + * but may be useful to support feature such as RPC where bandwidth is limited. + * \sa Reader, Value + * \deprecated Use StreamWriterBuilder. + */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4996) // Deriving from deprecated class +#endif +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter + : public Writer { +public: + FastWriter(); + ~FastWriter() override = default; + + void enableYAMLCompatibility(); + + /** \brief Drop the "null" string from the writer's output for nullValues. + * Strictly speaking, this is not valid JSON. But when the output is being + * fed to a browser's JavaScript, it makes for smaller output and the + * browser can handle the output just fine. + */ + void dropNullPlaceholders(); + + void omitEndingLineFeed(); + +public: // overridden from Writer + String write(const Value& root) override; + +private: + void writeValue(const Value& value); + + String document_; + bool yamlCompatibilityEnabled_{false}; + bool dropNullPlaceholders_{false}; + bool omitEndingLineFeed_{false}; +}; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +/** \brief Writes a Value in JSON format in a + *human friendly way. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + *line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + *types, + * and all the values fit on one lines, then print the array on a single + *line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their + *#CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4996) // Deriving from deprecated class +#endif +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API + StyledWriter : public Writer { +public: + StyledWriter(); + ~StyledWriter() override = default; + +public: // overridden from Writer + /** \brief Serialize a Value in JSON format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + String write(const Value& root) override; + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultilineArray(const Value& value); + void pushValue(const String& value); + void writeIndent(); + void writeWithIndent(const String& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + static bool hasCommentForValue(const Value& value); + static String normalizeEOL(const String& text); + + using ChildValues = std::vector; + + ChildValues childValues_; + String document_; + String indentString_; + unsigned int rightMargin_{74}; + unsigned int indentSize_{3}; + bool addChildValues_{false}; +}; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +/** \brief Writes a Value in JSON format in a + human friendly way, + to a stream rather than to a string. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + types, + * and all the values fit on one lines, then print the array on a single + line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their + #CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4996) // Deriving from deprecated class +#endif +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API + StyledStreamWriter { +public: + /** + * \param indentation Each level will be indented by this amount extra. + */ + StyledStreamWriter(String indentation = "\t"); + ~StyledStreamWriter() = default; + +public: + /** \brief Serialize a Value in JSON format. + * \param out Stream to write to. (Can be ostringstream, e.g.) + * \param root Value to serialize. + * \note There is no point in deriving from Writer, since write() should not + * return a value. + */ + void write(OStream& out, const Value& root); + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultilineArray(const Value& value); + void pushValue(const String& value); + void writeIndent(); + void writeWithIndent(const String& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + static bool hasCommentForValue(const Value& value); + static String normalizeEOL(const String& text); + + using ChildValues = std::vector; + + ChildValues childValues_; + OStream* document_; + String indentString_; + unsigned int rightMargin_{74}; + String indentation_; + bool addChildValues_ : 1; + bool indented_ : 1; +}; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#if defined(JSON_HAS_INT64) +String JSON_API valueToString(Int value); +String JSON_API valueToString(UInt value); +#endif // if defined(JSON_HAS_INT64) +String JSON_API valueToString(LargestInt value); +String JSON_API valueToString(LargestUInt value); +String JSON_API valueToString( + double value, unsigned int precision = Value::defaultRealPrecision, + PrecisionType precisionType = PrecisionType::significantDigits); +String JSON_API valueToString(bool value); +String JSON_API valueToQuotedString(const char* value); + +/// \brief Output using the StyledStreamWriter. +/// \see Json::operator>>() +JSON_API OStream& operator<<(OStream&, const Value& root); + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_WRITER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/assertions.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_ASSERTIONS_H_INCLUDED +#define JSON_ASSERTIONS_H_INCLUDED + +#include +#include + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +/** It should not be possible for a maliciously designed file to + * cause an abort() or seg-fault, so these macros are used only + * for pre-condition violations and internal logic errors. + */ +#if JSON_USE_EXCEPTION + +// @todo <= add detail about condition in exception +#define JSON_ASSERT(condition) \ + do { \ + if (!(condition)) { \ + Json::throwLogicError("assert json failed"); \ + } \ + } while (0) + +#define JSON_FAIL_MESSAGE(message) \ + do { \ + OStringStream oss; \ + oss << message; \ + Json::throwLogicError(oss.str()); \ + abort(); \ + } while (0) + +#else // JSON_USE_EXCEPTION + +#define JSON_ASSERT(condition) assert(condition) + +// The call to assert() will show the failure message in debug builds. In +// release builds we abort, for a core-dump or debugger. +#define JSON_FAIL_MESSAGE(message) \ + { \ + OStringStream oss; \ + oss << message; \ + assert(false && oss.str().c_str()); \ + abort(); \ + } + +#endif + +#define JSON_ASSERT_MESSAGE(condition, message) \ + do { \ + if (!(condition)) { \ + JSON_FAIL_MESSAGE(message); \ + } \ + } while (0) + +#endif // JSON_ASSERTIONS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/assertions.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_AMALGAMATED_H_INCLUDED diff --git a/engine/inc/sol/sol.hpp b/engine/inc/sol/sol.hpp index 4a52e7c6..047c1389 100644 --- a/engine/inc/sol/sol.hpp +++ b/engine/inc/sol/sol.hpp @@ -23079,6 +23079,13 @@ namespace sol { return std::move(*this).template tuple_get(idx_seq()); } + template + bool is() const { + typedef decltype(get()) U; + optional option = get>(); + return option; + } + template decltype(auto) get_or(T&& otherwise) const { typedef decltype(get()) U; @@ -23195,6 +23202,24 @@ namespace sol { } return *this; } + + // added by me + template + inline decltype(auto) as() const& { + return get(); + } + + template + inline decltype(auto) as() && { + return get(); + } + + inline decltype(auto) begin() { + return get().begin(); + } + inline decltype(auto) end() { + return get().end(); + } }; template diff --git a/engine/inc/uf/engine/asset/asset.h b/engine/inc/uf/engine/asset/asset.h index e2e4b023..68a1c22f 100644 --- a/engine/inc/uf/engine/asset/asset.h +++ b/engine/inc/uf/engine/asset/asset.h @@ -8,9 +8,9 @@ #include namespace uf { - class UF_API Asset : public uf::Entity { + class UF_API Asset : public uf::Component { protected: - static uf::Entity masterAssetLoader; + static uf::Asset masterAssetLoader; public: // URL or file path void processQueue(); @@ -22,7 +22,7 @@ namespace uf { template std::vector& getContainer() { - return masterAssetLoader.getComponent>(); + return this->getComponent>(); } template @@ -38,28 +38,38 @@ namespace uf { template T& get( const std::string& url ) { std::string extension = uf::io::extension( url ); - uf::Serializer& map = masterAssetLoader.getComponent(); - std::size_t index = map[extension][url].asUInt64(); + uf::Serializer& map = this->getComponent(); + + std::size_t index = map[extension][url].as(); + // std::size_t index = map[extension][url]; + return this->get(index); } template T& add( const std::string& url, const T& copy ) { std::string extension = uf::io::extension( url ); - uf::Serializer& map = masterAssetLoader.getComponent(); + uf::Serializer& map = this->getComponent(); auto& container = this->getContainer(); + if ( !ext::json::isNull( map[extension][url] ) ) return this->get(url); + + // sol::optional value = map[extension][url]; + // if ( !value ) return this->get(url); - if ( !map[extension][url].isNull() ) return this->get(url); container.push_back( copy ); return container.back(); } template T& add( const std::string& url, T&& move ) { std::string extension = uf::io::extension( url ); - uf::Serializer& map = masterAssetLoader.getComponent(); + uf::Serializer& map = this->getComponent(); auto& container = this->getContainer(); - if ( !map[extension][url].isNull() ) return this->get(url); + if ( !ext::json::isNull( map[extension][url] ) ) return this->get(url); + + // sol::optional value = map[extension][url]; + // if ( !value ) return this->get(url); + container.push_back( move ); return container.back(); } diff --git a/engine/inc/uf/engine/behavior/behavior.h b/engine/inc/uf/engine/behavior/behavior.h index 06fc0063..8ded8cd9 100644 --- a/engine/inc/uf/engine/behavior/behavior.h +++ b/engine/inc/uf/engine/behavior/behavior.h @@ -17,10 +17,10 @@ namespace pod { typedef std::function function_t; type_t type = std::type_index(typeid(pod::Behavior)); - function_t initialize; - function_t tick; - function_t render; - function_t destroy; + function_t initialize = function_t(); + function_t tick = function_t(); + function_t render = function_t(); + function_t destroy = function_t(); }; } diff --git a/engine/inc/uf/engine/behavior/macros.inl b/engine/inc/uf/engine/behavior/macros.inl index df541f48..2629b023 100644 --- a/engine/inc/uf/engine/behavior/macros.inl +++ b/engine/inc/uf/engine/behavior/macros.inl @@ -1,5 +1,32 @@ #pragma once +#define UF_BEHAVIOR_ENTITY_H( OBJ )\ + class UF_API OBJ ## Behavior {\ + public:\ + static void attach( uf::Entity& );\ + static void initialize( uf::Object& );\ + static void tick( uf::Object& );\ + static void render( uf::Object& );\ + static void destroy( uf::Object& );\ + }; + +#define UF_BEHAVIOR_ENTITY_CPP_BEGIN( OBJ )\ + void OBJ ## Behavior::attach( uf::Entity& self ) {\ + self.addBehavior(pod::Behavior{\ + .type = uf::Behaviors::getType(),\ + .initialize = OBJ ## Behavior::initialize,\ + .tick = OBJ ## Behavior::tick,\ + .render = OBJ ## Behavior::render,\ + .destroy = OBJ ## Behavior::destroy,\ + });\ + } +#define UF_BEHAVIOR_ENTITY_CPP_ATTACH( OBJ ) {\ + OBJ ## Behavior::attach( *this );\ +} + +#define UF_BEHAVIOR_ENTITY_CPP_END( OBJ ) + +/* #define UF_BEHAVIOR_VIRTUAL 0 #define UF_BEHAVIOR_ENTITY_H( OBJ )\ @@ -53,4 +80,5 @@ .destroy = ext::OBJ ## Behavior::destroy,\ });\ } -#define EXT_BEHAVIOR_ENTITY_CPP_END( OBJ ) \ No newline at end of file +#define EXT_BEHAVIOR_ENTITY_CPP_END( OBJ ) +*/ \ No newline at end of file diff --git a/engine/inc/uf/engine/entity/entity.h b/engine/inc/uf/engine/entity/entity.h index 5e601111..abff2c2e 100644 --- a/engine/inc/uf/engine/entity/entity.h +++ b/engine/inc/uf/engine/entity/entity.h @@ -14,8 +14,10 @@ namespace uf { friend class EntityBehavior; public: typedef std::vector container_t; - protected: static uf::Entity null; + static bool deleteChildrenOnDestroy; + static bool deleteComponentsOnDestroy; + protected: static std::size_t uids; uf::Entity* m_parent = NULL; diff --git a/engine/inc/uf/engine/instantiator/instantiator.h b/engine/inc/uf/engine/instantiator/instantiator.h index beefd9f2..98644ff7 100644 --- a/engine/inc/uf/engine/instantiator/instantiator.h +++ b/engine/inc/uf/engine/instantiator/instantiator.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,9 @@ namespace uf { template T* alloc(); void UF_API free( uf::Entity* ); + uf::Entity* UF_API reuse( size_t ); + size_t UF_API collect( uint8_t = 0 ); + template void registerObject( const std::string& name ); template void registerBehavior( const std::string& name ); template void registerBinding( const std::string& name ); diff --git a/engine/inc/uf/engine/instantiator/macros.inl b/engine/inc/uf/engine/instantiator/macros.inl index fde79fed..98622483 100644 --- a/engine/inc/uf/engine/instantiator/macros.inl +++ b/engine/inc/uf/engine/instantiator/macros.inl @@ -1,6 +1,48 @@ #pragma once -#define NAMESPACE_CONCAT +#define TOKEN__PASTE(x, y) x ## y +#define TOKEN_PASTE(x, y) TOKEN__PASTE(x, y) +#define UF_NS_GET_LAST(name) uf::string::replace( uf::string::split( #name, "::" ).back(), "<>", "" ) + +#define UF_OBJECT_REGISTER_CPP( OBJ ) \ +namespace {\ + static uf::StaticInitialization TOKEN_PASTE(STATIC_INITIALIZATION_, __LINE__)( []{\ + uf::instantiator::registerObject( UF_NS_GET_LAST(OBJ) );\ + });\ +} + +#define UF_BEHAVIOR_REGISTER_CPP( BEHAVIOR ) \ +namespace {\ + static uf::StaticInitialization TOKEN_PASTE(STATIC_INITIALIZATION_, __LINE__)( []{\ + uf::instantiator::registerBehavior( UF_NS_GET_LAST(BEHAVIOR) );\ + });\ +} + +#define UF_BEHAVIOR_REGISTER_AS_OBJECT( BEHAVIOR, OBJ )\ +namespace {\ + static uf::StaticInitialization TOKEN_PASTE(STATIC_INITIALIZATION_, __LINE__)( []{\ + uf::instantiator::registerBinding( UF_NS_GET_LAST(OBJ), UF_NS_GET_LAST(BEHAVIOR) );\ + });\ +} + +#define UF_OBJECT_REGISTER_BEGIN( OBJ )\ +namespace {\ + static uf::StaticInitialization TOKEN_PASTE(STATIC_INITIALIZATION_, __LINE__)( []{\ + std::string name = UF_NS_GET_LAST(OBJ);\ + uf::instantiator::registerObject( name ); + +#define UF_OBJECT_BIND_BEHAVIOR( BEHAVIOR )\ + uf::instantiator::registerBinding( name, UF_NS_GET_LAST(BEHAVIOR) ); + +#define UF_OBJECT_REGISTER_BEHAVIOR( BEHAVIOR )\ + uf::instantiator::registerBehavior( UF_NS_GET_LAST(BEHAVIOR) );\ + UF_OBJECT_BIND_BEHAVIOR( BEHAVIOR ) + +#define UF_OBJECT_REGISTER_END()\ + });\ +} + +/* #define UF_OBJECT_REGISTER_CPP( OBJ ) \ namespace {\ static uf::StaticInitialization REGISTER_UF_ ## OBJ( []{\ @@ -65,3 +107,4 @@ namespace {\ #define EXT_OBJECT_REGISTER_END()\ });\ } +*/ \ No newline at end of file diff --git a/engine/inc/uf/ext/json/json.h b/engine/inc/uf/ext/json/json.h new file mode 100644 index 00000000..f90d0d74 --- /dev/null +++ b/engine/inc/uf/ext/json/json.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +namespace ext { + namespace json { + inline bool isTable( const Json::Value& v ) { return v.isArray() || v.isObject(); } + inline bool isObject( const Json::Value& v ) { return v.isObject(); } + inline bool isArray( const Json::Value& v ) { return v.isArray(); } + inline bool isNull( const Json::Value& v ) { return v.isNull(); } + /* + inline bool isTable( sol::object v ) { return v.is(); } + inline bool isObject( sol::object v ) { return v.is(); } + inline bool isArray( sol::object v ) { return v.is(); } + inline bool isNull( sol::object v ) { return v == sol::lua_nil; } + + template + inline bool isTable( T v ) { return v.get_type() == sol::type::table; } + + template + inline bool isObject( T v ) { return v.get_type() == sol::type::table; } + + template + inline bool isArray( T v ) { return v.get_type() == sol::type::table; } + + template + inline bool isNull( T v ) { return v.get_type() == sol::type::nil; } + */ + } +} + +#include "json.inl" \ No newline at end of file diff --git a/engine/inc/uf/ext/json/json.inl b/engine/inc/uf/ext/json/json.inl new file mode 100644 index 00000000..e69de29b diff --git a/engine/inc/uf/ext/lua/lua.h b/engine/inc/uf/ext/lua/lua.h index c9463864..ba0210ab 100644 --- a/engine/inc/uf/ext/lua/lua.h +++ b/engine/inc/uf/ext/lua/lua.h @@ -2,14 +2,19 @@ #include +#define SOL_LUAJIT 1 +#define SOL_USING_CXX_LUA_JIT 1 +#define SOL_NO_EXCEPTIONS 1 #define SOL_ALL_SAFETIES_ON 1 #include +#include +#include +#include namespace pod { struct UF_API LuaScript { - std::string filename; - std::string header; + std::string file; sol::environment env; }; } @@ -18,13 +23,22 @@ namespace ext { namespace lua { extern UF_API sol::state state; extern UF_API std::string main; + extern UF_API std::unordered_map modules; + extern UF_API std::vector>* onInitializationFunctions; + void UF_API initialize(); void UF_API terminate(); + void UF_API onInitialization( const std::function& ); bool UF_API run( const std::string&, bool = true ); pod::LuaScript UF_API script( const std::string& ); - bool UF_API run( const pod::LuaScript& ); + bool UF_API run( const pod::LuaScript&, bool = true ); + + sol::table createTable(); + std::string sanitize( const std::string& dirty, int index = -1 ); + std::optional encode( sol::table table ); + std::optional decode( const std::string& string ); } } diff --git a/engine/inc/uf/ext/lua/lua.inl b/engine/inc/uf/ext/lua/lua.inl index d72e0b2f..9d218dfb 100644 --- a/engine/inc/uf/ext/lua/lua.inl +++ b/engine/inc/uf/ext/lua/lua.inl @@ -1,14 +1,56 @@ -#define POD_LUA_REGISTER_USERTYPE_BEGIN(x)\ - state.new_usertype(#x, -#define UF_LUA_REGISTER_USERTYPE_BEGIN(x)\ - state.new_usertype(#x, -#define EXT_LUA_REGISTER_USERTYPE_BEGIN(x)\ - state.new_usertype(#x, +#define UF_NS_GET_LAST(name) uf::string::replace( uf::string::split( #name, "::" ).back(), "<>", "" ) -#define POD_LUA_REGISTER_USERTYPE_MEMBER(x, y) #y, &pod::x::y -#define UF_LUA_REGISTER_USERTYPE_MEMBER(x, y) #y, &uf::x::y -#define EXT_LUA_REGISTER_USERTYPE_MEMBER(x, y) #y, &ext::x::y +#define TOKEN__PASTE(x, y) x ## y +#define TOKEN_PASTE(x, y) TOKEN__PASTE(x, y) -#define UF_LUA_REGISTER_USERTYPE_END(x) ); -#define POD_LUA_REGISTER_USERTYPE_END(x) UF_LUA_REGISTER_USERTYPE_END(x) -#define EXT_LUA_REGISTER_USERTYPE_END(x) UF_LUA_REGISTER_USERTYPE_END(x) \ No newline at end of file +#define UF_LUA_REGISTER_USERTYPE_BEGIN(type) \ +namespace {\ + static uf::StaticInitialization TOKEN_PASTE(STATIC_INITIALIZATION_, __LINE__)( []{\ + ext::lua::onInitialization( []{\ + std::string name = UF_NS_GET_LAST(type);\ + auto usertype = ext::lua::state.new_usertype(name); + +#define UF_LUA_REGISTER_USERTYPE_DEFINE_RT(k, v) usertype[#k] = v; +#define UF_LUA_REGISTER_USERTYPE_MEMBER_RT(member) usertype[UF_NS_GET_LAST(member)] = &member; + +#define UF_LUA_REGISTER_USERTYPE_END() \ + });\ + });\ +} + + +#define UF_LUA_REGISTER_USERTYPE(type, ...) \ +namespace {\ + static uf::StaticInitialization TOKEN_PASTE(STATIC_INITIALIZATION_, __LINE__)( []{\ + ext::lua::onInitialization( []{\ + ext::lua::state.new_usertype(UF_NS_GET_LAST(type), __VA_ARGS__);\ + });\ + });\ +} + +#define UF_LUA_REGISTER_USERTYPE_DEFINE(k, v) #k, v +#define UF_LUA_REGISTER_USERTYPE_MEMBER(member) UF_NS_GET_LAST(member), &member + + +/* +#define UF_NS_LUA_REGISTER_USERTYPE_BEGIN(k, v) {\ + std::string name = #v;\ + sol::usertype usertype = state.new_usertype(name); + +#define POD_LUA_REGISTER_USERTYPE_BEGIN(x) UF_NS_LUA_REGISTER_USERTYPE_BEGIN(pod, x) +#define UF_LUA_REGISTER_USERTYPE_BEGIN(x) UF_NS_LUA_REGISTER_USERTYPE_BEGIN(uf, x) +#define EXT_LUA_REGISTER_USERTYPE_BEGIN(x) UF_NS_LUA_REGISTER_USERTYPE_BEGIN(ext, x) + +#define UF_LUA_REGISTER_USERTYPE_DEFINE(k, v) usertype[#k] = v; +#define POD_LUA_REGISTER_USERTYPE_DEFINE(k, v) UF_LUA_REGISTER_USERTYPE_DEFINE(k, v) +#define EXT_LUA_REGISTER_USERTYPE_DEFINE(k, v) UF_LUA_REGISTER_USERTYPE_DEFINE(k, v) + +#define UF_NS_LUA_REGISTER_USERTYPE_MEMBER(ns, x, y) UF_LUA_REGISTER_USERTYPE_DEFINE(y, &ns::x::y) +#define POD_LUA_REGISTER_USERTYPE_MEMBER(x, y) UF_NS_LUA_REGISTER_USERTYPE_MEMBER(pod, x, y) +#define UF_LUA_REGISTER_USERTYPE_MEMBER(x, y) UF_NS_LUA_REGISTER_USERTYPE_MEMBER(uf, x, y) +#define EXT_LUA_REGISTER_USERTYPE_MEMBER(x, y) UF_NS_LUA_REGISTER_USERTYPE_MEMBER(ext, x, y) + +#define UF_LUA_REGISTER_USERTYPE_END() } +#define POD_LUA_REGISTER_USERTYPE_END() UF_LUA_REGISTER_USERTYPE_END() +#define EXT_LUA_REGISTER_USERTYPE_END() UF_LUA_REGISTER_USERTYPE_END() +*/ \ No newline at end of file diff --git a/engine/inc/uf/ext/oal/oal.h b/engine/inc/uf/ext/oal/oal.h index 730dd158..06a36499 100644 --- a/engine/inc/uf/ext/oal/oal.h +++ b/engine/inc/uf/ext/oal/oal.h @@ -12,6 +12,8 @@ #include +#define AL_CHECK_ERROR(...) __VA_ARGS__; ext::oal.checkError(__FUNCTION__, __LINE__) + namespace ext { class UF_API AL { protected: diff --git a/engine/inc/uf/ext/vulkan.h b/engine/inc/uf/ext/vulkan.h index b8a87657..05f500a1 100644 --- a/engine/inc/uf/ext/vulkan.h +++ b/engine/inc/uf/ext/vulkan.h @@ -20,14 +20,19 @@ #include #include */ +#define VK_DEBUG_MESSAGE(...)\ + uf::iostream << "[" << __FUNCTION__ << "@" << __FILE__ ":" << __LINE__ << "] " << __VA_ARGS__ << "\n" -#define VK_CHECK_RESULT(f) \ -{ \ - VkResult res = (f); \ - if (res != VK_SUCCESS) { \ - std::cerr << "Fatal : VkResult is \"" << ext::vulkan::errorString( res ) << "\" in " << __FILE__ << " at line " << __LINE__ << std::endl; \ - throw std::runtime_error(ext::vulkan::errorString( res )); \ - } \ +#define VK_VALIDATION_MESSAGE(...)\ + if ( ext::vulkan::settings::validation ) VK_DEBUG_MESSAGE(__VA_ARGS__); + +#define VK_CHECK_RESULT(f) { \ + VkResult res = (f); \ + if (res != VK_SUCCESS) { \ + std::string errorString = ext::vulkan::errorString( res ); \ + VK_DEBUG_MESSAGE(errorString); \ + throw std::runtime_error(errorString); \ + } \ } #define VK_FLAGS_NONE 0 diff --git a/engine/inc/uf/ext/vulkan/buffer.h b/engine/inc/uf/ext/vulkan/buffer.h index 67892c78..07da9b91 100644 --- a/engine/inc/uf/ext/vulkan/buffer.h +++ b/engine/inc/uf/ext/vulkan/buffer.h @@ -3,6 +3,8 @@ #include #include +#define VK_DEFAULT_STAGE_BUFFERS 0 + namespace ext { namespace vulkan { struct Device; @@ -66,15 +68,15 @@ namespace ext { void initialize( Device& device ); void destroy(); // - size_t initializeBuffer( void* data, VkDeviceSize length, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, bool stage = true ); - template inline size_t initializeBuffer( T data, VkDeviceSize length, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, bool stage = true ) { return initializeBuffer( (void*) &data, length, usageFlags, memoryPropertyFlags, stage ); } - template inline size_t initializeBuffer( T data, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, bool stage = true ) { return initializeBuffer( (void*) &data, static_cast(sizeof(T)), usageFlags, memoryPropertyFlags, stage ); } + size_t initializeBuffer( void* data, VkDeviceSize length, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, bool stage = VK_DEFAULT_STAGE_BUFFERS ); + template inline size_t initializeBuffer( T data, VkDeviceSize length, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, bool stage = VK_DEFAULT_STAGE_BUFFERS ) { return initializeBuffer( (void*) &data, length, usageFlags, memoryPropertyFlags, stage ); } + template inline size_t initializeBuffer( T data, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, bool stage = VK_DEFAULT_STAGE_BUFFERS ) { return initializeBuffer( (void*) &data, static_cast(sizeof(T)), usageFlags, memoryPropertyFlags, stage ); } - void updateBuffer( void* data, VkDeviceSize length, size_t index = 0, bool stage = true ); - void updateBuffer( void* data, VkDeviceSize length, Buffer& buffer, bool stage = true ); - template inline void updateBuffer( T data, VkDeviceSize length, size_t index = 0, bool stage = true ) { return updateBuffer( (void*) &data, length, index, stage ); } - template inline void updateBuffer( T data, size_t index = 0, bool stage = true ) { return updateBuffer( (void*) &data, static_cast(sizeof(T)), index, stage ); } - template inline void updateBuffer( T data, VkDeviceSize length, Buffer& buffer, bool stage = true ) { return updateBuffer( (void*) &data, length, buffer, stage ); } + void updateBuffer( void* data, VkDeviceSize length, size_t index = 0, bool stage = VK_DEFAULT_STAGE_BUFFERS ); + void updateBuffer( void* data, VkDeviceSize length, Buffer& buffer, bool stage = VK_DEFAULT_STAGE_BUFFERS ); + template inline void updateBuffer( T data, VkDeviceSize length, size_t index = 0, bool stage = VK_DEFAULT_STAGE_BUFFERS ) { return updateBuffer( (void*) &data, length, index, stage ); } + template inline void updateBuffer( T data, size_t index = 0, bool stage = VK_DEFAULT_STAGE_BUFFERS ) { return updateBuffer( (void*) &data, static_cast(sizeof(T)), index, stage ); } + template inline void updateBuffer( T data, VkDeviceSize length, Buffer& buffer, bool stage = VK_DEFAULT_STAGE_BUFFERS ) { return updateBuffer( (void*) &data, length, buffer, stage ); } }; } } \ No newline at end of file diff --git a/engine/inc/uf/ext/vulkan/graphic.h b/engine/inc/uf/ext/vulkan/graphic.h index 8b34ccac..d97e8f51 100644 --- a/engine/inc/uf/ext/vulkan/graphic.h +++ b/engine/inc/uf/ext/vulkan/graphic.h @@ -97,7 +97,7 @@ namespace ext { void destroy(); template - void initializeGeometry( uf::BaseMesh& mesh, bool = false ); + void initializeGeometry( uf::BaseMesh& mesh, bool stage = VK_DEFAULT_STAGE_BUFFERS ); bool hasPipeline( GraphicDescriptor& descriptor ); void initializePipeline(); diff --git a/engine/inc/uf/utils/audio/audio.h b/engine/inc/uf/utils/audio/audio.h index cc186da9..023f710a 100644 --- a/engine/inc/uf/utils/audio/audio.h +++ b/engine/inc/uf/utils/audio/audio.h @@ -20,6 +20,7 @@ namespace uf { ext::al::Buffer m_buffer; float m_duration; public: + static bool mute; /* Audio( const std::string& = "" ); Audio( Audio&& ); @@ -60,6 +61,7 @@ namespace uf { protected: uf::SoundEmitter::container_t m_container; public: + ~SoundEmitter(); uf::Audio& add( const std::string& ); uf::Audio& add( const uf::Audio& ); uf::Audio& get( const std::string& ); diff --git a/engine/inc/uf/utils/component/component.h b/engine/inc/uf/utils/component/component.h index 96042485..d32f3325 100644 --- a/engine/inc/uf/utils/component/component.h +++ b/engine/inc/uf/utils/component/component.h @@ -48,6 +48,8 @@ namespace uf { template T& addComponent( const T& = T() ); template void deleteComponent(); + + void destroyComponents(); }; } diff --git a/engine/inc/uf/utils/hook/hook.h b/engine/inc/uf/utils/hook/hook.h index fe1a3643..324107a5 100644 --- a/engine/inc/uf/utils/hook/hook.h +++ b/engine/inc/uf/utils/hook/hook.h @@ -95,9 +95,9 @@ namespace uf { bool isAliasToReadable( const Readable::alias_t::name_t& name ) const; // Is there an alias bound to a readable hook? bool isAliasToOptimal( const Optimal::alias_t::name_t& name ) const; // Is there an alias bound to an optimal hook? - void call( const Readable::name_t& name ); + std::vector call( const Readable::name_t& name ); std::vector call( const Readable::name_t& name, const Readable::argument_t& argument ); - void call( const Optimal::name_t& name, const Optimal::argument_t& argument ); + std::vector call( const Optimal::name_t& name, const Optimal::argument_t& argument ); }; class UF_API Hooks { public: diff --git a/engine/inc/uf/utils/math/vector.h b/engine/inc/uf/utils/math/vector.h index 690f9e2b..8d9a9c1e 100644 --- a/engine/inc/uf/utils/math/vector.h +++ b/engine/inc/uf/utils/math/vector.h @@ -128,9 +128,11 @@ namespace pod { // POD vector accessing/manipulation namespace uf { namespace vector { + template pod::Vector1t /*UF_API*/ create( T x ); template pod::Vector2t /*UF_API*/ create( T x, T y ); template pod::Vector3t /*UF_API*/ create( T x, T y, T z ); template pod::Vector4t /*UF_API*/ create( T x, T y, T z, T w ); + template pod::Vector /*UF_API*/ copy( const pod::Vector& = {}); // Equality checking template std::size_t /*UF_API*/ compareTo( const T& left, const T& right ); // Equality check between two vectors (less than) template bool /*UF_API*/ equals( const T& left, const T& right ); // Equality check between two vectors (equals) diff --git a/engine/inc/uf/utils/math/vector/pod.inl b/engine/inc/uf/utils/math/vector/pod.inl index d9f2e0ae..3bea8273 100644 --- a/engine/inc/uf/utils/math/vector/pod.inl +++ b/engine/inc/uf/utils/math/vector/pod.inl @@ -10,6 +10,8 @@ template pod::Vector3t /*UF_API*/ uf::vector::create( T x, T y, T z ) { pod::Vector3t vec; vec.x = x, vec.y = y, vec.z = z; return vec; } template pod::Vector4t /*UF_API*/ uf::vector::create( T x, T y, T z, T w ) { pod::Vector4t vec; vec.x = x, vec.y = y, vec.z = z, vec.w = w; return vec; } +template +pod::Vector /*UF_API*/ uf::vector::copy( const pod::Vector& v ) { return v; } // Equality checking template // Equality check between two vectors (less than) std::size_t /*UF_API*/ uf::vector::compareTo( const T& left, const T& right ) { diff --git a/engine/inc/uf/utils/serialize/serializer.h b/engine/inc/uf/utils/serialize/serializer.h index 67f31e15..07c5ba84 100644 --- a/engine/inc/uf/utils/serialize/serializer.h +++ b/engine/inc/uf/utils/serialize/serializer.h @@ -1,35 +1,38 @@ #pragma once #include -#include + +#include +#include +#include + #include #include -#include - namespace uf { +// class UF_API Serializer : public sol::table { class UF_API Serializer : public Json::Value { public: typedef std::string output_t; typedef std::string input_t; - protected: - public: + Serializer( const std::string& str = "" ); Serializer( const Json::Value& ); + Serializer( const sol::table& ); - Serializer::output_t serialize() const; + Serializer::output_t serialize( bool pretty = false ) const; void deserialize( const std::string& ); // serializeable template static bool serializeable() { - // return std::is_pod::value; - return std::is_standard_layout::value && std::is_trivial::value; + return std::is_standard_layout::value && std::is_trivial::value; // std::is_pod::value; } template static bool serializeable( const T& input ) { return serializeable(); } + // serialize to base64 template static uf::Serializer toBase64( const T& input ) { @@ -47,13 +50,13 @@ namespace uf { // ensure this is a safe type to serialize if ( !serializeable(input) ) return T(); // ensure it's "proper" - if ( !input["base64"].isString() ) return T(); - pod::Userdata* userdata = uf::userdata::fromBase64(input["base64"].asString()); + if ( !input["base64"].is() ) return T(); + pod::Userdata* userdata = uf::userdata::fromBase64(input["base64"].as()); T res = uf::userdata::get( userdata ); uf::userdata::destroy( userdata ); return res; } - + bool readFromFile( const std::string& from ); bool writeToFile( const std::string& to ) const; @@ -63,8 +66,11 @@ namespace uf { operator Serializer::output_t() const; uf::Serializer& operator=( const std::string& str ); uf::Serializer& operator=( const Json::Value& json ); + uf::Serializer& operator=( const sol::table& json ); uf::Serializer& operator<<( const std::string& str ); uf::Serializer& operator>>( std::string& str ); const uf::Serializer& operator>>( std::string& str ) const; }; + + typedef Serializer Metadata; } \ No newline at end of file diff --git a/engine/inc/uf/utils/userdata/userdata.h b/engine/inc/uf/utils/userdata/userdata.h index 90203c83..05d3fdfc 100644 --- a/engine/inc/uf/utils/userdata/userdata.h +++ b/engine/inc/uf/utils/userdata/userdata.h @@ -40,6 +40,8 @@ namespace uf { pod::Userdata* UF_API create( uf::MemoryPool&, std::size_t len, void* data = NULL ); template pod::Userdata* create( uf::MemoryPool&, const T& data = T() ); void UF_API destroy( uf::MemoryPool&, pod::Userdata* userdata ); + + size_t UF_API size( size_t size, size_t padding = 0 ); } } diff --git a/engine/inc/uf/utils/userdata/userdata.inl b/engine/inc/uf/utils/userdata/userdata.inl index 8c311e54..b90c4dbf 100644 --- a/engine/inc/uf/utils/userdata/userdata.inl +++ b/engine/inc/uf/utils/userdata/userdata.inl @@ -8,20 +8,22 @@ pod::Userdata* uf::userdata::create( const T& data ) { template pod::Userdata* uf::userdata::create( uf::MemoryPool& requestedMemoryPool, const T& data ) { // uf::MemoryPool& memoryPool = uf::MemoryPool::global.size() > 0 ? uf::MemoryPool::global : requestedMemoryPool; + size_t len = sizeof(data); + size_t requestedLen = size( len ); #if UF_MEMORYPOOL_INVALID_MALLOC uf::MemoryPool& memoryPool = requestedMemoryPool.size() > 0 ? requestedMemoryPool : uf::MemoryPool::global; - pod::Userdata* userdata = (pod::Userdata*) memoryPool.alloc( NULL, sizeof(pod::Userdata) + sizeof(data) ); + pod::Userdata* userdata = (pod::Userdata*) memoryPool.alloc( NULL, requestedLen ); #else uf::MemoryPool* memoryPool = NULL; if ( requestedMemoryPool.size() > 0 ) memoryPool = &requestedMemoryPool; else if ( uf::MemoryPool::global.size() > 0 ) memoryPool = &uf::MemoryPool::global; pod::Userdata* userdata = NULL; if ( memoryPool ) - userdata = (pod::Userdata*) memoryPool->alloc( NULL, sizeof(pod::Userdata) + sizeof(data) ); + userdata = (pod::Userdata*) memoryPool->alloc( NULL, requestedLen ); else - userdata = (pod::Userdata*) operator new( sizeof(pod::Userdata) + sizeof(data) ); // allocate data for the userdata struct, and then some } + userdata = (pod::Userdata*) operator new( requestedLen ); // allocate data for the userdata struct, and then some } #endif - userdata->len = sizeof(data); + userdata->len = len; union { uint8_t* from; T* to; diff --git a/engine/src/engine/asset/asset.cpp b/engine/src/engine/asset/asset.cpp index d3cc485f..edf1aa86 100644 --- a/engine/src/engine/asset/asset.cpp +++ b/engine/src/engine/asset/asset.cpp @@ -43,12 +43,12 @@ namespace { std::string callback; std::string type; }; - std::queue jobs; } -uf::Entity uf::Asset::masterAssetLoader; +uf::Asset uf::Asset::masterAssetLoader; void uf::Asset::processQueue() { + auto& jobs = this->getComponent>(); mutex.lock(); while ( !jobs.empty() ) { auto job = jobs.front(); @@ -70,11 +70,13 @@ void uf::Asset::processQueue() { } void uf::Asset::cache( const std::string& uri, const std::string& callback ) { mutex.lock(); + auto& jobs = this->getComponent>(); jobs.push({ uri, callback, "cache" }); mutex.unlock(); } void uf::Asset::load( const std::string& uri, const std::string& callback ) { mutex.lock(); + auto& jobs = this->getComponent>(); jobs.push({ uri, callback, "load" }); mutex.unlock(); } @@ -114,14 +116,16 @@ std::string uf::Asset::load( const std::string& uri ) { } #define UF_ASSET_REGISTER(type)\ auto& container = this->getContainer();\ - if ( !map[extension][uri].isNull() ) return filename;\ - if ( !map[extension][filename].isNull() ) return filename;\ + if ( !ext::json::isNull( map[extension][uri] ) ) return filename;\ + if ( !ext::json::isNull( map[extension][filename] ) ) return filename;\ map[extension][uri] = container.size();\ map[extension][filename] = container.size();\ type& asset = container.emplace_back(); +// auto& scene = uf::scene::getCurrentScene(); +// auto& masterAssetLoader = scene.getComponent(); + auto& map = this->getComponent(); // deduce PNG, load as texture - auto& map = masterAssetLoader.getComponent(); if ( extension == "png" ) { UF_ASSET_REGISTER(uf::Image) asset.open(filename); @@ -143,7 +147,7 @@ std::string uf::Asset::load( const std::string& uri ) { auto& metadata = this->getComponent(); #define LOAD_FLAG(name)\ - if ( metadata[uri]["flags"][#name].asBool() )\ + if ( metadata[uri]["flags"][#name].as() )\ LOAD_FLAGS |= ext::gltf::LoadMode::name; LOAD_FLAG(GENERATE_NORMALS); // 0x1 << 0; @@ -164,12 +168,14 @@ std::string uf::Asset::load( const std::string& uri ) { } std::string uf::Asset::getOriginal( const std::string& uri ) { std::string extension = uf::io::extension( uri ); - auto& map = masterAssetLoader.getComponent(); - if ( map[extension][uri].isNull() ) return uri; - std::size_t index = map[extension][uri].asUInt64(); +// auto& scene = uf::scene::getCurrentScene(); +// auto& masterAssetLoader = scene.getComponent(); + auto& map = this->getComponent(); + if ( ext::json::isNull( map[extension][uri] ) ) return uri; + std::size_t index = map[extension][uri].as(); for ( auto it = map[extension].begin(); it != map[extension].end(); ++it ) { - std::string key = it.key().asString(); - std::size_t i = it->asUInt64(); + std::string key = it.key().as(); + std::size_t i = it->as(); if ( index == i && key != uri ) return key; } return uri; diff --git a/engine/src/engine/behavior/behavior.cpp b/engine/src/engine/behavior/behavior.cpp index 78afa6a4..8a9b741f 100644 --- a/engine/src/engine/behavior/behavior.cpp +++ b/engine/src/engine/behavior/behavior.cpp @@ -24,6 +24,8 @@ void uf::Behaviors::removeBehavior( const pod::Behavior& behavior ) { if ( it != this->m_behaviors.end() ) this->m_behaviors.erase(it); } +#define FUNCTION_AS_VARIABLE(x) x + #define UF_BEHAVIOR_POLYFILL(f)\ uf::Object& self = *((uf::Object*) this);\ bool headLoopChildren = true;\ @@ -31,12 +33,12 @@ void uf::Behaviors::removeBehavior( const pod::Behavior& behavior ) { bool multithreading = false;\ if ( this->hasComponent() ) {\ auto& metadata = this->getComponent();\ - if ( !metadata["system"]["behavior"][#f]["head loop children"].isNull() )\ - headLoopChildren = metadata["system"]["behavior"][#f]["head loop children"].asBool();\ - if ( !metadata["system"]["behavior"][#f]["forward iteration"].isNull() )\ - forwardIteration = metadata["system"]["behavior"][#f]["forward iteration"].asBool();\ - if ( !metadata["system"]["behavior"][#f]["multithreading"].isNull() )\ - multithreading = metadata["system"]["behavior"][#f]["multithreading"].asBool();\ + if ( !ext::json::isNull( metadata["system"]["behavior"][#f]["head loop children"] ) )\ + headLoopChildren = metadata["system"]["behavior"][#f]["head loop children"].as();\ + if ( !ext::json::isNull( metadata["system"]["behavior"][#f]["forward iteration"] ) )\ + forwardIteration = metadata["system"]["behavior"][#f]["forward iteration"].as();\ + if ( !ext::json::isNull( metadata["system"]["behavior"][#f]["multithreading"] ) )\ + multithreading = metadata["system"]["behavior"][#f]["multithreading"].as();\ }\ auto function = [&]() -> int {\ if ( headLoopChildren ) {\ @@ -48,16 +50,18 @@ void uf::Behaviors::removeBehavior( const pod::Behavior& behavior ) { it->f(self);\ } else {\ if ( forwardIteration ) {\ - for ( auto it = this->m_behaviors.begin() + 1; it != this->m_behaviors.end(); ++it )\ + auto it = this->m_behaviors.begin();\ + for ( ++it; it != this->m_behaviors.end(); ++it )\ + it->f(self);\ + if ( (it = this->m_behaviors.begin()) != this->m_behaviors.end() ) {\ it->f(self);\ - if ( this->m_behaviors.begin() != this->m_behaviors.end() ) {\ - this->m_behaviors.begin()->f(self);\ }\ } else {\ - for ( auto it = this->m_behaviors.rbegin() + 1; it != this->m_behaviors.rend(); ++it )\ + auto it = this->m_behaviors.rbegin();\ + for ( ++it; it != this->m_behaviors.rend(); ++it )\ + it->f(self);\ + if ( (it = this->m_behaviors.rbegin()) != this->m_behaviors.rend() ) {\ it->f(self);\ - if ( this->m_behaviors.rbegin() != this->m_behaviors.rend() ) {\ - this->m_behaviors.rbegin()->f(self);\ }\ }\ }\ @@ -66,24 +70,25 @@ void uf::Behaviors::removeBehavior( const pod::Behavior& behavior ) { if ( multithreading ) uf::thread::add( uf::thread::fetchWorker(), function, true ); else function(); #define UF_BEHAVIOR_POLYFILL_FAST(f)\ + if ( this->m_behaviors.empty() ) return;\ uf::Object& self = *((uf::Object*) this);\ bool headLoopChildren = true;\ bool forwardIteration = true;\ bool multithreading = false;\ if ( this->hasComponent() ) {\ auto& metadata = this->getComponent();\ - if ( !metadata["system"]["behavior"][#f]["head loop children"].isNull() )\ - headLoopChildren = metadata["system"]["behavior"][#f]["head loop children"].asBool();\ - if ( !metadata["system"]["behavior"][#f]["forward iteration"].isNull() )\ - forwardIteration = metadata["system"]["behavior"][#f]["forward iteration"].asBool();\ - if ( !metadata["system"]["behavior"][#f]["multithreading"].isNull() )\ - multithreading = metadata["system"]["behavior"][#f]["multithreading"].asBool();\ + if ( !ext::json::isNull( metadata["system"]["behavior"][#f]["head loop children"] ) )\ + headLoopChildren = metadata["system"]["behavior"][#f]["head loop children"].as();\ + if ( !ext::json::isNull( metadata["system"]["behavior"][#f]["forward iteration"] ) )\ + forwardIteration = metadata["system"]["behavior"][#f]["forward iteration"].as();\ + if ( !ext::json::isNull( metadata["system"]["behavior"][#f]["multithreading"] ) )\ + multithreading = metadata["system"]["behavior"][#f]["multithreading"].as();\ }\ if ( headLoopChildren ) {\ if ( forwardIteration ) {\ auto it = this->m_behaviors.begin();\ if ( it != this->m_behaviors.end() ) {\ - this->m_behaviors.begin()->f(self);\ + it->f(self);\ }\ for ( ++it; it != this->m_behaviors.end(); ++it ) {\ auto function = [&]() -> int {\ @@ -95,7 +100,7 @@ void uf::Behaviors::removeBehavior( const pod::Behavior& behavior ) { } else {\ auto it = this->m_behaviors.rbegin();\ if ( it != this->m_behaviors.rend() ) {\ - this->m_behaviors.rbegin()->f(self);\ + it->f(self);\ }\ for ( ++it; it != this->m_behaviors.rend(); ++it ) {\ auto function = [&]() -> int {\ @@ -107,26 +112,28 @@ void uf::Behaviors::removeBehavior( const pod::Behavior& behavior ) { }\ } else {\ if ( forwardIteration ) {\ - for ( auto it = this->m_behaviors.begin() + 1; it != this->m_behaviors.end(); ++it ) {\ + auto it = this->m_behaviors.begin();\ + for ( ++it; it != this->m_behaviors.end(); ++it ) {\ auto function = [&]() -> int {\ it->f(self);\ return 0;\ };\ if ( multithreading ) uf::thread::add( uf::thread::fetchWorker(), function, true ); else function();\ }\ - if ( this->m_behaviors.begin() != this->m_behaviors.end() ) {\ - this->m_behaviors.begin()->f(self);\ + if ( (it = this->m_behaviors.begin()) != this->m_behaviors.end() ) {\ + it->f(self);\ }\ } else {\ - for ( auto it = this->m_behaviors.rbegin() + 1; it != this->m_behaviors.rend(); ++it ) {\ + auto it = this->m_behaviors.rbegin();\ + for ( ++it; it != this->m_behaviors.rend(); ++it ) {\ auto function = [&]() -> int {\ it->f(self);\ return 0;\ };\ if ( multithreading ) uf::thread::add( uf::thread::fetchWorker(), function, true ); else function();\ }\ - if ( this->m_behaviors.rbegin() != this->m_behaviors.rend() ) {\ - this->m_behaviors.rbegin()->f(self);\ + if ( (it = this->m_behaviors.rbegin()) != this->m_behaviors.rend() ) {\ + it->f(self);\ }\ }\ } diff --git a/engine/src/engine/entity/behavior.cpp b/engine/src/engine/entity/behavior.cpp index adfc8719..a8579e58 100644 --- a/engine/src/engine/entity/behavior.cpp +++ b/engine/src/engine/entity/behavior.cpp @@ -1,6 +1,7 @@ #include -UF_BEHAVIOR_ENTITY_CPP_BEGIN(Entity) +UF_BEHAVIOR_ENTITY_CPP_BEGIN(uf::Entity) +uf::Entity::Entity() UF_BEHAVIOR_ENTITY_CPP_ATTACH(uf::Entity) #define this ((uf::Entity*) &self) void uf::EntityBehavior::initialize( uf::Object& self ) { if ( this->m_uid == 0 ) @@ -25,11 +26,14 @@ void uf::EntityBehavior::destroy( uf::Object& self ) { if ( !kv ) continue; if ( kv->getUid() == 0 ) continue; kv->destroy(); - delete kv; + if ( uf::Entity::deleteChildrenOnDestroy ) delete kv; } this->m_children.clear(); this->m_uid = 0; - if ( this->hasParent() ) this->getParent().removeChild(*this); + if ( this->hasParent() ) + this->getParent().removeChild(*this); + + if ( uf::Entity::deleteComponentsOnDestroy ) this->destroyComponents(); } #undef this UF_BEHAVIOR_ENTITY_CPP_END(Entity) \ No newline at end of file diff --git a/engine/src/engine/entity/entity.cpp b/engine/src/engine/entity/entity.cpp index 47101363..8c1fb20d 100644 --- a/engine/src/engine/entity/entity.cpp +++ b/engine/src/engine/entity/entity.cpp @@ -5,6 +5,8 @@ uf::Entity uf::Entity::null; std::size_t uf::Entity::uids = 0; uf::MemoryPool uf::Entity::memoryPool; +bool uf::Entity::deleteChildrenOnDestroy = false; +bool uf::Entity::deleteComponentsOnDestroy = false; uf::Entity::~Entity(){ this->destroy(); } diff --git a/engine/src/engine/instantiator/instantiator.cpp b/engine/src/engine/instantiator/instantiator.cpp index ccee1301..99154829 100644 --- a/engine/src/engine/instantiator/instantiator.cpp +++ b/engine/src/engine/instantiator/instantiator.cpp @@ -1,11 +1,51 @@ #include #include +#include #include pod::NamedTypes* uf::instantiator::objects = NULL; pod::NamedTypes* uf::instantiator::behaviors = NULL; +uf::Entity* uf::instantiator::reuse( size_t size ) { + uf::Entity* laxed = NULL; + auto& allocations = uf::Entity::memoryPool.allocations(); + + for ( auto& allocation : allocations ) { + uf::Entity* e = (uf::Entity*) allocation.pointer; + // no scenes + if ( std::find( uf::scene::scenes.begin(), uf::scene::scenes.end(), (uf::Scene*) e ) != uf::scene::scenes.end() ) continue; + // only orphaned + if ( e->hasParent() ) continue; + // only destroyed entities + if ( e->getName() == "Entity" || e->getUid() > 0 ) continue; + if ( allocation.size == size ) return e; + if ( allocation.size > size ) laxed = e; + } + return laxed; +} +size_t uf::instantiator::collect( uint8_t level ) { + size_t collected = 0; + auto& allocations = uf::Entity::memoryPool.allocations(); + auto& scene = uf::scene::getCurrentScene(); + for ( auto& allocation : allocations ) { + uf::Entity* e = (uf::Entity*) allocation.pointer; + // no scenes + // if ( std::find( uf::scene::scenes.begin(), uf::scene::scenes.end(), (uf::Scene*) e ) != uf::scene::scenes.end() ) continue; + // not current scene + if ( e->getUid() == scene.getUid() ) continue; + // only orphaned + if ( e->hasParent() ) continue; + // uninitialized + if ( e->getName() == "Entity" && e->getUid() == 0 ) continue; + uf::iostream << "Found orphan: " << e->getName() << ": " << e->getUid() << "\n"; + uf::instantiator::free( e ); + ++collected; + } + return collected; +} + uf::Entity* uf::instantiator::alloc( size_t size ) { + // auto* reused = reuse( size ); if ( reused ) return reused; #if UF_MEMORYPOOL_INVALID_MALLOC uf::MemoryPool& memoryPool = uf::Entity::memoryPool.size() > 0 ? uf::Entity::memoryPool : uf::MemoryPool::global; return (uf::Entity*) memoryPool.alloc( NULL, size ); @@ -22,6 +62,9 @@ uf::Entity* uf::instantiator::alloc( size_t size ) { #endif } void uf::instantiator::free( uf::Entity* pointer ) { + if ( !pointer ) return; + if ( pointer->getUid() > 0 ) pointer->destroy(); + #if UF_MEMORYPOOL_INVALID_FREE uf::MemoryPool& memoryPool = uf::Entity::memoryPool.size() > 0 ? uf::Entity::memoryPool : uf::MemoryPool::global; memoryPool.free( pointer ); diff --git a/engine/src/engine/object/behavior.cpp b/engine/src/engine/object/behavior.cpp index 09527152..3af328fb 100644 --- a/engine/src/engine/object/behavior.cpp +++ b/engine/src/engine/object/behavior.cpp @@ -10,28 +10,17 @@ #include #include -UF_BEHAVIOR_ENTITY_CPP_BEGIN(Object) +UF_BEHAVIOR_ENTITY_CPP_BEGIN(uf::Object) #define this (&self) void uf::ObjectBehavior::initialize( uf::Object& self ) { auto& scene = uf::scene::getCurrentScene(); auto& assetLoader = scene.getComponent(); auto& metadata = this->getComponent(); -/* - size_t target = 0; - for ( int i = 0; i < metadata["system"]["assets"].size(); ++i ) { - std::string filename = metadata["system"]["assets"][i].isObject() ? metadata["system"]["assets"][i]["filename"].asString() : metadata["system"]["assets"][i].asString(); - if ( uf::io::extension(filename) != "json" ) ++target; - } - if ( target > 0 ) { - metadata["system"]["load"]["progress"] = 0; - metadata["system"]["load"]["total"] = target; - } -*/ // { size_t assets = metadata["system"]["assets"].size(); - if ( metadata["system"]["load"]["ignore"].isBool() ) assets = 0; + if ( metadata["system"]["load"]["ignore"].is() ) assets = 0; metadata["system"]["load"]["progress"] = 0; metadata["system"]["load"]["total"] = assets; if ( assets == 0 ) { @@ -42,11 +31,27 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { } } + this->addHook( "object:UpdateMetadata.%UID%", [&](const std::string& event)->std::string{ + uf::Serializer json = event; + metadata.merge(json, true); + return "true"; + /* + std::string keyString = match[1].str(); + std::string valueString = match[2].str(); + auto keys = uf::string::split(keyString, "."); + uf::Serializer value; value.deserialize(valueString); + Json::Value* traversal = &::config; + for ( auto& key : keys ) { + traversal = &((*traversal)[key]); + } + *traversal = value; + */ + }); this->addHook( "asset:QueueLoad.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - std::string filename = json["filename"].asString(); + std::string filename = json["filename"].as(); std::string callback = this->formatHookName("asset:FinishedLoad.%UID%"); - if ( json["single threaded"].asBool() ) { + if ( json["single threaded"].as() ) { assetLoader.load( filename ); this->queueHook( callback, event ); } else { @@ -62,8 +67,8 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { }); this->addHook( "asset:Load.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - std::string filename = json["filename"].asString(); - bool initialize = json["initialize"].isNull() ? true : json["initialize"].asBool(); + std::string filename = json["filename"].as(); + bool initialize = ext::json::isNull( json["initialize"] ) ? true : json["initialize"].as(); if ( uf::io::extension(filename) != "json" ) return "false"; @@ -84,8 +89,8 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { int portion = 1; auto& total = metadata["system"]["load"]["total"]; auto& progress = metadata["system"]["load"]["progress"]; - progress = progress.asInt() + portion; - if ( progress.asInt() == total.asInt() ) { + progress = progress.as() + portion; + if ( progress.as() == total.as() ) { auto& parent = this->getParent().as(); uf::Serializer payload; @@ -93,13 +98,13 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { parent.callHook("asset:Parsed.%UID%", payload); } /* - float portion = 1.0f / metadata["system"]["load"]["total"].asFloat(); + float portion = 1.0f / metadata["system"]["load"]["total"].as(); auto& progress = metadata["system"]["load"]["progress"]; - progress = progress.asFloat() + portion; + progress = progress.as() + portion; */ /* - if ( metadata["system"]["loaded"].asBool() ) return "false"; - if ( progress.asFloat() >= 1.0f ) { + if ( metadata["system"]["loaded"].as() ) return "false"; + if ( progress.as() >= 1.0f ) { this->queueHook("system:Load.Finished.%UID%"); } */ @@ -109,9 +114,9 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { void uf::ObjectBehavior::destroy( uf::Object& self ) { uf::Serializer& metadata = this->getComponent(); for( Json::Value::iterator it = metadata["system"]["hooks"]["alloc"].begin() ; it != metadata["system"]["hooks"]["alloc"].end() ; ++it ) { - std::string name = it.key().asString(); + std::string name = it.key().as(); for ( size_t i = 0; i < metadata["system"]["hooks"]["alloc"][name].size(); ++i ) { - size_t id = metadata["system"]["hooks"]["alloc"][name][(int) i].asUInt(); + size_t id = metadata["system"]["hooks"]["alloc"][name][(int) i].as(); uf::hooks.removeHook(name, id); } } @@ -125,10 +130,10 @@ void uf::ObjectBehavior::destroy( uf::Object& self ) { void uf::ObjectBehavior::tick( uf::Object& self ) { // listen for metadata file changes uf::Serializer& metadata = this->getComponent(); - if ( metadata["system"]["hot reload"]["enabled"].asBool() ) { - size_t mtime = uf::io::mtime( metadata["system"]["source"].asString() ); - if ( metadata["system"]["hot reload"]["mtime"].asUInt64() < mtime ) { - std::cout << "File reload detected: " << ": " << metadata["system"]["source"].asString() << ", " << metadata["system"]["hot reload"]["mtime"] << " -> " << mtime << std::endl; + if ( metadata["system"]["hot reload"]["enabled"].as() ) { + size_t mtime = uf::io::mtime( metadata["system"]["source"].as() ); + if ( metadata["system"]["hot reload"]["mtime"].as() < mtime ) { + std::cout << "File reload detected: " << ": " << metadata["system"]["source"].as() << ", " << metadata["system"]["hot reload"]["mtime"] << " -> " << mtime << std::endl; metadata["system"]["hot reload"]["mtime"] = mtime; this->reload(); //this->queueHook("metadata:Reload.%UID%"); @@ -142,21 +147,21 @@ void uf::ObjectBehavior::tick( uf::Object& self ) { uf::Serializer newQueue = Json::Value(Json::arrayValue); for ( auto& member : metadata["system"]["hooks"]["queue"] ) { uf::Serializer payload = member["payload"]; - std::string name = member["name"].asString(); - float timeout = member["timeout"].asFloat(); + std::string name = member["name"].as(); + float timeout = member["timeout"].as(); if ( timeout < curTime ) { this->callHook( name, payload ); } else { newQueue.append(member); } } - if ( metadata.isObject() ) metadata["system"]["hooks"]["queue"] = newQueue; + if ( ext::json::isObject( metadata ) ) metadata["system"]["hooks"]["queue"] = newQueue; } } void uf::ObjectBehavior::render( uf::Object& self ) { auto& metadata = this->getComponent(); /* - if ( metadata["system"]["type"].isNull() || metadata["system"]["defaults"]["render"].asBool() ) { + if ( ext::json::isNull( metadata["system"]["type"] ) || metadata["system"]["defaults"]["render"].as() ) { if ( this->hasComponent() ) { auto& scene = uf::scene::getCurrentScene(); auto& graphic = this->getComponent(); diff --git a/engine/src/engine/object/behaviors/gltf.cpp b/engine/src/engine/object/behaviors/gltf.cpp index 3a02db4e..fe76ef93 100644 --- a/engine/src/engine/object/behaviors/gltf.cpp +++ b/engine/src/engine/object/behaviors/gltf.cpp @@ -13,7 +13,7 @@ #include #include -UF_BEHAVIOR_REGISTER_CPP(GltfBehavior) +UF_BEHAVIOR_REGISTER_CPP(uf::GltfBehavior) #define this (&self) void uf::GltfBehavior::initialize( uf::Object& self ) { uf::Serializer& metadata = this->getComponent(); @@ -21,7 +21,7 @@ void uf::GltfBehavior::initialize( uf::Object& self ) { // Default load: GLTF model this->addHook( "asset:Load.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - std::string filename = json["filename"].asString(); + std::string filename = json["filename"].as(); if ( uf::io::extension(filename) != "png" ) return "false"; auto& vector = metadata["textures"]["additional"]; vector[vector.size()] = filename; @@ -29,7 +29,7 @@ void uf::GltfBehavior::initialize( uf::Object& self ) { }); this->addHook( "asset:Load.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - std::string filename = json["filename"].asString(); + std::string filename = json["filename"].as(); if ( uf::io::extension(filename) != "gltf" && uf::io::extension(filename) != "glb" ) return "false"; @@ -47,21 +47,21 @@ void uf::GltfBehavior::initialize( uf::Object& self ) { { std::string filename = "/gltf.stereo.vert.spv"; - if ( metadata["system"]["renderer"]["shaders"]["vertex"].isString() ) - filename = metadata["system"]["renderer"]["shaders"]["vertex"].asString(); - filename = this->grabURI( filename, metadata["system"]["root"].asString() ); + if ( metadata["system"]["renderer"]["shaders"]["vertex"].is() ) + filename = metadata["system"]["renderer"]["shaders"]["vertex"].as(); + filename = this->grabURI( filename, metadata["system"]["root"].as() ); graphic.material.attachShader(filename, VK_SHADER_STAGE_VERTEX_BIT); } { std::string filename = "/gltf.frag.spv"; - if ( metadata["system"]["renderer"]["shaders"]["fragment"].isString() ) - filename = metadata["system"]["renderer"]["shaders"]["fragment"].asString(); - filename = this->grabURI( filename, metadata["system"]["root"].asString() ); + if ( metadata["system"]["renderer"]["shaders"]["fragment"].is() ) + filename = metadata["system"]["renderer"]["shaders"]["fragment"].as(); + filename = this->grabURI( filename, metadata["system"]["root"].as() ); graphic.material.attachShader(filename, VK_SHADER_STAGE_FRAGMENT_BIT); } for ( int i = 0; i < metadata["textures"]["additional"].size(); ++i ) { - std::string filename = metadata["textures"]["additional"][i].asString(); + std::string filename = metadata["textures"]["additional"][i].as(); auto& scene = uf::scene::getCurrentScene(); auto& assetLoader = scene.getComponent(); const uf::Image* imagePointer = NULL; @@ -128,16 +128,16 @@ void uf::GltfBehavior::tick( uf::Object& self ) { mappings[i].blend = 0.0f; } for ( auto it = metadata["textures"]["map"].begin(); it != metadata["textures"]["map"].end(); ++it ) { - std::string key = it.key().asString(); + std::string key = it.key().as(); uint32_t from = std::stoi(key); - uint32_t to = metadata["textures"]["map"][key][0].asUInt(); + uint32_t to = metadata["textures"]["map"][key][0].as(); float blend = 1.0f; - if ( metadata["textures"]["map"][key][1].asString() == "sin(time)" ) { + if ( metadata["textures"]["map"][key][1].as() == "sin(time)" ) { blend = sin(uf::physics::time::current)*0.5f+0.5f; - } else if ( metadata["textures"]["map"][key][1].asString() == "cos(time)" ) { + } else if ( metadata["textures"]["map"][key][1].as() == "cos(time)" ) { blend = cos(uf::physics::time::current)*0.5f+0.5f; - } else if ( metadata["textures"]["map"][key][1].isNumeric() ) { - blend = metadata["textures"]["map"][key][1].asFloat(); + } else if ( metadata["textures"]["map"][key][1].is() ) { + blend = metadata["textures"]["map"][key][1].as(); } if ( from >= textures || to >= textures ) continue; mappings[from].target = to; diff --git a/engine/src/engine/object/behaviors/loading.cpp b/engine/src/engine/object/behaviors/loading.cpp index 0b0d9126..8ee24bf8 100644 --- a/engine/src/engine/object/behaviors/loading.cpp +++ b/engine/src/engine/object/behaviors/loading.cpp @@ -12,7 +12,7 @@ #include #include -UF_BEHAVIOR_REGISTER_CPP(LoadingBehavior) +UF_BEHAVIOR_REGISTER_CPP(uf::LoadingBehavior) #define this (&self) void uf::LoadingBehavior::initialize( uf::Object& self ) { auto& metadata = this->getComponent(); @@ -22,9 +22,9 @@ void uf::LoadingBehavior::initialize( uf::Object& self ) { int portion = 1; auto& total = metadata["system"]["load"]["total"]; auto& progress = metadata["system"]["load"]["progress"]; - if ( json["uid"].isNull() ) return "false"; - // progress = progress.asInt() + portion; - if ( progress.asInt() == total.asInt() ) { + if ( ext::json::isNull( json["uid"] ) ) return "false"; + // progress = progress.as() + portion; + if ( progress.as() == total.as() ) { auto& parent = this->getParent().as(); parent.callHook("asset:Parsed.%UID%"); } @@ -81,16 +81,16 @@ void uf::LoadingBehavior::destroy( uf::Object& self ) { } void uf::LoadingBehavior::tick( uf::Object& self ) { auto& metadata = this->getComponent(); - if ( metadata["system"]["loaded"].asBool() ) return; + if ( metadata["system"]["loaded"].as() ) return; size_t loading = 0; size_t loaded = 1; std::function filter = [&]( uf::Entity* entity ) { if ( !entity || entity->getUid() == 0 || !entity->hasComponent() ) return; auto& metadata = entity->getComponent(); - if ( metadata["system"]["load"]["ignore"].isBool() ) return; - if ( metadata["system"]["load"].isNull() ) return; + if ( metadata["system"]["load"]["ignore"].is() ) return; + if ( ext::json::isNull( metadata["system"]["load"] ) ) return; ++loading; - if ( metadata["system"]["load"]["progress"].asInt() < metadata["system"]["load"]["total"].asInt() ) return; + if ( metadata["system"]["load"]["progress"].as() < metadata["system"]["load"]["total"].as() ) return; ++loaded; }; this->process(filter); @@ -100,15 +100,15 @@ void uf::LoadingBehavior::tick( uf::Object& self ) { } /* auto& metadata = this->getComponent(); - if ( !metadata["system"]["loaded"].asBool() ) { + if ( !metadata["system"]["loaded"].as() ) { size_t loading = 0; size_t loaded = 0; std::function filter = [&]( uf::Entity* entity ) { if ( !entity || entity->getUid() == 0 || !entity->hasComponent() ) return; auto& metadata = entity->getComponent(); - if ( metadata["system"]["load"].isNull() ) return; + if ( ext::json::isNull( metadata["system"]["load"] ) ) return; ++loading; - if ( metadata["system"]["load"]["progress"].asFloat() < 1.0f ) return; + if ( metadata["system"]["load"]["progress"].as() < 1.0f ) return; ++loaded; }; this->process(filter); @@ -117,7 +117,7 @@ void uf::LoadingBehavior::tick( uf::Object& self ) { this->callHook("system:Load.Finished.%UID%"); } auto& metadata = this->getComponent(); - if ( metadata["system"]["load"]["progress"].asFloat() >= 1.0f ) { + if ( metadata["system"]["load"]["progress"].as() >= 1.0f ) { this->callHook("system:Load.Finished.%UID%"); } } diff --git a/engine/src/engine/object/behaviors/lua.cpp b/engine/src/engine/object/behaviors/lua.cpp index 9bd6f27d..f74a35a3 100644 --- a/engine/src/engine/object/behaviors/lua.cpp +++ b/engine/src/engine/object/behaviors/lua.cpp @@ -13,12 +13,12 @@ #include -UF_BEHAVIOR_REGISTER_CPP(LuaBehavior) +UF_BEHAVIOR_REGISTER_CPP(uf::LuaBehavior) #define this (&self) void uf::LuaBehavior::initialize( uf::Object& self ) { this->addHook( "asset:Load.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - std::string filename = json["filename"].asString(); + std::string filename = json["filename"].as(); if ( uf::io::extension(filename) != "lua" ) return "false"; uf::Scene& scene = uf::scene::getCurrentScene(); @@ -27,8 +27,8 @@ void uf::LuaBehavior::initialize( uf::Object& self ) { try { assetPointer = &assetLoader.get(filename); } catch ( ... ) {} if ( !assetPointer ) return "false"; pod::LuaScript script = *assetPointer; - script.header = "local ent = entities.get("+ std::to_string((uint) this->getUid()) +")"; - + // script.header = "local ent = entities.get("+ std::to_string((uint) this->getUid()) +")"; + script.env["ent"] = &this->as(); ext::lua::run( script ); return "true"; diff --git a/engine/src/engine/object/behaviors/render.cpp b/engine/src/engine/object/behaviors/render.cpp index 97b23858..0db9e012 100644 --- a/engine/src/engine/object/behaviors/render.cpp +++ b/engine/src/engine/object/behaviors/render.cpp @@ -11,7 +11,7 @@ #include #include -UF_BEHAVIOR_REGISTER_CPP(RenderBehavior) +UF_BEHAVIOR_REGISTER_CPP(uf::RenderBehavior) #define this (&self) void uf::RenderBehavior::initialize( uf::Object& self ) { diff --git a/engine/src/engine/object/object.cpp b/engine/src/engine/object/object.cpp index 6f02d1ae..1f335b98 100644 --- a/engine/src/engine/object/object.cpp +++ b/engine/src/engine/object/object.cpp @@ -14,10 +14,11 @@ namespace { uf::Object null; } -UF_OBJECT_REGISTER_BEGIN(Object) - UF_OBJECT_REGISTER_BEHAVIOR(EntityBehavior) - UF_OBJECT_REGISTER_BEHAVIOR(ObjectBehavior) +UF_OBJECT_REGISTER_BEGIN(uf::Object) + UF_OBJECT_REGISTER_BEHAVIOR(uf::EntityBehavior) + UF_OBJECT_REGISTER_BEHAVIOR(uf::ObjectBehavior) UF_OBJECT_REGISTER_END() +uf::Object::Object() UF_BEHAVIOR_ENTITY_CPP_ATTACH(uf::Object) void uf::Object::queueHook( const std::string& name, const std::string& payload, double timeout ) { if ( !uf::Object::timer.running() ) uf::Object::timer.start(); float start = uf::Object::timer.elapsed().asDouble(); @@ -29,9 +30,15 @@ void uf::Object::queueHook( const std::string& name, const std::string& payload, metadata["system"]["hooks"]["queue"].append(queue); } std::string uf::Object::formatHookName( const std::string& n ) { + if ( !this ) return n; + size_t uid = this->getUid(); + size_t parent = uid; + if ( this->hasParent() ) { + parent = this->getParent().getUid(); + } std::unordered_map formats = { - {"%UID%", std::to_string(this->getUid())}, - {"%P-UID%", std::to_string(this->getParent().getUid())}, + {"%UID%", std::to_string(uid)}, + {"%P-UID%", std::to_string(parent)}, }; std::string name = n; for ( auto& pair : formats ) { @@ -56,7 +63,7 @@ bool uf::Object::load( const std::string& f, bool inheritRoot ) { if ( inheritRoot && this->hasParent() ) { auto& parent = this->getParent(); uf::Serializer& metadata = parent.getComponent(); - root = metadata["system"]["root"].asString(); + root = metadata["system"]["root"].as(); } std::string filename = grabURI( f, root ); if ( !json.readFromFile( filename ) ) { @@ -71,10 +78,10 @@ bool uf::Object::load( const std::string& f, bool inheritRoot ) { bool uf::Object::reload( bool hard ) { uf::Serializer& metadata = this->getComponent(); - if ( !metadata["system"]["source"].isString() ) return false; + if ( !metadata["system"]["source"].is() ) return false; uf::Serializer json; uf::Serializer payload; - std::string filename = metadata["system"]["source"].asString(); //grabURI( metadata["system"]["source"].asString(), metadata["system"]["root"].asString() ); // uf::io::sanitize(metadata["system"]["source"].asString(), metadata["system"]["root"].asString()); + std::string filename = metadata["system"]["source"].as(); //grabURI( metadata["system"]["source"].as(), metadata["system"]["root"].as() ); // uf::io::sanitize(metadata["system"]["source"].as(), metadata["system"]["root"].as()); if ( !json.readFromFile( filename ) ) { uf::iostream << "Error @ " << __FILE__ << ":" << __LINE__ << ": failed to open `" + filename + "`" << "\n"; uf::iostream << this << ": " << this->getName() << ": " << this->getUid() << ": " << metadata << "\n"; @@ -84,7 +91,7 @@ bool uf::Object::reload( bool hard ) { payload["old"] = metadata; for ( auto it = json["metadata"].begin(); it != json["metadata"].end(); ++it ) { - metadata[it.key().asString()] = json["metadata"][it.key().asString()]; + metadata[it.key().as()] = json["metadata"][it.key().as()]; } payload["new"] = metadata; std::cout << "Updated metadata for " << this->getName() << ": " << this->getUid() << std::endl; @@ -98,87 +105,87 @@ bool uf::Object::load( const uf::Serializer& _json ) { uf::Serializer json = _json; // copy system table to base for ( auto it = json["system"].begin(); it != json["system"].end(); ++it ) { - std::string key = it.key().asString(); - if ( json[key].isNull() ) + std::string key = it.key().as(); + if ( ext::json::isNull( json[key] ) ) json[key] = json["system"][key]; } json["hot reload"]["enabled"] = json["system"]["hot reload"]["enabled"]; // Basic entity information { // Set name - this->m_name = json["name"].isString() ? json["name"].asString() : json["type"].asString(); + this->m_name = json["name"].is() ? json["name"].as() : json["type"].as(); } // Bind behaviors - if ( json["type"].isString() ) { - uf::instantiator::bind( json["type"].asString(), *this ); + if ( json["type"].is() ) { + uf::instantiator::bind( json["type"].as(), *this ); } - if ( json["defaults"]["render"].asBool() ) { + if ( json["defaults"]["render"].as() ) { uf::instantiator::bind( "RenderBehavior", *this ); } - if ( json["defaults"]["asset load"].asBool() ) { + if ( json["defaults"]["asset load"].as() ) { uf::instantiator::bind( "GltfBehavior", *this ); } { uf::Serializer target; - if ( metadata["system"]["behaviors"].isArray() ) { + if ( ext::json::isArray( metadata["system"]["behaviors"] ) ) { target = metadata["system"]["behaviors"]; - } else if ( json["behaviors"].isArray() ) { + } else if ( ext::json::isArray( json["behaviors"] ) ) { target = json["behaviors"]; } for ( uint i = 0; i < target.size(); ++i ) { - uf::instantiator::bind( target[i].asString(), *this ); + uf::instantiator::bind( target[i].as(), *this ); } } // Set transform { - bool load = json["transform"].isObject(); + bool load = ext::json::isObject( json["transform"] ); if ( this->hasComponent>() ) load = false; pod::Transform<>& transform = this->getComponent>(); if ( transform.position.x == 0 && transform.position.y == 0 && transform.position.z == 0 ) { load = true; } if ( load ) { - transform.position.x = json["transform"]["position"][0].asFloat(); - transform.position.y = json["transform"]["position"][1].asFloat(); - transform.position.z = json["transform"]["position"][2].asFloat(); + transform.position.x = json["transform"]["position"][0].as(); + transform.position.y = json["transform"]["position"][1].as(); + transform.position.z = json["transform"]["position"][2].as(); transform.orientation = uf::quaternion::identity(); - if ( json["transform"]["orientation"].isArray() ) { - transform.orientation.x = json["transform"]["orientation"][0].asFloat(); - transform.orientation.y = json["transform"]["orientation"][1].asFloat(); - transform.orientation.z = json["transform"]["orientation"][2].asFloat(); - transform.orientation.w = json["transform"]["orientation"][3].asFloat(); - } else if ( json["transform"]["rotation"]["angle"].asFloat() != 0 ) { + if ( ext::json::isArray( json["transform"]["orientation"] ) ) { + transform.orientation.x = json["transform"]["orientation"][0].as(); + transform.orientation.y = json["transform"]["orientation"][1].as(); + transform.orientation.z = json["transform"]["orientation"][2].as(); + transform.orientation.w = json["transform"]["orientation"][3].as(); + } else if ( json["transform"]["rotation"]["angle"].as() != 0 ) { transform.orientation = uf::quaternion::axisAngle( { - json["transform"]["rotation"]["axis"][0].asFloat(), - json["transform"]["rotation"]["axis"][1].asFloat(), - json["transform"]["rotation"]["axis"][2].asFloat() + json["transform"]["rotation"]["axis"][0].as(), + json["transform"]["rotation"]["axis"][1].as(), + json["transform"]["rotation"]["axis"][2].as() }, - json["transform"]["rotation"]["angle"].asFloat() + json["transform"]["rotation"]["angle"].as() ); } - if ( json["transform"]["scale"].isArray() ) { - transform.scale = uf::vector::create( json["transform"]["scale"][0].asFloat(),json["transform"]["scale"][1].asFloat(),json["transform"]["scale"][2].asFloat() ); + if ( ext::json::isArray( json["transform"]["scale"] ) ) { + transform.scale = uf::vector::create( json["transform"]["scale"][0].as(),json["transform"]["scale"][1].as(),json["transform"]["scale"][2].as() ); } transform = uf::transform::reorient( transform ); } } // Set movement { - if ( json["physics"].isObject() && !this->hasComponent() ) { + if ( ext::json::isObject( json["physics"] ) && !this->hasComponent() ) { auto& physics = this->getComponent(); - if ( json["physics"]["linear"]["velocity"].isArray() ) + if ( ext::json::isArray( json["physics"]["linear"]["velocity"] ) ) for ( uint j = 0; j < 3; ++j ) - physics.linear.velocity[j] = json["physics"]["linear"]["velocity"][j].asFloat(); - if ( json["physics"]["linear"]["acceleration"].isArray() ) + physics.linear.velocity[j] = json["physics"]["linear"]["velocity"][j].as(); + if ( ext::json::isArray( json["physics"]["linear"]["acceleration"] ) ) for ( uint j = 0; j < 3; ++j ) - physics.linear.acceleration[j] = json["physics"]["linear"]["acceleration"][j].asFloat(); + physics.linear.acceleration[j] = json["physics"]["linear"]["acceleration"][j].as(); - if ( json["physics"]["rotational"]["velocity"].isArray() ) + if ( ext::json::isArray( json["physics"]["rotational"]["velocity"] ) ) for ( uint j = 0; j < 4; ++j ) - physics.rotational.velocity[j] = json["physics"]["rotational"]["velocity"][j].asFloat(); - if ( json["physics"]["rotational"]["acceleration"].isArray() ) + physics.rotational.velocity[j] = json["physics"]["rotational"]["velocity"][j].as(); + if ( ext::json::isArray( json["physics"]["rotational"]["acceleration"] ) ) for ( uint j = 0; j < 4; ++j ) - physics.rotational.acceleration[j] = json["physics"]["rotational"]["acceleration"][j].asFloat(); + physics.rotational.acceleration[j] = json["physics"]["rotational"]["acceleration"][j].as(); } } @@ -186,12 +193,23 @@ bool uf::Object::load( const uf::Serializer& _json ) { uf::Asset& assetLoader = scene.getComponent(); // initialize base entity, needed for asset hooks + #define UF_OBJECT_LOAD_ASSET_HEADER(type)\ + bool addBehavior = false;\ + uf::Serializer target;\ + if ( ext::json::isObject( metadata["system"]["assets"] ) ) {\ + target = metadata["system"]["assets"];\ + } else if ( ext::json::isArray( json["assets"] ) ) {\ + target = json["assets"];\ + } else if ( ext::json::isObject( json["assets"] ) && !ext::json::isNull( json["assets"][#type] ) ) {\ + target = json["assets"][#type];\ + } + #define UF_OBJECT_LOAD_ASSET(...)\ std::string canonical = "";\ - std::string f = target[i].isObject() ? target[i]["filename"].asString() : target[i].asString();\ - float delay = target[i].isObject() ? target[i]["delay"].asFloat() : 0;\ - std::string filename = grabURI( f, json["root"].asString() );\ - bool singleThreaded = target[i].isObject() ? target[i]["single threaded"].asBool() : false;\ + std::string f = ext::json::isObject( target[i] ) ? target[i]["filename"].as() : target[i].as();\ + float delay = ext::json::isObject( target[i] ) ? target[i]["delay"].as() : 0;\ + std::string filename = grabURI( f, json["root"].as() );\ + bool singleThreaded = ext::json::isObject( target[i] ) ? target[i]["single threaded"].as() : false;\ std::vector allowedExtensions = {__VA_ARGS__};\ if ( std::find( allowedExtensions.begin(), allowedExtensions.end(), uf::io::extension(filename) ) == allowedExtensions.end() ) continue;\ uf::Serializer payload;\ @@ -203,15 +221,7 @@ bool uf::Object::load( const uf::Serializer& _json ) { // Audio { // find first valid texture in asset list - bool addBehavior = false; - uf::Serializer target; - if ( metadata["system"]["assets"].isArray() ) { - target = metadata["system"]["assets"]; - } else if ( json["assets"].isArray() ) { - target = json["assets"]; - } else if ( json["assets"].isObject() && !json["assets"]["audio"].isNull() ) { - target = json["assets"]["audio"]; - } + UF_OBJECT_LOAD_ASSET_HEADER(audio) for ( uint i = 0; i < target.size(); ++i ) { UF_OBJECT_LOAD_ASSET("ogg") } @@ -220,15 +230,7 @@ bool uf::Object::load( const uf::Serializer& _json ) { // Texture { // find first valid texture in asset list - bool addBehavior = false; - uf::Serializer target; - if ( metadata["system"]["assets"].isArray() ) { - target = metadata["system"]["assets"]; - } else if ( json["assets"].isArray() ) { - target = json["assets"]; - } else if ( json["assets"].isObject() && !json["assets"]["textures"].isNull() ) { - target = json["assets"]["textures"]; - } + UF_OBJECT_LOAD_ASSET_HEADER(textures) for ( uint i = 0; i < target.size(); ++i ) { UF_OBJECT_LOAD_ASSET("png") } @@ -237,15 +239,7 @@ bool uf::Object::load( const uf::Serializer& _json ) { // gltf { // find first valid texture in asset list - bool addBehavior = false; - uf::Serializer target; - if ( metadata["system"]["assets"].isArray() ) { - target = metadata["system"]["assets"]; - } else if ( json["assets"].isArray() ) { - target = json["assets"]; - } else if ( json["assets"].isObject() && !json["assets"]["models"].isNull() ) { - target = json["assets"]["models"]; - } + UF_OBJECT_LOAD_ASSET_HEADER(models) for ( uint i = 0; i < target.size(); ++i ) { UF_OBJECT_LOAD_ASSET("gltf", "glb") @@ -257,15 +251,7 @@ bool uf::Object::load( const uf::Serializer& _json ) { // lua { // find first valid texture in asset list - uf::Serializer target; - bool addBehavior = false; - if ( metadata["system"]["assets"].isArray() ) { - target = metadata["system"]["assets"]; - } else if ( json["assets"].isArray() ) { - target = json["assets"]; - } else if ( json["assets"].isObject() && !json["assets"]["scripts"].isNull() ) { - target = json["assets"]["scripts"]; - } + UF_OBJECT_LOAD_ASSET_HEADER(scripts) for ( uint i = 0; i < target.size(); ++i ) { UF_OBJECT_LOAD_ASSET("lua") } @@ -277,8 +263,8 @@ bool uf::Object::load( const uf::Serializer& _json ) { if ( json["metadata"] != Json::nullValue ) { uf::Serializer& metadata = this->getComponent(); if ( json["metadata"].type() == Json::stringValue ) { - std::string f = json["metadata"].asString(); - std::string filename = grabURI( json["metadata"].asString(), json["root"].asString() ); + std::string f = json["metadata"].as(); + std::string filename = grabURI( json["metadata"].as(), json["root"].as() ); if ( !metadata.readFromFile(filename) ) { uf::iostream << "Error @ " << __FILE__ << ":" << __LINE__ << ": failed to open `" + filename + "`" << "\n"; return false; @@ -292,26 +278,19 @@ bool uf::Object::load( const uf::Serializer& _json ) { metadata["system"]["hooks"] = hooks; /* for ( auto it = json["system"].begin(); it != json["system"].end(); ++it ) { - if ( metadata["system"][it.key().asString()].isNull() ) - metadata["system"][it.key().asString()] = json["system"][it.key().asString()]; + if ( ext::json::isNull( metadata["system"][it.key().as()] ) ) + metadata["system"][it.key().as()] = json["system"][it.key().as()]; } */ // check for children { - uf::Serializer target; - if ( metadata["system"]["assets"].isArray() ) { - target = metadata["system"]["assets"]; - } else if ( metadata["system"]["assets"].isArray() ) { - target = metadata["system"]["assets"]; - } else if ( metadata["system"]["assets"].isObject() && !metadata["system"]["assets"]["entities"].isNull() ) { - target = metadata["system"]["assets"]["entities"]; - } + UF_OBJECT_LOAD_ASSET_HEADER(entities) for ( uint i = 0; i < target.size(); ++i ) { std::string canonical = ""; - std::string f = target[i].isObject() ? target[i]["filename"].asString() : target[i].asString(); - float delay = target[i].isObject() ? target[i]["delay"].asFloat() : -1; - std::string filename = grabURI( f, json["root"].asString() ); + std::string f = ext::json::isObject( target[i] ) ? target[i]["filename"].as() : target[i].as(); + float delay = ext::json::isObject( target[i] ) ? target[i]["delay"].as() : -1; + std::string filename = grabURI( f, json["root"].as() ); if ( uf::io::extension(filename) != "json" ) continue; if ( (canonical = assetLoader.load( filename )) == "" ) continue; if ( delay > -1 ) { @@ -335,14 +314,14 @@ bool uf::Object::load( const uf::Serializer& _json ) { } } // Add lights - if ( metadata["system"]["lights"].isArray() ) { + if ( ext::json::isArray( metadata["system"]["lights"] ) ) { uf::Serializer target = metadata["system"]["lights"]; auto& pTransform = this->getComponent>(); for ( uint i = 0; i < target.size(); ++i ) { uf::Serializer json = target[i]; std::vector orientations; - if ( json["ignore"].asBool() ) continue; - if ( json["transform"]["orientation"].isNull() && json["shadows"]["fov"].asFloat() == 0.0f ) { + if ( json["ignore"].as() ) continue; + if ( ext::json::isNull( json["transform"]["orientation"] ) && json["shadows"]["fov"].as() == 0.0f ) { orientations.reserve(6); orientations.push_back({0, 0, 0, -1}); orientations.push_back({0, 0.707107, 0, -0.707107}); @@ -353,49 +332,50 @@ bool uf::Object::load( const uf::Serializer& _json ) { json["shadows"]["fov"] = 90.0f; } else { pod::Vector4f orientation; - if ( json["transform"]["orientation"].isArray() ) { + if ( ext::json::isArray( json["transform"]["orientation"] ) ) { orientation = pTransform.orientation; } else { - for ( uint j = 0; j < 4; ++j ) orientation[j] = json["transform"]["orientation"][j].asFloat(); + for ( uint j = 0; j < 4; ++j ) orientation[j] = json["transform"]["orientation"][j].as(); } orientations.push_back(orientation); } uf::Object* target = this; for ( auto& orientation : orientations ) { std::string fname = "/light.json"; - if ( json["system"]["filename"].isString() ) fname = json["system"]["filename"].asString(); + if ( json["system"]["filename"].is() ) fname = json["system"]["filename"].as(); auto* light = target->loadChildPointer(fname, false); if ( target == this ) target = light; auto& metadata = light->getComponent(); auto& transform = light->getComponent>(); - if ( json["transform"]["position"].isArray() ) { + if ( ext::json::isArray( json["transform"]["position"] ) ) { for ( uint j = 0; j < 3; ++j ) - transform.position[j] = json["transform"]["position"][j].asFloat(); + transform.position[j] = json["transform"]["position"][j].as(); } else { transform.position = pTransform.position; } for ( uint j = 0; j < 4; ++j ) transform.orientation[j] = orientation[j]; - if ( !json["color"].isNull() ) metadata["light"]["color"] = json["color"]; - if ( !json["radius"].isNull() ) metadata["light"]["radius"] = json["radius"]; - if ( !json["power"].isNull() ) metadata["light"]["power"] = json["power"]; - if ( !json["shadows"].isNull() ) metadata["light"]["shadows"] = json["shadows"]; - if ( !json["flicker"].isNull() ) metadata["light"]["flicker"] = json["flicker"]; - if ( !json["fade"].isNull() ) metadata["light"]["fade"] = json["fade"]; + if ( !ext::json::isNull( json["color"] ) ) metadata["light"]["color"] = json["color"]; + if ( !ext::json::isNull( json["radius"] ) ) metadata["light"]["radius"] = json["radius"]; + if ( !ext::json::isNull( json["power"] ) ) metadata["light"]["power"] = json["power"]; + if ( !ext::json::isNull( json["shadows"] ) ) metadata["light"]["shadows"] = json["shadows"]; + if ( !ext::json::isNull( json["flicker"] ) ) metadata["light"]["flicker"] = json["flicker"]; + if ( !ext::json::isNull( json["fade"] ) ) metadata["light"]["fade"] = json["fade"]; - if ( !json["system"]["track"].isNull() ) metadata["system"]["track"] = json["system"]["track"]; + if ( !ext::json::isNull( json["system"]["track"] ) ) metadata["system"]["track"] = json["system"]["track"]; light->initialize(); } } } + return true; } uf::Object& uf::Object::loadChild( const std::string& f, bool initialize ) { uf::Serializer& metadata = this->getComponent(); uf::Serializer json; - std::string filename = grabURI( f, metadata["system"]["root"].asString() ); + std::string filename = grabURI( f, metadata["system"]["root"].as() ); if ( !json.readFromFile(filename) ) { uf::iostream << "Error @ " << __FILE__ << ":" << __LINE__ << ": failed to open `" + filename + "`" << "\n"; return ::null; @@ -406,8 +386,8 @@ uf::Object& uf::Object::loadChild( const std::string& f, bool initialize ) { return this->loadChild(json, initialize); } uf::Object& uf::Object::loadChild( const uf::Serializer& json, bool initialize ) { - std::string type = json["type"].asString(); - if ( json["ignore"].asBool() ) return ::null; + std::string type = json["type"].as(); + if ( json["ignore"].as() ) return ::null; uf::Entity& entity = uf::instantiator::instantiate(type); uf::Object& object = entity.as(); diff --git a/engine/src/engine/scene/behavior.cpp b/engine/src/engine/scene/behavior.cpp index a06b09c9..80b4361b 100644 --- a/engine/src/engine/scene/behavior.cpp +++ b/engine/src/engine/scene/behavior.cpp @@ -3,10 +3,10 @@ #include #include -UF_BEHAVIOR_ENTITY_CPP_BEGIN(Scene) +UF_BEHAVIOR_ENTITY_CPP_BEGIN(uf::Scene) #define this ((uf::Scene*) &self) void uf::SceneBehavior::initialize( uf::Object& self ) { - uf::renderer::scenes.push_back(this); +// uf::renderer::scenes.push_back(this); uf::renderer::states::rebuild = true; this->addHook( "system:Renderer.QueueRebuild", [&](const std::string& event)->std::string{ @@ -15,7 +15,7 @@ void uf::SceneBehavior::initialize( uf::Object& self ) { }); this->addHook( "system:Destroy", [&](const std::string& event)->std::string{ uf::Serializer json = event; - size_t uid = json["uid"].asUInt64(); + size_t uid = json["uid"].as(); if ( uid <= 0 ) return "false"; auto* target = this->findByUid(uid); if ( !target ) return "false"; @@ -32,8 +32,10 @@ void uf::SceneBehavior::tick( uf::Object& self ) { void uf::SceneBehavior::render( uf::Object& self ) { } void uf::SceneBehavior::destroy( uf::Object& self ) { +/* auto it = std::find(uf::renderer::scenes.begin(), uf::renderer::scenes.end(), this); if ( it != uf::renderer::scenes.end() ) uf::renderer::scenes.erase(it); +*/ uf::renderer::states::rebuild = true; } #undef self diff --git a/engine/src/engine/scene/scene.cpp b/engine/src/engine/scene/scene.cpp index 56a3bdf8..0db3a825 100644 --- a/engine/src/engine/scene/scene.cpp +++ b/engine/src/engine/scene/scene.cpp @@ -2,12 +2,14 @@ #include #include #include +#include -UF_OBJECT_REGISTER_BEGIN(Scene) - UF_OBJECT_REGISTER_BEHAVIOR(EntityBehavior) - UF_OBJECT_REGISTER_BEHAVIOR(ObjectBehavior) - UF_OBJECT_REGISTER_BEHAVIOR(SceneBehavior) +UF_OBJECT_REGISTER_BEGIN(uf::Scene) + UF_OBJECT_REGISTER_BEHAVIOR(uf::EntityBehavior) + UF_OBJECT_REGISTER_BEHAVIOR(uf::ObjectBehavior) + UF_OBJECT_REGISTER_BEHAVIOR(uf::SceneBehavior) UF_OBJECT_REGISTER_END() +uf::Scene::Scene() UF_BEHAVIOR_ENTITY_CPP_ATTACH(uf::Scene) uf::Entity& uf::Scene::getController() { static uf::Entity* cachedController = NULL; if ( uf::renderer::currentRenderMode ) { @@ -35,16 +37,12 @@ const uf::Entity& uf::Scene::getController() const { uf::Scene& scene = *const_cast(this); return scene.getController(); } -#include std::vector uf::scene::scenes; uf::Scene& uf::scene::loadScene( const std::string& name, const std::string& filename ) { - uf::Scene* scene; - if ( uf::instantiator::objects->has( name ) ) { - scene = (uf::Scene*) &uf::instantiator::instantiate( name ); - } else { - scene = new uf::Scene; - } - uf::scene::scenes.push_back(scene); + uf::Scene* scene = uf::instantiator::objects->has( name ) ? (uf::Scene*) &uf::instantiator::instantiate( name ) : new uf::Scene; + +// uf::scene::scenes.insert(uf::scene::scenes.begin(), scene); + uf::scene::scenes.emplace_back( scene ); std::string target = name; @@ -60,13 +58,11 @@ uf::Scene& uf::scene::loadScene( const std::string& name, const std::string& fil return *scene; } uf::Scene& uf::scene::loadScene( const std::string& name, const uf::Serializer& data ) { - uf::Scene* scene; - if ( uf::instantiator::objects->has( name ) ) { - scene = (uf::Scene*) &uf::instantiator::instantiate( name ); - } else { - scene = new uf::Scene; - } - uf::scene::scenes.push_back(scene); + uf::Scene* scene = uf::instantiator::objects->has( name ) ? (uf::Scene*) &uf::instantiator::instantiate( name ) : new uf::Scene; + +// uf::scene::scenes.insert(uf::scene::scenes.begin(), scene); + uf::scene::scenes.emplace_back( scene ); + if ( data != "" ) scene->load(data); scene->initialize(); return *scene; diff --git a/engine/src/ext/discord/discord.cpp b/engine/src/ext/discord/discord.cpp index 7e3e83ff..67c62286 100644 --- a/engine/src/ext/discord/discord.cpp +++ b/engine/src/ext/discord/discord.cpp @@ -192,28 +192,28 @@ void UF_API ext::discord::initialize(){ uf::hooks.addHook( "discord:Activity.Update", [&](const std::string& event)->std::string{ - static uf::Serializer canonical; if ( canonical["details"].isNull() ) { + static uf::Serializer canonical; if ( ext::json::isNull( canonical["details"] ) ) { canonical["large image"] = "icon"; canonical["large text"] = "Playing"; } uf::Serializer json = event; { - if ( json["details"].isString() ) canonical["details"] = json["details"]; - if ( json["state"].isString() ) canonical["state"] = json["state"]; - if ( json["small image"].isString() ) canonical["small image"] = json["small image"]; - if ( json["small text"].isString() ) canonical["small text"] = json["small text"]; - if ( json["large image"].isString() ) canonical["large image"] = json["large image"]; - if ( json["large text"].isString() ) canonical["large text"] = json["large text"]; + if ( json["details"].is() ) canonical["details"] = json["details"]; + if ( json["state"].is() ) canonical["state"] = json["state"]; + if ( json["small image"].is() ) canonical["small image"] = json["small image"]; + if ( json["small text"].is() ) canonical["small text"] = json["small text"]; + if ( json["large image"].is() ) canonical["large image"] = json["large image"]; + if ( json["large text"].is() ) canonical["large text"] = json["large text"]; } ::discord::Activity activity{}; - if ( canonical["details"].isString() ) activity.SetDetails(canonical["details"].asCString()); - if ( canonical["state"].isString() ) activity.SetState(canonical["state"].asCString()); - if ( canonical["small image"].isString() ) activity.GetAssets().SetSmallImage(canonical["small image"].asCString()); - if ( canonical["small text"].isString() ) activity.GetAssets().SetSmallText(canonical["small text"].asCString()); - if ( canonical["large image"].isString() ) activity.GetAssets().SetLargeImage(canonical["large image"].asCString()); - if ( canonical["large text"].isString() ) activity.GetAssets().SetLargeText(canonical["large text"].asCString()); + if ( canonical["details"].is() ) activity.SetDetails(canonical["details"].asCString()); + if ( canonical["state"].is() ) activity.SetState(canonical["state"].asCString()); + if ( canonical["small image"].is() ) activity.GetAssets().SetSmallImage(canonical["small image"].asCString()); + if ( canonical["small text"].is() ) activity.GetAssets().SetSmallText(canonical["small text"].asCString()); + if ( canonical["large image"].is() ) activity.GetAssets().SetLargeImage(canonical["large image"].asCString()); + if ( canonical["large text"].is() ) activity.GetAssets().SetLargeText(canonical["large text"].asCString()); activity.SetType(::discord::ActivityType::Playing); state.core->ActivityManager().UpdateActivity(activity, [](::discord::Result result) { std::cout << ((result == ::discord::Result::Ok) ? "Succeeded" : "Failed") << " updating activity!\n"; diff --git a/engine/src/ext/json/jsoncpp.cpp2 b/engine/src/ext/json/jsoncpp.cpp similarity index 67% rename from engine/src/ext/json/jsoncpp.cpp2 rename to engine/src/ext/json/jsoncpp.cpp index 54cfae27..863d35b9 100644 --- a/engine/src/ext/json/jsoncpp.cpp2 +++ b/engine/src/ext/json/jsoncpp.cpp @@ -69,10 +69,11 @@ license you like. // ////////////////////////////////////////////////////////////////////// -#include -#if defined(UF_USE_JSON) -#include + + + +#include "json/json.h" #ifndef JSON_IS_AMALGAMATION #error "Compile with -I PATH_TO_JSON_DIRECTORY" @@ -91,6 +92,9 @@ license you like. #ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED #define LIB_JSONCPP_JSON_TOOL_H_INCLUDED +#if !defined(JSON_IS_AMALGAMATION) +#include +#endif // Also support old flag NO_LOCALE_SUPPORT #ifdef NO_LOCALE_SUPPORT @@ -108,7 +112,7 @@ license you like. */ namespace Json { -static char getDecimalPoint() { +static inline char getDecimalPoint() { #ifdef JSONCPP_NO_LOCALE_SUPPORT return '\0'; #else @@ -118,8 +122,8 @@ static char getDecimalPoint() { } /// Converts a unicode code-point to UTF-8. -static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) { - JSONCPP_STRING result; +static inline String codePointToUTF8(unsigned int cp) { + String result; // based on description from http://en.wikipedia.org/wiki/UTF-8 @@ -153,7 +157,7 @@ enum { }; // Defines a char buffer for use with uintToString(). -typedef char UIntToStringBuffer[uintToStringBufferSize]; +using UIntToStringBuffer = char[uintToStringBufferSize]; /** Converts an unsigned integer to string. * @param value Unsigned integer to convert to string @@ -173,42 +177,45 @@ static inline void uintToString(LargestUInt value, char*& current) { * We had a sophisticated way, but it did not work in WinCE. * @see https://github.com/open-source-parsers/jsoncpp/pull/9 */ -static inline void fixNumericLocale(char* begin, char* end) { - while (begin < end) { +template Iter fixNumericLocale(Iter begin, Iter end) { + for (; begin != end; ++begin) { if (*begin == ',') { *begin = '.'; } - ++begin; } + return begin; } -static inline void fixNumericLocaleInput(char* begin, char* end) { +template void fixNumericLocaleInput(Iter begin, Iter end) { char decimalPoint = getDecimalPoint(); - if (decimalPoint != '\0' && decimalPoint != '.') { - while (begin < end) { - if (*begin == '.') { - *begin = decimalPoint; - } - ++begin; + if (decimalPoint == '\0' || decimalPoint == '.') { + return; + } + for (; begin != end; ++begin) { + if (*begin == '.') { + *begin = decimalPoint; } } } /** - * Delete zeros in the end of string, if it isn't last zero before '.' character. + * Return iterator that would be the new end of the range [begin,end), if we + * were to delete zeros in the end of string, but not the last zero before '.'. */ -static inline void fixZerosInTheEnd(char* begin, char* end) { - end--; - while ((begin < end) && (*end == '0')) { - // don't delete last zero before point. - if (*(end - 1) != '.') { - *end = '\0'; +template Iter fixZerosInTheEnd(Iter begin, Iter end) { + for (; begin != end; --end) { + if (*(end - 1) != '0') { + return end; + } + // Don't delete the last zero before the decimal point. + if (begin != (end - 1) && *(end - 2) == '.') { + return end; } - end--; } + return end; } -} // namespace Json { +} // namespace Json #endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED @@ -232,69 +239,65 @@ static inline void fixZerosInTheEnd(char* begin, char* end) { // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #if !defined(JSON_IS_AMALGAMATION) +#include "json_tool.h" #include #include #include -#include "json_tool.h" #endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include +#include #include #include +#include #include -#include +#include #include #include -#include +#include +#include -#if defined(_MSC_VER) -#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above -#define snprintf sprintf_s -#elif _MSC_VER >= 1900 // VC++ 14.0 and above -#define snprintf std::snprintf -#else -#define snprintf _snprintf -#endif -#elif defined(__ANDROID__) || defined(__QNXNTO__) -#define snprintf snprintf -#elif __cplusplus >= 201103L -#if !defined(__MINGW32__) && !defined(__CYGWIN__) -#define snprintf std::snprintf -#endif -#endif +#include +#if __cplusplus >= 201103L -#if defined(__QNXNTO__) +#if !defined(sscanf) #define sscanf std::sscanf #endif -#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +#endif //__cplusplus + +#if defined(_MSC_VER) +#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) +#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 +#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES +#endif //_MSC_VER + +#if defined(_MSC_VER) // Disable warning about strdup being deprecated. #pragma warning(disable : 4996) #endif -// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile time to change the stack limit +// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile +// time to change the stack limit #if !defined(JSONCPP_DEPRECATED_STACK_LIMIT) #define JSONCPP_DEPRECATED_STACK_LIMIT 1000 #endif -static size_t const stackLimit_g = JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue() +static size_t const stackLimit_g = + JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue() namespace Json { #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) -typedef std::unique_ptr CharReaderPtr; +using CharReaderPtr = std::unique_ptr; #else -typedef std::auto_ptr CharReaderPtr; +using CharReaderPtr = std::auto_ptr; #endif // Implementation of class Features // //////////////////////////////// -Features::Features() - : allowComments_(true), strictRoot_(false), - allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} +Features::Features() = default; -Features Features::all() { return Features(); } +Features Features::all() { return {}; } Features Features::strictMode() { Features features; @@ -309,49 +312,38 @@ Features Features::strictMode() { // //////////////////////////////// bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) { - for (; begin < end; ++begin) - if (*begin == '\n' || *begin == '\r') - return true; - return false; + return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; }); } // Class Reader // ////////////////////////////////////////////////////////////////// -Reader::Reader() - : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), - lastValue_(), commentsBefore_(), features_(Features::all()), - collectComments_() {} +Reader::Reader() : features_(Features::all()) {} -Reader::Reader(const Features& features) - : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), - lastValue_(), commentsBefore_(), features_(features), collectComments_() { -} +Reader::Reader(const Features& features) : features_(features) {} -bool -Reader::parse(const std::string& document, Value& root, bool collectComments) { +bool Reader::parse(const std::string& document, Value& root, + bool collectComments) { document_.assign(document.begin(), document.end()); const char* begin = document_.c_str(); const char* end = begin + document_.length(); return parse(begin, end, root, collectComments); } -bool Reader::parse(std::istream& sin, Value& root, bool collectComments) { - // std::istream_iterator begin(sin); +bool Reader::parse(std::istream& is, Value& root, bool collectComments) { + // std::istream_iterator begin(is); // std::istream_iterator end; // Those would allow streamed input from a file, if parse() were a // template function. - // Since JSONCPP_STRING is reference-counted, this at least does not + // Since String is reference-counted, this at least does not // create an extra copy. - JSONCPP_STRING doc; - std::getline(sin, doc, (char)EOF); + String doc; + std::getline(is, doc, static_cast EOF); return parse(doc.data(), doc.data() + doc.size(), root, collectComments); } -bool Reader::parse(const char* beginDoc, - const char* endDoc, - Value& root, +bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root, bool collectComments) { if (!features_.allowComments_) { collectComments = false; @@ -361,8 +353,8 @@ bool Reader::parse(const char* beginDoc, end_ = endDoc; collectComments_ = collectComments; current_ = begin_; - lastValueEnd_ = 0; - lastValue_ = 0; + lastValueEnd_ = nullptr; + lastValue_ = nullptr; commentsBefore_.clear(); errors_.clear(); while (!nodes_.empty()) @@ -392,9 +384,11 @@ bool Reader::parse(const char* beginDoc, bool Reader::readValue() { // readValue() may call itself only if it calls readObject() or ReadArray(). - // These methods execute nodes_.push() just before and nodes_.pop)() just after calling readValue(). - // parse() executes one nodes_.push(), so > instead of >=. - if (nodes_.size() > stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue()."); + // These methods execute nodes_.push() just before and nodes_.pop)() just + // after calling readValue(). parse() executes one nodes_.push(), so > instead + // of >=. + if (nodes_.size() > stackLimit_g) + throwRuntimeError("Exceeded stackLimit in readValue()."); Token token; skipCommentTokens(token); @@ -420,30 +414,24 @@ bool Reader::readValue() { case tokenString: successful = decodeString(token); break; - case tokenTrue: - { + case tokenTrue: { Value v(true); currentValue().swapPayload(v); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenFalse: - { + } break; + case tokenFalse: { Value v(false); currentValue().swapPayload(v); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenNull: - { + } break; + case tokenNull: { Value v; currentValue().swapPayload(v); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); - } - break; + } break; case tokenArraySeparator: case tokenObjectEnd: case tokenArrayEnd: @@ -549,7 +537,7 @@ bool Reader::readToken(Token& token) { if (!ok) token.type_ = tokenError; token.end_ = current_; - return true; + return ok; } void Reader::skipSpaces() { @@ -562,7 +550,7 @@ void Reader::skipSpaces() { } } -bool Reader::match(Location pattern, int patternLength) { +bool Reader::match(const Char* pattern, int patternLength) { if (end_ - current_ < patternLength) return false; int index = patternLength; @@ -596,16 +584,16 @@ bool Reader::readComment() { return true; } -JSONCPP_STRING Reader::normalizeEOL(Reader::Location begin, Reader::Location end) { - JSONCPP_STRING normalized; +String Reader::normalizeEOL(Reader::Location begin, Reader::Location end) { + String normalized; normalized.reserve(static_cast(end - begin)); Reader::Location current = begin; while (current != end) { char c = *current++; if (c == '\r') { if (current != end && *current == '\n') - // convert dos EOL - ++current; + // convert dos EOL + ++current; // convert Mac EOL normalized += '\n'; } else { @@ -615,12 +603,12 @@ JSONCPP_STRING Reader::normalizeEOL(Reader::Location begin, Reader::Location end return normalized; } -void -Reader::addComment(Location begin, Location end, CommentPlacement placement) { +void Reader::addComment(Location begin, Location end, + CommentPlacement placement) { assert(collectComments_); - const JSONCPP_STRING& normalized = normalizeEOL(begin, end); + const String& normalized = normalizeEOL(begin, end); if (placement == commentAfterOnSameLine) { - assert(lastValue_ != 0); + assert(lastValue_ != nullptr); lastValue_->setComment(normalized, placement); } else { commentsBefore_ += normalized; @@ -653,7 +641,7 @@ bool Reader::readCppStyleComment() { } void Reader::readNumber() { - const char *p = current_; + Location p = current_; char c = '0'; // stopgap for already consumed character // integral part while (c >= '0' && c <= '9') @@ -686,12 +674,12 @@ bool Reader::readString() { return c == '"'; } -bool Reader::readObject(Token& tokenStart) { +bool Reader::readObject(Token& token) { Token tokenName; - JSONCPP_STRING name; + String name; Value init(objectValue); currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); + currentValue().setOffsetStart(token.start_ - begin_); while (readToken(tokenName)) { bool initialTokenOk = true; while (tokenName.type_ == tokenComment && initialTokenOk) @@ -708,15 +696,15 @@ bool Reader::readObject(Token& tokenStart) { Value numberName; if (!decodeNumber(tokenName, numberName)) return recoverFromError(tokenObjectEnd); - name = JSONCPP_STRING(numberName.asCString()); + name = numberName.asString(); } else { break; } Token colon; if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { - return addErrorAndRecover( - "Missing ':' after object member name", colon, tokenObjectEnd); + return addErrorAndRecover("Missing ':' after object member name", colon, + tokenObjectEnd); } Value& value = currentValue()[name]; nodes_.push(&value); @@ -729,8 +717,8 @@ bool Reader::readObject(Token& tokenStart) { if (!readToken(comma) || (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && comma.type_ != tokenComment)) { - return addErrorAndRecover( - "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); + return addErrorAndRecover("Missing ',' or '}' in object declaration", + comma, tokenObjectEnd); } bool finalizeTokenOk = true; while (comma.type_ == tokenComment && finalizeTokenOk) @@ -738,14 +726,14 @@ bool Reader::readObject(Token& tokenStart) { if (comma.type_ == tokenObjectEnd) return true; } - return addErrorAndRecover( - "Missing '}' or object member name", tokenName, tokenObjectEnd); + return addErrorAndRecover("Missing '}' or object member name", tokenName, + tokenObjectEnd); } -bool Reader::readArray(Token& tokenStart) { +bool Reader::readArray(Token& token) { Value init(arrayValue); currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); + currentValue().setOffsetStart(token.start_ - begin_); skipSpaces(); if (current_ != end_ && *current_ == ']') // empty array { @@ -762,19 +750,19 @@ bool Reader::readArray(Token& tokenStart) { if (!ok) // error already set return recoverFromError(tokenArrayEnd); - Token token; + Token currentToken; // Accept Comment after last item in the array. - ok = readToken(token); - while (token.type_ == tokenComment && ok) { - ok = readToken(token); + ok = readToken(currentToken); + while (currentToken.type_ == tokenComment && ok) { + ok = readToken(currentToken); } - bool badTokenType = - (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); + bool badTokenType = (currentToken.type_ != tokenArraySeparator && + currentToken.type_ != tokenArrayEnd); if (!ok || badTokenType) { - return addErrorAndRecover( - "Missing ',' or ']' in array declaration", token, tokenArrayEnd); + return addErrorAndRecover("Missing ',' or ']' in array declaration", + currentToken, tokenArrayEnd); } - if (token.type_ == tokenArrayEnd) + if (currentToken.type_ == tokenArrayEnd) break; } return true; @@ -798,7 +786,8 @@ bool Reader::decodeNumber(Token& token, Value& decoded) { bool isNegative = *current == '-'; if (isNegative) ++current; - // TODO: Help the compiler do the div and mod at compile time or get rid of them. + // TODO: Help the compiler do the div and mod at compile time or get rid of + // them. Value::LargestUInt maxIntegerValue = isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 : Value::maxLargestUInt; @@ -808,7 +797,7 @@ bool Reader::decodeNumber(Token& token, Value& decoded) { Char c = *current++; if (c < '0' || c > '9') return decodeDouble(token, decoded); - Value::UInt digit(static_cast(c - '0')); + auto digit(static_cast(c - '0')); if (value >= threshold) { // We've hit or exceeded the max value divided by 10 (rounded down). If // a) we've only just touched the limit, b) this is the last digit, and @@ -844,18 +833,17 @@ bool Reader::decodeDouble(Token& token) { bool Reader::decodeDouble(Token& token, Value& decoded) { double value = 0; - JSONCPP_STRING buffer(token.start_, token.end_); - JSONCPP_ISTRINGSTREAM is(buffer); + String buffer(token.start_, token.end_); + IStringStream is(buffer); if (!(is >> value)) - return addError("'" + JSONCPP_STRING(token.start_, token.end_) + - "' is not a number.", - token); + return addError( + "'" + String(token.start_, token.end_) + "' is not a number.", token); decoded = value; return true; } bool Reader::decodeString(Token& token) { - JSONCPP_STRING decoded_string; + String decoded_string; if (!decodeString(token, decoded_string)) return false; Value decoded(decoded_string); @@ -865,7 +853,7 @@ bool Reader::decodeString(Token& token) { return true; } -bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) { +bool Reader::decodeString(Token& token, String& decoded) { decoded.reserve(static_cast(token.end_ - token.start_ - 2)); Location current = token.start_ + 1; // skip '"' Location end = token.end_ - 1; // do not include '"' @@ -873,7 +861,7 @@ bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) { Char c = *current++; if (c == '"') break; - else if (c == '\\') { + if (c == '\\') { if (current == end) return addError("Empty escape sequence in string", token, current); Char escape = *current++; @@ -918,10 +906,8 @@ bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) { return true; } -bool Reader::decodeUnicodeCodePoint(Token& token, - Location& current, - Location end, - unsigned int& unicode) { +bool Reader::decodeUnicodeCodePoint(Token& token, Location& current, + Location end, unsigned int& unicode) { if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) return false; @@ -930,10 +916,9 @@ bool Reader::decodeUnicodeCodePoint(Token& token, if (end - current < 6) return addError( "additional six characters expected to parse unicode surrogate pair.", - token, - current); - unsigned int surrogatePair; + token, current); if (*(current++) == '\\' && *(current++) == 'u') { + unsigned int surrogatePair; if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); } else @@ -941,20 +926,17 @@ bool Reader::decodeUnicodeCodePoint(Token& token, } else return addError("expecting another \\u token to begin the second half of " "a unicode surrogate pair", - token, - current); + token, current); } return true; } -bool Reader::decodeUnicodeEscapeSequence(Token& token, - Location& current, +bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current, Location end, unsigned int& ret_unicode) { if (end - current < 4) return addError( - "Bad unicode escape sequence in string: four digits expected.", - token, + "Bad unicode escape sequence in string: four digits expected.", token, current); int unicode = 0; for (int index = 0; index < 4; ++index) { @@ -969,15 +951,13 @@ bool Reader::decodeUnicodeEscapeSequence(Token& token, else return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", - token, - current); + token, current); } ret_unicode = static_cast(unicode); return true; } -bool -Reader::addError(const JSONCPP_STRING& message, Token& token, Location extra) { +bool Reader::addError(const String& message, Token& token, Location extra) { ErrorInfo info; info.token_ = token; info.message_ = message; @@ -999,8 +979,7 @@ bool Reader::recoverFromError(TokenType skipUntilToken) { return false; } -bool Reader::addErrorAndRecover(const JSONCPP_STRING& message, - Token& token, +bool Reader::addErrorAndRecover(const String& message, Token& token, TokenType skipUntilToken) { addError(message, token); return recoverFromError(skipUntilToken); @@ -1014,8 +993,7 @@ Reader::Char Reader::getNextChar() { return *current_++; } -void Reader::getLocationLineAndColumn(Location location, - int& line, +void Reader::getLocationLineAndColumn(Location location, int& line, int& column) const { Location current = begin_; Location lastLineStart = current; @@ -1037,25 +1015,22 @@ void Reader::getLocationLineAndColumn(Location location, ++line; } -JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const { +String Reader::getLocationLineAndColumn(Location location) const { int line, column; getLocationLineAndColumn(location, line, column); char buffer[18 + 16 + 16 + 1]; - snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); return buffer; } // Deprecated. Preserved for backward compatibility -JSONCPP_STRING Reader::getFormatedErrorMessages() const { +String Reader::getFormatedErrorMessages() const { return getFormattedErrorMessages(); } -JSONCPP_STRING Reader::getFormattedErrorMessages() const { - JSONCPP_STRING formattedMessage; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { - const ErrorInfo& error = *itError; +String Reader::getFormattedErrorMessages() const { + String formattedMessage; + for (const auto& error : errors_) { formattedMessage += "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; formattedMessage += " " + error.message_ + "\n"; @@ -1068,10 +1043,7 @@ JSONCPP_STRING Reader::getFormattedErrorMessages() const { std::vector Reader::getStructuredErrors() const { std::vector allErrors; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { - const ErrorInfo& error = *itError; + for (const auto& error : errors_) { Reader::StructuredError structured; structured.offset_start = error.token_.start_ - begin_; structured.offset_limit = error.token_.end_ - begin_; @@ -1081,28 +1053,27 @@ std::vector Reader::getStructuredErrors() const { return allErrors; } -bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) { +bool Reader::pushError(const Value& value, const String& message) { ptrdiff_t const length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length) + if (value.getOffsetStart() > length || value.getOffsetLimit() > length) return false; Token token; token.type_ = tokenError; token.start_ = begin_ + value.getOffsetStart(); - token.end_ = end_ + value.getOffsetLimit(); + token.end_ = begin_ + value.getOffsetLimit(); ErrorInfo info; info.token_ = token; info.message_ = message; - info.extra_ = 0; + info.extra_ = nullptr; errors_.push_back(info); return true; } -bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) { +bool Reader::pushError(const Value& value, const String& message, + const Value& extra) { ptrdiff_t const length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length - || extra.getOffsetLimit() > length) + if (value.getOffsetStart() > length || value.getOffsetLimit() > length || + extra.getOffsetLimit() > length) return false; Token token; token.type_ = tokenError; @@ -1116,15 +1087,15 @@ bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const return true; } -bool Reader::good() const { - return !errors_.size(); -} +bool Reader::good() const { return errors_.empty(); } -// exact copy of Features +// Originally copied from the Features class (now deprecated), used internally +// for features implementation. class OurFeatures { public: static OurFeatures all(); bool allowComments_; + bool allowTrailingCommas_; bool strictRoot_; bool allowDroppedNullPlaceholders_; bool allowNumericKeys_; @@ -1132,42 +1103,36 @@ public: bool failIfExtra_; bool rejectDupKeys_; bool allowSpecialFloats_; - int stackLimit_; -}; // OurFeatures + bool skipBom_; + size_t stackLimit_; +}; // OurFeatures -// exact copy of Implementation of class Features -// //////////////////////////////// - -OurFeatures OurFeatures::all() { return OurFeatures(); } +OurFeatures OurFeatures::all() { return {}; } // Implementation of class Reader // //////////////////////////////// -// exact copy of Reader, renamed to OurReader +// Originally copied from the Reader class (now deprecated), used internally +// for implementing JSON reading. class OurReader { public: - typedef char Char; - typedef const Char* Location; + using Char = char; + using Location = const Char*; struct StructuredError { ptrdiff_t offset_start; ptrdiff_t offset_limit; - JSONCPP_STRING message; + String message; }; - OurReader(OurFeatures const& features); - bool parse(const char* beginDoc, - const char* endDoc, - Value& root, + explicit OurReader(OurFeatures const& features); + bool parse(const char* beginDoc, const char* endDoc, Value& root, bool collectComments = true); - JSONCPP_STRING getFormattedErrorMessages() const; + String getFormattedErrorMessages() const; std::vector getStructuredErrors() const; - bool pushError(const Value& value, const JSONCPP_STRING& message); - bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); - bool good() const; private: - OurReader(OurReader const&); // no impl - void operator=(OurReader const&); // no impl + OurReader(OurReader const&); // no impl + void operator=(OurReader const&); // no impl enum TokenType { tokenEndOfStream = 0, @@ -1199,17 +1164,18 @@ private: class ErrorInfo { public: Token token_; - JSONCPP_STRING message_; + String message_; Location extra_; }; - typedef std::deque Errors; + using Errors = std::deque; bool readToken(Token& token); void skipSpaces(); - bool match(Location pattern, int patternLength); + void skipBom(bool skipBom); + bool match(const Char* pattern, int patternLength); bool readComment(); - bool readCStyleComment(); + bool readCStyleComment(bool* containsNewLineResult); bool readCppStyleComment(); bool readString(); bool readStringSingleQuote(); @@ -1220,68 +1186,57 @@ private: bool decodeNumber(Token& token); bool decodeNumber(Token& token, Value& decoded); bool decodeString(Token& token); - bool decodeString(Token& token, JSONCPP_STRING& decoded); + bool decodeString(Token& token, String& decoded); bool decodeDouble(Token& token); bool decodeDouble(Token& token, Value& decoded); - bool decodeUnicodeCodePoint(Token& token, - Location& current, - Location end, + bool decodeUnicodeCodePoint(Token& token, Location& current, Location end, unsigned int& unicode); - bool decodeUnicodeEscapeSequence(Token& token, - Location& current, - Location end, - unsigned int& unicode); - bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); + bool decodeUnicodeEscapeSequence(Token& token, Location& current, + Location end, unsigned int& unicode); + bool addError(const String& message, Token& token, Location extra = nullptr); bool recoverFromError(TokenType skipUntilToken); - bool addErrorAndRecover(const JSONCPP_STRING& message, - Token& token, + bool addErrorAndRecover(const String& message, Token& token, TokenType skipUntilToken); void skipUntilSpace(); Value& currentValue(); Char getNextChar(); - void - getLocationLineAndColumn(Location location, int& line, int& column) const; - JSONCPP_STRING getLocationLineAndColumn(Location location) const; + void getLocationLineAndColumn(Location location, int& line, + int& column) const; + String getLocationLineAndColumn(Location location) const; void addComment(Location begin, Location end, CommentPlacement placement); void skipCommentTokens(Token& token); - static JSONCPP_STRING normalizeEOL(Location begin, Location end); + static String normalizeEOL(Location begin, Location end); static bool containsNewLine(Location begin, Location end); - typedef std::stack Nodes; - Nodes nodes_; - Errors errors_; - JSONCPP_STRING document_; - Location begin_; - Location end_; - Location current_; - Location lastValueEnd_; - Value* lastValue_; - JSONCPP_STRING commentsBefore_; + using Nodes = std::stack; + + Nodes nodes_{}; + Errors errors_{}; + String document_{}; + Location begin_ = nullptr; + Location end_ = nullptr; + Location current_ = nullptr; + Location lastValueEnd_ = nullptr; + Value* lastValue_ = nullptr; + bool lastValueHasAComment_ = false; + String commentsBefore_{}; OurFeatures const features_; - bool collectComments_; -}; // OurReader + bool collectComments_ = false; +}; // OurReader // complete copy of Read impl, for OurReader -bool OurReader::containsNewLine(OurReader::Location begin, OurReader::Location end) { - for (; begin < end; ++begin) - if (*begin == '\n' || *begin == '\r') - return true; - return false; +bool OurReader::containsNewLine(OurReader::Location begin, + OurReader::Location end) { + return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; }); } -OurReader::OurReader(OurFeatures const& features) - : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), - lastValue_(), commentsBefore_(), - features_(features), collectComments_() { -} +OurReader::OurReader(OurFeatures const& features) : features_(features) {} -bool OurReader::parse(const char* beginDoc, - const char* endDoc, - Value& root, - bool collectComments) { +bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root, + bool collectComments) { if (!features_.allowComments_) { collectComments = false; } @@ -1290,22 +1245,23 @@ bool OurReader::parse(const char* beginDoc, end_ = endDoc; collectComments_ = collectComments; current_ = begin_; - lastValueEnd_ = 0; - lastValue_ = 0; + lastValueEnd_ = nullptr; + lastValue_ = nullptr; commentsBefore_.clear(); errors_.clear(); while (!nodes_.empty()) nodes_.pop(); nodes_.push(&root); + // skip byte order mark if it exists at the beginning of the UTF-8 text. + skipBom(features_.skipBom_); bool successful = readValue(); + nodes_.pop(); Token token; skipCommentTokens(token); - if (features_.failIfExtra_) { - if ((features_.strictRoot_ || token.type_ != tokenError) && token.type_ != tokenEndOfStream) { - addError("Extra non-whitespace after JSON value.", token); - return false; - } + if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) { + addError("Extra non-whitespace after JSON value.", token); + return false; } if (collectComments_ && !commentsBefore_.empty()) root.setComment(commentsBefore_, commentAfter); @@ -1327,7 +1283,8 @@ bool OurReader::parse(const char* beginDoc, bool OurReader::readValue() { // To preserve the old behaviour we cast size_t to int. - if (static_cast(nodes_.size()) > features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); + if (nodes_.size() > features_.stackLimit_) + throwRuntimeError("Exceeded stackLimit in readValue()."); Token token; skipCommentTokens(token); bool successful = true; @@ -1352,54 +1309,42 @@ bool OurReader::readValue() { case tokenString: successful = decodeString(token); break; - case tokenTrue: - { + case tokenTrue: { Value v(true); currentValue().swapPayload(v); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenFalse: - { + } break; + case tokenFalse: { Value v(false); currentValue().swapPayload(v); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenNull: - { + } break; + case tokenNull: { Value v; currentValue().swapPayload(v); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenNaN: - { + } break; + case tokenNaN: { Value v(std::numeric_limits::quiet_NaN()); currentValue().swapPayload(v); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenPosInf: - { + } break; + case tokenPosInf: { Value v(std::numeric_limits::infinity()); currentValue().swapPayload(v); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenNegInf: - { + } break; + case tokenNegInf: { Value v(-std::numeric_limits::infinity()); currentValue().swapPayload(v); currentValue().setOffsetStart(token.start_ - begin_); currentValue().setOffsetLimit(token.end_ - begin_); - } - break; + } break; case tokenArraySeparator: case tokenObjectEnd: case tokenArrayEnd: @@ -1421,6 +1366,7 @@ bool OurReader::readValue() { if (collectComments_) { lastValueEnd_ = current_; + lastValueHasAComment_ = false; lastValue_ = ¤tValue(); } @@ -1461,10 +1407,13 @@ bool OurReader::readToken(Token& token) { break; case '\'': if (features_.allowSingleQuotes_) { - token.type_ = tokenString; - ok = readStringSingleQuote(); + token.type_ = tokenString; + ok = readStringSingleQuote(); + } else { + // If we don't allow single quotes, this is a failure case. + ok = false; + } break; - } // else fall through case '/': token.type_ = tokenComment; ok = readComment(); @@ -1490,6 +1439,14 @@ bool OurReader::readToken(Token& token) { ok = features_.allowSpecialFloats_ && match("nfinity", 7); } break; + case '+': + if (readNumber(true)) { + token.type_ = tokenNumber; + } else { + token.type_ = tokenPosInf; + ok = features_.allowSpecialFloats_ && match("nfinity", 7); + } + break; case 't': token.type_ = tokenTrue; ok = match("rue", 3); @@ -1534,7 +1491,7 @@ bool OurReader::readToken(Token& token) { if (!ok) token.type_ = tokenError; token.end_ = current_; - return true; + return ok; } void OurReader::skipSpaces() { @@ -1547,7 +1504,17 @@ void OurReader::skipSpaces() { } } -bool OurReader::match(Location pattern, int patternLength) { +void OurReader::skipBom(bool skipBom) { + // The default behavior is to skip BOM. + if (skipBom) { + if ((end_ - begin_) >= 3 && strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) { + begin_ += 3; + current_ = begin_; + } + } +} + +bool OurReader::match(const Char* pattern, int patternLength) { if (end_ - current_ < patternLength) return false; int index = patternLength; @@ -1559,21 +1526,32 @@ bool OurReader::match(Location pattern, int patternLength) { } bool OurReader::readComment() { - Location commentBegin = current_ - 1; - Char c = getNextChar(); + const Location commentBegin = current_ - 1; + const Char c = getNextChar(); bool successful = false; - if (c == '*') - successful = readCStyleComment(); - else if (c == '/') + bool cStyleWithEmbeddedNewline = false; + + const bool isCStyleComment = (c == '*'); + const bool isCppStyleComment = (c == '/'); + if (isCStyleComment) { + successful = readCStyleComment(&cStyleWithEmbeddedNewline); + } else if (isCppStyleComment) { successful = readCppStyleComment(); + } + if (!successful) return false; if (collectComments_) { CommentPlacement placement = commentBefore; - if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { - if (c != '*' || !containsNewLine(commentBegin, current_)) - placement = commentAfterOnSameLine; + + if (!lastValueHasAComment_) { + if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { + if (isCppStyleComment || !cStyleWithEmbeddedNewline) { + placement = commentAfterOnSameLine; + lastValueHasAComment_ = true; + } + } } addComment(commentBegin, current_, placement); @@ -1581,16 +1559,17 @@ bool OurReader::readComment() { return true; } -JSONCPP_STRING OurReader::normalizeEOL(OurReader::Location begin, OurReader::Location end) { - JSONCPP_STRING normalized; +String OurReader::normalizeEOL(OurReader::Location begin, + OurReader::Location end) { + String normalized; normalized.reserve(static_cast(end - begin)); OurReader::Location current = begin; while (current != end) { char c = *current++; if (c == '\r') { if (current != end && *current == '\n') - // convert dos EOL - ++current; + // convert dos EOL + ++current; // convert Mac EOL normalized += '\n'; } else { @@ -1600,24 +1579,29 @@ JSONCPP_STRING OurReader::normalizeEOL(OurReader::Location begin, OurReader::Loc return normalized; } -void -OurReader::addComment(Location begin, Location end, CommentPlacement placement) { +void OurReader::addComment(Location begin, Location end, + CommentPlacement placement) { assert(collectComments_); - const JSONCPP_STRING& normalized = normalizeEOL(begin, end); + const String& normalized = normalizeEOL(begin, end); if (placement == commentAfterOnSameLine) { - assert(lastValue_ != 0); + assert(lastValue_ != nullptr); lastValue_->setComment(normalized, placement); } else { commentsBefore_ += normalized; } } -bool OurReader::readCStyleComment() { +bool OurReader::readCStyleComment(bool* containsNewLineResult) { + *containsNewLineResult = false; + while ((current_ + 1) < end_) { Char c = getNextChar(); if (c == '*' && *current_ == '/') break; + if (c == '\n') + *containsNewLineResult = true; } + return getNextChar() == '/'; } @@ -1638,7 +1622,7 @@ bool OurReader::readCppStyleComment() { } bool OurReader::readNumber(bool checkInf) { - const char *p = current_; + Location p = current_; if (checkInf && p != end_ && *p == 'I') { current_ = ++p; return false; @@ -1675,7 +1659,6 @@ bool OurReader::readString() { return c == '"'; } - bool OurReader::readStringSingleQuote() { Char c = 0; while (current_ != end_) { @@ -1688,19 +1671,21 @@ bool OurReader::readStringSingleQuote() { return c == '\''; } -bool OurReader::readObject(Token& tokenStart) { +bool OurReader::readObject(Token& token) { Token tokenName; - JSONCPP_STRING name; + String name; Value init(objectValue); currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); + currentValue().setOffsetStart(token.start_ - begin_); while (readToken(tokenName)) { bool initialTokenOk = true; while (tokenName.type_ == tokenComment && initialTokenOk) initialTokenOk = readToken(tokenName); if (!initialTokenOk) break; - if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object + if (tokenName.type_ == tokenObjectEnd && + (name.empty() || + features_.allowTrailingCommas_)) // empty object or trailing comma return true; name.clear(); if (tokenName.type_ == tokenString) { @@ -1714,17 +1699,17 @@ bool OurReader::readObject(Token& tokenStart) { } else { break; } + if (name.length() >= (1U << 30)) + throwRuntimeError("keylength >= 2^30"); + if (features_.rejectDupKeys_ && currentValue().isMember(name)) { + String msg = "Duplicate key: '" + name + "'"; + return addErrorAndRecover(msg, tokenName, tokenObjectEnd); + } Token colon; if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { - return addErrorAndRecover( - "Missing ':' after object member name", colon, tokenObjectEnd); - } - if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30"); - if (features_.rejectDupKeys_ && currentValue().isMember(name)) { - JSONCPP_STRING msg = "Duplicate key: '" + name + "'"; - return addErrorAndRecover( - msg, tokenName, tokenObjectEnd); + return addErrorAndRecover("Missing ':' after object member name", colon, + tokenObjectEnd); } Value& value = currentValue()[name]; nodes_.push(&value); @@ -1737,8 +1722,8 @@ bool OurReader::readObject(Token& tokenStart) { if (!readToken(comma) || (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && comma.type_ != tokenComment)) { - return addErrorAndRecover( - "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); + return addErrorAndRecover("Missing ',' or '}' in object declaration", + comma, tokenObjectEnd); } bool finalizeTokenOk = true; while (comma.type_ == tokenComment && finalizeTokenOk) @@ -1746,23 +1731,27 @@ bool OurReader::readObject(Token& tokenStart) { if (comma.type_ == tokenObjectEnd) return true; } - return addErrorAndRecover( - "Missing '}' or object member name", tokenName, tokenObjectEnd); + return addErrorAndRecover("Missing '}' or object member name", tokenName, + tokenObjectEnd); } -bool OurReader::readArray(Token& tokenStart) { +bool OurReader::readArray(Token& token) { Value init(arrayValue); currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); - skipSpaces(); - if (current_ != end_ && *current_ == ']') // empty array - { - Token endArray; - readToken(endArray); - return true; - } + currentValue().setOffsetStart(token.start_ - begin_); int index = 0; for (;;) { + skipSpaces(); + if (current_ != end_ && *current_ == ']' && + (index == 0 || + (features_.allowTrailingCommas_ && + !features_.allowDroppedNullPlaceholders_))) // empty array or trailing + // comma + { + Token endArray; + readToken(endArray); + return true; + } Value& value = currentValue()[index++]; nodes_.push(&value); bool ok = readValue(); @@ -1770,19 +1759,19 @@ bool OurReader::readArray(Token& tokenStart) { if (!ok) // error already set return recoverFromError(tokenArrayEnd); - Token token; + Token currentToken; // Accept Comment after last item in the array. - ok = readToken(token); - while (token.type_ == tokenComment && ok) { - ok = readToken(token); + ok = readToken(currentToken); + while (currentToken.type_ == tokenComment && ok) { + ok = readToken(currentToken); } - bool badTokenType = - (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); + bool badTokenType = (currentToken.type_ != tokenArraySeparator && + currentToken.type_ != tokenArrayEnd); if (!ok || badTokenType) { - return addErrorAndRecover( - "Missing ',' or ']' in array declaration", token, tokenArrayEnd); + return addErrorAndRecover("Missing ',' or ']' in array declaration", + currentToken, tokenArrayEnd); } - if (token.type_ == tokenArrayEnd) + if (currentToken.type_ == tokenArrayEnd) break; } return true; @@ -1803,38 +1792,78 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) { // larger than the maximum supported value of an integer then // we decode the number as a double. Location current = token.start_; - bool isNegative = *current == '-'; - if (isNegative) + const bool isNegative = *current == '-'; + if (isNegative) { ++current; - // TODO: Help the compiler do the div and mod at compile time or get rid of them. - Value::LargestUInt maxIntegerValue = - isNegative ? Value::LargestUInt(-Value::minLargestInt) - : Value::maxLargestUInt; - Value::LargestUInt threshold = maxIntegerValue / 10; + } + + // We assume we can represent the largest and smallest integer types as + // unsigned integers with separate sign. This is only true if they can fit + // into an unsigned integer. + static_assert(Value::maxLargestInt <= Value::maxLargestUInt, + "Int must be smaller than UInt"); + + // We need to convert minLargestInt into a positive number. The easiest way + // to do this conversion is to assume our "threshold" value of minLargestInt + // divided by 10 can fit in maxLargestInt when absolute valued. This should + // be a safe assumption. + static_assert(Value::minLargestInt <= -Value::maxLargestInt, + "The absolute value of minLargestInt must be greater than or " + "equal to maxLargestInt"); + static_assert(Value::minLargestInt / 10 >= -Value::maxLargestInt, + "The absolute value of minLargestInt must be only 1 magnitude " + "larger than maxLargest Int"); + + static constexpr Value::LargestUInt positive_threshold = + Value::maxLargestUInt / 10; + static constexpr Value::UInt positive_last_digit = Value::maxLargestUInt % 10; + + // For the negative values, we have to be more careful. Since typically + // -Value::minLargestInt will cause an overflow, we first divide by 10 and + // then take the inverse. This assumes that minLargestInt is only a single + // power of 10 different in magnitude, which we check above. For the last + // digit, we take the modulus before negating for the same reason. + static constexpr auto negative_threshold = + Value::LargestUInt(-(Value::minLargestInt / 10)); + static constexpr auto negative_last_digit = + Value::UInt(-(Value::minLargestInt % 10)); + + const Value::LargestUInt threshold = + isNegative ? negative_threshold : positive_threshold; + const Value::UInt max_last_digit = + isNegative ? negative_last_digit : positive_last_digit; + Value::LargestUInt value = 0; while (current < token.end_) { Char c = *current++; if (c < '0' || c > '9') return decodeDouble(token, decoded); - Value::UInt digit(static_cast(c - '0')); + + const auto digit(static_cast(c - '0')); if (value >= threshold) { // We've hit or exceeded the max value divided by 10 (rounded down). If - // a) we've only just touched the limit, b) this is the last digit, and + // a) we've only just touched the limit, meaing value == threshold, + // b) this is the last digit, or // c) it's small enough to fit in that rounding delta, we're okay. // Otherwise treat this number as a double to avoid overflow. if (value > threshold || current != token.end_ || - digit > maxIntegerValue % 10) { + digit > max_last_digit) { return decodeDouble(token, decoded); } } value = value * 10 + digit; } - if (isNegative) - decoded = -Value::LargestInt(value); - else if (value <= Value::LargestUInt(Value::maxInt)) + + if (isNegative) { + // We use the same magnitude assumption here, just in case. + const auto last_digit = static_cast(value % 10); + decoded = -Value::LargestInt(value / 10) * 10 - last_digit; + } else if (value <= Value::LargestUInt(Value::maxLargestInt)) { decoded = Value::LargestInt(value); - else + } else { decoded = value; + } + return true; } @@ -1850,44 +1879,18 @@ bool OurReader::decodeDouble(Token& token) { bool OurReader::decodeDouble(Token& token, Value& decoded) { double value = 0; - const int bufferSize = 32; - int count; - ptrdiff_t const length = token.end_ - token.start_; - - // Sanity check to avoid buffer overflow exploits. - if (length < 0) { - return addError("Unable to parse token length", token); + const String buffer(token.start_, token.end_); + IStringStream is(buffer); + if (!(is >> value)) { + return addError( + "'" + String(token.start_, token.end_) + "' is not a number.", token); } - size_t const ulength = static_cast(length); - - // Avoid using a string constant for the format control string given to - // sscanf, as this can cause hard to debug crashes on OS X. See here for more - // info: - // - // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html - char format[] = "%lf"; - - if (length <= bufferSize) { - Char buffer[bufferSize + 1]; - memcpy(buffer, token.start_, ulength); - buffer[length] = 0; - fixNumericLocaleInput(buffer, buffer + length); - count = sscanf(buffer, format, &value); - } else { - JSONCPP_STRING buffer(token.start_, token.end_); - count = sscanf(buffer.c_str(), format, &value); - } - - if (count != 1) - return addError("'" + JSONCPP_STRING(token.start_, token.end_) + - "' is not a number.", - token); decoded = value; return true; } bool OurReader::decodeString(Token& token) { - JSONCPP_STRING decoded_string; + String decoded_string; if (!decodeString(token, decoded_string)) return false; Value decoded(decoded_string); @@ -1897,7 +1900,7 @@ bool OurReader::decodeString(Token& token) { return true; } -bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) { +bool OurReader::decodeString(Token& token, String& decoded) { decoded.reserve(static_cast(token.end_ - token.start_ - 2)); Location current = token.start_ + 1; // skip '"' Location end = token.end_ - 1; // do not include '"' @@ -1905,7 +1908,7 @@ bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) { Char c = *current++; if (c == '"') break; - else if (c == '\\') { + if (c == '\\') { if (current == end) return addError("Empty escape sequence in string", token, current); Char escape = *current++; @@ -1950,10 +1953,8 @@ bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) { return true; } -bool OurReader::decodeUnicodeCodePoint(Token& token, - Location& current, - Location end, - unsigned int& unicode) { +bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current, + Location end, unsigned int& unicode) { if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) return false; @@ -1962,10 +1963,9 @@ bool OurReader::decodeUnicodeCodePoint(Token& token, if (end - current < 6) return addError( "additional six characters expected to parse unicode surrogate pair.", - token, - current); - unsigned int surrogatePair; + token, current); if (*(current++) == '\\' && *(current++) == 'u') { + unsigned int surrogatePair; if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); } else @@ -1973,20 +1973,17 @@ bool OurReader::decodeUnicodeCodePoint(Token& token, } else return addError("expecting another \\u token to begin the second half of " "a unicode surrogate pair", - token, - current); + token, current); } return true; } -bool OurReader::decodeUnicodeEscapeSequence(Token& token, - Location& current, - Location end, - unsigned int& ret_unicode) { +bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current, + Location end, + unsigned int& ret_unicode) { if (end - current < 4) return addError( - "Bad unicode escape sequence in string: four digits expected.", - token, + "Bad unicode escape sequence in string: four digits expected.", token, current); int unicode = 0; for (int index = 0; index < 4; ++index) { @@ -2001,15 +1998,13 @@ bool OurReader::decodeUnicodeEscapeSequence(Token& token, else return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", - token, - current); + token, current); } ret_unicode = static_cast(unicode); return true; } -bool -OurReader::addError(const JSONCPP_STRING& message, Token& token, Location extra) { +bool OurReader::addError(const String& message, Token& token, Location extra) { ErrorInfo info; info.token_ = token; info.message_ = message; @@ -2031,9 +2026,8 @@ bool OurReader::recoverFromError(TokenType skipUntilToken) { return false; } -bool OurReader::addErrorAndRecover(const JSONCPP_STRING& message, - Token& token, - TokenType skipUntilToken) { +bool OurReader::addErrorAndRecover(const String& message, Token& token, + TokenType skipUntilToken) { addError(message, token); return recoverFromError(skipUntilToken); } @@ -2046,9 +2040,8 @@ OurReader::Char OurReader::getNextChar() { return *current_++; } -void OurReader::getLocationLineAndColumn(Location location, - int& line, - int& column) const { +void OurReader::getLocationLineAndColumn(Location location, int& line, + int& column) const { Location current = begin_; Location lastLineStart = current; line = 0; @@ -2069,20 +2062,17 @@ void OurReader::getLocationLineAndColumn(Location location, ++line; } -JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const { +String OurReader::getLocationLineAndColumn(Location location) const { int line, column; getLocationLineAndColumn(location, line, column); char buffer[18 + 16 + 16 + 1]; - snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); return buffer; } -JSONCPP_STRING OurReader::getFormattedErrorMessages() const { - JSONCPP_STRING formattedMessage; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { - const ErrorInfo& error = *itError; +String OurReader::getFormattedErrorMessages() const { + String formattedMessage; + for (const auto& error : errors_) { formattedMessage += "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; formattedMessage += " " + error.message_ + "\n"; @@ -2095,10 +2085,7 @@ JSONCPP_STRING OurReader::getFormattedErrorMessages() const { std::vector OurReader::getStructuredErrors() const { std::vector allErrors; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { - const ErrorInfo& error = *itError; + for (const auto& error : errors_) { OurReader::StructuredError structured; structured.offset_start = error.token_.start_ - begin_; structured.offset_limit = error.token_.end_ - begin_; @@ -2108,59 +2095,15 @@ std::vector OurReader::getStructuredErrors() const { return allErrors; } -bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) { - ptrdiff_t length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = end_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = 0; - errors_.push_back(info); - return true; -} - -bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) { - ptrdiff_t length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length - || extra.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = begin_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = begin_ + extra.getOffsetStart(); - errors_.push_back(info); - return true; -} - -bool OurReader::good() const { - return !errors_.size(); -} - - class OurCharReader : public CharReader { bool const collectComments_; OurReader reader_; + public: - OurCharReader( - bool collectComments, - OurFeatures const& features) - : collectComments_(collectComments) - , reader_(features) - {} - bool parse( - char const* beginDoc, char const* endDoc, - Value* root, JSONCPP_STRING* errs) JSONCPP_OVERRIDE { + OurCharReader(bool collectComments, OurFeatures const& features) + : collectComments_(collectComments), reader_(features) {} + bool parse(char const* beginDoc, char const* endDoc, Value* root, + String* errs) override { bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); if (errs) { *errs = reader_.getFormattedErrorMessages(); @@ -2169,67 +2112,64 @@ public: } }; -CharReaderBuilder::CharReaderBuilder() -{ - setDefaults(&settings_); -} -CharReaderBuilder::~CharReaderBuilder() -{} -CharReader* CharReaderBuilder::newCharReader() const -{ +CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); } +CharReaderBuilder::~CharReaderBuilder() = default; +CharReader* CharReaderBuilder::newCharReader() const { bool collectComments = settings_["collectComments"].asBool(); OurFeatures features = OurFeatures::all(); features.allowComments_ = settings_["allowComments"].asBool(); + features.allowTrailingCommas_ = settings_["allowTrailingCommas"].asBool(); features.strictRoot_ = settings_["strictRoot"].asBool(); - features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool(); + features.allowDroppedNullPlaceholders_ = + settings_["allowDroppedNullPlaceholders"].asBool(); features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); - features.stackLimit_ = settings_["stackLimit"].asInt(); + + // Stack limit is always a size_t, so we get this as an unsigned int + // regardless of it we have 64-bit integer support enabled. + features.stackLimit_ = static_cast(settings_["stackLimit"].asUInt()); features.failIfExtra_ = settings_["failIfExtra"].asBool(); features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); + features.skipBom_ = settings_["skipBom"].asBool(); return new OurCharReader(collectComments, features); } -static void getValidReaderKeys(std::set* valid_keys) -{ - valid_keys->clear(); - valid_keys->insert("collectComments"); - valid_keys->insert("allowComments"); - valid_keys->insert("strictRoot"); - valid_keys->insert("allowDroppedNullPlaceholders"); - valid_keys->insert("allowNumericKeys"); - valid_keys->insert("allowSingleQuotes"); - valid_keys->insert("stackLimit"); - valid_keys->insert("failIfExtra"); - valid_keys->insert("rejectDupKeys"); - valid_keys->insert("allowSpecialFloats"); -} -bool CharReaderBuilder::validate(Json::Value* invalid) const -{ - Json::Value my_invalid; - if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL - Json::Value& inv = *invalid; - std::set valid_keys; - getValidReaderKeys(&valid_keys); - Value::Members keys = settings_.getMemberNames(); - size_t n = keys.size(); - for (size_t i = 0; i < n; ++i) { - JSONCPP_STRING const& key = keys[i]; - if (valid_keys.find(key) == valid_keys.end()) { - inv[key] = settings_[key]; - } + +bool CharReaderBuilder::validate(Json::Value* invalid) const { + static const auto& valid_keys = *new std::set{ + "collectComments", + "allowComments", + "allowTrailingCommas", + "strictRoot", + "allowDroppedNullPlaceholders", + "allowNumericKeys", + "allowSingleQuotes", + "stackLimit", + "failIfExtra", + "rejectDupKeys", + "allowSpecialFloats", + "skipBom", + }; + for (auto si = settings_.begin(); si != settings_.end(); ++si) { + auto key = si.name(); + if (valid_keys.count(key)) + continue; + if (invalid) + (*invalid)[key] = *si; + else + return false; } - return 0u == inv.size(); + return invalid ? invalid->empty() : true; } -Value& CharReaderBuilder::operator[](JSONCPP_STRING key) -{ + +Value& CharReaderBuilder::operator[](const String& key) { return settings_[key]; } // static -void CharReaderBuilder::strictMode(Json::Value* settings) -{ -//! [CharReaderBuilderStrictMode] +void CharReaderBuilder::strictMode(Json::Value* settings) { + //! [CharReaderBuilderStrictMode] (*settings)["allowComments"] = false; + (*settings)["allowTrailingCommas"] = false; (*settings)["strictRoot"] = true; (*settings)["allowDroppedNullPlaceholders"] = false; (*settings)["allowNumericKeys"] = false; @@ -2238,14 +2178,15 @@ void CharReaderBuilder::strictMode(Json::Value* settings) (*settings)["failIfExtra"] = true; (*settings)["rejectDupKeys"] = true; (*settings)["allowSpecialFloats"] = false; -//! [CharReaderBuilderStrictMode] + (*settings)["skipBom"] = true; + //! [CharReaderBuilderStrictMode] } // static -void CharReaderBuilder::setDefaults(Json::Value* settings) -{ -//! [CharReaderBuilderDefaults] +void CharReaderBuilder::setDefaults(Json::Value* settings) { + //! [CharReaderBuilderDefaults] (*settings)["collectComments"] = true; (*settings)["allowComments"] = true; + (*settings)["allowTrailingCommas"] = true; (*settings)["strictRoot"] = false; (*settings)["allowDroppedNullPlaceholders"] = false; (*settings)["allowNumericKeys"] = false; @@ -2254,19 +2195,18 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) (*settings)["failIfExtra"] = false; (*settings)["rejectDupKeys"] = false; (*settings)["allowSpecialFloats"] = false; -//! [CharReaderBuilderDefaults] + (*settings)["skipBom"] = true; + //! [CharReaderBuilderDefaults] } ////////////////////////////////// // global functions -bool parseFromStream( - CharReader::Factory const& fact, JSONCPP_ISTREAM& sin, - Value* root, JSONCPP_STRING* errs) -{ - JSONCPP_OSTRINGSTREAM ssin; +bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root, + String* errs) { + OStringStream ssin; ssin << sin.rdbuf(); - JSONCPP_STRING doc = ssin.str(); + String doc = ssin.str(); char const* begin = doc.data(); char const* end = begin + doc.size(); // Note that we do not actually need a null-terminator. @@ -2274,9 +2214,9 @@ bool parseFromStream( return reader->parse(begin, end, root, errs); } -JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) { +IStream& operator>>(IStream& sin, Value& root) { CharReaderBuilder b; - JSONCPP_STRING errs; + String errs; bool ok = parseFromStream(b, sin, &root, &errs); if (!ok) { throwRuntimeError(errs); @@ -2316,31 +2256,21 @@ namespace Json { // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// -ValueIteratorBase::ValueIteratorBase() - : current_(), isNull_(true) { -} +ValueIteratorBase::ValueIteratorBase() : current_() {} ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator& current) : current_(current), isNull_(false) {} -Value& ValueIteratorBase::deref() const { - return current_->second; -} +Value& ValueIteratorBase::deref() { return current_->second; } +const Value& ValueIteratorBase::deref() const { return current_->second; } -void ValueIteratorBase::increment() { - ++current_; -} +void ValueIteratorBase::increment() { ++current_; } -void ValueIteratorBase::decrement() { - --current_; -} +void ValueIteratorBase::decrement() { --current_; } ValueIteratorBase::difference_type ValueIteratorBase::computeDistance(const SelfType& other) const { -#ifdef JSON_USE_CPPTL_SMALLMAP - return other.current_ - current_; -#else // Iterator for null value are initialized using the default // constructor, which initialize current_ to the default // std::map::iterator. As begin() and end() are two instance @@ -2361,7 +2291,6 @@ ValueIteratorBase::computeDistance(const SelfType& other) const { ++myDistance; } return myDistance; -#endif } bool ValueIteratorBase::isEqual(const SelfType& other) const { @@ -2393,12 +2322,13 @@ UInt ValueIteratorBase::index() const { return Value::UInt(-1); } -JSONCPP_STRING ValueIteratorBase::name() const { +String ValueIteratorBase::name() const { char const* keey; char const* end; keey = memberName(&end); - if (!keey) return JSONCPP_STRING(); - return JSONCPP_STRING(keey, end); + if (!keey) + return String(); + return String(keey, end); } char const* ValueIteratorBase::memberName() const { @@ -2409,8 +2339,8 @@ char const* ValueIteratorBase::memberName() const { char const* ValueIteratorBase::memberName(char const** end) const { const char* cname = (*current_).first.data(); if (!cname) { - *end = NULL; - return NULL; + *end = nullptr; + return nullptr; } *end = cname + (*current_).first.length(); return cname; @@ -2424,7 +2354,7 @@ char const* ValueIteratorBase::memberName(char const** end) const { // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// -ValueConstIterator::ValueConstIterator() {} +ValueConstIterator::ValueConstIterator() = default; ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator& current) @@ -2447,7 +2377,7 @@ operator=(const ValueIteratorBase& other) { // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// -ValueIterator::ValueIterator() {} +ValueIterator::ValueIterator() = default; ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) : ValueIteratorBase(current) {} @@ -2457,8 +2387,7 @@ ValueIterator::ValueIterator(const ValueConstIterator& other) throwRuntimeError("ConstIterator to Iterator should never be allowed."); } -ValueIterator::ValueIterator(const ValueIterator& other) - : ValueIteratorBase(other) {} +ValueIterator::ValueIterator(const ValueIterator& other) = default; ValueIterator& ValueIterator::operator=(const SelfType& other) { copy(other); @@ -2490,20 +2419,54 @@ ValueIterator& ValueIterator::operator=(const SelfType& other) { #include #include #endif // if !defined(JSON_IS_AMALGAMATION) -#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include -#ifdef JSON_USE_CPPTL -#include + +// Provide implementation equivalent of std::snprintf for older _MSC compilers +#if defined(_MSC_VER) && _MSC_VER < 1900 +#include +static int msvc_pre1900_c99_vsnprintf(char* outBuf, size_t size, + const char* format, va_list ap) { + int count = -1; + if (size != 0) + count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); + if (count == -1) + count = _vscprintf(format, ap); + return count; +} + +int JSON_API msvc_pre1900_c99_snprintf(char* outBuf, size_t size, + const char* format, ...) { + va_list ap; + va_start(ap, format); + const int count = msvc_pre1900_c99_vsnprintf(outBuf, size, format, ap); + va_end(ap); + return count; +} +#endif + +// Disable warning C4702 : unreachable code +#if defined(_MSC_VER) +#pragma warning(disable : 4702) #endif -#include // size_t -#include // min() #define JSON_ASSERT_UNREACHABLE assert(false) namespace Json { +template +static std::unique_ptr cloneUnique(const std::unique_ptr& p) { + std::unique_ptr r; + if (p) { + r = std::unique_ptr(new T(*p)); + } + return r; +} // This is a walkaround to avoid the static initialization of Value::null. // kNull must be word-aligned to avoid crashing on ARM. We use an alignment of @@ -2513,52 +2476,34 @@ namespace Json { #else #define ALIGNAS(byte_alignment) #endif -//static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; -//const unsigned char& kNullRef = kNull[0]; -//const Value& Value::null = reinterpret_cast(kNullRef); -//const Value& Value::nullRef = null; // static -Value const& Value::nullSingleton() -{ - static Value const nullStatic; - return nullStatic; +Value const& Value::nullSingleton() { + static Value const nullStatic; + return nullStatic; } -// for backwards compatibility, we'll leave these global references around, but DO NOT -// use them in JSONCPP library code any more! +#if JSON_USE_NULLREF +// for backwards compatibility, we'll leave these global references around, but +// DO NOT use them in JSONCPP library code any more! +// static Value const& Value::null = Value::nullSingleton(); + +// static Value const& Value::nullRef = Value::nullSingleton(); - -const Int Value::minInt = Int(~(UInt(-1) / 2)); -const Int Value::maxInt = Int(UInt(-1) / 2); -const UInt Value::maxUInt = UInt(-1); -#if defined(JSON_HAS_INT64) -const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2)); -const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2); -const UInt64 Value::maxUInt64 = UInt64(-1); -// The constant is hard-coded because some compiler have trouble -// converting Value::maxUInt64 to a double correctly (AIX/xlC). -// Assumes that UInt64 is a 64 bits integer. -static const double maxUInt64AsDouble = 18446744073709551615.0; -#endif // defined(JSON_HAS_INT64) -const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2)); -const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2); -const LargestUInt Value::maxLargestUInt = LargestUInt(-1); - -const UInt Value::defaultRealPrecision = 17; +#endif #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) template static inline bool InRange(double d, T min, U max) { // The casts can lose precision, but we are looking only for // an approximate range. Might fail on edge cases though. ~cdunn - //return d >= static_cast(min) && d <= static_cast(max); - return d >= min && d <= max; + return d >= static_cast(min) && d <= static_cast(max); } #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) static inline double integerToDouble(Json::UInt64 value) { - return static_cast(Int64(value / 2)) * 2.0 + static_cast(Int64(value & 1)); + return static_cast(Int64(value / 2)) * 2.0 + + static_cast(Int64(value & 1)); } template static inline double integerToDouble(T value) { @@ -2578,19 +2523,16 @@ static inline bool InRange(double d, T min, U max) { * computed using strlen(value). * @return Pointer on the duplicate instance of string. */ -static inline char* duplicateStringValue(const char* value, - size_t length) -{ +static inline char* duplicateStringValue(const char* value, size_t length) { // Avoid an integer overflow in the call to malloc below by limiting length // to a sane value. if (length >= static_cast(Value::maxInt)) length = Value::maxInt - 1; - char* newString = static_cast(malloc(length + 1)); - if (newString == NULL) { - throwRuntimeError( - "in Json::Value::duplicateStringValue(): " - "Failed to allocate string value buffer"); + auto newString = static_cast(malloc(length + 1)); + if (newString == nullptr) { + throwRuntimeError("in Json::Value::duplicateStringValue(): " + "Failed to allocate string value buffer"); } memcpy(newString, value, length); newString[length] = 0; @@ -2599,31 +2541,28 @@ static inline char* duplicateStringValue(const char* value, /* Record the length as a prefix. */ -static inline char* duplicateAndPrefixStringValue( - const char* value, - unsigned int length) -{ +static inline char* duplicateAndPrefixStringValue(const char* value, + unsigned int length) { // Avoid an integer overflow in the call to malloc below by limiting length // to a sane value. - JSON_ASSERT_MESSAGE(length <= static_cast(Value::maxInt) - sizeof(unsigned) - 1U, + JSON_ASSERT_MESSAGE(length <= static_cast(Value::maxInt) - + sizeof(unsigned) - 1U, "in Json::Value::duplicateAndPrefixStringValue(): " "length too big for prefixing"); - unsigned actualLength = length + static_cast(sizeof(unsigned)) + 1U; - char* newString = static_cast(malloc(actualLength)); - if (newString == 0) { - throwRuntimeError( - "in Json::Value::duplicateAndPrefixStringValue(): " - "Failed to allocate string value buffer"); + size_t actualLength = sizeof(length) + length + 1; + auto newString = static_cast(malloc(actualLength)); + if (newString == nullptr) { + throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): " + "Failed to allocate string value buffer"); } *reinterpret_cast(newString) = length; memcpy(newString + sizeof(unsigned), value, length); - newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later + newString[actualLength - 1U] = + 0; // to avoid buffer over-run accidents by users later return newString; } -inline static void decodePrefixedString( - bool isPrefixed, char const* prefixed, - unsigned* length, char const** value) -{ +inline static void decodePrefixedString(bool isPrefixed, char const* prefixed, + unsigned* length, char const** value) { if (!isPrefixed) { *length = static_cast(strlen(prefixed)); *value = prefixed; @@ -2632,7 +2571,8 @@ inline static void decodePrefixedString( *value = prefixed + sizeof(unsigned); } } -/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue(). +/** Free the string duplicated by + * duplicateStringValue()/duplicateAndPrefixStringValue(). */ #if JSONCPP_USING_SECURE_MEMORY static inline void releasePrefixedStringValue(char* value) { @@ -2645,17 +2585,13 @@ static inline void releasePrefixedStringValue(char* value) { } static inline void releaseStringValue(char* value, unsigned length) { // length==0 => we allocated the strings memory - size_t size = (length==0) ? strlen(value) : length; + size_t size = (length == 0) ? strlen(value) : length; memset(value, 0, size); free(value); } -#else // !JSONCPP_USING_SECURE_MEMORY -static inline void releasePrefixedStringValue(char* value) { - free(value); -} -static inline void releaseStringValue(char* value, unsigned) { - free(value); -} +#else // !JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { free(value); } +static inline void releaseStringValue(char* value, unsigned) { free(value); } #endif // JSONCPP_USING_SECURE_MEMORY } // namespace Json @@ -2674,58 +2610,28 @@ static inline void releaseStringValue(char* value, unsigned) { namespace Json { -Exception::Exception(JSONCPP_STRING const& msg) - : msg_(msg) -{} -Exception::~Exception() JSONCPP_NOEXCEPT -{} -char const* Exception::what() const JSONCPP_NOEXCEPT -{ - return msg_.c_str(); -} -RuntimeError::RuntimeError(JSONCPP_STRING const& msg) - : Exception(msg) -{} -LogicError::LogicError(JSONCPP_STRING const& msg) - : Exception(msg) -{} -JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg) -{ +#if JSON_USE_EXCEPTION +Exception::Exception(String msg) : msg_(std::move(msg)) {} +Exception::~Exception() noexcept = default; +char const* Exception::what() const noexcept { return msg_.c_str(); } +RuntimeError::RuntimeError(String const& msg) : Exception(msg) {} +LogicError::LogicError(String const& msg) : Exception(msg) {} +JSONCPP_NORETURN void throwRuntimeError(String const& msg) { throw RuntimeError(msg); } -JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) -{ +JSONCPP_NORETURN void throwLogicError(String const& msg) { throw LogicError(msg); } - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::CommentInfo -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -Value::CommentInfo::CommentInfo() : comment_(0) -{} - -Value::CommentInfo::~CommentInfo() { - if (comment_) - releaseStringValue(comment_, 0u); +#else // !JSON_USE_EXCEPTION +JSONCPP_NORETURN void throwRuntimeError(String const& msg) { + std::cerr << msg << std::endl; + abort(); } - -void Value::CommentInfo::setComment(const char* text, size_t len) { - if (comment_) { - releaseStringValue(comment_, 0u); - comment_ = 0; - } - JSON_ASSERT(text != 0); - JSON_ASSERT_MESSAGE( - text[0] == '\0' || text[0] == '/', - "in Json::Value::setComment(): Comments must start with /"); - // It seems that /**/ style comments are acceptable as well. - comment_ = duplicateStringValue(text, len); +JSONCPP_NORETURN void throwLogicError(String const& msg) { + std::cerr << msg << std::endl; + abort(); } +#endif // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// @@ -2738,36 +2644,44 @@ void Value::CommentInfo::setComment(const char* text, size_t len) { // Notes: policy_ indicates if the string was allocated when // a string is stored. -Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {} +Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {} -Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate) +Value::CZString::CZString(char const* str, unsigned length, + DuplicationPolicy allocate) : cstr_(str) { // allocate != duplicate storage_.policy_ = allocate & 0x3; - storage_.length_ = ulength & 0x3FFFFFFF; + storage_.length_ = length & 0x3FFFFFFF; } Value::CZString::CZString(const CZString& other) { - cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != 0 - ? duplicateStringValue(other.cstr_, other.storage_.length_) - : other.cstr_); - storage_.policy_ = static_cast(other.cstr_ - ? (static_cast(other.storage_.policy_) == noDuplication - ? noDuplication : duplicate) - : static_cast(other.storage_.policy_)) & 3U; + cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr + ? duplicateStringValue(other.cstr_, other.storage_.length_) + : other.cstr_); + storage_.policy_ = + static_cast( + other.cstr_ + ? (static_cast(other.storage_.policy_) == + noDuplication + ? noDuplication + : duplicate) + : static_cast(other.storage_.policy_)) & + 3U; storage_.length_ = other.storage_.length_; } -#if JSON_HAS_RVALUE_REFERENCES -Value::CZString::CZString(CZString&& other) - : cstr_(other.cstr_), index_(other.index_) { +Value::CZString::CZString(CZString&& other) noexcept + : cstr_(other.cstr_), index_(other.index_) { other.cstr_ = nullptr; } -#endif Value::CZString::~CZString() { if (cstr_ && storage_.policy_ == duplicate) { - releaseStringValue(const_cast(cstr_), storage_.length_ + 1u); //+1 for null terminating character for sake of completeness but not actually necessary + releaseStringValue(const_cast(cstr_), + storage_.length_ + 1U); // +1 for null terminating + // character for sake of + // completeness but not actually + // necessary } } @@ -2782,36 +2696,39 @@ Value::CZString& Value::CZString::operator=(const CZString& other) { return *this; } -#if JSON_HAS_RVALUE_REFERENCES -Value::CZString& Value::CZString::operator=(CZString&& other) { +Value::CZString& Value::CZString::operator=(CZString&& other) noexcept { cstr_ = other.cstr_; index_ = other.index_; other.cstr_ = nullptr; return *this; } -#endif bool Value::CZString::operator<(const CZString& other) const { - if (!cstr_) return index_ < other.index_; - //return strcmp(cstr_, other.cstr_) < 0; + if (!cstr_) + return index_ < other.index_; + // return strcmp(cstr_, other.cstr_) < 0; // Assume both are strings. unsigned this_len = this->storage_.length_; unsigned other_len = other.storage_.length_; unsigned min_len = std::min(this_len, other_len); JSON_ASSERT(this->cstr_ && other.cstr_); int comp = memcmp(this->cstr_, other.cstr_, min_len); - if (comp < 0) return true; - if (comp > 0) return false; + if (comp < 0) + return true; + if (comp > 0) + return false; return (this_len < other_len); } bool Value::CZString::operator==(const CZString& other) const { - if (!cstr_) return index_ == other.index_; - //return strcmp(cstr_, other.cstr_) == 0; + if (!cstr_) + return index_ == other.index_; + // return strcmp(cstr_, other.cstr_) == 0; // Assume both are strings. unsigned this_len = this->storage_.length_; unsigned other_len = other.storage_.length_; - if (this_len != other_len) return false; + if (this_len != other_len) + return false; JSON_ASSERT(this->cstr_ && other.cstr_); int comp = memcmp(this->cstr_, other.cstr_, this_len); return comp == 0; @@ -2819,10 +2736,12 @@ bool Value::CZString::operator==(const CZString& other) const { ArrayIndex Value::CZString::index() const { return index_; } -//const char* Value::CZString::c_str() const { return cstr_; } +// const char* Value::CZString::c_str() const { return cstr_; } const char* Value::CZString::data() const { return cstr_; } unsigned Value::CZString::length() const { return storage_.length_; } -bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; } +bool Value::CZString::isStaticString() const { + return storage_.policy_ == noDuplication; +} // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// @@ -2836,10 +2755,10 @@ bool Value::CZString::isStaticString() const { return storage_.policy_ == noDupl * memset( this, 0, sizeof(Value) ) * This optimization is used in ValueInternalMap fast allocator. */ -Value::Value(ValueType vtype) { +Value::Value(ValueType type) { static char const emptyString[] = ""; - initBasic(vtype); - switch (vtype) { + initBasic(type); + switch (type) { case nullValue: break; case intValue: @@ -2892,20 +2811,22 @@ Value::Value(double value) { Value::Value(const char* value) { initBasic(stringValue, true); - JSON_ASSERT_MESSAGE(value != NULL, "Null Value Passed to Value Constructor"); - value_.string_ = duplicateAndPrefixStringValue(value, static_cast(strlen(value))); + JSON_ASSERT_MESSAGE(value != nullptr, + "Null Value Passed to Value Constructor"); + value_.string_ = duplicateAndPrefixStringValue( + value, static_cast(strlen(value))); } -Value::Value(const char* beginValue, const char* endValue) { +Value::Value(const char* begin, const char* end) { initBasic(stringValue, true); value_.string_ = - duplicateAndPrefixStringValue(beginValue, static_cast(endValue - beginValue)); + duplicateAndPrefixStringValue(begin, static_cast(end - begin)); } -Value::Value(const JSONCPP_STRING& value) { +Value::Value(const String& value) { initBasic(stringValue, true); - value_.string_ = - duplicateAndPrefixStringValue(value.data(), static_cast(value.length())); + value_.string_ = duplicateAndPrefixStringValue( + value.data(), static_cast(value.length())); } Value::Value(const StaticString& value) { @@ -2913,13 +2834,6 @@ Value::Value(const StaticString& value) { value_.string_ = const_cast(value.c_str()); } -#ifdef JSON_USE_CPPTL -Value::Value(const CppTL::ConstString& value) { - initBasic(stringValue, true); - value_.string_ = duplicateAndPrefixStringValue(value, static_cast(value.length())); -} -#endif - Value::Value(bool value) { initBasic(booleanValue); value_.bool_ = value; @@ -2930,35 +2844,29 @@ Value::Value(const Value& other) { dupMeta(other); } -#if JSON_HAS_RVALUE_REFERENCES -// Move constructor -Value::Value(Value&& other) { +Value::Value(Value&& other) noexcept { initBasic(nullValue); swap(other); } -#endif Value::~Value() { releasePayload(); - - delete[] comments_; - value_.uint_ = 0; } -Value& Value::operator=(Value other) { - swap(other); +Value& Value::operator=(const Value& other) { + Value(other).swap(*this); + return *this; +} + +Value& Value::operator=(Value&& other) noexcept { + other.swap(*this); return *this; } void Value::swapPayload(Value& other) { - ValueType temp = type_; - type_ = other.type_; - other.type_ = temp; + std::swap(bits_, other.bits_); std::swap(value_, other.value_); - int temp2 = allocated_; - allocated_ = other.allocated_; - other.allocated_ = temp2 & 0x1; } void Value::copyPayload(const Value& other) { @@ -2975,11 +2883,12 @@ void Value::swap(Value& other) { void Value::copy(const Value& other) { copyPayload(other); - delete[] comments_; dupMeta(other); } -ValueType Value::type() const { return type_; } +ValueType Value::type() const { + return static_cast(bits_.value_type_); +} int Value::compare(const Value& other) const { if (*this < other) @@ -2990,10 +2899,10 @@ int Value::compare(const Value& other) const { } bool Value::operator<(const Value& other) const { - int typeDelta = type_ - other.type_; + int typeDelta = type() - other.type(); if (typeDelta) - return typeDelta < 0 ? true : false; - switch (type_) { + return typeDelta < 0; + switch (type()) { case nullValue: return false; case intValue: @@ -3004,30 +2913,33 @@ bool Value::operator<(const Value& other) const { return value_.real_ < other.value_.real_; case booleanValue: return value_.bool_ < other.value_.bool_; - case stringValue: - { - if ((value_.string_ == 0) || (other.value_.string_ == 0)) { - if (other.value_.string_) return true; - else return false; + case stringValue: { + if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) { + return other.value_.string_ != nullptr; } unsigned this_len; unsigned other_len; char const* this_str; char const* other_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); + decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, + &this_str); + decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len, + &other_str); unsigned min_len = std::min(this_len, other_len); JSON_ASSERT(this_str && other_str); int comp = memcmp(this_str, other_str, min_len); - if (comp < 0) return true; - if (comp > 0) return false; + if (comp < 0) + return true; + if (comp > 0) + return false; return (this_len < other_len); } case arrayValue: case objectValue: { - int delta = int(value_.map_->size() - other.value_.map_->size()); - if (delta) - return delta < 0; + auto thisSize = value_.map_->size(); + auto otherSize = other.value_.map_->size(); + if (thisSize != otherSize) + return thisSize < otherSize; return (*value_.map_) < (*other.value_.map_); } default: @@ -3043,14 +2955,9 @@ bool Value::operator>=(const Value& other) const { return !(*this < other); } bool Value::operator>(const Value& other) const { return other < *this; } bool Value::operator==(const Value& other) const { - // if ( type_ != other.type_ ) - // GCC 2.95.3 says: - // attempt to take address of bit-field structure member `Json::Value::type_' - // Beats me, but a temp solves the problem. - int temp = other.type_; - if (type_ != temp) + if (type() != other.type()) return false; - switch (type_) { + switch (type()) { case nullValue: return true; case intValue: @@ -3061,18 +2968,20 @@ bool Value::operator==(const Value& other) const { return value_.real_ == other.value_.real_; case booleanValue: return value_.bool_ == other.value_.bool_; - case stringValue: - { - if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + case stringValue: { + if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) { return (value_.string_ == other.value_.string_); } unsigned this_len; unsigned other_len; char const* this_str; char const* other_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); - if (this_len != other_len) return false; + decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, + &this_str); + decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len, + &other_str); + if (this_len != other_len) + return false; JSON_ASSERT(this_str && other_str); int comp = memcmp(this_str, other_str, this_len); return comp == 0; @@ -3090,47 +2999,55 @@ bool Value::operator==(const Value& other) const { bool Value::operator!=(const Value& other) const { return !(*this == other); } const char* Value::asCString() const { - JSON_ASSERT_MESSAGE(type_ == stringValue, + JSON_ASSERT_MESSAGE(type() == stringValue, "in Json::Value::asCString(): requires stringValue"); - if (value_.string_ == 0) return 0; + if (value_.string_ == nullptr) + return nullptr; unsigned this_len; char const* this_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, + &this_str); return this_str; } #if JSONCPP_USING_SECURE_MEMORY unsigned Value::getCStringLength() const { - JSON_ASSERT_MESSAGE(type_ == stringValue, - "in Json::Value::asCString(): requires stringValue"); - if (value_.string_ == 0) return 0; + JSON_ASSERT_MESSAGE(type() == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) + return 0; unsigned this_len; char const* this_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, + &this_str); return this_len; } #endif -bool Value::getString(char const** str, char const** cend) const { - if (type_ != stringValue) return false; - if (value_.string_ == 0) return false; +bool Value::getString(char const** begin, char const** end) const { + if (type() != stringValue) + return false; + if (value_.string_ == nullptr) + return false; unsigned length; - decodePrefixedString(this->allocated_, this->value_.string_, &length, str); - *cend = *str + length; + decodePrefixedString(this->isAllocated(), this->value_.string_, &length, + begin); + *end = *begin + length; return true; } -JSONCPP_STRING Value::asString() const { - switch (type_) { +String Value::asString() const { + switch (type()) { case nullValue: return ""; - case stringValue: - { - if (value_.string_ == 0) return ""; + case stringValue: { + if (value_.string_ == nullptr) + return ""; unsigned this_len; char const* this_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - return JSONCPP_STRING(this_str, this_len); + decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, + &this_str); + return String(this_str, this_len); } case booleanValue: return value_.bool_ ? "true" : "false"; @@ -3145,18 +3062,8 @@ JSONCPP_STRING Value::asString() const { } } -#ifdef JSON_USE_CPPTL -CppTL::ConstString Value::asConstString() const { - unsigned len; - char const* str; - decodePrefixedString(allocated_, value_.string_, - &len, &str); - return CppTL::ConstString(str, len); -} -#endif - Value::Int Value::asInt() const { - switch (type_) { + switch (type()) { case intValue: JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); return Int(value_.int_); @@ -3178,7 +3085,7 @@ Value::Int Value::asInt() const { } Value::UInt Value::asUInt() const { - switch (type_) { + switch (type()) { case intValue: JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); return UInt(value_.int_); @@ -3202,7 +3109,7 @@ Value::UInt Value::asUInt() const { #if defined(JSON_HAS_INT64) Value::Int64 Value::asInt64() const { - switch (type_) { + switch (type()) { case intValue: return Int64(value_.int_); case uintValue: @@ -3223,7 +3130,7 @@ Value::Int64 Value::asInt64() const { } Value::UInt64 Value::asUInt64() const { - switch (type_) { + switch (type()) { case intValue: JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); return UInt64(value_.int_); @@ -3261,7 +3168,7 @@ LargestUInt Value::asLargestUInt() const { } double Value::asDouble() const { - switch (type_) { + switch (type()) { case intValue: return static_cast(value_.int_); case uintValue: @@ -3283,7 +3190,7 @@ double Value::asDouble() const { } float Value::asFloat() const { - switch (type_) { + switch (type()) { case intValue: return static_cast(value_.int_); case uintValue: @@ -3298,7 +3205,7 @@ float Value::asFloat() const { case nullValue: return 0.0; case booleanValue: - return value_.bool_ ? 1.0f : 0.0f; + return value_.bool_ ? 1.0F : 0.0F; default: break; } @@ -3306,18 +3213,20 @@ float Value::asFloat() const { } bool Value::asBool() const { - switch (type_) { + switch (type()) { case booleanValue: return value_.bool_; case nullValue: return false; case intValue: - return value_.int_ ? true : false; + return value_.int_ != 0; case uintValue: - return value_.uint_ ? true : false; - case realValue: - // This is kind of strange. Not recommended. - return (value_.real_ != 0.0) ? true : false; + return value_.uint_ != 0; + case realValue: { + // According to JavaScript language zero or NaN is regarded as false + const auto value_classification = std::fpclassify(value_.real_); + return value_classification != FP_ZERO && value_classification != FP_NAN; + } default: break; } @@ -3328,30 +3237,30 @@ bool Value::isConvertibleTo(ValueType other) const { switch (other) { case nullValue: return (isNumeric() && asDouble() == 0.0) || - (type_ == booleanValue && value_.bool_ == false) || - (type_ == stringValue && asString().empty()) || - (type_ == arrayValue && value_.map_->size() == 0) || - (type_ == objectValue && value_.map_->size() == 0) || - type_ == nullValue; + (type() == booleanValue && !value_.bool_) || + (type() == stringValue && asString().empty()) || + (type() == arrayValue && value_.map_->empty()) || + (type() == objectValue && value_.map_->empty()) || + type() == nullValue; case intValue: return isInt() || - (type_ == realValue && InRange(value_.real_, minInt, maxInt)) || - type_ == booleanValue || type_ == nullValue; + (type() == realValue && InRange(value_.real_, minInt, maxInt)) || + type() == booleanValue || type() == nullValue; case uintValue: return isUInt() || - (type_ == realValue && InRange(value_.real_, 0, maxUInt)) || - type_ == booleanValue || type_ == nullValue; + (type() == realValue && InRange(value_.real_, 0, maxUInt)) || + type() == booleanValue || type() == nullValue; case realValue: - return isNumeric() || type_ == booleanValue || type_ == nullValue; + return isNumeric() || type() == booleanValue || type() == nullValue; case booleanValue: - return isNumeric() || type_ == booleanValue || type_ == nullValue; + return isNumeric() || type() == booleanValue || type() == nullValue; case stringValue: - return isNumeric() || type_ == booleanValue || type_ == stringValue || - type_ == nullValue; + return isNumeric() || type() == booleanValue || type() == stringValue || + type() == nullValue; case arrayValue: - return type_ == arrayValue || type_ == nullValue; + return type() == arrayValue || type() == nullValue; case objectValue: - return type_ == objectValue || type_ == nullValue; + return type() == objectValue || type() == nullValue; } JSON_ASSERT_UNREACHABLE; return false; @@ -3359,7 +3268,7 @@ bool Value::isConvertibleTo(ValueType other) const { /// Number of values in array or object ArrayIndex Value::size() const { - switch (type_) { + switch (type()) { case nullValue: case intValue: case uintValue: @@ -3383,20 +3292,19 @@ ArrayIndex Value::size() const { bool Value::empty() const { if (isNull() || isArray() || isObject()) - return size() == 0u; - else - return false; + return size() == 0U; + return false; } -Value::operator bool() const { return ! isNull(); } +Value::operator bool() const { return !isNull(); } void Value::clear() { - JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || - type_ == objectValue, + JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue || + type() == objectValue, "in Json::Value::clear(): requires complex value"); start_ = 0; limit_ = 0; - switch (type_) { + switch (type()) { case arrayValue: case objectValue: value_.map_->clear(); @@ -3407,9 +3315,9 @@ void Value::clear() { } void Value::resize(ArrayIndex newSize) { - JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue, + JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, "in Json::Value::resize(): requires arrayValue"); - if (type_ == nullValue) + if (type() == nullValue) *this = Value(arrayValue); ArrayIndex oldSize = size(); if (newSize == 0) @@ -3426,12 +3334,12 @@ void Value::resize(ArrayIndex newSize) { Value& Value::operator[](ArrayIndex index) { JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == arrayValue, + type() == nullValue || type() == arrayValue, "in Json::Value::operator[](ArrayIndex): requires arrayValue"); - if (type_ == nullValue) + if (type() == nullValue) *this = Value(arrayValue); CZString key(index); - ObjectValues::iterator it = value_.map_->lower_bound(key); + auto it = value_.map_->lower_bound(key); if (it != value_.map_->end() && (*it).first == key) return (*it).second; @@ -3449,9 +3357,9 @@ Value& Value::operator[](int index) { const Value& Value::operator[](ArrayIndex index) const { JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == arrayValue, + type() == nullValue || type() == arrayValue, "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); - if (type_ == nullValue) + if (type() == nullValue) return nullSingleton(); CZString key(index); ObjectValues::const_iterator it = value_.map_->find(key); @@ -3467,18 +3375,18 @@ const Value& Value::operator[](int index) const { return (*this)[ArrayIndex(index)]; } -void Value::initBasic(ValueType vtype, bool allocated) { - type_ = vtype; - allocated_ = allocated; - comments_ = 0; +void Value::initBasic(ValueType type, bool allocated) { + setType(type); + setIsAllocated(allocated); + comments_ = Comments{}; start_ = 0; limit_ = 0; } void Value::dupPayload(const Value& other) { - type_ = other.type_; - allocated_ = false; - switch (type_) { + setType(other.type()); + setIsAllocated(false); + switch (type()) { case nullValue: case intValue: case uintValue: @@ -3487,13 +3395,13 @@ void Value::dupPayload(const Value& other) { value_ = other.value_; break; case stringValue: - if (other.value_.string_ && other.allocated_) { + if (other.value_.string_ && other.isAllocated()) { unsigned len; char const* str; - decodePrefixedString(other.allocated_, other.value_.string_, - &len, &str); + decodePrefixedString(other.isAllocated(), other.value_.string_, &len, + &str); value_.string_ = duplicateAndPrefixStringValue(str, len); - allocated_ = true; + setIsAllocated(true); } else { value_.string_ = other.value_.string_; } @@ -3508,7 +3416,7 @@ void Value::dupPayload(const Value& other) { } void Value::releasePayload() { - switch (type_) { + switch (type()) { case nullValue: case intValue: case uintValue: @@ -3516,7 +3424,7 @@ void Value::releasePayload() { case booleanValue: break; case stringValue: - if (allocated_) + if (isAllocated()) releasePrefixedStringValue(value_.string_); break; case arrayValue: @@ -3529,17 +3437,7 @@ void Value::releasePayload() { } void Value::dupMeta(const Value& other) { - if (other.comments_) { - comments_ = new CommentInfo[numberOfCommentPlacement]; - for (int comment = 0; comment < numberOfCommentPlacement; ++comment) { - const CommentInfo& otherComment = other.comments_[comment]; - if (otherComment.comment_) - comments_[comment].setComment( - otherComment.comment_, strlen(otherComment.comment_)); - } - } else { - comments_ = 0; - } + comments_ = other.comments_; start_ = other.start_; limit_ = other.limit_; } @@ -3549,13 +3447,13 @@ void Value::dupMeta(const Value& other) { // @param key is null-terminated. Value& Value::resolveReference(const char* key) { JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == objectValue, + type() == nullValue || type() == objectValue, "in Json::Value::resolveReference(): requires objectValue"); - if (type_ == nullValue) + if (type() == nullValue) *this = Value(objectValue); - CZString actualKey( - key, static_cast(strlen(key)), CZString::noDuplication); // NOTE! - ObjectValues::iterator it = value_.map_->lower_bound(actualKey); + CZString actualKey(key, static_cast(strlen(key)), + CZString::noDuplication); // NOTE! + auto it = value_.map_->lower_bound(actualKey); if (it != value_.map_->end() && (*it).first == actualKey) return (*it).second; @@ -3566,16 +3464,15 @@ Value& Value::resolveReference(const char* key) { } // @param key is not null-terminated. -Value& Value::resolveReference(char const* key, char const* cend) -{ +Value& Value::resolveReference(char const* key, char const* end) { JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == objectValue, + type() == nullValue || type() == objectValue, "in Json::Value::resolveReference(key, end): requires objectValue"); - if (type_ == nullValue) + if (type() == nullValue) *this = Value(objectValue); - CZString actualKey( - key, static_cast(cend-key), CZString::duplicateOnCopy); - ObjectValues::iterator it = value_.map_->lower_bound(actualKey); + CZString actualKey(key, static_cast(end - key), + CZString::duplicateOnCopy); + auto it = value_.map_->lower_bound(actualKey); if (it != value_.map_->end() && (*it).first == actualKey) return (*it).second; @@ -3592,27 +3489,35 @@ Value Value::get(ArrayIndex index, const Value& defaultValue) const { bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } -Value const* Value::find(char const* key, char const* cend) const -{ - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == objectValue, - "in Json::Value::find(key, end, found): requires objectValue or nullValue"); - if (type_ == nullValue) return NULL; - CZString actualKey(key, static_cast(cend-key), CZString::noDuplication); +Value const* Value::find(char const* begin, char const* end) const { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, + "in Json::Value::find(begin, end): requires " + "objectValue or nullValue"); + if (type() == nullValue) + return nullptr; + CZString actualKey(begin, static_cast(end - begin), + CZString::noDuplication); ObjectValues::const_iterator it = value_.map_->find(actualKey); - if (it == value_.map_->end()) return NULL; + if (it == value_.map_->end()) + return nullptr; return &(*it).second; } -const Value& Value::operator[](const char* key) const -{ +Value* Value::demand(char const* begin, char const* end) { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, + "in Json::Value::demand(begin, end): requires " + "objectValue or nullValue"); + return &resolveReference(begin, end); +} +const Value& Value::operator[](const char* key) const { Value const* found = find(key, key + strlen(key)); - if (!found) return nullSingleton(); + if (!found) + return nullSingleton(); return *found; } -Value const& Value::operator[](JSONCPP_STRING const& key) const -{ +Value const& Value::operator[](const String& key) const { Value const* found = find(key.data(), key.data() + key.length()); - if (!found) return nullSingleton(); + if (!found) + return nullSingleton(); return *found; } @@ -3620,7 +3525,7 @@ Value& Value::operator[](const char* key) { return resolveReference(key, key + strlen(key)); } -Value& Value::operator[](const JSONCPP_STRING& key) { +Value& Value::operator[](const String& key) { return resolveReference(key.data(), key.data() + key.length()); } @@ -3628,183 +3533,140 @@ Value& Value::operator[](const StaticString& key) { return resolveReference(key.c_str()); } -#ifdef JSON_USE_CPPTL -Value& Value::operator[](const CppTL::ConstString& key) { - return resolveReference(key.c_str(), key.end_c_str()); +Value& Value::append(const Value& value) { return append(Value(value)); } + +Value& Value::append(Value&& value) { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, + "in Json::Value::append: requires arrayValue"); + if (type() == nullValue) { + *this = Value(arrayValue); + } + return this->value_.map_->emplace(size(), std::move(value)).first->second; } -Value const& Value::operator[](CppTL::ConstString const& key) const -{ - Value const* found = find(key.c_str(), key.end_c_str()); - if (!found) return nullSingleton(); - return *found; + +bool Value::insert(ArrayIndex index, const Value& newValue) { + return insert(index, Value(newValue)); } -#endif -Value& Value::append(const Value& value) { return (*this)[size()] = value; } +bool Value::insert(ArrayIndex index, Value&& newValue) { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, + "in Json::Value::insert: requires arrayValue"); + ArrayIndex length = size(); + if (index > length) { + return false; + } + for (ArrayIndex i = length; i > index; i--) { + (*this)[i] = std::move((*this)[i - 1]); + } + (*this)[index] = std::move(newValue); + return true; +} -#if JSON_HAS_RVALUE_REFERENCES - Value& Value::append(Value&& value) { return (*this)[size()] = std::move(value); } -#endif - -Value Value::get(char const* key, char const* cend, Value const& defaultValue) const -{ - Value const* found = find(key, cend); +Value Value::get(char const* begin, char const* end, + Value const& defaultValue) const { + Value const* found = find(begin, end); return !found ? defaultValue : *found; } -Value Value::get(char const* key, Value const& defaultValue) const -{ +Value Value::get(char const* key, Value const& defaultValue) const { return get(key, key + strlen(key), defaultValue); } -Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue) const -{ +Value Value::get(String const& key, Value const& defaultValue) const { return get(key.data(), key.data() + key.length(), defaultValue); } - -bool Value::removeMember(const char* key, const char* cend, Value* removed) -{ - if (type_ != objectValue) { +bool Value::removeMember(const char* begin, const char* end, Value* removed) { + if (type() != objectValue) { return false; } - CZString actualKey(key, static_cast(cend-key), CZString::noDuplication); - ObjectValues::iterator it = value_.map_->find(actualKey); + CZString actualKey(begin, static_cast(end - begin), + CZString::noDuplication); + auto it = value_.map_->find(actualKey); if (it == value_.map_->end()) return false; if (removed) -#if JSON_HAS_RVALUE_REFERENCES *removed = std::move(it->second); -#else - *removed = it->second; -#endif value_.map_->erase(it); return true; } -bool Value::removeMember(const char* key, Value* removed) -{ +bool Value::removeMember(const char* key, Value* removed) { return removeMember(key, key + strlen(key), removed); } -bool Value::removeMember(JSONCPP_STRING const& key, Value* removed) -{ +bool Value::removeMember(String const& key, Value* removed) { return removeMember(key.data(), key.data() + key.length(), removed); } -void Value::removeMember(const char* key) -{ - JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, +void Value::removeMember(const char* key) { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, "in Json::Value::removeMember(): requires objectValue"); - if (type_ == nullValue) + if (type() == nullValue) return; CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication); value_.map_->erase(actualKey); } -void Value::removeMember(const JSONCPP_STRING& key) -{ - removeMember(key.c_str()); -} +void Value::removeMember(const String& key) { removeMember(key.c_str()); } bool Value::removeIndex(ArrayIndex index, Value* removed) { - if (type_ != arrayValue) { + if (type() != arrayValue) { return false; } CZString key(index); - ObjectValues::iterator it = value_.map_->find(key); + auto it = value_.map_->find(key); if (it == value_.map_->end()) { return false; } - *removed = it->second; + if (removed) + *removed = it->second; ArrayIndex oldSize = size(); // shift left all items left, into the place of the "removed" - for (ArrayIndex i = index; i < (oldSize - 1); ++i){ + for (ArrayIndex i = index; i < (oldSize - 1); ++i) { CZString keey(i); (*value_.map_)[keey] = (*this)[i + 1]; } // erase the last one ("leftover") CZString keyLast(oldSize - 1); - ObjectValues::iterator itLast = value_.map_->find(keyLast); + auto itLast = value_.map_->find(keyLast); value_.map_->erase(itLast); return true; } -#ifdef JSON_USE_CPPTL -Value Value::get(const CppTL::ConstString& key, - const Value& defaultValue) const { - return get(key.c_str(), key.end_c_str(), defaultValue); +bool Value::isMember(char const* begin, char const* end) const { + Value const* value = find(begin, end); + return nullptr != value; } -#endif - -bool Value::isMember(char const* key, char const* cend) const -{ - Value const* value = find(key, cend); - return NULL != value; -} -bool Value::isMember(char const* key) const -{ +bool Value::isMember(char const* key) const { return isMember(key, key + strlen(key)); } -bool Value::isMember(JSONCPP_STRING const& key) const -{ +bool Value::isMember(String const& key) const { return isMember(key.data(), key.data() + key.length()); } -#ifdef JSON_USE_CPPTL -bool Value::isMember(const CppTL::ConstString& key) const { - return isMember(key.c_str(), key.end_c_str()); -} -#endif - Value::Members Value::getMemberNames() const { JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == objectValue, + type() == nullValue || type() == objectValue, "in Json::Value::getMemberNames(), value must be objectValue"); - if (type_ == nullValue) + if (type() == nullValue) return Value::Members(); Members members; members.reserve(value_.map_->size()); ObjectValues::const_iterator it = value_.map_->begin(); ObjectValues::const_iterator itEnd = value_.map_->end(); for (; it != itEnd; ++it) { - members.push_back(JSONCPP_STRING((*it).first.data(), - (*it).first.length())); + members.push_back(String((*it).first.data(), (*it).first.length())); } return members; } -// -//# ifdef JSON_USE_CPPTL -// EnumMemberNames -// Value::enumMemberNames() const -//{ -// if ( type_ == objectValue ) -// { -// return CppTL::Enum::any( CppTL::Enum::transform( -// CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), -// MemberNamesTransform() ) ); -// } -// return EnumMemberNames(); -//} -// -// -// EnumValues -// Value::enumValues() const -//{ -// if ( type_ == objectValue || type_ == arrayValue ) -// return CppTL::Enum::anyValues( *(value_.map_), -// CppTL::Type() ); -// return EnumValues(); -//} -// -//# endif static bool IsIntegral(double d) { double integral_part; return modf(d, &integral_part) == 0.0; } -bool Value::isNull() const { return type_ == nullValue; } +bool Value::isNull() const { return type() == nullValue; } -bool Value::isBool() const { return type_ == booleanValue; } +bool Value::isBool() const { return type() == booleanValue; } bool Value::isInt() const { - switch (type_) { + switch (type()) { case intValue: #if defined(JSON_HAS_INT64) return value_.int_ >= minInt && value_.int_ <= maxInt; @@ -3823,7 +3685,7 @@ bool Value::isInt() const { } bool Value::isUInt() const { - switch (type_) { + switch (type()) { case intValue: #if defined(JSON_HAS_INT64) return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); @@ -3847,7 +3709,7 @@ bool Value::isUInt() const { bool Value::isInt64() const { #if defined(JSON_HAS_INT64) - switch (type_) { + switch (type()) { case intValue: return true; case uintValue: @@ -3867,7 +3729,7 @@ bool Value::isInt64() const { bool Value::isUInt64() const { #if defined(JSON_HAS_INT64) - switch (type_) { + switch (type()) { case intValue: return value_.int_ >= 0; case uintValue: @@ -3886,61 +3748,93 @@ bool Value::isUInt64() const { } bool Value::isIntegral() const { - switch (type_) { - case intValue: - case uintValue: - return true; - case realValue: + switch (type()) { + case intValue: + case uintValue: + return true; + case realValue: #if defined(JSON_HAS_INT64) - // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a - // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we - // require the value to be strictly less than the limit. - return value_.real_ >= double(minInt64) && value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_); + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && + value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_); #else - return value_.real_ >= minInt && value_.real_ <= maxUInt && IsIntegral(value_.real_); + return value_.real_ >= minInt && value_.real_ <= maxUInt && + IsIntegral(value_.real_); #endif // JSON_HAS_INT64 - default: - break; + default: + break; } return false; } -bool Value::isDouble() const { return type_ == intValue || type_ == uintValue || type_ == realValue; } +bool Value::isDouble() const { + return type() == intValue || type() == uintValue || type() == realValue; +} bool Value::isNumeric() const { return isDouble(); } -bool Value::isString() const { return type_ == stringValue; } +bool Value::isString() const { return type() == stringValue; } -bool Value::isArray() const { return type_ == arrayValue; } +bool Value::isArray() const { return type() == arrayValue; } -bool Value::isObject() const { return type_ == objectValue; } +bool Value::isObject() const { return type() == objectValue; } -void Value::setComment(const char* comment, size_t len, CommentPlacement placement) { - if (!comments_) - comments_ = new CommentInfo[numberOfCommentPlacement]; - if ((len > 0) && (comment[len-1] == '\n')) { - // Always discard trailing newline, to aid indentation. - len -= 1; +Value::Comments::Comments(const Comments& that) + : ptr_{cloneUnique(that.ptr_)} {} + +Value::Comments::Comments(Comments&& that) noexcept + : ptr_{std::move(that.ptr_)} {} + +Value::Comments& Value::Comments::operator=(const Comments& that) { + ptr_ = cloneUnique(that.ptr_); + return *this; +} + +Value::Comments& Value::Comments::operator=(Comments&& that) noexcept { + ptr_ = std::move(that.ptr_); + return *this; +} + +bool Value::Comments::has(CommentPlacement slot) const { + return ptr_ && !(*ptr_)[slot].empty(); +} + +String Value::Comments::get(CommentPlacement slot) const { + if (!ptr_) + return {}; + return (*ptr_)[slot]; +} + +void Value::Comments::set(CommentPlacement slot, String comment) { + if (!ptr_) { + ptr_ = std::unique_ptr(new Array()); + } + // check comments array boundry. + if (slot < CommentPlacement::numberOfCommentPlacement) { + (*ptr_)[slot] = std::move(comment); } - comments_[placement].setComment(comment, len); } -void Value::setComment(const char* comment, CommentPlacement placement) { - setComment(comment, strlen(comment), placement); -} - -void Value::setComment(const JSONCPP_STRING& comment, CommentPlacement placement) { - setComment(comment.c_str(), comment.length(), placement); +void Value::setComment(String comment, CommentPlacement placement) { + if (!comment.empty() && (comment.back() == '\n')) { + // Always discard trailing newline, to aid indentation. + comment.pop_back(); + } + JSON_ASSERT(!comment.empty()); + JSON_ASSERT_MESSAGE( + comment[0] == '\0' || comment[0] == '/', + "in Json::Value::setComment(): Comments must start with /"); + comments_.set(placement, std::move(comment)); } bool Value::hasComment(CommentPlacement placement) const { - return comments_ != 0 && comments_[placement].comment_ != 0; + return comments_.has(placement); } -JSONCPP_STRING Value::getComment(CommentPlacement placement) const { - if (hasComment(placement)) - return comments_[placement].comment_; - return ""; +String Value::getComment(CommentPlacement placement) const { + return comments_.get(placement); } void Value::setOffsetStart(ptrdiff_t start) { start_ = start; } @@ -3951,18 +3845,18 @@ ptrdiff_t Value::getOffsetStart() const { return start_; } ptrdiff_t Value::getOffsetLimit() const { return limit_; } -JSONCPP_STRING Value::toStyledString() const { +String Value::toStyledString() const { StreamWriterBuilder builder; - JSONCPP_STRING out = this->hasComment(commentBefore) ? "\n" : ""; + String out = this->hasComment(commentBefore) ? "\n" : ""; out += Json::writeString(builder, *this); - out += "\n"; + out += '\n'; return out; } Value::const_iterator Value::begin() const { - switch (type_) { + switch (type()) { case arrayValue: case objectValue: if (value_.map_) @@ -3971,11 +3865,11 @@ Value::const_iterator Value::begin() const { default: break; } - return const_iterator(); + return {}; } Value::const_iterator Value::end() const { - switch (type_) { + switch (type()) { case arrayValue: case objectValue: if (value_.map_) @@ -3984,11 +3878,11 @@ Value::const_iterator Value::end() const { default: break; } - return const_iterator(); + return {}; } Value::iterator Value::begin() { - switch (type_) { + switch (type()) { case arrayValue: case objectValue: if (value_.map_) @@ -4001,7 +3895,7 @@ Value::iterator Value::begin() { } Value::iterator Value::end() { - switch (type_) { + switch (type()) { case arrayValue: case objectValue: if (value_.map_) @@ -4016,25 +3910,20 @@ Value::iterator Value::end() { // class PathArgument // ////////////////////////////////////////////////////////////////// -PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {} +PathArgument::PathArgument() = default; PathArgument::PathArgument(ArrayIndex index) - : key_(), index_(index), kind_(kindIndex) {} + : index_(index), kind_(kindIndex) {} -PathArgument::PathArgument(const char* key) - : key_(key), index_(), kind_(kindKey) {} +PathArgument::PathArgument(const char* key) : key_(key), kind_(kindKey) {} -PathArgument::PathArgument(const JSONCPP_STRING& key) - : key_(key.c_str()), index_(), kind_(kindKey) {} +PathArgument::PathArgument(String key) : key_(std::move(key)), kind_(kindKey) {} // class Path // ////////////////////////////////////////////////////////////////// -Path::Path(const JSONCPP_STRING& path, - const PathArgument& a1, - const PathArgument& a2, - const PathArgument& a3, - const PathArgument& a4, +Path::Path(const String& path, const PathArgument& a1, const PathArgument& a2, + const PathArgument& a3, const PathArgument& a4, const PathArgument& a5) { InArgs in; in.reserve(5); @@ -4046,10 +3935,10 @@ Path::Path(const JSONCPP_STRING& path, makePath(path, in); } -void Path::makePath(const JSONCPP_STRING& path, const InArgs& in) { +void Path::makePath(const String& path, const InArgs& in) { const char* current = path.c_str(); const char* end = current + path.length(); - InArgs::const_iterator itInArg = in.begin(); + auto itInArg = in.begin(); while (current != end) { if (*current == '[') { ++current; @@ -4072,13 +3961,12 @@ void Path::makePath(const JSONCPP_STRING& path, const InArgs& in) { const char* beginName = current; while (current != end && !strchr("[.", *current)) ++current; - args_.push_back(JSONCPP_STRING(beginName, current)); + args_.push_back(String(beginName, current)); } } } -void Path::addPathInArg(const JSONCPP_STRING& /*path*/, - const InArgs& in, +void Path::addPathInArg(const String& /*path*/, const InArgs& in, InArgs::const_iterator& itInArg, PathArgument::Kind kind) { if (itInArg == in.end()) { @@ -4090,30 +3978,29 @@ void Path::addPathInArg(const JSONCPP_STRING& /*path*/, } } -void Path::invalidPath(const JSONCPP_STRING& /*path*/, int /*location*/) { +void Path::invalidPath(const String& /*path*/, int /*location*/) { // Error: invalid path. } const Value& Path::resolve(const Value& root) const { const Value* node = &root; - for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { - const PathArgument& arg = *it; + for (const auto& arg : args_) { if (arg.kind_ == PathArgument::kindIndex) { if (!node->isArray() || !node->isValidIndex(arg.index_)) { - // Error: unable to resolve path (array value expected at position... - return Value::null; + // Error: unable to resolve path (array value expected at position... ) + return Value::nullSingleton(); } node = &((*node)[arg.index_]); } else if (arg.kind_ == PathArgument::kindKey) { if (!node->isObject()) { // Error: unable to resolve path (object value expected at position...) - return Value::null; + return Value::nullSingleton(); } node = &((*node)[arg.key_]); if (node == &Value::nullSingleton()) { // Error: unable to resolve path (object has no member named '' at // position...) - return Value::null; + return Value::nullSingleton(); } } } @@ -4122,8 +4009,7 @@ const Value& Path::resolve(const Value& root) const { Value Path::resolve(const Value& root, const Value& defaultValue) const { const Value* node = &root; - for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { - const PathArgument& arg = *it; + for (const auto& arg : args_) { if (arg.kind_ == PathArgument::kindIndex) { if (!node->isArray() || !node->isValidIndex(arg.index_)) return defaultValue; @@ -4141,8 +4027,7 @@ Value Path::resolve(const Value& root, const Value& defaultValue) const { Value& Path::make(Value& root) const { Value* node = &root; - for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { - const PathArgument& arg = *it; + for (const auto& arg : args_) { if (arg.kind_ == PathArgument::kindIndex) { if (!node->isArray()) { // Error: node is not an array at position ... @@ -4179,71 +4064,81 @@ Value& Path::make(Value& root) const { // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE #if !defined(JSON_IS_AMALGAMATION) -#include #include "json_tool.h" +#include #endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include #include #include +#include #include #include -#include -#include -#include + +#if __cplusplus >= 201103L +#include #include -#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0 +#if !defined(isnan) +#define isnan std::isnan +#endif + +#if !defined(isfinite) +#define isfinite std::isfinite +#endif + +#else +#include +#include + +#if defined(_MSC_VER) +#if !defined(isnan) +#include +#define isnan _isnan +#endif + +#if !defined(isfinite) #include #define isfinite _finite -#elif defined(__sun) && defined(__SVR4) //Solaris +#endif + +#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) +#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 +#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES + +#endif //_MSC_VER + +#if defined(__sun) && defined(__SVR4) // Solaris #if !defined(isfinite) #include #define isfinite finite #endif -#elif defined(_AIX) -#if !defined(isfinite) -#include -#define isfinite finite #endif -#elif defined(__hpux) + +#if defined(__hpux) #if !defined(isfinite) #if defined(__ia64) && !defined(finite) -#define isfinite(x) ((sizeof(x) == sizeof(float) ? \ - _Isfinitef(x) : _IsFinite(x))) -#else -#include +#define isfinite(x) \ + ((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x))) +#endif +#endif +#endif + +#if !defined(isnan) +// IEEE standard states that NaN values will not compare to themselves +#define isnan(x) (x != x) +#endif + +#if !defined(__APPLE__) +#if !defined(isfinite) #define isfinite finite #endif #endif -#else -#include -#if !(defined(__QNXNTO__)) // QNX already defines isfinite -#define isfinite std::isfinite -#endif #endif #if defined(_MSC_VER) -#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above -#define snprintf sprintf_s -#elif _MSC_VER >= 1900 // VC++ 14.0 and above -#define snprintf std::snprintf -#else -#define snprintf _snprintf -#endif -#elif defined(__ANDROID__) || defined(__QNXNTO__) -#define snprintf snprintf -#elif __cplusplus >= 201103L -#if !defined(__MINGW32__) && !defined(__CYGWIN__) -#define snprintf std::snprintf -#endif -#endif - -#if defined(__BORLANDC__) -#include -#define isfinite _finite -#define snprintf _snprintf -#endif - -#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 // Disable warning about strdup being deprecated. #pragma warning(disable : 4996) #endif @@ -4251,12 +4146,12 @@ Value& Path::make(Value& root) const { namespace Json { #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) -typedef std::unique_ptr StreamWriterPtr; +using StreamWriterPtr = std::unique_ptr; #else -typedef std::auto_ptr StreamWriterPtr; +using StreamWriterPtr = std::auto_ptr; #endif -JSONCPP_STRING valueToString(LargestInt value) { +String valueToString(LargestInt value) { UIntToStringBuffer buffer; char* current = buffer + sizeof(buffer); if (value == Value::minLargestInt) { @@ -4272,7 +4167,7 @@ JSONCPP_STRING valueToString(LargestInt value) { return current; } -JSONCPP_STRING valueToString(LargestUInt value) { +String valueToString(LargestUInt value) { UIntToStringBuffer buffer; char* current = buffer + sizeof(buffer); uintToString(value, current); @@ -4282,77 +4177,70 @@ JSONCPP_STRING valueToString(LargestUInt value) { #if defined(JSON_HAS_INT64) -JSONCPP_STRING valueToString(Int value) { - return valueToString(LargestInt(value)); -} +String valueToString(Int value) { return valueToString(LargestInt(value)); } -JSONCPP_STRING valueToString(UInt value) { - return valueToString(LargestUInt(value)); -} +String valueToString(UInt value) { return valueToString(LargestUInt(value)); } #endif // # if defined(JSON_HAS_INT64) namespace { -JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision, PrecisionType precisionType) { - // Allocate a buffer that is more than large enough to store the 16 digits of - // precision requested below. - char buffer[36]; - int len = -1; - - char formatString[15]; - if (precisionType == PrecisionType::significantDigits) { - snprintf(formatString, sizeof(formatString), "%%.%ug", precision); - } else { - snprintf(formatString, sizeof(formatString), "%%.%uf", precision); - } - +String valueToString(double value, bool useSpecialFloats, + unsigned int precision, PrecisionType precisionType) { // Print into the buffer. We need not request the alternative representation // that always has a decimal point because JSON doesn't distinguish the // concepts of reals and integers. - if (isfinite(value)) { - len = snprintf(buffer, sizeof(buffer), formatString, value); - fixNumericLocale(buffer, buffer + len); - // to delete use-less too much zeros in the end of string - if (precisionType == PrecisionType::decimalPlaces) { - fixZerosInTheEnd(buffer, buffer + len); - } - - // try to ensure we preserve the fact that this was given to us as a double on input - if (!strchr(buffer, '.') && !strchr(buffer, 'e')) { - strcat(buffer, ".0"); - } - - } else { - // IEEE standard states that NaN values will not compare to themselves - if (value != value) { - len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null"); - } else if (value < 0) { - len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999"); - } else { - len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999"); - } + if (!isfinite(value)) { + static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"}, + {"null", "-1e+9999", "1e+9999"}}; + return reps[useSpecialFloats ? 0 : 1] + [isnan(value) ? 0 : (value < 0) ? 1 : 2]; + } + + String buffer(size_t(36), '\0'); + while (true) { + int len = jsoncpp_snprintf( + &*buffer.begin(), buffer.size(), + (precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f", + precision, value); + assert(len >= 0); + auto wouldPrint = static_cast(len); + if (wouldPrint >= buffer.size()) { + buffer.resize(wouldPrint + 1); + continue; + } + buffer.resize(wouldPrint); + break; + } + + buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end()); + + // strip the zero padding from the right + if (precisionType == PrecisionType::decimalPlaces) { + buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end()); + } + + // try to ensure we preserve the fact that this was given to us as a double on + // input + if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) { + buffer += ".0"; } - assert(len >= 0); return buffer; } -} +} // namespace -JSONCPP_STRING valueToString(double value, unsigned int precision, PrecisionType precisionType) { +String valueToString(double value, unsigned int precision, + PrecisionType precisionType) { return valueToString(value, false, precision, precisionType); } -JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; } +String valueToString(bool value) { return value ? "true" : "false"; } -static bool isAnyCharRequiredQuoting(char const* s, size_t n) { +static bool doesAnyCharRequireEscaping(char const* s, size_t n) { assert(s || !n); - char const* const end = s + n; - for (char const* cur = s; cur < end; ++cur) { - if (*cur == '\\' || *cur == '\"' || *cur < ' ' - || static_cast(*cur) < 0x80) - return true; - } - return false; + return std::any_of(s, s + n, [](unsigned char c) { + return c == '\\' || c == '"' || c < 0x20 || c > 0x7F; + }); } static unsigned int utf8ToCodepoint(const char*& s, const char* e) { @@ -4367,8 +4255,8 @@ static unsigned int utf8ToCodepoint(const char*& s, const char* e) { if (e - s < 2) return REPLACEMENT_CHARACTER; - unsigned int calculated = ((firstByte & 0x1F) << 6) - | (static_cast(s[1]) & 0x3F); + unsigned int calculated = + ((firstByte & 0x1F) << 6) | (static_cast(s[1]) & 0x3F); s += 1; // oversized encoded characters are invalid return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated; @@ -4378,9 +4266,9 @@ static unsigned int utf8ToCodepoint(const char*& s, const char* e) { if (e - s < 3) return REPLACEMENT_CHARACTER; - unsigned int calculated = ((firstByte & 0x0F) << 12) - | ((static_cast(s[1]) & 0x3F) << 6) - | (static_cast(s[2]) & 0x3F); + unsigned int calculated = ((firstByte & 0x0F) << 12) | + ((static_cast(s[1]) & 0x3F) << 6) | + (static_cast(s[2]) & 0x3F); s += 2; // surrogates aren't valid codepoints itself // shouldn't be UTF-8 encoded @@ -4394,10 +4282,10 @@ static unsigned int utf8ToCodepoint(const char*& s, const char* e) { if (e - s < 4) return REPLACEMENT_CHARACTER; - unsigned int calculated = ((firstByte & 0x07) << 18) - | ((static_cast(s[1]) & 0x3F) << 12) - | ((static_cast(s[2]) & 0x3F) << 6) - | (static_cast(s[3]) & 0x3F); + unsigned int calculated = ((firstByte & 0x07) << 18) | + ((static_cast(s[1]) & 0x3F) << 12) | + ((static_cast(s[2]) & 0x3F) << 6) | + (static_cast(s[3]) & 0x3F); s += 3; // oversized encoded characters are invalid return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated; @@ -4406,28 +4294,27 @@ static unsigned int utf8ToCodepoint(const char*& s, const char* e) { return REPLACEMENT_CHARACTER; } -static const char hex2[] = - "000102030405060708090a0b0c0d0e0f" - "101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f" - "303132333435363738393a3b3c3d3e3f" - "404142434445464748494a4b4c4d4e4f" - "505152535455565758595a5b5c5d5e5f" - "606162636465666768696a6b6c6d6e6f" - "707172737475767778797a7b7c7d7e7f" - "808182838485868788898a8b8c8d8e8f" - "909192939495969798999a9b9c9d9e9f" - "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" - "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" - "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" - "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" - "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" - "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; +static const char hex2[] = "000102030405060708090a0b0c0d0e0f" + "101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f" + "303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f" + "505152535455565758595a5b5c5d5e5f" + "606162636465666768696a6b6c6d6e6f" + "707172737475767778797a7b7c7d7e7f" + "808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f" + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; -static JSONCPP_STRING toHex16Bit(unsigned int x) { +static String toHex16Bit(unsigned int x) { const unsigned int hi = (x >> 8) & 0xff; const unsigned int lo = x & 0xff; - JSONCPP_STRING result(4, ' '); + String result(4, ' '); result[0] = hex2[2 * hi]; result[1] = hex2[2 * hi + 1]; result[2] = hex2[2 * lo]; @@ -4435,18 +4322,26 @@ static JSONCPP_STRING toHex16Bit(unsigned int x) { return result; } -static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) { - if (value == NULL) +static void appendRaw(String& result, unsigned ch) { + result += static_cast(ch); +} + +static void appendHex(String& result, unsigned ch) { + result.append("\\u").append(toHex16Bit(ch)); +} + +static String valueToQuotedStringN(const char* value, unsigned length, + bool emitUTF8 = false) { + if (value == nullptr) return ""; - if (!isAnyCharRequiredQuoting(value, length)) - return JSONCPP_STRING("\"") + value + "\""; + if (!doesAnyCharRequireEscaping(value, length)) + return String("\"") + value + "\""; // We have to walk value and escape any special characters. - // Appending to JSONCPP_STRING is not efficient, but this should be rare. + // Appending to String is not efficient, but this should be rare. // (Note: forward slashes are *not* rare, but I am not escaping them.) - JSONCPP_STRING::size_type maxsize = - length * 2 + 3; // allescaped+quotes+NULL - JSONCPP_STRING result; + String::size_type maxsize = length * 2 + 3; // allescaped+quotes+NULL + String result; result.reserve(maxsize); // to avoid lots of mallocs result += "\""; char const* end = value + length; @@ -4482,45 +4377,50 @@ static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) { // Should add a flag to allow this compatibility mode and prevent this // sequence from occurring. default: { - unsigned int cp = utf8ToCodepoint(c, end); - // don't escape non-control characters - // (short escape sequence are applied above) - if (cp < 0x80 && cp >= 0x20) - result += static_cast(cp); - else if (cp < 0x10000) { // codepoint is in Basic Multilingual Plane - result += "\\u"; - result += toHex16Bit(cp); + if (emitUTF8) { + unsigned codepoint = static_cast(*c); + if (codepoint < 0x20) { + appendHex(result, codepoint); + } else { + appendRaw(result, codepoint); } - else { // codepoint is not in Basic Multilingual Plane - // convert to surrogate pair first - cp -= 0x10000; - result += "\\u"; - result += toHex16Bit((cp >> 10) + 0xD800); - result += "\\u"; - result += toHex16Bit((cp & 0x3FF) + 0xDC00); + } else { + unsigned codepoint = utf8ToCodepoint(c, end); // modifies `c` + if (codepoint < 0x20) { + appendHex(result, codepoint); + } else if (codepoint < 0x80) { + appendRaw(result, codepoint); + } else if (codepoint < 0x10000) { + // Basic Multilingual Plane + appendHex(result, codepoint); + } else { + // Extended Unicode. Encode 20 bits as a surrogate pair. + codepoint -= 0x10000; + appendHex(result, 0xd800 + ((codepoint >> 10) & 0x3ff)); + appendHex(result, 0xdc00 + (codepoint & 0x3ff)); } } - break; + } break; } } result += "\""; return result; } -JSONCPP_STRING valueToQuotedString(const char* value) { +String valueToQuotedString(const char* value) { return valueToQuotedStringN(value, static_cast(strlen(value))); } // Class Writer // ////////////////////////////////////////////////////////////////// -Writer::~Writer() {} +Writer::~Writer() = default; // Class FastWriter // ////////////////////////////////////////////////////////////////// FastWriter::FastWriter() - : yamlCompatibilityEnabled_(false), dropNullPlaceholders_(false), - omitEndingLineFeed_(false) {} + + = default; void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; } @@ -4528,11 +4428,11 @@ void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } -JSONCPP_STRING FastWriter::write(const Value& root) { +String FastWriter::write(const Value& root) { document_.clear(); writeValue(root); if (!omitEndingLineFeed_) - document_ += "\n"; + document_ += '\n'; return document_; } @@ -4551,13 +4451,13 @@ void FastWriter::writeValue(const Value& value) { case realValue: document_ += valueToString(value.asDouble()); break; - case stringValue: - { + case stringValue: { // Is NULL possible for value.string_? No. char const* str; char const* end; bool ok = value.getString(&str, &end); - if (ok) document_ += valueToQuotedStringN(str, static_cast(end-str)); + if (ok) + document_ += valueToQuotedStringN(str, static_cast(end - str)); break; } case booleanValue: @@ -4576,12 +4476,12 @@ void FastWriter::writeValue(const Value& value) { case objectValue: { Value::Members members(value.getMemberNames()); document_ += '{'; - for (Value::Members::iterator it = members.begin(); it != members.end(); - ++it) { - const JSONCPP_STRING& name = *it; + for (auto it = members.begin(); it != members.end(); ++it) { + const String& name = *it; if (it != members.begin()) document_ += ','; - document_ += valueToQuotedStringN(name.data(), static_cast(name.length())); + document_ += valueToQuotedStringN(name.data(), + static_cast(name.length())); document_ += yamlCompatibilityEnabled_ ? ": " : ":"; writeValue(value[name]); } @@ -4593,17 +4493,16 @@ void FastWriter::writeValue(const Value& value) { // Class StyledWriter // ////////////////////////////////////////////////////////////////// -StyledWriter::StyledWriter() - : rightMargin_(74), indentSize_(3), addChildValues_() {} +StyledWriter::StyledWriter() = default; -JSONCPP_STRING StyledWriter::write(const Value& root) { +String StyledWriter::write(const Value& root) { document_.clear(); addChildValues_ = false; indentString_.clear(); writeCommentBeforeValue(root); writeValue(root); writeCommentAfterValueOnSameLine(root); - document_ += "\n"; + document_ += '\n'; return document_; } @@ -4621,14 +4520,15 @@ void StyledWriter::writeValue(const Value& value) { case realValue: pushValue(valueToString(value.asDouble())); break; - case stringValue: - { + case stringValue: { // Is NULL possible for value.string_? No. char const* str; char const* end; bool ok = value.getString(&str, &end); - if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); - else pushValue(""); + if (ok) + pushValue(valueToQuotedStringN(str, static_cast(end - str))); + else + pushValue(""); break; } case booleanValue: @@ -4644,9 +4544,9 @@ void StyledWriter::writeValue(const Value& value) { else { writeWithIndent("{"); indent(); - Value::Members::iterator it = members.begin(); + auto it = members.begin(); for (;;) { - const JSONCPP_STRING& name = *it; + const String& name = *it; const Value& childValue = value[name]; writeCommentBeforeValue(childValue); writeWithIndent(valueToQuotedString(name.c_str())); @@ -4716,7 +4616,7 @@ bool StyledWriter::isMultilineArray(const Value& value) { for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { const Value& childValue = value[index]; isMultiLine = ((childValue.isArray() || childValue.isObject()) && - childValue.size() > 0); + !childValue.empty()); } if (!isMultiLine) // check if line length > max line length { @@ -4736,7 +4636,7 @@ bool StyledWriter::isMultilineArray(const Value& value) { return isMultiLine; } -void StyledWriter::pushValue(const JSONCPP_STRING& value) { +void StyledWriter::pushValue(const String& value) { if (addChildValues_) childValues_.push_back(value); else @@ -4754,12 +4654,12 @@ void StyledWriter::writeIndent() { document_ += indentString_; } -void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) { +void StyledWriter::writeWithIndent(const String& value) { writeIndent(); document_ += value; } -void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); } +void StyledWriter::indent() { indentString_ += String(indentSize_, ' '); } void StyledWriter::unindent() { assert(indentString_.size() >= indentSize_); @@ -4770,20 +4670,19 @@ void StyledWriter::writeCommentBeforeValue(const Value& root) { if (!root.hasComment(commentBefore)) return; - document_ += "\n"; + document_ += '\n'; writeIndent(); - const JSONCPP_STRING& comment = root.getComment(commentBefore); - JSONCPP_STRING::const_iterator iter = comment.begin(); + const String& comment = root.getComment(commentBefore); + String::const_iterator iter = comment.begin(); while (iter != comment.end()) { document_ += *iter; - if (*iter == '\n' && - ((iter+1) != comment.end() && *(iter + 1) == '/')) + if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) writeIndent(); ++iter; } // Comments are stripped of trailing newlines, so add one here - document_ += "\n"; + document_ += '\n'; } void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { @@ -4791,9 +4690,9 @@ void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { document_ += " " + root.getComment(commentAfterOnSameLine); if (root.hasComment(commentAfter)) { - document_ += "\n"; + document_ += '\n'; document_ += root.getComment(commentAfter); - document_ += "\n"; + document_ += '\n'; } } @@ -4806,23 +4705,23 @@ bool StyledWriter::hasCommentForValue(const Value& value) { // Class StyledStreamWriter // ////////////////////////////////////////////////////////////////// -StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation) - : document_(NULL), rightMargin_(74), indentation_(indentation), - addChildValues_(), indented_(false) -{} +StyledStreamWriter::StyledStreamWriter(String indentation) + : document_(nullptr), indentation_(std::move(indentation)), + addChildValues_(), indented_(false) {} -void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) { +void StyledStreamWriter::write(OStream& out, const Value& root) { document_ = &out; addChildValues_ = false; indentString_.clear(); indented_ = true; writeCommentBeforeValue(root); - if (!indented_) writeIndent(); + if (!indented_) + writeIndent(); indented_ = true; writeValue(root); writeCommentAfterValueOnSameLine(root); *document_ << "\n"; - document_ = NULL; // Forget the stream, for safety. + document_ = nullptr; // Forget the stream, for safety. } void StyledStreamWriter::writeValue(const Value& value) { @@ -4839,14 +4738,15 @@ void StyledStreamWriter::writeValue(const Value& value) { case realValue: pushValue(valueToString(value.asDouble())); break; - case stringValue: - { + case stringValue: { // Is NULL possible for value.string_? No. char const* str; char const* end; bool ok = value.getString(&str, &end); - if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); - else pushValue(""); + if (ok) + pushValue(valueToQuotedStringN(str, static_cast(end - str))); + else + pushValue(""); break; } case booleanValue: @@ -4862,9 +4762,9 @@ void StyledStreamWriter::writeValue(const Value& value) { else { writeWithIndent("{"); indent(); - Value::Members::iterator it = members.begin(); + auto it = members.begin(); for (;;) { - const JSONCPP_STRING& name = *it; + const String& name = *it; const Value& childValue = value[name]; writeCommentBeforeValue(childValue); writeWithIndent(valueToQuotedString(name.c_str())); @@ -4901,7 +4801,8 @@ void StyledStreamWriter::writeArrayValue(const Value& value) { if (hasChildValue) writeWithIndent(childValues_[index]); else { - if (!indented_) writeIndent(); + if (!indented_) + writeIndent(); indented_ = true; writeValue(childValue); indented_ = false; @@ -4936,7 +4837,7 @@ bool StyledStreamWriter::isMultilineArray(const Value& value) { for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { const Value& childValue = value[index]; isMultiLine = ((childValue.isArray() || childValue.isObject()) && - childValue.size() > 0); + !childValue.empty()); } if (!isMultiLine) // check if line length > max line length { @@ -4956,7 +4857,7 @@ bool StyledStreamWriter::isMultilineArray(const Value& value) { return isMultiLine; } -void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) { +void StyledStreamWriter::pushValue(const String& value) { if (addChildValues_) childValues_.push_back(value); else @@ -4971,8 +4872,9 @@ void StyledStreamWriter::writeIndent() { *document_ << '\n' << indentString_; } -void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) { - if (!indented_) writeIndent(); +void StyledStreamWriter::writeWithIndent(const String& value) { + if (!indented_) + writeIndent(); *document_ << value; indented_ = false; } @@ -4988,13 +4890,13 @@ void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { if (!root.hasComment(commentBefore)) return; - if (!indented_) writeIndent(); - const JSONCPP_STRING& comment = root.getComment(commentBefore); - JSONCPP_STRING::const_iterator iter = comment.begin(); + if (!indented_) + writeIndent(); + const String& comment = root.getComment(commentBefore); + String::const_iterator iter = comment.begin(); while (iter != comment.end()) { *document_ << *iter; - if (*iter == '\n' && - ((iter+1) != comment.end() && *(iter + 1) == '/')) + if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) // writeIndent(); // would include newline *document_ << indentString_; ++iter; @@ -5026,88 +4928,73 @@ bool StyledStreamWriter::hasCommentForValue(const Value& value) { struct CommentStyle { /// Decide whether to write comments. enum Enum { - None, ///< Drop all comments. - Most, ///< Recover odd behavior of previous versions (not implemented yet). - All ///< Keep all comments. + None, ///< Drop all comments. + Most, ///< Recover odd behavior of previous versions (not implemented yet). + All ///< Keep all comments. }; }; -struct BuiltStyledStreamWriter : public StreamWriter -{ - BuiltStyledStreamWriter( - JSONCPP_STRING const& indentation, - CommentStyle::Enum cs, - JSONCPP_STRING const& colonSymbol, - JSONCPP_STRING const& nullSymbol, - JSONCPP_STRING const& endingLineFeedSymbol, - bool useSpecialFloats, - unsigned int precision, - PrecisionType precisionType); - int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE; +struct BuiltStyledStreamWriter : public StreamWriter { + BuiltStyledStreamWriter(String indentation, CommentStyle::Enum cs, + String colonSymbol, String nullSymbol, + String endingLineFeedSymbol, bool useSpecialFloats, + bool emitUTF8, unsigned int precision, + PrecisionType precisionType); + int write(Value const& root, OStream* sout) override; + private: void writeValue(Value const& value); void writeArrayValue(Value const& value); bool isMultilineArray(Value const& value); - void pushValue(JSONCPP_STRING const& value); + void pushValue(String const& value); void writeIndent(); - void writeWithIndent(JSONCPP_STRING const& value); + void writeWithIndent(String const& value); void indent(); void unindent(); void writeCommentBeforeValue(Value const& root); void writeCommentAfterValueOnSameLine(Value const& root); static bool hasCommentForValue(const Value& value); - typedef std::vector ChildValues; + using ChildValues = std::vector; ChildValues childValues_; - JSONCPP_STRING indentString_; + String indentString_; unsigned int rightMargin_; - JSONCPP_STRING indentation_; + String indentation_; CommentStyle::Enum cs_; - JSONCPP_STRING colonSymbol_; - JSONCPP_STRING nullSymbol_; - JSONCPP_STRING endingLineFeedSymbol_; + String colonSymbol_; + String nullSymbol_; + String endingLineFeedSymbol_; bool addChildValues_ : 1; bool indented_ : 1; bool useSpecialFloats_ : 1; + bool emitUTF8_ : 1; unsigned int precision_; PrecisionType precisionType_; }; BuiltStyledStreamWriter::BuiltStyledStreamWriter( - JSONCPP_STRING const& indentation, - CommentStyle::Enum cs, - JSONCPP_STRING const& colonSymbol, - JSONCPP_STRING const& nullSymbol, - JSONCPP_STRING const& endingLineFeedSymbol, - bool useSpecialFloats, - unsigned int precision, - PrecisionType precisionType) - : rightMargin_(74) - , indentation_(indentation) - , cs_(cs) - , colonSymbol_(colonSymbol) - , nullSymbol_(nullSymbol) - , endingLineFeedSymbol_(endingLineFeedSymbol) - , addChildValues_(false) - , indented_(false) - , useSpecialFloats_(useSpecialFloats) - , precision_(precision) - , precisionType_(precisionType) -{ -} -int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout) -{ + String indentation, CommentStyle::Enum cs, String colonSymbol, + String nullSymbol, String endingLineFeedSymbol, bool useSpecialFloats, + bool emitUTF8, unsigned int precision, PrecisionType precisionType) + : rightMargin_(74), indentation_(std::move(indentation)), cs_(cs), + colonSymbol_(std::move(colonSymbol)), nullSymbol_(std::move(nullSymbol)), + endingLineFeedSymbol_(std::move(endingLineFeedSymbol)), + addChildValues_(false), indented_(false), + useSpecialFloats_(useSpecialFloats), emitUTF8_(emitUTF8), + precision_(precision), precisionType_(precisionType) {} +int BuiltStyledStreamWriter::write(Value const& root, OStream* sout) { sout_ = sout; addChildValues_ = false; indented_ = true; indentString_.clear(); writeCommentBeforeValue(root); - if (!indented_) writeIndent(); + if (!indented_) + writeIndent(); indented_ = true; writeValue(root); writeCommentAfterValueOnSameLine(root); *sout_ << endingLineFeedSymbol_; - sout_ = NULL; + sout_ = nullptr; return 0; } void BuiltStyledStreamWriter::writeValue(Value const& value) { @@ -5122,16 +5009,19 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) { pushValue(valueToString(value.asLargestUInt())); break; case realValue: - pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_, precisionType_)); + pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_, + precisionType_)); break; - case stringValue: - { + case stringValue: { // Is NULL is possible for value.string_? No. char const* str; char const* end; bool ok = value.getString(&str, &end); - if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); - else pushValue(""); + if (ok) + pushValue(valueToQuotedStringN(str, static_cast(end - str), + emitUTF8_)); + else + pushValue(""); break; } case booleanValue: @@ -5147,12 +5037,13 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) { else { writeWithIndent("{"); indent(); - Value::Members::iterator it = members.begin(); + auto it = members.begin(); for (;;) { - JSONCPP_STRING const& name = *it; + String const& name = *it; Value const& childValue = value[name]; writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedStringN(name.data(), static_cast(name.length()))); + writeWithIndent(valueToQuotedStringN( + name.data(), static_cast(name.length()), emitUTF8_)); *sout_ << colonSymbol_; writeValue(childValue); if (++it == members.end()) { @@ -5186,7 +5077,8 @@ void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { if (hasChildValue) writeWithIndent(childValues_[index]); else { - if (!indented_) writeIndent(); + if (!indented_) + writeIndent(); indented_ = true; writeValue(childValue); indented_ = false; @@ -5204,13 +5096,15 @@ void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { { assert(childValues_.size() == size); *sout_ << "["; - if (!indentation_.empty()) *sout_ << " "; + if (!indentation_.empty()) + *sout_ << " "; for (unsigned index = 0; index < size; ++index) { if (index > 0) *sout_ << ((!indentation_.empty()) ? ", " : ","); *sout_ << childValues_[index]; } - if (!indentation_.empty()) *sout_ << " "; + if (!indentation_.empty()) + *sout_ << " "; *sout_ << "]"; } } @@ -5223,7 +5117,7 @@ bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) { for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { Value const& childValue = value[index]; isMultiLine = ((childValue.isArray() || childValue.isObject()) && - childValue.size() > 0); + !childValue.empty()); } if (!isMultiLine) // check if line length > max line length { @@ -5243,7 +5137,7 @@ bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) { return isMultiLine; } -void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) { +void BuiltStyledStreamWriter::pushValue(String const& value) { if (addChildValues_) childValues_.push_back(value); else @@ -5262,8 +5156,9 @@ void BuiltStyledStreamWriter::writeIndent() { } } -void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) { - if (!indented_) writeIndent(); +void BuiltStyledStreamWriter::writeWithIndent(String const& value) { + if (!indented_) + writeIndent(); *sout_ << value; indented_ = false; } @@ -5276,17 +5171,18 @@ void BuiltStyledStreamWriter::unindent() { } void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { - if (cs_ == CommentStyle::None) return; + if (cs_ == CommentStyle::None) + return; if (!root.hasComment(commentBefore)) return; - if (!indented_) writeIndent(); - const JSONCPP_STRING& comment = root.getComment(commentBefore); - JSONCPP_STRING::const_iterator iter = comment.begin(); + if (!indented_) + writeIndent(); + const String& comment = root.getComment(commentBefore); + String::const_iterator iter = comment.begin(); while (iter != comment.end()) { *sout_ << *iter; - if (*iter == '\n' && - ((iter+1) != comment.end() && *(iter + 1) == '/')) + if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) // writeIndent(); // would write extra newline *sout_ << indentString_; ++iter; @@ -5294,8 +5190,10 @@ void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { indented_ = false; } -void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) { - if (cs_ == CommentStyle::None) return; +void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine( + Value const& root) { + if (cs_ == CommentStyle::None) + return; if (root.hasComment(commentAfterOnSameLine)) *sout_ << " " + root.getComment(commentAfterOnSameLine); @@ -5315,29 +5213,19 @@ bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { /////////////// // StreamWriter -StreamWriter::StreamWriter() - : sout_(NULL) -{ -} -StreamWriter::~StreamWriter() -{ -} -StreamWriter::Factory::~Factory() -{} -StreamWriterBuilder::StreamWriterBuilder() -{ - setDefaults(&settings_); -} -StreamWriterBuilder::~StreamWriterBuilder() -{} -StreamWriter* StreamWriterBuilder::newStreamWriter() const -{ - JSONCPP_STRING indentation = settings_["indentation"].asString(); - JSONCPP_STRING cs_str = settings_["commentStyle"].asString(); - JSONCPP_STRING pt_str = settings_["precisionType"].asString(); - bool eyc = settings_["enableYAMLCompatibility"].asBool(); - bool dnp = settings_["dropNullPlaceholders"].asBool(); - bool usf = settings_["useSpecialFloats"].asBool(); +StreamWriter::StreamWriter() : sout_(nullptr) {} +StreamWriter::~StreamWriter() = default; +StreamWriter::Factory::~Factory() = default; +StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); } +StreamWriterBuilder::~StreamWriterBuilder() = default; +StreamWriter* StreamWriterBuilder::newStreamWriter() const { + const String indentation = settings_["indentation"].asString(); + const String cs_str = settings_["commentStyle"].asString(); + const String pt_str = settings_["precisionType"].asString(); + const bool eyc = settings_["enableYAMLCompatibility"].asBool(); + const bool dnp = settings_["dropNullPlaceholders"].asBool(); + const bool usf = settings_["useSpecialFloats"].asBool(); + const bool emitUTF8 = settings_["emitUTF8"].asBool(); unsigned int pre = settings_["precision"].asUInt(); CommentStyle::Enum cs = CommentStyle::All; if (cs_str == "All") { @@ -5355,76 +5243,72 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const } else { throwRuntimeError("precisionType must be 'significant' or 'decimal'"); } - JSONCPP_STRING colonSymbol = " : "; + String colonSymbol = " : "; if (eyc) { colonSymbol = ": "; } else if (indentation.empty()) { colonSymbol = ":"; } - JSONCPP_STRING nullSymbol = "null"; + String nullSymbol = "null"; if (dnp) { nullSymbol.clear(); } - if (pre > 17) pre = 17; - JSONCPP_STRING endingLineFeedSymbol; - return new BuiltStyledStreamWriter( - indentation, cs, - colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre, precisionType); + if (pre > 17) + pre = 17; + String endingLineFeedSymbol; + return new BuiltStyledStreamWriter(indentation, cs, colonSymbol, nullSymbol, + endingLineFeedSymbol, usf, emitUTF8, pre, + precisionType); } -static void getValidWriterKeys(std::set* valid_keys) -{ - valid_keys->clear(); - valid_keys->insert("indentation"); - valid_keys->insert("commentStyle"); - valid_keys->insert("enableYAMLCompatibility"); - valid_keys->insert("dropNullPlaceholders"); - valid_keys->insert("useSpecialFloats"); - valid_keys->insert("precision"); - valid_keys->insert("precisionType"); -} -bool StreamWriterBuilder::validate(Json::Value* invalid) const -{ - Json::Value my_invalid; - if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL - Json::Value& inv = *invalid; - std::set valid_keys; - getValidWriterKeys(&valid_keys); - Value::Members keys = settings_.getMemberNames(); - size_t n = keys.size(); - for (size_t i = 0; i < n; ++i) { - JSONCPP_STRING const& key = keys[i]; - if (valid_keys.find(key) == valid_keys.end()) { - inv[key] = settings_[key]; - } + +bool StreamWriterBuilder::validate(Json::Value* invalid) const { + static const auto& valid_keys = *new std::set{ + "indentation", + "commentStyle", + "enableYAMLCompatibility", + "dropNullPlaceholders", + "useSpecialFloats", + "emitUTF8", + "precision", + "precisionType", + }; + for (auto si = settings_.begin(); si != settings_.end(); ++si) { + auto key = si.name(); + if (valid_keys.count(key)) + continue; + if (invalid) + (*invalid)[key] = *si; + else + return false; } - return 0u == inv.size(); + return invalid ? invalid->empty() : true; } -Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) -{ + +Value& StreamWriterBuilder::operator[](const String& key) { return settings_[key]; } // static -void StreamWriterBuilder::setDefaults(Json::Value* settings) -{ +void StreamWriterBuilder::setDefaults(Json::Value* settings) { //! [StreamWriterBuilderDefaults] (*settings)["commentStyle"] = "All"; (*settings)["indentation"] = "\t"; (*settings)["enableYAMLCompatibility"] = false; (*settings)["dropNullPlaceholders"] = false; (*settings)["useSpecialFloats"] = false; + (*settings)["emitUTF8"] = false; (*settings)["precision"] = 17; (*settings)["precisionType"] = "significant"; //! [StreamWriterBuilderDefaults] } -JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) { - JSONCPP_OSTRINGSTREAM sout; - StreamWriterPtr const writer(builder.newStreamWriter()); +String writeString(StreamWriter::Factory const& factory, Value const& root) { + OStringStream sout; + StreamWriterPtr const writer(factory.newStreamWriter()); writer->write(root, &sout); return sout.str(); } -JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) { +OStream& operator<<(OStream& sout, Value const& root) { StreamWriterBuilder builder; StreamWriterPtr const writer(builder.newStreamWriter()); writer->write(root, &sout); @@ -5441,4 +5325,3 @@ JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) { -#endif \ No newline at end of file diff --git a/engine/src/ext/json/jsoncpp.cpp1 b/engine/src/ext/json/jsoncpp.cpp1 deleted file mode 100644 index 54244fce..00000000 --- a/engine/src/ext/json/jsoncpp.cpp1 +++ /dev/null @@ -1,5139 +0,0 @@ -/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/). -/// It is intended to be used with #include "json/json.h" - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - -/* -The JsonCpp library's source code, including accompanying documentation, -tests and demonstration applications, are licensed under the following -conditions... - -The author (Baptiste Lepilleur) explicitly disclaims copyright in all -jurisdictions which recognize such a disclaimer. In such jurisdictions, -this software is released into the Public Domain. - -In jurisdictions which do not recognize Public Domain property (e.g. Germany as of -2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is -released under the terms of the MIT License (see below). - -In jurisdictions which recognize Public Domain property, the user of this -software may choose to accept it either as 1) Public Domain, 2) under the -conditions of the MIT License (see below), or 3) under the terms of dual -Public Domain/MIT License conditions described here, as they choose. - -The MIT License is about as close to Public Domain as a license can get, and is -described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - -The full text of the MIT License follows: - -======================================================================== -Copyright (c) 2007-2010 Baptiste Lepilleur - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, -modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -======================================================================== -(END LICENSE TEXT) - -The MIT license is compatible with both the GPL and commercial -software, affording one all of the rights of Public Domain with the -minor nuisance of being required to keep the above copyright notice -and license text in the source code. Note also that by accepting the -Public Domain "license" you can re-license your copy using whatever -license you like. - -*/ - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - -#include -#if defined(UF_USE_JSON) - - - -#include - -#ifndef JSON_IS_AMALGAMATION -#error "Compile with -I PATH_TO_JSON_DIRECTORY" -#endif - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_tool.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED -#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED - -/* This header provides common string manipulation support, such as UTF-8, - * portable conversion from/to string... - * - * It is an internal header that must not be exposed. - */ - -namespace Json { - -/// Converts a unicode code-point to UTF-8. -static inline std::string codePointToUTF8(unsigned int cp) { - std::string result; - - // based on description from http://en.wikipedia.org/wiki/UTF-8 - - if (cp <= 0x7f) { - result.resize(1); - result[0] = static_cast(cp); - } else if (cp <= 0x7FF) { - result.resize(2); - result[1] = static_cast(0x80 | (0x3f & cp)); - result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); - } else if (cp <= 0xFFFF) { - result.resize(3); - result[2] = static_cast(0x80 | (0x3f & cp)); - result[1] = 0x80 | static_cast((0x3f & (cp >> 6))); - result[0] = 0xE0 | static_cast((0xf & (cp >> 12))); - } else if (cp <= 0x10FFFF) { - result.resize(4); - result[3] = static_cast(0x80 | (0x3f & cp)); - result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); - result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); - result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); - } - - return result; -} - -/// Returns true if ch is a control character (in range [0,32[). -static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; } - -enum { - /// Constant that specify the size of the buffer that must be passed to - /// uintToString. - uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1 -}; - -// Defines a char buffer for use with uintToString(). -typedef char UIntToStringBuffer[uintToStringBufferSize]; - -/** Converts an unsigned integer to string. - * @param value Unsigned interger to convert to string - * @param current Input/Output string buffer. - * Must have at least uintToStringBufferSize chars free. - */ -static inline void uintToString(LargestUInt value, char*& current) { - *--current = 0; - do { - *--current = char(value % 10) + '0'; - value /= 10; - } while (value != 0); -} - -/** Change ',' to '.' everywhere in buffer. - * - * We had a sophisticated way, but it did not work in WinCE. - * @see https://github.com/open-source-parsers/jsoncpp/pull/9 - */ -static inline void fixNumericLocale(char* begin, char* end) { - while (begin < end) { - if (*begin == ',') { - *begin = '.'; - } - ++begin; - } -} - -} // namespace Json { - -#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_tool.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_reader.cpp -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2011 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include "json_tool.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below -#define snprintf _snprintf -#endif - -#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 -// Disable warning about strdup being deprecated. -#pragma warning(disable : 4996) -#endif - -static int const stackLimit_g = 1000; -static int stackDepth_g = 0; // see readValue() - -namespace Json { - -#if __cplusplus >= 201103L -typedef std::unique_ptr CharReaderPtr; -#else -typedef std::auto_ptr CharReaderPtr; -#endif - -// Implementation of class Features -// //////////////////////////////// - -Features::Features() - : allowComments_(true), strictRoot_(false), - allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} - -Features Features::all() { return Features(); } - -Features Features::strictMode() { - Features features; - features.allowComments_ = false; - features.strictRoot_ = true; - features.allowDroppedNullPlaceholders_ = false; - features.allowNumericKeys_ = false; - return features; -} - -// Implementation of class Reader -// //////////////////////////////// - -static bool containsNewLine(Reader::Location begin, Reader::Location end) { - for (; begin < end; ++begin) - if (*begin == '\n' || *begin == '\r') - return true; - return false; -} - -// Class Reader -// ////////////////////////////////////////////////////////////////// - -Reader::Reader() - : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), - lastValue_(), commentsBefore_(), features_(Features::all()), - collectComments_() {} - -Reader::Reader(const Features& features) - : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), - lastValue_(), commentsBefore_(), features_(features), collectComments_() { -} - -bool -Reader::parse(const std::string& document, Value& root, bool collectComments) { - document_ = document; - const char* begin = document_.c_str(); - const char* end = begin + document_.length(); - return parse(begin, end, root, collectComments); -} - -bool Reader::parse(std::istream& sin, Value& root, bool collectComments) { - // std::istream_iterator begin(sin); - // std::istream_iterator end; - // Those would allow streamed input from a file, if parse() were a - // template function. - - // Since std::string is reference-counted, this at least does not - // create an extra copy. - std::string doc; - std::getline(sin, doc, (char)EOF); - return parse(doc, root, collectComments); -} - -bool Reader::parse(const char* beginDoc, - const char* endDoc, - Value& root, - bool collectComments) { - if (!features_.allowComments_) { - collectComments = false; - } - - begin_ = beginDoc; - end_ = endDoc; - collectComments_ = collectComments; - current_ = begin_; - lastValueEnd_ = 0; - lastValue_ = 0; - commentsBefore_ = ""; - errors_.clear(); - while (!nodes_.empty()) - nodes_.pop(); - nodes_.push(&root); - - stackDepth_g = 0; // Yes, this is bad coding, but options are limited. - bool successful = readValue(); - Token token; - skipCommentTokens(token); - if (collectComments_ && !commentsBefore_.empty()) - root.setComment(commentsBefore_, commentAfter); - if (features_.strictRoot_) { - if (!root.isArray() && !root.isObject()) { - // Set error location to start of doc, ideally should be first token found - // in doc - token.type_ = tokenError; - token.start_ = beginDoc; - token.end_ = endDoc; - addError( - "A valid JSON document must be either an array or an object value.", - token); - return false; - } - } - return successful; -} - -bool Reader::readValue() { - // This is a non-reentrant way to support a stackLimit. Terrible! - // But this deprecated class has a security problem: Bad input can - // cause a seg-fault. This seems like a fair, binary-compatible way - // to prevent the problem. - if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue()."); - ++stackDepth_g; - - Token token; - skipCommentTokens(token); - bool successful = true; - - if (collectComments_ && !commentsBefore_.empty()) { - currentValue().setComment(commentsBefore_, commentBefore); - commentsBefore_ = ""; - } - - switch (token.type_) { - case tokenObjectBegin: - successful = readObject(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenArrayBegin: - successful = readArray(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenNumber: - successful = decodeNumber(token); - break; - case tokenString: - successful = decodeString(token); - break; - case tokenTrue: - { - Value v(true); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenFalse: - { - Value v(false); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenNull: - { - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenArraySeparator: - case tokenObjectEnd: - case tokenArrayEnd: - if (features_.allowDroppedNullPlaceholders_) { - // "Un-read" the current token and mark the current value as a null - // token. - current_--; - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(current_ - begin_ - 1); - currentValue().setOffsetLimit(current_ - begin_); - break; - } // Else, fall through... - default: - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return addError("Syntax error: value, object or array expected.", token); - } - - if (collectComments_) { - lastValueEnd_ = current_; - lastValue_ = ¤tValue(); - } - - --stackDepth_g; - return successful; -} - -void Reader::skipCommentTokens(Token& token) { - if (features_.allowComments_) { - do { - readToken(token); - } while (token.type_ == tokenComment); - } else { - readToken(token); - } -} - -bool Reader::readToken(Token& token) { - skipSpaces(); - token.start_ = current_; - Char c = getNextChar(); - bool ok = true; - switch (c) { - case '{': - token.type_ = tokenObjectBegin; - break; - case '}': - token.type_ = tokenObjectEnd; - break; - case '[': - token.type_ = tokenArrayBegin; - break; - case ']': - token.type_ = tokenArrayEnd; - break; - case '"': - token.type_ = tokenString; - ok = readString(); - break; - case '/': - token.type_ = tokenComment; - ok = readComment(); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - token.type_ = tokenNumber; - readNumber(); - break; - case 't': - token.type_ = tokenTrue; - ok = match("rue", 3); - break; - case 'f': - token.type_ = tokenFalse; - ok = match("alse", 4); - break; - case 'n': - token.type_ = tokenNull; - ok = match("ull", 3); - break; - case ',': - token.type_ = tokenArraySeparator; - break; - case ':': - token.type_ = tokenMemberSeparator; - break; - case 0: - token.type_ = tokenEndOfStream; - break; - default: - ok = false; - break; - } - if (!ok) - token.type_ = tokenError; - token.end_ = current_; - return true; -} - -void Reader::skipSpaces() { - while (current_ != end_) { - Char c = *current_; - if (c == ' ' || c == '\t' || c == '\r' || c == '\n') - ++current_; - else - break; - } -} - -bool Reader::match(Location pattern, int patternLength) { - if (end_ - current_ < patternLength) - return false; - int index = patternLength; - while (index--) - if (current_[index] != pattern[index]) - return false; - current_ += patternLength; - return true; -} - -bool Reader::readComment() { - Location commentBegin = current_ - 1; - Char c = getNextChar(); - bool successful = false; - if (c == '*') - successful = readCStyleComment(); - else if (c == '/') - successful = readCppStyleComment(); - if (!successful) - return false; - - if (collectComments_) { - CommentPlacement placement = commentBefore; - if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { - if (c != '*' || !containsNewLine(commentBegin, current_)) - placement = commentAfterOnSameLine; - } - - addComment(commentBegin, current_, placement); - } - return true; -} - -static std::string normalizeEOL(Reader::Location begin, Reader::Location end) { - std::string normalized; - normalized.reserve(end - begin); - Reader::Location current = begin; - while (current != end) { - char c = *current++; - if (c == '\r') { - if (current != end && *current == '\n') - // convert dos EOL - ++current; - // convert Mac EOL - normalized += '\n'; - } else { - normalized += c; - } - } - return normalized; -} - -void -Reader::addComment(Location begin, Location end, CommentPlacement placement) { - assert(collectComments_); - const std::string& normalized = normalizeEOL(begin, end); - if (placement == commentAfterOnSameLine) { - assert(lastValue_ != 0); - lastValue_->setComment(normalized, placement); - } else { - commentsBefore_ += normalized; - } -} - -bool Reader::readCStyleComment() { - while (current_ != end_) { - Char c = getNextChar(); - if (c == '*' && *current_ == '/') - break; - } - return getNextChar() == '/'; -} - -bool Reader::readCppStyleComment() { - while (current_ != end_) { - Char c = getNextChar(); - if (c == '\n') - break; - if (c == '\r') { - // Consume DOS EOL. It will be normalized in addComment. - if (current_ != end_ && *current_ == '\n') - getNextChar(); - // Break on Moc OS 9 EOL. - break; - } - } - return true; -} - -void Reader::readNumber() { - const char *p = current_; - char c = '0'; // stopgap for already consumed character - // integral part - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; - // fractional part - if (c == '.') { - c = (current_ = p) < end_ ? *p++ : 0; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; - } - // exponential part - if (c == 'e' || c == 'E') { - c = (current_ = p) < end_ ? *p++ : 0; - if (c == '+' || c == '-') - c = (current_ = p) < end_ ? *p++ : 0; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; - } -} - -bool Reader::readString() { - Char c = 0; - while (current_ != end_) { - c = getNextChar(); - if (c == '\\') - getNextChar(); - else if (c == '"') - break; - } - return c == '"'; -} - -bool Reader::readObject(Token& tokenStart) { - Token tokenName; - std::string name; - Value init(objectValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); - while (readToken(tokenName)) { - bool initialTokenOk = true; - while (tokenName.type_ == tokenComment && initialTokenOk) - initialTokenOk = readToken(tokenName); - if (!initialTokenOk) - break; - if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object - return true; - name = ""; - if (tokenName.type_ == tokenString) { - if (!decodeString(tokenName, name)) - return recoverFromError(tokenObjectEnd); - } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { - Value numberName; - if (!decodeNumber(tokenName, numberName)) - return recoverFromError(tokenObjectEnd); - name = numberName.asString(); - } else { - break; - } - - Token colon; - if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { - return addErrorAndRecover( - "Missing ':' after object member name", colon, tokenObjectEnd); - } - Value& value = currentValue()[name]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenObjectEnd); - - Token comma; - if (!readToken(comma) || - (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && - comma.type_ != tokenComment)) { - return addErrorAndRecover( - "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); - } - bool finalizeTokenOk = true; - while (comma.type_ == tokenComment && finalizeTokenOk) - finalizeTokenOk = readToken(comma); - if (comma.type_ == tokenObjectEnd) - return true; - } - return addErrorAndRecover( - "Missing '}' or object member name", tokenName, tokenObjectEnd); -} - -bool Reader::readArray(Token& tokenStart) { - Value init(arrayValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); - skipSpaces(); - if (*current_ == ']') // empty array - { - Token endArray; - readToken(endArray); - return true; - } - int index = 0; - for (;;) { - Value& value = currentValue()[index++]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenArrayEnd); - - Token token; - // Accept Comment after last item in the array. - ok = readToken(token); - while (token.type_ == tokenComment && ok) { - ok = readToken(token); - } - bool badTokenType = - (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); - if (!ok || badTokenType) { - return addErrorAndRecover( - "Missing ',' or ']' in array declaration", token, tokenArrayEnd); - } - if (token.type_ == tokenArrayEnd) - break; - } - return true; -} - -bool Reader::decodeNumber(Token& token) { - Value decoded; - if (!decodeNumber(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool Reader::decodeNumber(Token& token, Value& decoded) { - // Attempts to parse the number as an integer. If the number is - // larger than the maximum supported value of an integer then - // we decode the number as a double. - Location current = token.start_; - bool isNegative = *current == '-'; - if (isNegative) - ++current; - // TODO: Help the compiler do the div and mod at compile time or get rid of them. - Value::LargestUInt maxIntegerValue = - isNegative ? Value::LargestUInt(-Value::minLargestInt) - : Value::maxLargestUInt; - Value::LargestUInt threshold = maxIntegerValue / 10; - Value::LargestUInt value = 0; - while (current < token.end_) { - Char c = *current++; - if (c < '0' || c > '9') - return decodeDouble(token, decoded); - Value::UInt digit(c - '0'); - if (value >= threshold) { - // We've hit or exceeded the max value divided by 10 (rounded down). If - // a) we've only just touched the limit, b) this is the last digit, and - // c) it's small enough to fit in that rounding delta, we're okay. - // Otherwise treat this number as a double to avoid overflow. - if (value > threshold || current != token.end_ || - digit > maxIntegerValue % 10) { - return decodeDouble(token, decoded); - } - } - value = value * 10 + digit; - } - if (isNegative) - decoded = -Value::LargestInt(value); - else if (value <= Value::LargestUInt(Value::maxInt)) - decoded = Value::LargestInt(value); - else - decoded = value; - return true; -} - -bool Reader::decodeDouble(Token& token) { - Value decoded; - if (!decodeDouble(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool Reader::decodeDouble(Token& token, Value& decoded) { - double value = 0; - const int bufferSize = 32; - int count; - int length = int(token.end_ - token.start_); - - // Sanity check to avoid buffer overflow exploits. - if (length < 0) { - return addError("Unable to parse token length", token); - } - - // Avoid using a string constant for the format control string given to - // sscanf, as this can cause hard to debug crashes on OS X. See here for more - // info: - // - // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html - char format[] = "%lf"; - - if (length <= bufferSize) { - Char buffer[bufferSize + 1]; - memcpy(buffer, token.start_, length); - buffer[length] = 0; - count = sscanf(buffer, format, &value); - } else { - std::string buffer(token.start_, token.end_); - count = sscanf(buffer.c_str(), format, &value); - } - - if (count != 1) - return addError("'" + std::string(token.start_, token.end_) + - "' is not a number.", - token); - decoded = value; - return true; -} - -bool Reader::decodeString(Token& token) { - std::string decoded_string; - if (!decodeString(token, decoded_string)) - return false; - Value decoded(decoded_string); - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool Reader::decodeString(Token& token, std::string& decoded) { - decoded.reserve(token.end_ - token.start_ - 2); - Location current = token.start_ + 1; // skip '"' - Location end = token.end_ - 1; // do not include '"' - while (current != end) { - Char c = *current++; - if (c == '"') - break; - else if (c == '\\') { - if (current == end) - return addError("Empty escape sequence in string", token, current); - Char escape = *current++; - switch (escape) { - case '"': - decoded += '"'; - break; - case '/': - decoded += '/'; - break; - case '\\': - decoded += '\\'; - break; - case 'b': - decoded += '\b'; - break; - case 'f': - decoded += '\f'; - break; - case 'n': - decoded += '\n'; - break; - case 'r': - decoded += '\r'; - break; - case 't': - decoded += '\t'; - break; - case 'u': { - unsigned int unicode; - if (!decodeUnicodeCodePoint(token, current, end, unicode)) - return false; - decoded += codePointToUTF8(unicode); - } break; - default: - return addError("Bad escape sequence in string", token, current); - } - } else { - decoded += c; - } - } - return true; -} - -bool Reader::decodeUnicodeCodePoint(Token& token, - Location& current, - Location end, - unsigned int& unicode) { - - if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) - return false; - if (unicode >= 0xD800 && unicode <= 0xDBFF) { - // surrogate pairs - if (end - current < 6) - return addError( - "additional six characters expected to parse unicode surrogate pair.", - token, - current); - unsigned int surrogatePair; - if (*(current++) == '\\' && *(current++) == 'u') { - if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { - unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); - } else - return false; - } else - return addError("expecting another \\u token to begin the second half of " - "a unicode surrogate pair", - token, - current); - } - return true; -} - -bool Reader::decodeUnicodeEscapeSequence(Token& token, - Location& current, - Location end, - unsigned int& unicode) { - if (end - current < 4) - return addError( - "Bad unicode escape sequence in string: four digits expected.", - token, - current); - unicode = 0; - for (int index = 0; index < 4; ++index) { - Char c = *current++; - unicode *= 16; - if (c >= '0' && c <= '9') - unicode += c - '0'; - else if (c >= 'a' && c <= 'f') - unicode += c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - unicode += c - 'A' + 10; - else - return addError( - "Bad unicode escape sequence in string: hexadecimal digit expected.", - token, - current); - } - return true; -} - -bool -Reader::addError(const std::string& message, Token& token, Location extra) { - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = extra; - errors_.push_back(info); - return false; -} - -bool Reader::recoverFromError(TokenType skipUntilToken) { - int errorCount = int(errors_.size()); - Token skip; - for (;;) { - if (!readToken(skip)) - errors_.resize(errorCount); // discard errors caused by recovery - if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) - break; - } - errors_.resize(errorCount); - return false; -} - -bool Reader::addErrorAndRecover(const std::string& message, - Token& token, - TokenType skipUntilToken) { - addError(message, token); - return recoverFromError(skipUntilToken); -} - -Value& Reader::currentValue() { return *(nodes_.top()); } - -Reader::Char Reader::getNextChar() { - if (current_ == end_) - return 0; - return *current_++; -} - -void Reader::getLocationLineAndColumn(Location location, - int& line, - int& column) const { - Location current = begin_; - Location lastLineStart = current; - line = 0; - while (current < location && current != end_) { - Char c = *current++; - if (c == '\r') { - if (*current == '\n') - ++current; - lastLineStart = current; - ++line; - } else if (c == '\n') { - lastLineStart = current; - ++line; - } - } - // column & line start at 1 - column = int(location - lastLineStart) + 1; - ++line; -} - -std::string Reader::getLocationLineAndColumn(Location location) const { - int line, column; - getLocationLineAndColumn(location, line, column); - char buffer[18 + 16 + 16 + 1]; -#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) -#if defined(WINCE) - _snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); -#else - sprintf_s(buffer, sizeof(buffer), "Line %d, Column %d", line, column); -#endif -#else - snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); -#endif - return buffer; -} - -// Deprecated. Preserved for backward compatibility -std::string Reader::getFormatedErrorMessages() const { - return getFormattedErrorMessages(); -} - -std::string Reader::getFormattedErrorMessages() const { - std::string formattedMessage; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { - const ErrorInfo& error = *itError; - formattedMessage += - "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; - formattedMessage += " " + error.message_ + "\n"; - if (error.extra_) - formattedMessage += - "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; - } - return formattedMessage; -} - -std::vector Reader::getStructuredErrors() const { - std::vector allErrors; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { - const ErrorInfo& error = *itError; - Reader::StructuredError structured; - structured.offset_start = error.token_.start_ - begin_; - structured.offset_limit = error.token_.end_ - begin_; - structured.message = error.message_; - allErrors.push_back(structured); - } - return allErrors; -} - -bool Reader::pushError(const Value& value, const std::string& message) { - size_t length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = end_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = 0; - errors_.push_back(info); - return true; -} - -bool Reader::pushError(const Value& value, const std::string& message, const Value& extra) { - size_t length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length - || extra.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = begin_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = begin_ + extra.getOffsetStart(); - errors_.push_back(info); - return true; -} - -bool Reader::good() const { - return !errors_.size(); -} - -// exact copy of Features -class OurFeatures { -public: - static OurFeatures all(); - OurFeatures(); - bool allowComments_; - bool strictRoot_; - bool allowDroppedNullPlaceholders_; - bool allowNumericKeys_; - bool allowSingleQuotes_; - bool failIfExtra_; - bool rejectDupKeys_; - int stackLimit_; -}; // OurFeatures - -// exact copy of Implementation of class Features -// //////////////////////////////// - -OurFeatures::OurFeatures() - : allowComments_(true), strictRoot_(false) - , allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) - , allowSingleQuotes_(false) - , failIfExtra_(false) -{ -} - -OurFeatures OurFeatures::all() { return OurFeatures(); } - -// Implementation of class Reader -// //////////////////////////////// - -// exact copy of Reader, renamed to OurReader -class OurReader { -public: - typedef char Char; - typedef const Char* Location; - struct StructuredError { - size_t offset_start; - size_t offset_limit; - std::string message; - }; - - OurReader(OurFeatures const& features); - bool parse(const char* beginDoc, - const char* endDoc, - Value& root, - bool collectComments = true); - std::string getFormattedErrorMessages() const; - std::vector getStructuredErrors() const; - bool pushError(const Value& value, const std::string& message); - bool pushError(const Value& value, const std::string& message, const Value& extra); - bool good() const; - -private: - OurReader(OurReader const&); // no impl - void operator=(OurReader const&); // no impl - - enum TokenType { - tokenEndOfStream = 0, - tokenObjectBegin, - tokenObjectEnd, - tokenArrayBegin, - tokenArrayEnd, - tokenString, - tokenNumber, - tokenTrue, - tokenFalse, - tokenNull, - tokenArraySeparator, - tokenMemberSeparator, - tokenComment, - tokenError - }; - - class Token { - public: - TokenType type_; - Location start_; - Location end_; - }; - - class ErrorInfo { - public: - Token token_; - std::string message_; - Location extra_; - }; - - typedef std::deque Errors; - - bool readToken(Token& token); - void skipSpaces(); - bool match(Location pattern, int patternLength); - bool readComment(); - bool readCStyleComment(); - bool readCppStyleComment(); - bool readString(); - bool readStringSingleQuote(); - void readNumber(); - bool readValue(); - bool readObject(Token& token); - bool readArray(Token& token); - bool decodeNumber(Token& token); - bool decodeNumber(Token& token, Value& decoded); - bool decodeString(Token& token); - bool decodeString(Token& token, std::string& decoded); - bool decodeDouble(Token& token); - bool decodeDouble(Token& token, Value& decoded); - bool decodeUnicodeCodePoint(Token& token, - Location& current, - Location end, - unsigned int& unicode); - bool decodeUnicodeEscapeSequence(Token& token, - Location& current, - Location end, - unsigned int& unicode); - bool addError(const std::string& message, Token& token, Location extra = 0); - bool recoverFromError(TokenType skipUntilToken); - bool addErrorAndRecover(const std::string& message, - Token& token, - TokenType skipUntilToken); - void skipUntilSpace(); - Value& currentValue(); - Char getNextChar(); - void - getLocationLineAndColumn(Location location, int& line, int& column) const; - std::string getLocationLineAndColumn(Location location) const; - void addComment(Location begin, Location end, CommentPlacement placement); - void skipCommentTokens(Token& token); - - typedef std::stack Nodes; - Nodes nodes_; - Errors errors_; - std::string document_; - Location begin_; - Location end_; - Location current_; - Location lastValueEnd_; - Value* lastValue_; - std::string commentsBefore_; - int stackDepth_; - - OurFeatures const features_; - bool collectComments_; -}; // OurReader - -// complete copy of Read impl, for OurReader - -OurReader::OurReader(OurFeatures const& features) - : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), - lastValue_(), commentsBefore_(), features_(features), collectComments_() { -} - -bool OurReader::parse(const char* beginDoc, - const char* endDoc, - Value& root, - bool collectComments) { - if (!features_.allowComments_) { - collectComments = false; - } - - begin_ = beginDoc; - end_ = endDoc; - collectComments_ = collectComments; - current_ = begin_; - lastValueEnd_ = 0; - lastValue_ = 0; - commentsBefore_ = ""; - errors_.clear(); - while (!nodes_.empty()) - nodes_.pop(); - nodes_.push(&root); - - stackDepth_ = 0; - bool successful = readValue(); - Token token; - skipCommentTokens(token); - if (features_.failIfExtra_) { - if (token.type_ != tokenError && token.type_ != tokenEndOfStream) { - addError("Extra non-whitespace after JSON value.", token); - return false; - } - } - if (collectComments_ && !commentsBefore_.empty()) - root.setComment(commentsBefore_, commentAfter); - if (features_.strictRoot_) { - if (!root.isArray() && !root.isObject()) { - // Set error location to start of doc, ideally should be first token found - // in doc - token.type_ = tokenError; - token.start_ = beginDoc; - token.end_ = endDoc; - addError( - "A valid JSON document must be either an array or an object value.", - token); - return false; - } - } - return successful; -} - -bool OurReader::readValue() { - if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); - ++stackDepth_; - Token token; - skipCommentTokens(token); - bool successful = true; - - if (collectComments_ && !commentsBefore_.empty()) { - currentValue().setComment(commentsBefore_, commentBefore); - commentsBefore_ = ""; - } - - switch (token.type_) { - case tokenObjectBegin: - successful = readObject(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenArrayBegin: - successful = readArray(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenNumber: - successful = decodeNumber(token); - break; - case tokenString: - successful = decodeString(token); - break; - case tokenTrue: - { - Value v(true); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenFalse: - { - Value v(false); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenNull: - { - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenArraySeparator: - case tokenObjectEnd: - case tokenArrayEnd: - if (features_.allowDroppedNullPlaceholders_) { - // "Un-read" the current token and mark the current value as a null - // token. - current_--; - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(current_ - begin_ - 1); - currentValue().setOffsetLimit(current_ - begin_); - break; - } // else, fall through ... - default: - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return addError("Syntax error: value, object or array expected.", token); - } - - if (collectComments_) { - lastValueEnd_ = current_; - lastValue_ = ¤tValue(); - } - - --stackDepth_; - return successful; -} - -void OurReader::skipCommentTokens(Token& token) { - if (features_.allowComments_) { - do { - readToken(token); - } while (token.type_ == tokenComment); - } else { - readToken(token); - } -} - -bool OurReader::readToken(Token& token) { - skipSpaces(); - token.start_ = current_; - Char c = getNextChar(); - bool ok = true; - switch (c) { - case '{': - token.type_ = tokenObjectBegin; - break; - case '}': - token.type_ = tokenObjectEnd; - break; - case '[': - token.type_ = tokenArrayBegin; - break; - case ']': - token.type_ = tokenArrayEnd; - break; - case '"': - token.type_ = tokenString; - ok = readString(); - break; - case '\'': - if (features_.allowSingleQuotes_) { - token.type_ = tokenString; - ok = readStringSingleQuote(); - break; - } // else continue - case '/': - token.type_ = tokenComment; - ok = readComment(); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - token.type_ = tokenNumber; - readNumber(); - break; - case 't': - token.type_ = tokenTrue; - ok = match("rue", 3); - break; - case 'f': - token.type_ = tokenFalse; - ok = match("alse", 4); - break; - case 'n': - token.type_ = tokenNull; - ok = match("ull", 3); - break; - case ',': - token.type_ = tokenArraySeparator; - break; - case ':': - token.type_ = tokenMemberSeparator; - break; - case 0: - token.type_ = tokenEndOfStream; - break; - default: - ok = false; - break; - } - if (!ok) - token.type_ = tokenError; - token.end_ = current_; - return true; -} - -void OurReader::skipSpaces() { - while (current_ != end_) { - Char c = *current_; - if (c == ' ' || c == '\t' || c == '\r' || c == '\n') - ++current_; - else - break; - } -} - -bool OurReader::match(Location pattern, int patternLength) { - if (end_ - current_ < patternLength) - return false; - int index = patternLength; - while (index--) - if (current_[index] != pattern[index]) - return false; - current_ += patternLength; - return true; -} - -bool OurReader::readComment() { - Location commentBegin = current_ - 1; - Char c = getNextChar(); - bool successful = false; - if (c == '*') - successful = readCStyleComment(); - else if (c == '/') - successful = readCppStyleComment(); - if (!successful) - return false; - - if (collectComments_) { - CommentPlacement placement = commentBefore; - if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { - if (c != '*' || !containsNewLine(commentBegin, current_)) - placement = commentAfterOnSameLine; - } - - addComment(commentBegin, current_, placement); - } - return true; -} - -void -OurReader::addComment(Location begin, Location end, CommentPlacement placement) { - assert(collectComments_); - const std::string& normalized = normalizeEOL(begin, end); - if (placement == commentAfterOnSameLine) { - assert(lastValue_ != 0); - lastValue_->setComment(normalized, placement); - } else { - commentsBefore_ += normalized; - } -} - -bool OurReader::readCStyleComment() { - while (current_ != end_) { - Char c = getNextChar(); - if (c == '*' && *current_ == '/') - break; - } - return getNextChar() == '/'; -} - -bool OurReader::readCppStyleComment() { - while (current_ != end_) { - Char c = getNextChar(); - if (c == '\n') - break; - if (c == '\r') { - // Consume DOS EOL. It will be normalized in addComment. - if (current_ != end_ && *current_ == '\n') - getNextChar(); - // Break on Moc OS 9 EOL. - break; - } - } - return true; -} - -void OurReader::readNumber() { - const char *p = current_; - char c = '0'; // stopgap for already consumed character - // integral part - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; - // fractional part - if (c == '.') { - c = (current_ = p) < end_ ? *p++ : 0; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; - } - // exponential part - if (c == 'e' || c == 'E') { - c = (current_ = p) < end_ ? *p++ : 0; - if (c == '+' || c == '-') - c = (current_ = p) < end_ ? *p++ : 0; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; - } -} -bool OurReader::readString() { - Char c = 0; - while (current_ != end_) { - c = getNextChar(); - if (c == '\\') - getNextChar(); - else if (c == '"') - break; - } - return c == '"'; -} - - -bool OurReader::readStringSingleQuote() { - Char c = 0; - while (current_ != end_) { - c = getNextChar(); - if (c == '\\') - getNextChar(); - else if (c == '\'') - break; - } - return c == '\''; -} - -bool OurReader::readObject(Token& tokenStart) { - Token tokenName; - std::string name; - Value init(objectValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); - while (readToken(tokenName)) { - bool initialTokenOk = true; - while (tokenName.type_ == tokenComment && initialTokenOk) - initialTokenOk = readToken(tokenName); - if (!initialTokenOk) - break; - if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object - return true; - name = ""; - if (tokenName.type_ == tokenString) { - if (!decodeString(tokenName, name)) - return recoverFromError(tokenObjectEnd); - } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { - Value numberName; - if (!decodeNumber(tokenName, numberName)) - return recoverFromError(tokenObjectEnd); - name = numberName.asString(); - } else { - break; - } - - Token colon; - if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { - return addErrorAndRecover( - "Missing ':' after object member name", colon, tokenObjectEnd); - } - if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30"); - if (features_.rejectDupKeys_ && currentValue().isMember(name)) { - std::string msg = "Duplicate key: '" + name + "'"; - return addErrorAndRecover( - msg, tokenName, tokenObjectEnd); - } - Value& value = currentValue()[name]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenObjectEnd); - - Token comma; - if (!readToken(comma) || - (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && - comma.type_ != tokenComment)) { - return addErrorAndRecover( - "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); - } - bool finalizeTokenOk = true; - while (comma.type_ == tokenComment && finalizeTokenOk) - finalizeTokenOk = readToken(comma); - if (comma.type_ == tokenObjectEnd) - return true; - } - return addErrorAndRecover( - "Missing '}' or object member name", tokenName, tokenObjectEnd); -} - -bool OurReader::readArray(Token& tokenStart) { - Value init(arrayValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); - skipSpaces(); - if (*current_ == ']') // empty array - { - Token endArray; - readToken(endArray); - return true; - } - int index = 0; - for (;;) { - Value& value = currentValue()[index++]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenArrayEnd); - - Token token; - // Accept Comment after last item in the array. - ok = readToken(token); - while (token.type_ == tokenComment && ok) { - ok = readToken(token); - } - bool badTokenType = - (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); - if (!ok || badTokenType) { - return addErrorAndRecover( - "Missing ',' or ']' in array declaration", token, tokenArrayEnd); - } - if (token.type_ == tokenArrayEnd) - break; - } - return true; -} - -bool OurReader::decodeNumber(Token& token) { - Value decoded; - if (!decodeNumber(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool OurReader::decodeNumber(Token& token, Value& decoded) { - // Attempts to parse the number as an integer. If the number is - // larger than the maximum supported value of an integer then - // we decode the number as a double. - Location current = token.start_; - bool isNegative = *current == '-'; - if (isNegative) - ++current; - // TODO: Help the compiler do the div and mod at compile time or get rid of them. - Value::LargestUInt maxIntegerValue = - isNegative ? Value::LargestUInt(-Value::minLargestInt) - : Value::maxLargestUInt; - Value::LargestUInt threshold = maxIntegerValue / 10; - Value::LargestUInt value = 0; - while (current < token.end_) { - Char c = *current++; - if (c < '0' || c > '9') - return decodeDouble(token, decoded); - Value::UInt digit(c - '0'); - if (value >= threshold) { - // We've hit or exceeded the max value divided by 10 (rounded down). If - // a) we've only just touched the limit, b) this is the last digit, and - // c) it's small enough to fit in that rounding delta, we're okay. - // Otherwise treat this number as a double to avoid overflow. - if (value > threshold || current != token.end_ || - digit > maxIntegerValue % 10) { - return decodeDouble(token, decoded); - } - } - value = value * 10 + digit; - } - if (isNegative) - decoded = -Value::LargestInt(value); - else if (value <= Value::LargestUInt(Value::maxInt)) - decoded = Value::LargestInt(value); - else - decoded = value; - return true; -} - -bool OurReader::decodeDouble(Token& token) { - Value decoded; - if (!decodeDouble(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool OurReader::decodeDouble(Token& token, Value& decoded) { - double value = 0; - const int bufferSize = 32; - int count; - int length = int(token.end_ - token.start_); - - // Sanity check to avoid buffer overflow exploits. - if (length < 0) { - return addError("Unable to parse token length", token); - } - - // Avoid using a string constant for the format control string given to - // sscanf, as this can cause hard to debug crashes on OS X. See here for more - // info: - // - // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html - char format[] = "%lf"; - - if (length <= bufferSize) { - Char buffer[bufferSize + 1]; - memcpy(buffer, token.start_, length); - buffer[length] = 0; - count = sscanf(buffer, format, &value); - } else { - std::string buffer(token.start_, token.end_); - count = sscanf(buffer.c_str(), format, &value); - } - - if (count != 1) - return addError("'" + std::string(token.start_, token.end_) + - "' is not a number.", - token); - decoded = value; - return true; -} - -bool OurReader::decodeString(Token& token) { - std::string decoded_string; - if (!decodeString(token, decoded_string)) - return false; - Value decoded(decoded_string); - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool OurReader::decodeString(Token& token, std::string& decoded) { - decoded.reserve(token.end_ - token.start_ - 2); - Location current = token.start_ + 1; // skip '"' - Location end = token.end_ - 1; // do not include '"' - while (current != end) { - Char c = *current++; - if (c == '"') - break; - else if (c == '\\') { - if (current == end) - return addError("Empty escape sequence in string", token, current); - Char escape = *current++; - switch (escape) { - case '"': - decoded += '"'; - break; - case '/': - decoded += '/'; - break; - case '\\': - decoded += '\\'; - break; - case 'b': - decoded += '\b'; - break; - case 'f': - decoded += '\f'; - break; - case 'n': - decoded += '\n'; - break; - case 'r': - decoded += '\r'; - break; - case 't': - decoded += '\t'; - break; - case 'u': { - unsigned int unicode; - if (!decodeUnicodeCodePoint(token, current, end, unicode)) - return false; - decoded += codePointToUTF8(unicode); - } break; - default: - return addError("Bad escape sequence in string", token, current); - } - } else { - decoded += c; - } - } - return true; -} - -bool OurReader::decodeUnicodeCodePoint(Token& token, - Location& current, - Location end, - unsigned int& unicode) { - - if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) - return false; - if (unicode >= 0xD800 && unicode <= 0xDBFF) { - // surrogate pairs - if (end - current < 6) - return addError( - "additional six characters expected to parse unicode surrogate pair.", - token, - current); - unsigned int surrogatePair; - if (*(current++) == '\\' && *(current++) == 'u') { - if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { - unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); - } else - return false; - } else - return addError("expecting another \\u token to begin the second half of " - "a unicode surrogate pair", - token, - current); - } - return true; -} - -bool OurReader::decodeUnicodeEscapeSequence(Token& token, - Location& current, - Location end, - unsigned int& unicode) { - if (end - current < 4) - return addError( - "Bad unicode escape sequence in string: four digits expected.", - token, - current); - unicode = 0; - for (int index = 0; index < 4; ++index) { - Char c = *current++; - unicode *= 16; - if (c >= '0' && c <= '9') - unicode += c - '0'; - else if (c >= 'a' && c <= 'f') - unicode += c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - unicode += c - 'A' + 10; - else - return addError( - "Bad unicode escape sequence in string: hexadecimal digit expected.", - token, - current); - } - return true; -} - -bool -OurReader::addError(const std::string& message, Token& token, Location extra) { - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = extra; - errors_.push_back(info); - return false; -} - -bool OurReader::recoverFromError(TokenType skipUntilToken) { - int errorCount = int(errors_.size()); - Token skip; - for (;;) { - if (!readToken(skip)) - errors_.resize(errorCount); // discard errors caused by recovery - if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) - break; - } - errors_.resize(errorCount); - return false; -} - -bool OurReader::addErrorAndRecover(const std::string& message, - Token& token, - TokenType skipUntilToken) { - addError(message, token); - return recoverFromError(skipUntilToken); -} - -Value& OurReader::currentValue() { return *(nodes_.top()); } - -OurReader::Char OurReader::getNextChar() { - if (current_ == end_) - return 0; - return *current_++; -} - -void OurReader::getLocationLineAndColumn(Location location, - int& line, - int& column) const { - Location current = begin_; - Location lastLineStart = current; - line = 0; - while (current < location && current != end_) { - Char c = *current++; - if (c == '\r') { - if (*current == '\n') - ++current; - lastLineStart = current; - ++line; - } else if (c == '\n') { - lastLineStart = current; - ++line; - } - } - // column & line start at 1 - column = int(location - lastLineStart) + 1; - ++line; -} - -std::string OurReader::getLocationLineAndColumn(Location location) const { - int line, column; - getLocationLineAndColumn(location, line, column); - char buffer[18 + 16 + 16 + 1]; -#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) -#if defined(WINCE) - _snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); -#else - sprintf_s(buffer, sizeof(buffer), "Line %d, Column %d", line, column); -#endif -#else - snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); -#endif - return buffer; -} - -std::string OurReader::getFormattedErrorMessages() const { - std::string formattedMessage; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { - const ErrorInfo& error = *itError; - formattedMessage += - "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; - formattedMessage += " " + error.message_ + "\n"; - if (error.extra_) - formattedMessage += - "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; - } - return formattedMessage; -} - -std::vector OurReader::getStructuredErrors() const { - std::vector allErrors; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { - const ErrorInfo& error = *itError; - OurReader::StructuredError structured; - structured.offset_start = error.token_.start_ - begin_; - structured.offset_limit = error.token_.end_ - begin_; - structured.message = error.message_; - allErrors.push_back(structured); - } - return allErrors; -} - -bool OurReader::pushError(const Value& value, const std::string& message) { - size_t length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = end_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = 0; - errors_.push_back(info); - return true; -} - -bool OurReader::pushError(const Value& value, const std::string& message, const Value& extra) { - size_t length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length - || extra.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = begin_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = begin_ + extra.getOffsetStart(); - errors_.push_back(info); - return true; -} - -bool OurReader::good() const { - return !errors_.size(); -} - - -class OurCharReader : public CharReader { - bool const collectComments_; - OurReader reader_; -public: - OurCharReader( - bool collectComments, - OurFeatures const& features) - : collectComments_(collectComments) - , reader_(features) - {} - virtual bool parse( - char const* beginDoc, char const* endDoc, - Value* root, std::string* errs) { - bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); - if (errs) { - *errs = reader_.getFormattedErrorMessages(); - } - return ok; - } -}; - -CharReaderBuilder::CharReaderBuilder() -{ - setDefaults(&settings_); -} -CharReaderBuilder::~CharReaderBuilder() -{} -CharReader* CharReaderBuilder::newCharReader() const -{ - bool collectComments = settings_["collectComments"].asBool(); - OurFeatures features = OurFeatures::all(); - features.allowComments_ = settings_["allowComments"].asBool(); - features.strictRoot_ = settings_["strictRoot"].asBool(); - features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool(); - features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); - features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); - features.stackLimit_ = settings_["stackLimit"].asInt(); - features.failIfExtra_ = settings_["failIfExtra"].asBool(); - features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); - return new OurCharReader(collectComments, features); -} -static void getValidReaderKeys(std::set* valid_keys) -{ - valid_keys->clear(); - valid_keys->insert("collectComments"); - valid_keys->insert("allowComments"); - valid_keys->insert("strictRoot"); - valid_keys->insert("allowDroppedNullPlaceholders"); - valid_keys->insert("allowNumericKeys"); - valid_keys->insert("allowSingleQuotes"); - valid_keys->insert("stackLimit"); - valid_keys->insert("failIfExtra"); - valid_keys->insert("rejectDupKeys"); -} -bool CharReaderBuilder::validate(Json::Value* invalid) const -{ - Json::Value my_invalid; - if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL - Json::Value& inv = *invalid; - std::set valid_keys; - getValidReaderKeys(&valid_keys); - Value::Members keys = settings_.getMemberNames(); - size_t n = keys.size(); - for (size_t i = 0; i < n; ++i) { - std::string const& key = keys[i]; - if (valid_keys.find(key) == valid_keys.end()) { - inv[key] = settings_[key]; - } - } - return 0u == inv.size(); -} -Value& CharReaderBuilder::operator[](std::string key) -{ - return settings_[key]; -} -// static -void CharReaderBuilder::strictMode(Json::Value* settings) -{ -//! [CharReaderBuilderStrictMode] - (*settings)["allowComments"] = false; - (*settings)["strictRoot"] = true; - (*settings)["allowDroppedNullPlaceholders"] = false; - (*settings)["allowNumericKeys"] = false; - (*settings)["allowSingleQuotes"] = false; - (*settings)["failIfExtra"] = true; - (*settings)["rejectDupKeys"] = true; -//! [CharReaderBuilderStrictMode] -} -// static -void CharReaderBuilder::setDefaults(Json::Value* settings) -{ -//! [CharReaderBuilderDefaults] - (*settings)["collectComments"] = true; - (*settings)["allowComments"] = true; - (*settings)["strictRoot"] = false; - (*settings)["allowDroppedNullPlaceholders"] = false; - (*settings)["allowNumericKeys"] = false; - (*settings)["allowSingleQuotes"] = false; - (*settings)["stackLimit"] = 1000; - (*settings)["failIfExtra"] = false; - (*settings)["rejectDupKeys"] = false; -//! [CharReaderBuilderDefaults] -} - -////////////////////////////////// -// global functions - -bool parseFromStream( - CharReader::Factory const& fact, std::istream& sin, - Value* root, std::string* errs) -{ - std::ostringstream ssin; - ssin << sin.rdbuf(); - std::string doc = ssin.str(); - char const* begin = doc.data(); - char const* end = begin + doc.size(); - // Note that we do not actually need a null-terminator. - CharReaderPtr const reader(fact.newCharReader()); - return reader->parse(begin, end, root, errs); -} - -std::istream& operator>>(std::istream& sin, Value& root) { - CharReaderBuilder b; - std::string errs; - bool ok = parseFromStream(b, sin, &root, &errs); - if (!ok) { - fprintf(stderr, - "Error from reader: %s", - errs.c_str()); - - throwRuntimeError("reader error"); - } - return sin; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_reader.cpp -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_valueiterator.inl -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -// included by json_value.cpp - -namespace Json { - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueIteratorBase -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueIteratorBase::ValueIteratorBase() - : current_(), isNull_(true) { -} - -ValueIteratorBase::ValueIteratorBase( - const Value::ObjectValues::iterator& current) - : current_(current), isNull_(false) {} - -Value& ValueIteratorBase::deref() const { - return current_->second; -} - -void ValueIteratorBase::increment() { - ++current_; -} - -void ValueIteratorBase::decrement() { - --current_; -} - -ValueIteratorBase::difference_type -ValueIteratorBase::computeDistance(const SelfType& other) const { -#ifdef JSON_USE_CPPTL_SMALLMAP - return other.current_ - current_; -#else - // Iterator for null value are initialized using the default - // constructor, which initialize current_ to the default - // std::map::iterator. As begin() and end() are two instance - // of the default std::map::iterator, they can not be compared. - // To allow this, we handle this comparison specifically. - if (isNull_ && other.isNull_) { - return 0; - } - - // Usage of std::distance is not portable (does not compile with Sun Studio 12 - // RogueWave STL, - // which is the one used by default). - // Using a portable hand-made version for non random iterator instead: - // return difference_type( std::distance( current_, other.current_ ) ); - difference_type myDistance = 0; - for (Value::ObjectValues::iterator it = current_; it != other.current_; - ++it) { - ++myDistance; - } - return myDistance; -#endif -} - -bool ValueIteratorBase::isEqual(const SelfType& other) const { - if (isNull_) { - return other.isNull_; - } - return current_ == other.current_; -} - -void ValueIteratorBase::copy(const SelfType& other) { - current_ = other.current_; - isNull_ = other.isNull_; -} - -Value ValueIteratorBase::key() const { - const Value::CZString czstring = (*current_).first; - if (czstring.data()) { - if (czstring.isStaticString()) - return Value(StaticString(czstring.data())); - return Value(czstring.data(), czstring.data() + czstring.length()); - } - return Value(czstring.index()); -} - -UInt ValueIteratorBase::index() const { - const Value::CZString czstring = (*current_).first; - if (!czstring.data()) - return czstring.index(); - return Value::UInt(-1); -} - -std::string ValueIteratorBase::name() const { - char const* key; - char const* end; - key = memberName(&end); - if (!key) return std::string(); - return std::string(key, end); -} - -char const* ValueIteratorBase::memberName() const { - const char* name = (*current_).first.data(); - return name ? name : ""; -} - -char const* ValueIteratorBase::memberName(char const** end) const { - const char* name = (*current_).first.data(); - if (!name) { - *end = NULL; - return NULL; - } - *end = name + (*current_).first.length(); - return name; -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueConstIterator -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueConstIterator::ValueConstIterator() {} - -ValueConstIterator::ValueConstIterator( - const Value::ObjectValues::iterator& current) - : ValueIteratorBase(current) {} - -ValueConstIterator& ValueConstIterator:: -operator=(const ValueIteratorBase& other) { - copy(other); - return *this; -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueIterator -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueIterator::ValueIterator() {} - -ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) - : ValueIteratorBase(current) {} - -ValueIterator::ValueIterator(const ValueConstIterator& other) - : ValueIteratorBase(other) {} - -ValueIterator::ValueIterator(const ValueIterator& other) - : ValueIteratorBase(other) {} - -ValueIterator& ValueIterator::operator=(const SelfType& other) { - copy(other); - return *this; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_valueiterator.inl -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_value.cpp -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2011 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include -#ifdef JSON_USE_CPPTL -#include -#endif -#include // size_t -#include // min() - -#define JSON_ASSERT_UNREACHABLE assert(false) - -namespace Json { - -// This is a walkaround to avoid the static initialization of Value::null. -// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of -// 8 (instead of 4) as a bit of future-proofing. -#if defined(__ARMEL__) -#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) -#else -#define ALIGNAS(byte_alignment) -#endif -static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; -const unsigned char& kNullRef = kNull[0]; -const Value& Value::null = reinterpret_cast(kNullRef); -const Value& Value::nullRef = null; - -const Int Value::minInt = Int(~(UInt(-1) / 2)); -const Int Value::maxInt = Int(UInt(-1) / 2); -const UInt Value::maxUInt = UInt(-1); -#if defined(JSON_HAS_INT64) -const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2)); -const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2); -const UInt64 Value::maxUInt64 = UInt64(-1); -// The constant is hard-coded because some compiler have trouble -// converting Value::maxUInt64 to a double correctly (AIX/xlC). -// Assumes that UInt64 is a 64 bits integer. -static const double maxUInt64AsDouble = 18446744073709551615.0; -#endif // defined(JSON_HAS_INT64) -const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2)); -const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2); -const LargestUInt Value::maxLargestUInt = LargestUInt(-1); - -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) -template -static inline bool InRange(double d, T min, U max) { - return d >= min && d <= max; -} -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) -static inline double integerToDouble(Json::UInt64 value) { - return static_cast(Int64(value / 2)) * 2.0 + Int64(value & 1); -} - -template static inline double integerToDouble(T value) { - return static_cast(value); -} - -template -static inline bool InRange(double d, T min, U max) { - return d >= integerToDouble(min) && d <= integerToDouble(max); -} -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - -/** Duplicates the specified string value. - * @param value Pointer to the string to duplicate. Must be zero-terminated if - * length is "unknown". - * @param length Length of the value. if equals to unknown, then it will be - * computed using strlen(value). - * @return Pointer on the duplicate instance of string. - */ -static inline char* duplicateStringValue(const char* value, - size_t length) { - // Avoid an integer overflow in the call to malloc below by limiting length - // to a sane value. - if (length >= (size_t)Value::maxInt) - length = Value::maxInt - 1; - - char* newString = static_cast(malloc(length + 1)); - if (newString == NULL) { - throwRuntimeError( - "in Json::Value::duplicateStringValue(): " - "Failed to allocate string value buffer"); - } - memcpy(newString, value, length); - newString[length] = 0; - return newString; -} - -/* Record the length as a prefix. - */ -static inline char* duplicateAndPrefixStringValue( - const char* value, - unsigned int length) -{ - // Avoid an integer overflow in the call to malloc below by limiting length - // to a sane value. - JSON_ASSERT_MESSAGE(length <= (unsigned)Value::maxInt - sizeof(unsigned) - 1U, - "in Json::Value::duplicateAndPrefixStringValue(): " - "length too big for prefixing"); - unsigned actualLength = length + sizeof(unsigned) + 1U; - char* newString = static_cast(malloc(actualLength)); - if (newString == 0) { - throwRuntimeError( - "in Json::Value::duplicateAndPrefixStringValue(): " - "Failed to allocate string value buffer"); - } - *reinterpret_cast(newString) = length; - memcpy(newString + sizeof(unsigned), value, length); - newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later - return newString; -} -inline static void decodePrefixedString( - bool isPrefixed, char const* prefixed, - unsigned* length, char const** value) -{ - if (!isPrefixed) { - *length = strlen(prefixed); - *value = prefixed; - } else { - *length = *reinterpret_cast(prefixed); - *value = prefixed + sizeof(unsigned); - } -} -/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue(). - */ -static inline void releaseStringValue(char* value) { free(value); } - -} // namespace Json - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ValueInternals... -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -#if !defined(JSON_IS_AMALGAMATION) - -#include "json_valueiterator.inl" -#endif // if !defined(JSON_IS_AMALGAMATION) - -namespace Json { - -class JSON_API Exception : public std::exception { -public: - Exception(std::string const& msg); - virtual ~Exception() throw(); - virtual char const* what() const throw(); -protected: - std::string const msg_; -}; -class JSON_API RuntimeError : public Exception { -public: - RuntimeError(std::string const& msg); -}; -class JSON_API LogicError : public Exception { -public: - LogicError(std::string const& msg); -}; - -Exception::Exception(std::string const& msg) - : msg_(msg) -{} -Exception::~Exception() throw() -{} -char const* Exception::what() const throw() -{ - return msg_.c_str(); -} -RuntimeError::RuntimeError(std::string const& msg) - : Exception(msg) -{} -LogicError::LogicError(std::string const& msg) - : Exception(msg) -{} -void throwRuntimeError(std::string const& msg) -{ - throw RuntimeError(msg); -} -void throwLogicError(std::string const& msg) -{ - throw LogicError(msg); -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::CommentInfo -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -Value::CommentInfo::CommentInfo() : comment_(0) {} - -Value::CommentInfo::~CommentInfo() { - if (comment_) - releaseStringValue(comment_); -} - -void Value::CommentInfo::setComment(const char* text, size_t len) { - if (comment_) { - releaseStringValue(comment_); - comment_ = 0; - } - JSON_ASSERT(text != 0); - JSON_ASSERT_MESSAGE( - text[0] == '\0' || text[0] == '/', - "in Json::Value::setComment(): Comments must start with /"); - // It seems that /**/ style comments are acceptable as well. - comment_ = duplicateStringValue(text, len); -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::CZString -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -// Notes: policy_ indicates if the string was allocated when -// a string is stored. - -Value::CZString::CZString(ArrayIndex index) : cstr_(0), index_(index) {} - -Value::CZString::CZString(char const* str, unsigned length, DuplicationPolicy allocate) - : cstr_(str) -{ - // allocate != duplicate - storage_.policy_ = allocate; - storage_.length_ = length; -} - -Value::CZString::CZString(const CZString& other) - : cstr_(other.storage_.policy_ != noDuplication && other.cstr_ != 0 - ? duplicateStringValue(other.cstr_, other.storage_.length_) - : other.cstr_) -{ - storage_.policy_ = (other.cstr_ - ? (other.storage_.policy_ == noDuplication - ? noDuplication : duplicate) - : other.storage_.policy_); - storage_.length_ = other.storage_.length_; -} - -Value::CZString::~CZString() { - if (cstr_ && storage_.policy_ == duplicate) - releaseStringValue(const_cast(cstr_)); -} - -void Value::CZString::swap(CZString& other) { - std::swap(cstr_, other.cstr_); - std::swap(index_, other.index_); -} - -Value::CZString& Value::CZString::operator=(CZString other) { - swap(other); - return *this; -} - -bool Value::CZString::operator<(const CZString& other) const { - if (!cstr_) return index_ < other.index_; - //return strcmp(cstr_, other.cstr_) < 0; - // Assume both are strings. - unsigned this_len = this->storage_.length_; - unsigned other_len = other.storage_.length_; - unsigned min_len = std::min(this_len, other_len); - int comp = memcmp(this->cstr_, other.cstr_, min_len); - if (comp < 0) return true; - if (comp > 0) return false; - return (this_len < other_len); -} - -bool Value::CZString::operator==(const CZString& other) const { - if (!cstr_) return index_ == other.index_; - //return strcmp(cstr_, other.cstr_) == 0; - // Assume both are strings. - unsigned this_len = this->storage_.length_; - unsigned other_len = other.storage_.length_; - if (this_len != other_len) return false; - int comp = memcmp(this->cstr_, other.cstr_, this_len); - return comp == 0; -} - -ArrayIndex Value::CZString::index() const { return index_; } - -//const char* Value::CZString::c_str() const { return cstr_; } -const char* Value::CZString::data() const { return cstr_; } -unsigned Value::CZString::length() const { return storage_.length_; } -bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; } - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::Value -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -/*! \internal Default constructor initialization must be equivalent to: - * memset( this, 0, sizeof(Value) ) - * This optimization is used in ValueInternalMap fast allocator. - */ -Value::Value(ValueType type) { - initBasic(type); - switch (type) { - case nullValue: - break; - case intValue: - case uintValue: - value_.int_ = 0; - break; - case realValue: - value_.real_ = 0.0; - break; - case stringValue: - value_.string_ = 0; - break; - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues(); - break; - case booleanValue: - value_.bool_ = false; - break; - default: - JSON_ASSERT_UNREACHABLE; - } -} - -Value::Value(Int value) { - initBasic(intValue); - value_.int_ = value; -} - -Value::Value(UInt value) { - initBasic(uintValue); - value_.uint_ = value; -} -#if defined(JSON_HAS_INT64) -Value::Value(Int64 value) { - initBasic(intValue); - value_.int_ = value; -} -Value::Value(UInt64 value) { - initBasic(uintValue); - value_.uint_ = value; -} -#endif // defined(JSON_HAS_INT64) - -Value::Value(double value) { - initBasic(realValue); - value_.real_ = value; -} - -Value::Value(const char* value) { - initBasic(stringValue, true); - value_.string_ = duplicateAndPrefixStringValue(value, static_cast(strlen(value))); -} - -Value::Value(const char* beginValue, const char* endValue) { - initBasic(stringValue, true); - value_.string_ = - duplicateAndPrefixStringValue(beginValue, static_cast(endValue - beginValue)); -} - -Value::Value(const std::string& value) { - initBasic(stringValue, true); - value_.string_ = - duplicateAndPrefixStringValue(value.data(), static_cast(value.length())); -} - -Value::Value(const StaticString& value) { - initBasic(stringValue); - value_.string_ = const_cast(value.c_str()); -} - -#ifdef JSON_USE_CPPTL -Value::Value(const CppTL::ConstString& value) { - initBasic(stringValue, true); - value_.string_ = duplicateAndPrefixStringValue(value, static_cast(value.length())); -} -#endif - -Value::Value(bool value) { - initBasic(booleanValue); - value_.bool_ = value; -} - -Value::Value(Value const& other) - : type_(other.type_), allocated_(false) - , - comments_(0), start_(other.start_), limit_(other.limit_) -{ - switch (type_) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - value_ = other.value_; - break; - case stringValue: - if (other.value_.string_ && other.allocated_) { - unsigned len; - char const* str; - decodePrefixedString(other.allocated_, other.value_.string_, - &len, &str); - value_.string_ = duplicateAndPrefixStringValue(str, len); - allocated_ = true; - } else { - value_.string_ = other.value_.string_; - allocated_ = false; - } - break; - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues(*other.value_.map_); - break; - default: - JSON_ASSERT_UNREACHABLE; - } - if (other.comments_) { - comments_ = new CommentInfo[numberOfCommentPlacement]; - for (int comment = 0; comment < numberOfCommentPlacement; ++comment) { - const CommentInfo& otherComment = other.comments_[comment]; - if (otherComment.comment_) - comments_[comment].setComment( - otherComment.comment_, strlen(otherComment.comment_)); - } - } -} - -Value::~Value() { - switch (type_) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - break; - case stringValue: - if (allocated_) - releaseStringValue(value_.string_); - break; - case arrayValue: - case objectValue: - delete value_.map_; - break; - default: - JSON_ASSERT_UNREACHABLE; - } - - if (comments_) - delete[] comments_; -} - -Value& Value::operator=(Value other) { - swap(other); - return *this; -} - -void Value::swapPayload(Value& other) { - ValueType temp = type_; - type_ = other.type_; - other.type_ = temp; - std::swap(value_, other.value_); - int temp2 = allocated_; - allocated_ = other.allocated_; - other.allocated_ = temp2; -} - -void Value::swap(Value& other) { - swapPayload(other); - std::swap(comments_, other.comments_); - std::swap(start_, other.start_); - std::swap(limit_, other.limit_); -} - -ValueType Value::type() const { return type_; } - -int Value::compare(const Value& other) const { - if (*this < other) - return -1; - if (*this > other) - return 1; - return 0; -} - -bool Value::operator<(const Value& other) const { - int typeDelta = type_ - other.type_; - if (typeDelta) - return typeDelta < 0 ? true : false; - switch (type_) { - case nullValue: - return false; - case intValue: - return value_.int_ < other.value_.int_; - case uintValue: - return value_.uint_ < other.value_.uint_; - case realValue: - return value_.real_ < other.value_.real_; - case booleanValue: - return value_.bool_ < other.value_.bool_; - case stringValue: - { - if ((value_.string_ == 0) || (other.value_.string_ == 0)) { - if (other.value_.string_) return true; - else return false; - } - unsigned this_len; - unsigned other_len; - char const* this_str; - char const* other_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); - unsigned min_len = std::min(this_len, other_len); - int comp = memcmp(this_str, other_str, min_len); - if (comp < 0) return true; - if (comp > 0) return false; - return (this_len < other_len); - } - case arrayValue: - case objectValue: { - int delta = int(value_.map_->size() - other.value_.map_->size()); - if (delta) - return delta < 0; - return (*value_.map_) < (*other.value_.map_); - } - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable -} - -bool Value::operator<=(const Value& other) const { return !(other < *this); } - -bool Value::operator>=(const Value& other) const { return !(*this < other); } - -bool Value::operator>(const Value& other) const { return other < *this; } - -bool Value::operator==(const Value& other) const { - // if ( type_ != other.type_ ) - // GCC 2.95.3 says: - // attempt to take address of bit-field structure member `Json::Value::type_' - // Beats me, but a temp solves the problem. - int temp = other.type_; - if (type_ != temp) - return false; - switch (type_) { - case nullValue: - return true; - case intValue: - return value_.int_ == other.value_.int_; - case uintValue: - return value_.uint_ == other.value_.uint_; - case realValue: - return value_.real_ == other.value_.real_; - case booleanValue: - return value_.bool_ == other.value_.bool_; - case stringValue: - { - if ((value_.string_ == 0) || (other.value_.string_ == 0)) { - return (value_.string_ == other.value_.string_); - } - unsigned this_len; - unsigned other_len; - char const* this_str; - char const* other_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); - if (this_len != other_len) return false; - int comp = memcmp(this_str, other_str, this_len); - return comp == 0; - } - case arrayValue: - case objectValue: - return value_.map_->size() == other.value_.map_->size() && - (*value_.map_) == (*other.value_.map_); - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable -} - -bool Value::operator!=(const Value& other) const { return !(*this == other); } - -const char* Value::asCString() const { - JSON_ASSERT_MESSAGE(type_ == stringValue, - "in Json::Value::asCString(): requires stringValue"); - if (value_.string_ == 0) return 0; - unsigned this_len; - char const* this_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - return this_str; -} - -bool Value::getString(char const** str, char const** end) const { - if (type_ != stringValue) return false; - if (value_.string_ == 0) return false; - unsigned length; - decodePrefixedString(this->allocated_, this->value_.string_, &length, str); - *end = *str + length; - return true; -} - -std::string Value::asString() const { - switch (type_) { - case nullValue: - return ""; - case stringValue: - { - if (value_.string_ == 0) return ""; - unsigned this_len; - char const* this_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - return std::string(this_str, this_len); - } - case booleanValue: - return value_.bool_ ? "true" : "false"; - case intValue: - return valueToString(value_.int_); - case uintValue: - return valueToString(value_.uint_); - case realValue: - return valueToString(value_.real_); - default: - JSON_FAIL_MESSAGE("Type is not convertible to string"); - } -} - -#ifdef JSON_USE_CPPTL -CppTL::ConstString Value::asConstString() const { - unsigned len; - char const* str; - decodePrefixedString(allocated_, value_.string_, - &len, &str); - return CppTL::ConstString(str, len); -} -#endif - -Value::Int Value::asInt() const { - switch (type_) { - case intValue: - JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); - return Int(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); - return Int(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), - "double out of Int range"); - return Int(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to Int."); -} - -Value::UInt Value::asUInt() const { - switch (type_) { - case intValue: - JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); - return UInt(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); - return UInt(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), - "double out of UInt range"); - return UInt(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to UInt."); -} - -#if defined(JSON_HAS_INT64) - -Value::Int64 Value::asInt64() const { - switch (type_) { - case intValue: - return Int64(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); - return Int64(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), - "double out of Int64 range"); - return Int64(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to Int64."); -} - -Value::UInt64 Value::asUInt64() const { - switch (type_) { - case intValue: - JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); - return UInt64(value_.int_); - case uintValue: - return UInt64(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), - "double out of UInt64 range"); - return UInt64(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); -} -#endif // if defined(JSON_HAS_INT64) - -LargestInt Value::asLargestInt() const { -#if defined(JSON_NO_INT64) - return asInt(); -#else - return asInt64(); -#endif -} - -LargestUInt Value::asLargestUInt() const { -#if defined(JSON_NO_INT64) - return asUInt(); -#else - return asUInt64(); -#endif -} - -double Value::asDouble() const { - switch (type_) { - case intValue: - return static_cast(value_.int_); - case uintValue: -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return static_cast(value_.uint_); -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return integerToDouble(value_.uint_); -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - case realValue: - return value_.real_; - case nullValue: - return 0.0; - case booleanValue: - return value_.bool_ ? 1.0 : 0.0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to double."); -} - -float Value::asFloat() const { - switch (type_) { - case intValue: - return static_cast(value_.int_); - case uintValue: -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return static_cast(value_.uint_); -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return integerToDouble(value_.uint_); -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - case realValue: - return static_cast(value_.real_); - case nullValue: - return 0.0; - case booleanValue: - return value_.bool_ ? 1.0f : 0.0f; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to float."); -} - -bool Value::asBool() const { - switch (type_) { - case booleanValue: - return value_.bool_; - case nullValue: - return false; - case intValue: - return value_.int_ ? true : false; - case uintValue: - return value_.uint_ ? true : false; - case realValue: - return value_.real_ ? true : false; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to bool."); -} - -bool Value::isConvertibleTo(ValueType other) const { - switch (other) { - case nullValue: - return (isNumeric() && asDouble() == 0.0) || - (type_ == booleanValue && value_.bool_ == false) || - (type_ == stringValue && asString() == "") || - (type_ == arrayValue && value_.map_->size() == 0) || - (type_ == objectValue && value_.map_->size() == 0) || - type_ == nullValue; - case intValue: - return isInt() || - (type_ == realValue && InRange(value_.real_, minInt, maxInt)) || - type_ == booleanValue || type_ == nullValue; - case uintValue: - return isUInt() || - (type_ == realValue && InRange(value_.real_, 0, maxUInt)) || - type_ == booleanValue || type_ == nullValue; - case realValue: - return isNumeric() || type_ == booleanValue || type_ == nullValue; - case booleanValue: - return isNumeric() || type_ == booleanValue || type_ == nullValue; - case stringValue: - return isNumeric() || type_ == booleanValue || type_ == stringValue || - type_ == nullValue; - case arrayValue: - return type_ == arrayValue || type_ == nullValue; - case objectValue: - return type_ == objectValue || type_ == nullValue; - } - JSON_ASSERT_UNREACHABLE; - return false; -} - -/// Number of values in array or object -ArrayIndex Value::size() const { - switch (type_) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - case stringValue: - return 0; - case arrayValue: // size of the array is highest index + 1 - if (!value_.map_->empty()) { - ObjectValues::const_iterator itLast = value_.map_->end(); - --itLast; - return (*itLast).first.index() + 1; - } - return 0; - case objectValue: - return ArrayIndex(value_.map_->size()); - } - JSON_ASSERT_UNREACHABLE; - return 0; // unreachable; -} - -bool Value::empty() const { - if (isNull() || isArray() || isObject()) - return size() == 0u; - else - return false; -} - -bool Value::operator!() const { return isNull(); } - -void Value::clear() { - JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || - type_ == objectValue, - "in Json::Value::clear(): requires complex value"); - start_ = 0; - limit_ = 0; - switch (type_) { - case arrayValue: - case objectValue: - value_.map_->clear(); - break; - default: - break; - } -} - -void Value::resize(ArrayIndex newSize) { - JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue, - "in Json::Value::resize(): requires arrayValue"); - if (type_ == nullValue) - *this = Value(arrayValue); - ArrayIndex oldSize = size(); - if (newSize == 0) - clear(); - else if (newSize > oldSize) - (*this)[newSize - 1]; - else { - for (ArrayIndex index = newSize; index < oldSize; ++index) { - value_.map_->erase(index); - } - assert(size() == newSize); - } -} - -Value& Value::operator[](ArrayIndex index) { - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == arrayValue, - "in Json::Value::operator[](ArrayIndex): requires arrayValue"); - if (type_ == nullValue) - *this = Value(arrayValue); - CZString key(index); - ObjectValues::iterator it = value_.map_->lower_bound(key); - if (it != value_.map_->end() && (*it).first == key) - return (*it).second; - - ObjectValues::value_type defaultValue(key, nullRef); - it = value_.map_->insert(it, defaultValue); - return (*it).second; -} - -Value& Value::operator[](int index) { - JSON_ASSERT_MESSAGE( - index >= 0, - "in Json::Value::operator[](int index): index cannot be negative"); - return (*this)[ArrayIndex(index)]; -} - -const Value& Value::operator[](ArrayIndex index) const { - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == arrayValue, - "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); - if (type_ == nullValue) - return nullRef; - CZString key(index); - ObjectValues::const_iterator it = value_.map_->find(key); - if (it == value_.map_->end()) - return nullRef; - return (*it).second; -} - -const Value& Value::operator[](int index) const { - JSON_ASSERT_MESSAGE( - index >= 0, - "in Json::Value::operator[](int index) const: index cannot be negative"); - return (*this)[ArrayIndex(index)]; -} - -void Value::initBasic(ValueType type, bool allocated) { - type_ = type; - allocated_ = allocated; - comments_ = 0; - start_ = 0; - limit_ = 0; -} - -// Access an object value by name, create a null member if it does not exist. -// @pre Type of '*this' is object or null. -// @param key is null-terminated. -Value& Value::resolveReference(const char* key) { - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == objectValue, - "in Json::Value::resolveReference(): requires objectValue"); - if (type_ == nullValue) - *this = Value(objectValue); - CZString actualKey( - key, static_cast(strlen(key)), CZString::noDuplication); // NOTE! - ObjectValues::iterator it = value_.map_->lower_bound(actualKey); - if (it != value_.map_->end() && (*it).first == actualKey) - return (*it).second; - - ObjectValues::value_type defaultValue(actualKey, nullRef); - it = value_.map_->insert(it, defaultValue); - Value& value = (*it).second; - return value; -} - -// @param key is not null-terminated. -Value& Value::resolveReference(char const* key, char const* end) -{ - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == objectValue, - "in Json::Value::resolveReference(key, end): requires objectValue"); - if (type_ == nullValue) - *this = Value(objectValue); - CZString actualKey( - key, static_cast(end-key), CZString::duplicateOnCopy); - ObjectValues::iterator it = value_.map_->lower_bound(actualKey); - if (it != value_.map_->end() && (*it).first == actualKey) - return (*it).second; - - ObjectValues::value_type defaultValue(actualKey, nullRef); - it = value_.map_->insert(it, defaultValue); - Value& value = (*it).second; - return value; -} - -Value Value::get(ArrayIndex index, const Value& defaultValue) const { - const Value* value = &((*this)[index]); - return value == &nullRef ? defaultValue : *value; -} - -bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } - -Value const* Value::find(char const* key, char const* end) const -{ - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == objectValue, - "in Json::Value::find(key, end, found): requires objectValue or nullValue"); - if (type_ == nullValue) return NULL; - CZString actualKey(key, static_cast(end-key), CZString::noDuplication); - ObjectValues::const_iterator it = value_.map_->find(actualKey); - if (it == value_.map_->end()) return NULL; - return &(*it).second; -} -const Value& Value::operator[](const char* key) const -{ - Value const* found = find(key, key + strlen(key)); - if (!found) return nullRef; - return *found; -} -Value const& Value::operator[](std::string const& key) const -{ - Value const* found = find(key.data(), key.data() + key.length()); - if (!found) return nullRef; - return *found; -} - -Value& Value::operator[](const char* key) { - return resolveReference(key, key + strlen(key)); -} - -Value& Value::operator[](const std::string& key) { - return resolveReference(key.data(), key.data() + key.length()); -} - -Value& Value::operator[](const StaticString& key) { - return resolveReference(key.c_str()); -} - -#ifdef JSON_USE_CPPTL -Value& Value::operator[](const CppTL::ConstString& key) { - return resolveReference(key.c_str(), key.end_c_str()); -} -Value const& Value::operator[](CppTL::ConstString const& key) const -{ - Value const* found = find(key.c_str(), key.end_c_str()); - if (!found) return nullRef; - return *found; -} -#endif - -Value& Value::append(const Value& value) { return (*this)[size()] = value; } - -Value Value::get(char const* key, char const* end, Value const& defaultValue) const -{ - Value const* found = find(key, end); - return !found ? defaultValue : *found; -} -Value Value::get(char const* key, Value const& defaultValue) const -{ - return get(key, key + strlen(key), defaultValue); -} -Value Value::get(std::string const& key, Value const& defaultValue) const -{ - return get(key.data(), key.data() + key.length(), defaultValue); -} - - -bool Value::removeMember(const char* key, const char* end, Value* removed) -{ - if (type_ != objectValue) { - return false; - } - CZString actualKey(key, static_cast(end-key), CZString::noDuplication); - ObjectValues::iterator it = value_.map_->find(actualKey); - if (it == value_.map_->end()) - return false; - *removed = it->second; - value_.map_->erase(it); - return true; -} -bool Value::removeMember(const char* key, Value* removed) -{ - return removeMember(key, key + strlen(key), removed); -} -bool Value::removeMember(std::string const& key, Value* removed) -{ - return removeMember(key.data(), key.data() + key.length(), removed); -} -Value Value::removeMember(const char* key) -{ - JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, - "in Json::Value::removeMember(): requires objectValue"); - if (type_ == nullValue) - return nullRef; - - Value removed; // null - removeMember(key, key + strlen(key), &removed); - return removed; // still null if removeMember() did nothing -} -Value Value::removeMember(const std::string& key) -{ - return removeMember(key.c_str()); -} - -bool Value::removeIndex(ArrayIndex index, Value* removed) { - if (type_ != arrayValue) { - return false; - } - CZString key(index); - ObjectValues::iterator it = value_.map_->find(key); - if (it == value_.map_->end()) { - return false; - } - *removed = it->second; - ArrayIndex oldSize = size(); - // shift left all items left, into the place of the "removed" - for (ArrayIndex i = index; i < (oldSize - 1); ++i){ - CZString key(i); - (*value_.map_)[key] = (*this)[i + 1]; - } - // erase the last one ("leftover") - CZString keyLast(oldSize - 1); - ObjectValues::iterator itLast = value_.map_->find(keyLast); - value_.map_->erase(itLast); - return true; -} - -#ifdef JSON_USE_CPPTL -Value Value::get(const CppTL::ConstString& key, - const Value& defaultValue) const { - return get(key.c_str(), key.end_c_str(), defaultValue); -} -#endif - -bool Value::isMember(char const* key, char const* end) const -{ - Value const* value = find(key, end); - return NULL != value; -} -bool Value::isMember(char const* key) const -{ - return isMember(key, key + strlen(key)); -} -bool Value::isMember(std::string const& key) const -{ - return isMember(key.data(), key.data() + key.length()); -} - -#ifdef JSON_USE_CPPTL -bool Value::isMember(const CppTL::ConstString& key) const { - return isMember(key.c_str(), key.end_c_str()); -} -#endif - -Value::Members Value::getMemberNames() const { - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == objectValue, - "in Json::Value::getMemberNames(), value must be objectValue"); - if (type_ == nullValue) - return Value::Members(); - Members members; - members.reserve(value_.map_->size()); - ObjectValues::const_iterator it = value_.map_->begin(); - ObjectValues::const_iterator itEnd = value_.map_->end(); - for (; it != itEnd; ++it) { - members.push_back(std::string((*it).first.data(), - (*it).first.length())); - } - return members; -} -// -//# ifdef JSON_USE_CPPTL -// EnumMemberNames -// Value::enumMemberNames() const -//{ -// if ( type_ == objectValue ) -// { -// return CppTL::Enum::any( CppTL::Enum::transform( -// CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), -// MemberNamesTransform() ) ); -// } -// return EnumMemberNames(); -//} -// -// -// EnumValues -// Value::enumValues() const -//{ -// if ( type_ == objectValue || type_ == arrayValue ) -// return CppTL::Enum::anyValues( *(value_.map_), -// CppTL::Type() ); -// return EnumValues(); -//} -// -//# endif - -static bool IsIntegral(double d) { - double integral_part; - return modf(d, &integral_part) == 0.0; -} - -bool Value::isNull() const { return type_ == nullValue; } - -bool Value::isBool() const { return type_ == booleanValue; } - -bool Value::isInt() const { - switch (type_) { - case intValue: - return value_.int_ >= minInt && value_.int_ <= maxInt; - case uintValue: - return value_.uint_ <= UInt(maxInt); - case realValue: - return value_.real_ >= minInt && value_.real_ <= maxInt && - IsIntegral(value_.real_); - default: - break; - } - return false; -} - -bool Value::isUInt() const { - switch (type_) { - case intValue: - return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); - case uintValue: - return value_.uint_ <= maxUInt; - case realValue: - return value_.real_ >= 0 && value_.real_ <= maxUInt && - IsIntegral(value_.real_); - default: - break; - } - return false; -} - -bool Value::isInt64() const { -#if defined(JSON_HAS_INT64) - switch (type_) { - case intValue: - return true; - case uintValue: - return value_.uint_ <= UInt64(maxInt64); - case realValue: - // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a - // double, so double(maxInt64) will be rounded up to 2^63. Therefore we - // require the value to be strictly less than the limit. - return value_.real_ >= double(minInt64) && - value_.real_ < double(maxInt64) && IsIntegral(value_.real_); - default: - break; - } -#endif // JSON_HAS_INT64 - return false; -} - -bool Value::isUInt64() const { -#if defined(JSON_HAS_INT64) - switch (type_) { - case intValue: - return value_.int_ >= 0; - case uintValue: - return true; - case realValue: - // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a - // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we - // require the value to be strictly less than the limit. - return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && - IsIntegral(value_.real_); - default: - break; - } -#endif // JSON_HAS_INT64 - return false; -} - -bool Value::isIntegral() const { -#if defined(JSON_HAS_INT64) - return isInt64() || isUInt64(); -#else - return isInt() || isUInt(); -#endif -} - -bool Value::isDouble() const { return type_ == realValue || isIntegral(); } - -bool Value::isNumeric() const { return isIntegral() || isDouble(); } - -bool Value::isString() const { return type_ == stringValue; } - -bool Value::isArray() const { return type_ == arrayValue; } - -bool Value::isObject() const { return type_ == objectValue; } - -void Value::setComment(const char* comment, size_t len, CommentPlacement placement) { - if (!comments_) - comments_ = new CommentInfo[numberOfCommentPlacement]; - if ((len > 0) && (comment[len-1] == '\n')) { - // Always discard trailing newline, to aid indentation. - len -= 1; - } - comments_[placement].setComment(comment, len); -} - -void Value::setComment(const char* comment, CommentPlacement placement) { - setComment(comment, strlen(comment), placement); -} - -void Value::setComment(const std::string& comment, CommentPlacement placement) { - setComment(comment.c_str(), comment.length(), placement); -} - -bool Value::hasComment(CommentPlacement placement) const { - return comments_ != 0 && comments_[placement].comment_ != 0; -} - -std::string Value::getComment(CommentPlacement placement) const { - if (hasComment(placement)) - return comments_[placement].comment_; - return ""; -} - -void Value::setOffsetStart(size_t start) { start_ = start; } - -void Value::setOffsetLimit(size_t limit) { limit_ = limit; } - -size_t Value::getOffsetStart() const { return start_; } - -size_t Value::getOffsetLimit() const { return limit_; } - -std::string Value::toStyledString() const { - StyledWriter writer; - return writer.write(*this); -} - -Value::const_iterator Value::begin() const { - switch (type_) { - case arrayValue: - case objectValue: - if (value_.map_) - return const_iterator(value_.map_->begin()); - break; - default: - break; - } - return const_iterator(); -} - -Value::const_iterator Value::end() const { - switch (type_) { - case arrayValue: - case objectValue: - if (value_.map_) - return const_iterator(value_.map_->end()); - break; - default: - break; - } - return const_iterator(); -} - -Value::iterator Value::begin() { - switch (type_) { - case arrayValue: - case objectValue: - if (value_.map_) - return iterator(value_.map_->begin()); - break; - default: - break; - } - return iterator(); -} - -Value::iterator Value::end() { - switch (type_) { - case arrayValue: - case objectValue: - if (value_.map_) - return iterator(value_.map_->end()); - break; - default: - break; - } - return iterator(); -} - -// class PathArgument -// ////////////////////////////////////////////////////////////////// - -PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {} - -PathArgument::PathArgument(ArrayIndex index) - : key_(), index_(index), kind_(kindIndex) {} - -PathArgument::PathArgument(const char* key) - : key_(key), index_(), kind_(kindKey) {} - -PathArgument::PathArgument(const std::string& key) - : key_(key.c_str()), index_(), kind_(kindKey) {} - -// class Path -// ////////////////////////////////////////////////////////////////// - -Path::Path(const std::string& path, - const PathArgument& a1, - const PathArgument& a2, - const PathArgument& a3, - const PathArgument& a4, - const PathArgument& a5) { - InArgs in; - in.push_back(&a1); - in.push_back(&a2); - in.push_back(&a3); - in.push_back(&a4); - in.push_back(&a5); - makePath(path, in); -} - -void Path::makePath(const std::string& path, const InArgs& in) { - const char* current = path.c_str(); - const char* end = current + path.length(); - InArgs::const_iterator itInArg = in.begin(); - while (current != end) { - if (*current == '[') { - ++current; - if (*current == '%') - addPathInArg(path, in, itInArg, PathArgument::kindIndex); - else { - ArrayIndex index = 0; - for (; current != end && *current >= '0' && *current <= '9'; ++current) - index = index * 10 + ArrayIndex(*current - '0'); - args_.push_back(index); - } - if (current == end || *current++ != ']') - invalidPath(path, int(current - path.c_str())); - } else if (*current == '%') { - addPathInArg(path, in, itInArg, PathArgument::kindKey); - ++current; - } else if (*current == '.') { - ++current; - } else { - const char* beginName = current; - while (current != end && !strchr("[.", *current)) - ++current; - args_.push_back(std::string(beginName, current)); - } - } -} - -void Path::addPathInArg(const std::string& /*path*/, - const InArgs& in, - InArgs::const_iterator& itInArg, - PathArgument::Kind kind) { - if (itInArg == in.end()) { - // Error: missing argument %d - } else if ((*itInArg)->kind_ != kind) { - // Error: bad argument type - } else { - args_.push_back(**itInArg); - } -} - -void Path::invalidPath(const std::string& /*path*/, int /*location*/) { - // Error: invalid path. -} - -const Value& Path::resolve(const Value& root) const { - const Value* node = &root; - for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { - const PathArgument& arg = *it; - if (arg.kind_ == PathArgument::kindIndex) { - if (!node->isArray() || !node->isValidIndex(arg.index_)) { - // Error: unable to resolve path (array value expected at position... - } - node = &((*node)[arg.index_]); - } else if (arg.kind_ == PathArgument::kindKey) { - if (!node->isObject()) { - // Error: unable to resolve path (object value expected at position...) - } - node = &((*node)[arg.key_]); - if (node == &Value::nullRef) { - // Error: unable to resolve path (object has no member named '' at - // position...) - } - } - } - return *node; -} - -Value Path::resolve(const Value& root, const Value& defaultValue) const { - const Value* node = &root; - for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { - const PathArgument& arg = *it; - if (arg.kind_ == PathArgument::kindIndex) { - if (!node->isArray() || !node->isValidIndex(arg.index_)) - return defaultValue; - node = &((*node)[arg.index_]); - } else if (arg.kind_ == PathArgument::kindKey) { - if (!node->isObject()) - return defaultValue; - node = &((*node)[arg.key_]); - if (node == &Value::nullRef) - return defaultValue; - } - } - return *node; -} - -Value& Path::make(Value& root) const { - Value* node = &root; - for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { - const PathArgument& arg = *it; - if (arg.kind_ == PathArgument::kindIndex) { - if (!node->isArray()) { - // Error: node is not an array at position ... - } - node = &((*node)[arg.index_]); - } else if (arg.kind_ == PathArgument::kindKey) { - if (!node->isObject()) { - // Error: node is not an object at position... - } - node = &((*node)[arg.key_]); - } - } - return *node; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_value.cpp -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_writer.cpp -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2011 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -#include -#include "json_tool.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0 -#include -#define isfinite _finite -#elif defined(__sun) && defined(__SVR4) //Solaris -#include -#define isfinite finite -#else -#include -#define isfinite std::isfinite -#endif - -#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below -#define snprintf _snprintf -#elif __cplusplus >= 201103L -#ifndef __CYGWIN__ -#define snprintf std::snprintf -#endif -#endif - -#if defined(__BORLANDC__) -#include -#define isfinite _finite -#define snprintf _snprintf -#endif - -#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 -// Disable warning about strdup being deprecated. -#pragma warning(disable : 4996) -#endif - -namespace Json { - -#if __cplusplus >= 201103L -typedef std::unique_ptr StreamWriterPtr; -#else -typedef std::auto_ptr StreamWriterPtr; -#endif - -static bool containsControlCharacter(const char* str) { - while (*str) { - if (isControlCharacter(*(str++))) - return true; - } - return false; -} - -static bool containsControlCharacter0(const char* str, unsigned len) { - char const* end = str + len; - while (end != str) { - if (isControlCharacter(*str) || 0==*str) - return true; - ++str; - } - return false; -} - -std::string valueToString(LargestInt value) { - UIntToStringBuffer buffer; - char* current = buffer + sizeof(buffer); - bool isNegative = value < 0; - if (isNegative) - value = -value; - uintToString(LargestUInt(value), current); - if (isNegative) - *--current = '-'; - assert(current >= buffer); - return current; -} - -std::string valueToString(LargestUInt value) { - UIntToStringBuffer buffer; - char* current = buffer + sizeof(buffer); - uintToString(value, current); - assert(current >= buffer); - return current; -} - -#if defined(JSON_HAS_INT64) - -std::string valueToString(Int value) { - return valueToString(LargestInt(value)); -} - -std::string valueToString(UInt value) { - return valueToString(LargestUInt(value)); -} - -#endif // # if defined(JSON_HAS_INT64) - -std::string valueToString(double value) { - // Allocate a buffer that is more than large enough to store the 16 digits of - // precision requested below. - char buffer[32]; - int len = -1; - -// Print into the buffer. We need not request the alternative representation -// that always has a decimal point because JSON doesn't distingish the -// concepts of reals and integers. -#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with - // visual studio 2005 to - // avoid warning. -#if defined(WINCE) - len = _snprintf(buffer, sizeof(buffer), "%.17g", value); -#else - len = sprintf_s(buffer, sizeof(buffer), "%.17g", value); -#endif -#else - if (isfinite(value)) { - len = snprintf(buffer, sizeof(buffer), "%.17g", value); - } else { - // IEEE standard states that NaN values will not compare to themselves - if (value != value) { - len = snprintf(buffer, sizeof(buffer), "null"); - } else if (value < 0) { - len = snprintf(buffer, sizeof(buffer), "-1e+9999"); - } else { - len = snprintf(buffer, sizeof(buffer), "1e+9999"); - } - // For those, we do not need to call fixNumLoc, but it is fast. - } -#endif - assert(len >= 0); - fixNumericLocale(buffer, buffer + len); - return buffer; -} - -std::string valueToString(bool value) { return value ? "true" : "false"; } - -std::string valueToQuotedString(const char* value) { - if (value == NULL) - return ""; - // Not sure how to handle unicode... - if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && - !containsControlCharacter(value)) - return std::string("\"") + value + "\""; - // We have to walk value and escape any special characters. - // Appending to std::string is not efficient, but this should be rare. - // (Note: forward slashes are *not* rare, but I am not escaping them.) - std::string::size_type maxsize = - strlen(value) * 2 + 3; // allescaped+quotes+NULL - std::string result; - result.reserve(maxsize); // to avoid lots of mallocs - result += "\""; - for (const char* c = value; *c != 0; ++c) { - switch (*c) { - case '\"': - result += "\\\""; - break; - case '\\': - result += "\\\\"; - break; - case '\b': - result += "\\b"; - break; - case '\f': - result += "\\f"; - break; - case '\n': - result += "\\n"; - break; - case '\r': - result += "\\r"; - break; - case '\t': - result += "\\t"; - break; - // case '/': - // Even though \/ is considered a legal escape in JSON, a bare - // slash is also legal, so I see no reason to escape it. - // (I hope I am not misunderstanding something. - // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); - result += oss.str(); - } else { - result += *c; - } - break; - } - } - result += "\""; - return result; -} - -// https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp -static char const* strnpbrk(char const* s, char const* accept, size_t n) { - assert((s || !n) && accept); - - char const* const end = s + n; - for (char const* cur = s; cur < end; ++cur) { - int const c = *cur; - for (char const* a = accept; *a; ++a) { - if (*a == c) { - return cur; - } - } - } - return NULL; -} -static std::string valueToQuotedStringN(const char* value, unsigned length) { - if (value == NULL) - return ""; - // Not sure how to handle unicode... - if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL && - !containsControlCharacter0(value, length)) - return std::string("\"") + value + "\""; - // We have to walk value and escape any special characters. - // Appending to std::string is not efficient, but this should be rare. - // (Note: forward slashes are *not* rare, but I am not escaping them.) - std::string::size_type maxsize = - length * 2 + 3; // allescaped+quotes+NULL - std::string result; - result.reserve(maxsize); // to avoid lots of mallocs - result += "\""; - char const* end = value + length; - for (const char* c = value; c != end; ++c) { - switch (*c) { - case '\"': - result += "\\\""; - break; - case '\\': - result += "\\\\"; - break; - case '\b': - result += "\\b"; - break; - case '\f': - result += "\\f"; - break; - case '\n': - result += "\\n"; - break; - case '\r': - result += "\\r"; - break; - case '\t': - result += "\\t"; - break; - // case '/': - // Even though \/ is considered a legal escape in JSON, a bare - // slash is also legal, so I see no reason to escape it. - // (I hope I am not misunderstanding something.) - // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); - result += oss.str(); - } else { - result += *c; - } - break; - } - } - result += "\""; - return result; -} - -// Class Writer -// ////////////////////////////////////////////////////////////////// -Writer::~Writer() {} - -// Class FastWriter -// ////////////////////////////////////////////////////////////////// - -FastWriter::FastWriter() - : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false), - omitEndingLineFeed_(false) {} - -void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } - -void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } - -void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } - -std::string FastWriter::write(const Value& root) { - document_ = ""; - writeValue(root); - if (!omitEndingLineFeed_) - document_ += "\n"; - return document_; -} - -void FastWriter::writeValue(const Value& value) { - switch (value.type()) { - case nullValue: - if (!dropNullPlaceholders_) - document_ += "null"; - break; - case intValue: - document_ += valueToString(value.asLargestInt()); - break; - case uintValue: - document_ += valueToString(value.asLargestUInt()); - break; - case realValue: - document_ += valueToString(value.asDouble()); - break; - case stringValue: - { - // Is NULL possible for value.string_? - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) document_ += valueToQuotedStringN(str, static_cast(end-str)); - break; - } - case booleanValue: - document_ += valueToString(value.asBool()); - break; - case arrayValue: { - document_ += '['; - int size = value.size(); - for (int index = 0; index < size; ++index) { - if (index > 0) - document_ += ','; - writeValue(value[index]); - } - document_ += ']'; - } break; - case objectValue: { - Value::Members members(value.getMemberNames()); - document_ += '{'; - for (Value::Members::iterator it = members.begin(); it != members.end(); - ++it) { - const std::string& name = *it; - if (it != members.begin()) - document_ += ','; - document_ += valueToQuotedStringN(name.data(), name.length()); - document_ += yamlCompatiblityEnabled_ ? ": " : ":"; - writeValue(value[name]); - } - document_ += '}'; - } break; - } -} - -// Class StyledWriter -// ////////////////////////////////////////////////////////////////// - -StyledWriter::StyledWriter() - : rightMargin_(74), indentSize_(3), addChildValues_() {} - -std::string StyledWriter::write(const Value& root) { - document_ = ""; - addChildValues_ = false; - indentString_ = ""; - writeCommentBeforeValue(root); - writeValue(root); - writeCommentAfterValueOnSameLine(root); - document_ += "\n"; - return document_; -} - -void StyledWriter::writeValue(const Value& value) { - switch (value.type()) { - case nullValue: - pushValue("null"); - break; - case intValue: - pushValue(valueToString(value.asLargestInt())); - break; - case uintValue: - pushValue(valueToString(value.asLargestUInt())); - break; - case realValue: - pushValue(valueToString(value.asDouble())); - break; - case stringValue: - { - // Is NULL possible for value.string_? - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); - else pushValue(""); - break; - } - case booleanValue: - pushValue(valueToString(value.asBool())); - break; - case arrayValue: - writeArrayValue(value); - break; - case objectValue: { - Value::Members members(value.getMemberNames()); - if (members.empty()) - pushValue("{}"); - else { - writeWithIndent("{"); - indent(); - Value::Members::iterator it = members.begin(); - for (;;) { - const std::string& name = *it; - const Value& childValue = value[name]; - writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedString(name.c_str())); - document_ += " : "; - writeValue(childValue); - if (++it == members.end()) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - document_ += ','; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("}"); - } - } break; - } -} - -void StyledWriter::writeArrayValue(const Value& value) { - unsigned size = value.size(); - if (size == 0) - pushValue("[]"); - else { - bool isArrayMultiLine = isMultineArray(value); - if (isArrayMultiLine) { - writeWithIndent("["); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index = 0; - for (;;) { - const Value& childValue = value[index]; - writeCommentBeforeValue(childValue); - if (hasChildValue) - writeWithIndent(childValues_[index]); - else { - writeIndent(); - writeValue(childValue); - } - if (++index == size) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - document_ += ','; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("]"); - } else // output on a single line - { - assert(childValues_.size() == size); - document_ += "[ "; - for (unsigned index = 0; index < size; ++index) { - if (index > 0) - document_ += ", "; - document_ += childValues_[index]; - } - document_ += " ]"; - } - } -} - -bool StyledWriter::isMultineArray(const Value& value) { - int size = value.size(); - bool isMultiLine = size * 3 >= rightMargin_; - childValues_.clear(); - for (int index = 0; index < size && !isMultiLine; ++index) { - const Value& childValue = value[index]; - isMultiLine = - isMultiLine || ((childValue.isArray() || childValue.isObject()) && - childValue.size() > 0); - } - if (!isMultiLine) // check if line length > max line length - { - childValues_.reserve(size); - addChildValues_ = true; - int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (int index = 0; index < size; ++index) { - if (hasCommentForValue(value[index])) { - isMultiLine = true; - } - writeValue(value[index]); - lineLength += int(childValues_[index].length()); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - -void StyledWriter::pushValue(const std::string& value) { - if (addChildValues_) - childValues_.push_back(value); - else - document_ += value; -} - -void StyledWriter::writeIndent() { - if (!document_.empty()) { - char last = document_[document_.length() - 1]; - if (last == ' ') // already indented - return; - if (last != '\n') // Comments may add new-line - document_ += '\n'; - } - document_ += indentString_; -} - -void StyledWriter::writeWithIndent(const std::string& value) { - writeIndent(); - document_ += value; -} - -void StyledWriter::indent() { indentString_ += std::string(indentSize_, ' '); } - -void StyledWriter::unindent() { - assert(int(indentString_.size()) >= indentSize_); - indentString_.resize(indentString_.size() - indentSize_); -} - -void StyledWriter::writeCommentBeforeValue(const Value& root) { - if (!root.hasComment(commentBefore)) - return; - - document_ += "\n"; - writeIndent(); - const std::string& comment = root.getComment(commentBefore); - std::string::const_iterator iter = comment.begin(); - while (iter != comment.end()) { - document_ += *iter; - if (*iter == '\n' && - (iter != comment.end() && *(iter + 1) == '/')) - writeIndent(); - ++iter; - } - - // Comments are stripped of trailing newlines, so add one here - document_ += "\n"; -} - -void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { - if (root.hasComment(commentAfterOnSameLine)) - document_ += " " + root.getComment(commentAfterOnSameLine); - - if (root.hasComment(commentAfter)) { - document_ += "\n"; - document_ += root.getComment(commentAfter); - document_ += "\n"; - } -} - -bool StyledWriter::hasCommentForValue(const Value& value) { - return value.hasComment(commentBefore) || - value.hasComment(commentAfterOnSameLine) || - value.hasComment(commentAfter); -} - -// Class StyledStreamWriter -// ////////////////////////////////////////////////////////////////// - -StyledStreamWriter::StyledStreamWriter(std::string indentation) - : document_(NULL), rightMargin_(74), indentation_(indentation), - addChildValues_() {} - -void StyledStreamWriter::write(std::ostream& out, const Value& root) { - document_ = &out; - addChildValues_ = false; - indentString_ = ""; - indented_ = true; - writeCommentBeforeValue(root); - if (!indented_) writeIndent(); - indented_ = true; - writeValue(root); - writeCommentAfterValueOnSameLine(root); - *document_ << "\n"; - document_ = NULL; // Forget the stream, for safety. -} - -void StyledStreamWriter::writeValue(const Value& value) { - switch (value.type()) { - case nullValue: - pushValue("null"); - break; - case intValue: - pushValue(valueToString(value.asLargestInt())); - break; - case uintValue: - pushValue(valueToString(value.asLargestUInt())); - break; - case realValue: - pushValue(valueToString(value.asDouble())); - break; - case stringValue: - { - // Is NULL possible for value.string_? - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); - else pushValue(""); - break; - } - case booleanValue: - pushValue(valueToString(value.asBool())); - break; - case arrayValue: - writeArrayValue(value); - break; - case objectValue: { - Value::Members members(value.getMemberNames()); - if (members.empty()) - pushValue("{}"); - else { - writeWithIndent("{"); - indent(); - Value::Members::iterator it = members.begin(); - for (;;) { - const std::string& name = *it; - const Value& childValue = value[name]; - writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedString(name.c_str())); - *document_ << " : "; - writeValue(childValue); - if (++it == members.end()) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("}"); - } - } break; - } -} - -void StyledStreamWriter::writeArrayValue(const Value& value) { - unsigned size = value.size(); - if (size == 0) - pushValue("[]"); - else { - bool isArrayMultiLine = isMultineArray(value); - if (isArrayMultiLine) { - writeWithIndent("["); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index = 0; - for (;;) { - const Value& childValue = value[index]; - writeCommentBeforeValue(childValue); - if (hasChildValue) - writeWithIndent(childValues_[index]); - else { - if (!indented_) writeIndent(); - indented_ = true; - writeValue(childValue); - indented_ = false; - } - if (++index == size) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("]"); - } else // output on a single line - { - assert(childValues_.size() == size); - *document_ << "[ "; - for (unsigned index = 0; index < size; ++index) { - if (index > 0) - *document_ << ", "; - *document_ << childValues_[index]; - } - *document_ << " ]"; - } - } -} - -bool StyledStreamWriter::isMultineArray(const Value& value) { - int size = value.size(); - bool isMultiLine = size * 3 >= rightMargin_; - childValues_.clear(); - for (int index = 0; index < size && !isMultiLine; ++index) { - const Value& childValue = value[index]; - isMultiLine = - isMultiLine || ((childValue.isArray() || childValue.isObject()) && - childValue.size() > 0); - } - if (!isMultiLine) // check if line length > max line length - { - childValues_.reserve(size); - addChildValues_ = true; - int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (int index = 0; index < size; ++index) { - if (hasCommentForValue(value[index])) { - isMultiLine = true; - } - writeValue(value[index]); - lineLength += int(childValues_[index].length()); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - -void StyledStreamWriter::pushValue(const std::string& value) { - if (addChildValues_) - childValues_.push_back(value); - else - *document_ << value; -} - -void StyledStreamWriter::writeIndent() { - // blep intended this to look at the so-far-written string - // to determine whether we are already indented, but - // with a stream we cannot do that. So we rely on some saved state. - // The caller checks indented_. - *document_ << '\n' << indentString_; -} - -void StyledStreamWriter::writeWithIndent(const std::string& value) { - if ( value == "{" ) { - *document_ << value; - if (!indented_) writeIndent(); - indented_ = false; - return; - } - if (!indented_) writeIndent(); - *document_ << value; - indented_ = false; -} - -void StyledStreamWriter::indent() { indentString_ += indentation_; } - -void StyledStreamWriter::unindent() { - assert(indentString_.size() >= indentation_.size()); - indentString_.resize(indentString_.size() - indentation_.size()); -} - -void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { - if (!root.hasComment(commentBefore)) - return; - - if (!indented_) writeIndent(); - const std::string& comment = root.getComment(commentBefore); - std::string::const_iterator iter = comment.begin(); - while (iter != comment.end()) { - *document_ << *iter; - if (*iter == '\n' && - (iter != comment.end() && *(iter + 1) == '/')) - // writeIndent(); // would include newline - *document_ << indentString_; - ++iter; - } - indented_ = false; -} - -void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { - if (root.hasComment(commentAfterOnSameLine)) - *document_ << ' ' << root.getComment(commentAfterOnSameLine); - - if (root.hasComment(commentAfter)) { - writeIndent(); - *document_ << root.getComment(commentAfter); - } - indented_ = false; -} - -bool StyledStreamWriter::hasCommentForValue(const Value& value) { - return value.hasComment(commentBefore) || - value.hasComment(commentAfterOnSameLine) || - value.hasComment(commentAfter); -} - -////////////////////////// -// BuiltStyledStreamWriter - -/// Scoped enums are not available until C++11. -struct CommentStyle { - /// Decide whether to write comments. - enum Enum { - None, ///< Drop all comments. - Most, ///< Recover odd behavior of previous versions (not implemented yet). - All ///< Keep all comments. - }; -}; - -struct BuiltStyledStreamWriter : public StreamWriter -{ - BuiltStyledStreamWriter( - std::string const& indentation, - CommentStyle::Enum cs, - std::string const& colonSymbol, - std::string const& nullSymbol, - std::string const& endingLineFeedSymbol); - virtual int write(Value const& root, std::ostream* sout); -private: - void writeValue(Value const& value); - void writeArrayValue(Value const& value); - bool isMultineArray(Value const& value); - void pushValue(std::string const& value); - void writeIndent(); - void writeWithIndent(std::string const& value); - void indent(); - void unindent(); - void writeCommentBeforeValue(Value const& root); - void writeCommentAfterValueOnSameLine(Value const& root); - static bool hasCommentForValue(const Value& value); - - typedef std::vector ChildValues; - - ChildValues childValues_; - std::string indentString_; - int rightMargin_; - std::string indentation_; - CommentStyle::Enum cs_; - std::string colonSymbol_; - std::string nullSymbol_; - std::string endingLineFeedSymbol_; - bool addChildValues_ : 1; - bool indented_ : 1; -}; -BuiltStyledStreamWriter::BuiltStyledStreamWriter( - std::string const& indentation, - CommentStyle::Enum cs, - std::string const& colonSymbol, - std::string const& nullSymbol, - std::string const& endingLineFeedSymbol) - : rightMargin_(74) - , indentation_(indentation) - , cs_(cs) - , colonSymbol_(colonSymbol) - , nullSymbol_(nullSymbol) - , endingLineFeedSymbol_(endingLineFeedSymbol) - , addChildValues_(false) - , indented_(false) -{ -} -int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout) -{ - sout_ = sout; - addChildValues_ = false; - indented_ = true; - indentString_ = ""; - writeCommentBeforeValue(root); - if (!indented_) writeIndent(); - indented_ = true; - writeValue(root); - writeCommentAfterValueOnSameLine(root); - *sout_ << endingLineFeedSymbol_; - sout_ = NULL; - return 0; -} -void BuiltStyledStreamWriter::writeValue(Value const& value) { - switch (value.type()) { - case nullValue: - pushValue(nullSymbol_); - break; - case intValue: - pushValue(valueToString(value.asLargestInt())); - break; - case uintValue: - pushValue(valueToString(value.asLargestUInt())); - break; - case realValue: - pushValue(valueToString(value.asDouble())); - break; - case stringValue: - { - // Is NULL is possible for value.string_? - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); - else pushValue(""); - break; - } - case booleanValue: - pushValue(valueToString(value.asBool())); - break; - case arrayValue: - writeArrayValue(value); - break; - case objectValue: { - Value::Members members(value.getMemberNames()); - if (members.empty()) - pushValue("{}"); - else { - writeWithIndent("{"); - indent(); - Value::Members::iterator it = members.begin(); - for (;;) { - std::string const& name = *it; - Value const& childValue = value[name]; - writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedStringN(name.data(), name.length())); - *sout_ << colonSymbol_; - writeValue(childValue); - if (++it == members.end()) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *sout_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("}"); - } - } break; - } -} - -void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { - unsigned size = value.size(); - if (size == 0) - pushValue("[]"); - else { - bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value); - if (isMultiLine) { - writeWithIndent("["); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index = 0; - for (;;) { - Value const& childValue = value[index]; - writeCommentBeforeValue(childValue); - if (hasChildValue) - writeWithIndent(childValues_[index]); - else { - if (!indented_) writeIndent(); - indented_ = true; - writeValue(childValue); - indented_ = false; - } - if (++index == size) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *sout_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("]"); - } else // output on a single line - { - assert(childValues_.size() == size); - *sout_ << "["; - if (!indentation_.empty()) *sout_ << " "; - for (unsigned index = 0; index < size; ++index) { - if (index > 0) - *sout_ << ", "; - *sout_ << childValues_[index]; - } - if (!indentation_.empty()) *sout_ << " "; - *sout_ << "]"; - } - } -} - -bool BuiltStyledStreamWriter::isMultineArray(Value const& value) { - int size = value.size(); - bool isMultiLine = size * 3 >= rightMargin_; - childValues_.clear(); - for (int index = 0; index < size && !isMultiLine; ++index) { - Value const& childValue = value[index]; - isMultiLine = - isMultiLine || ((childValue.isArray() || childValue.isObject()) && - childValue.size() > 0); - } - if (!isMultiLine) // check if line length > max line length - { - childValues_.reserve(size); - addChildValues_ = true; - int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (int index = 0; index < size; ++index) { - if (hasCommentForValue(value[index])) { - isMultiLine = true; - } - writeValue(value[index]); - lineLength += int(childValues_[index].length()); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - -void BuiltStyledStreamWriter::pushValue(std::string const& value) { - if (addChildValues_) - childValues_.push_back(value); - else - *sout_ << value; -} - -void BuiltStyledStreamWriter::writeIndent() { - // blep intended this to look at the so-far-written string - // to determine whether we are already indented, but - // with a stream we cannot do that. So we rely on some saved state. - // The caller checks indented_. - - if (!indentation_.empty()) { - // In this case, drop newlines too. - *sout_ << '\n' << indentString_; - } -} - -void BuiltStyledStreamWriter::writeWithIndent(std::string const& value) { - if ( value == "{" ) { - *sout_ << value; - if ( sout_->tellp() < 2 ) { - if (!indented_) writeIndent(); - indented_ = false; - } - return; - } - if (!indented_) writeIndent(); - *sout_ << value; - indented_ = false; -} - -void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } - -void BuiltStyledStreamWriter::unindent() { - assert(indentString_.size() >= indentation_.size()); - indentString_.resize(indentString_.size() - indentation_.size()); -} - -void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { - if (cs_ == CommentStyle::None) return; - if (!root.hasComment(commentBefore)) - return; - - if (!indented_) writeIndent(); - const std::string& comment = root.getComment(commentBefore); - std::string::const_iterator iter = comment.begin(); - while (iter != comment.end()) { - *sout_ << *iter; - if (*iter == '\n' && - (iter != comment.end() && *(iter + 1) == '/')) - // writeIndent(); // would write extra newline - *sout_ << indentString_; - ++iter; - } - indented_ = false; -} - -void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) { - if (cs_ == CommentStyle::None) return; - if (root.hasComment(commentAfterOnSameLine)) - *sout_ << " " + root.getComment(commentAfterOnSameLine); - - if (root.hasComment(commentAfter)) { - writeIndent(); - *sout_ << root.getComment(commentAfter); - } -} - -// static -bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { - return value.hasComment(commentBefore) || - value.hasComment(commentAfterOnSameLine) || - value.hasComment(commentAfter); -} - -/////////////// -// StreamWriter - -StreamWriter::StreamWriter() - : sout_(NULL) -{ -} -StreamWriter::~StreamWriter() -{ -} -StreamWriter::Factory::~Factory() -{} -StreamWriterBuilder::StreamWriterBuilder() -{ - setDefaults(&settings_); -} -StreamWriterBuilder::~StreamWriterBuilder() -{} -StreamWriter* StreamWriterBuilder::newStreamWriter() const -{ - std::string indentation = settings_["indentation"].asString(); - std::string cs_str = settings_["commentStyle"].asString(); - bool eyc = settings_["enableYAMLCompatibility"].asBool(); - bool dnp = settings_["dropNullPlaceholders"].asBool(); - CommentStyle::Enum cs = CommentStyle::All; - if (cs_str == "All") { - cs = CommentStyle::All; - } else if (cs_str == "None") { - cs = CommentStyle::None; - } else { - throwRuntimeError("commentStyle must be 'All' or 'None'"); - } - std::string colonSymbol = " : "; - if (eyc) { - colonSymbol = ": "; - } else if (indentation.empty()) { - colonSymbol = ":"; - } - std::string nullSymbol = "null"; - if (dnp) { - nullSymbol = ""; - } - std::string endingLineFeedSymbol = ""; - return new BuiltStyledStreamWriter( - indentation, cs, - colonSymbol, nullSymbol, endingLineFeedSymbol); -} -static void getValidWriterKeys(std::set* valid_keys) -{ - valid_keys->clear(); - valid_keys->insert("indentation"); - valid_keys->insert("commentStyle"); - valid_keys->insert("enableYAMLCompatibility"); - valid_keys->insert("dropNullPlaceholders"); -} -bool StreamWriterBuilder::validate(Json::Value* invalid) const -{ - Json::Value my_invalid; - if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL - Json::Value& inv = *invalid; - std::set valid_keys; - getValidWriterKeys(&valid_keys); - Value::Members keys = settings_.getMemberNames(); - size_t n = keys.size(); - for (size_t i = 0; i < n; ++i) { - std::string const& key = keys[i]; - if (valid_keys.find(key) == valid_keys.end()) { - inv[key] = settings_[key]; - } - } - return 0u == inv.size(); -} -Value& StreamWriterBuilder::operator[](std::string key) -{ - return settings_[key]; -} -// static -void StreamWriterBuilder::setDefaults(Json::Value* settings) -{ - //! [StreamWriterBuilderDefaults] - (*settings)["commentStyle"] = "All"; - (*settings)["indentation"] = "\t"; - (*settings)["enableYAMLCompatibility"] = false; - (*settings)["dropNullPlaceholders"] = false; - //! [StreamWriterBuilderDefaults] -} - -std::string writeString(StreamWriter::Factory const& builder, Value const& root) { - std::ostringstream sout; - StreamWriterPtr const writer(builder.newStreamWriter()); - writer->write(root, &sout); - return sout.str(); -} - -std::ostream& operator<<(std::ostream& sout, Value const& root) { - StreamWriterBuilder builder; - StreamWriterPtr const writer(builder.newStreamWriter()); - writer->write(root, &sout); - return sout; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_writer.cpp -// ////////////////////////////////////////////////////////////////////// - - - - - -#endif \ No newline at end of file diff --git a/engine/src/ext/lua/lua.cpp b/engine/src/ext/lua/lua.cpp index 1ceb4599..26b85bf7 100644 --- a/engine/src/ext/lua/lua.cpp +++ b/engine/src/ext/lua/lua.cpp @@ -2,161 +2,97 @@ sol::state ext::lua::state; std::string ext::lua::main = "./data/scripts/main.lua"; +std::unordered_map ext::lua::modules; #include #include #include +#include #include #include #include +#include #include +#include + +sol::table ext::lua::createTable() { + return sol::table(ext::lua::state, sol::create); +} +std::string ext::lua::sanitize( const std::string& dirty, int index ) { + auto split = uf::string::split( dirty, "::" ); + if ( index < 0 ) index = split.size() + index; + std::string part = split.at(index); + part = uf::string::replace( part, "<>", "" ); + return part; +} +std::optional ext::lua::encode( sol::table table ) { + sol::protected_function fun = ext::lua::state["json"]["encode"]; + auto result = fun( table ); + if ( !result.valid() ) { + sol::error err = result; + uf::iostream << err.what() << "\n"; + return "{}"; + } + return result; +} +std::optional ext::lua::decode( const std::string& string ) { + sol::protected_function fun = ext::lua::state["json"]["decode"]; + auto result = fun( string ); + if ( !result.valid() ) { + sol::error err = result; + uf::iostream << err.what() << "\n"; + return createTable(); + } + return result; +} + +std::vector>* ext::lua::onInitializationFunctions = NULL; +void ext::lua::onInitialization( const std::function& function ) { + if ( !ext::lua::onInitializationFunctions ) { + ext::lua::onInitializationFunctions = new std::vector>; + } + auto& functions = *ext::lua::onInitializationFunctions; + functions.emplace_back(function); +} void ext::lua::initialize() { - state.open_libraries(sol::lib::base, sol::lib::package, sol::lib::table, sol::lib::math, sol::lib::string); + state.open_libraries(sol::lib::base, sol::lib::package, sol::lib::table, sol::lib::math, sol::lib::string, sol::lib::ffi, sol::lib::jit); - POD_LUA_REGISTER_USERTYPE_BEGIN(Matrix4f) - "value", []( pod::Matrix4f& self, const size_t& index ) { - return self[index]; + // load modules + for ( auto pair : modules ) { + const std::string& name = pair.first; + const std::string& script = pair.second; + if ( uf::io::extension(script) == "lua" ) { + state.require_file(name, uf::io::resolveURI( script ), true); + } else { + state.require_script(name, script, true); } - POD_LUA_REGISTER_USERTYPE_END() - POD_LUA_REGISTER_USERTYPE_BEGIN(Vector3f) - POD_LUA_REGISTER_USERTYPE_MEMBER(Vector3f, x), - POD_LUA_REGISTER_USERTYPE_MEMBER(Vector3f, y), - POD_LUA_REGISTER_USERTYPE_MEMBER(Vector3f, z) - POD_LUA_REGISTER_USERTYPE_END() - POD_LUA_REGISTER_USERTYPE_BEGIN(Vector4f) - POD_LUA_REGISTER_USERTYPE_MEMBER(Vector4f, x), - POD_LUA_REGISTER_USERTYPE_MEMBER(Vector4f, y), - POD_LUA_REGISTER_USERTYPE_MEMBER(Vector4f, z), - POD_LUA_REGISTER_USERTYPE_MEMBER(Vector4f, w) - POD_LUA_REGISTER_USERTYPE_END() - POD_LUA_REGISTER_USERTYPE_BEGIN(Quaternion<>) - POD_LUA_REGISTER_USERTYPE_MEMBER(Quaternion<>, x), - POD_LUA_REGISTER_USERTYPE_MEMBER(Quaternion<>, y), - POD_LUA_REGISTER_USERTYPE_MEMBER(Quaternion<>, z), - POD_LUA_REGISTER_USERTYPE_MEMBER(Quaternion<>, w) - POD_LUA_REGISTER_USERTYPE_END() - POD_LUA_REGISTER_USERTYPE_BEGIN(Transform<>) - POD_LUA_REGISTER_USERTYPE_MEMBER(Transform<>, position), - POD_LUA_REGISTER_USERTYPE_MEMBER(Transform<>, scale), - POD_LUA_REGISTER_USERTYPE_MEMBER(Transform<>, up), - POD_LUA_REGISTER_USERTYPE_MEMBER(Transform<>, right), - POD_LUA_REGISTER_USERTYPE_MEMBER(Transform<>, forward), - POD_LUA_REGISTER_USERTYPE_MEMBER(Transform<>, orientation), - POD_LUA_REGISTER_USERTYPE_MEMBER(Transform<>, model), - "move", []( pod::Transform<>& self, sol::variadic_args va ) { - auto it = va.begin(); - if ( va.size() == 1 ) { - pod::Vector3f delta = *it++; - self = uf::transform::move( self, delta ); - } else if ( va.size() == 2 ) { - pod::Vector3f axis = *it++; - double delta = *it++; - self = uf::transform::move( self, axis, delta ); - } - }, - "rotate", []( pod::Transform<>& self, sol::variadic_args va ) { - auto it = va.begin(); - if ( va.size() == 1 ) { - pod::Quaternion<> delta = *it++; - self = uf::transform::rotate( self, delta ); - } else if ( va.size() == 2 ) { - pod::Vector3f axis = *it++; - double delta = *it++; - self = uf::transform::rotate( self, axis, delta ); - } - } - POD_LUA_REGISTER_USERTYPE_END() - - UF_LUA_REGISTER_USERTYPE_BEGIN(Object) - "uid", &uf::Object::getUid, - "name", &uf::Object::getName, - "getComponent", [](uf::Object& self, const std::string& type, sol::this_state L ) { - sol::variadic_results values; - if ( type == "Metadata" ) { - std::string serialized = self.getComponent(); - sol::table table = state["json"]["decode"]( serialized ); - values.push_back( { L, sol::in_place, table } ); - } else if ( type == "Transform" ) { - values.push_back( { L, sol::in_place, &self.getComponent>() } ); - } - return values; - }, - "setComponent", [](uf::Object& self, const std::string& type, sol::variadic_args va ) { - auto value = *va.begin(); - if ( type == "Metadata" ) { - std::string encoded = state["json"]["encode"]( value.as() ); - self.getComponent().merge(encoded); - } else if ( type == "Transform" ) { - self.getComponent>() = value.as>(); - } - }, - "bind", [](uf::Object& self, const std::string& type, const sol::function& fun ) { - if ( !self.hasBehavior() ) uf::instantiator::bind( "LuaBehavior", self ); - pod::Behavior* behaviorPointer = NULL; - auto& behaviors = self.getBehaviors(); - for ( auto& b : behaviors ) { - if ( b.type != self.getType() ) continue; - behaviorPointer = &b; - break; - } - if ( !behaviorPointer ) return false; - pod::Behavior& behavior = *behaviorPointer; - - pod::Behavior::function_t* functionPointer = NULL; - if ( type == "initialize" ) functionPointer = &behavior.initialize; - else if ( type == "tick" ) functionPointer = &behavior.tick; - else if ( type == "render" ) functionPointer = &behavior.render; - else if ( type == "destroy" ) functionPointer = &behavior.destroy; - - if ( !functionPointer ) return false; - pod::Behavior::function_t& function = *functionPointer; - - function = [fun]( uf::Object& s ) { - fun(s); - }; - return true; - }, - "findByUid", []( uf::Object& self, const size_t& index )->uf::Object&{ - auto* pointer = self.findByUid( index ); - if ( pointer ) return pointer->as(); - static uf::Object null; - return null; - }, - "findByName", []( uf::Object& self, const std::string& index )->uf::Object&{ - auto* pointer = self.findByName( index ); - if ( pointer ) return pointer->as(); - static uf::Object null; - return null; - }, - "loadChild", []( uf::Object& self, const std::string& filename )->uf::Object&{ - auto* pointer = self.loadChildPointer( filename ); - if ( pointer ) return pointer->as(); - static uf::Object null; - return null; - }, - "getChildren", []( uf::Object& self )->sol::table{ - sol::table table(ext::lua::state, sol::create); - for ( auto* child : self.getChildren() ) { - table.add(&child->as()); - } - return table; - }, - "getParent", []( uf::Object& self )->uf::Object&{ - return self.getParent().as(); - } - UF_LUA_REGISTER_USERTYPE_END() + } + // load on-initialization defines + if ( ext::lua::onInitializationFunctions ) { + auto& functions = *ext::lua::onInitializationFunctions; + for ( auto& function : functions ) function(); + } + // `hooks` table { auto hooks = state["hooks"].get_or_create(); hooks["add"] = []( const std::string& name, const sol::function& function ) { uf::hooks.addHook( name, [function]( const std::string& payload )->std::string{ - return function( payload ); + sol::table table = ext::lua::state["json"]["decode"]( payload ); + auto result = function( table ); + if ( !result.valid() ) { + sol::error err = result; + uf::iostream << err.what() << "\n"; + return "false"; + } + return "true"; }); }; - hooks["call"] = []( const std::string& name, const std::string& payload ) { + hooks["call"] = []( const std::string& name, sol::table table = createTable() ) { + uf::Serializer payload = table; return uf::hooks.call( name, payload ); }; } @@ -169,6 +105,54 @@ void ext::lua::initialize() { static uf::Object null; return null; }; + entities["currentScene"] = []()->uf::Object&{ + return uf::scene::getCurrentScene().as(); + }; + entities["controller"] = []()->uf::Object&{ + return uf::scene::getCurrentScene().getController().as(); + }; + entities["destroy"] = []( uf::Object& object ){ + object.getParent().removeChild(object); + object.destroy(); + // delete &object; + }; + } + // `string` table + { + auto string = state["string"].get_or_create(); + string["extension"] = []( const std::string& filename ) { + return uf::io::extension( filename ); + }; + string["resolveURI"] = []( const std::string& filename ) { + return uf::io::resolveURI( filename ); + }; + string["si"] = []( sol::variadic_args va ) { + auto it = va.begin(); + double value = *(it++); + std::string unit = *(it++); + size_t precision = va.size() > 2 ? *(it++) : 3; + return uf::string::si( value, unit, precision ); + }; + } + // `io` table + { + auto io = state["io"].get_or_create(); + io["print"] = []( sol::variadic_args va ) { + size_t count = va.size(); + for ( auto value : va ) { + std::string str = ext::lua::state["tostring"]( value ); + uf::iostream << str; + if ( --count != 0 ) uf::iostream << "\t"; + } + uf::iostream << "\n"; + }; + } + // `math` table + { + auto math = state["math"].get_or_create(); + math["clamp"] = []( double value, double min, double max ) { + return std::clamp( value, min, max ); + }; } // `time` table { @@ -179,11 +163,27 @@ void ext::lua::initialize() { } // `json` table { - auto json = state.require_file("json", "./data/scripts/json.lua", true); state["json"]["pretty"] = []( const std::string& json )->std::string{ uf::Serializer serializer = json; return serializer.serialize(); }; + state["json"]["readFromFile"] = []( const std::string& filename ){ + uf::Serializer serializer; + serializer.readFromFile( filename ); + std::string string = serializer.serialize(false); + auto decoded = decode( string ); + return decoded ? decoded.value() : ext::lua::createTable(); + }; + state["json"]["writeToFile"] = []( sol::table table, const std::string& path ) { + if ( uf::io::extension(path) != "json" ) return false; + auto encoded = encode( table ); + if ( encoded ) { + uf::Serializer json = encoded.value(); + json.writeToFile( path ); + return true; + } + return false; + }; } // `window` table { @@ -198,14 +198,14 @@ bool ext::lua::run( const std::string& s, bool safe ) { // is file if ( uf::io::extension(s) == "lua" ) { if ( safe ) { - auto result = state.safe_script_file( s, sol::script_pass_on_error ); + auto result = state.safe_script_file( uf::io::resolveURI( s ), sol::script_pass_on_error ); if ( !result.valid() ) { sol::error err = result; - uf::iostream << "Invalid call to Lua script: " << err.what() << "\n"; + uf::iostream << err.what() << "\n"; return false; } } else { - state.script_file( s ); + state.script_file( uf::io::resolveURI( s ) ); } // is string with lua } else { @@ -213,7 +213,7 @@ bool ext::lua::run( const std::string& s, bool safe ) { auto result = state.safe_script( s, sol::script_pass_on_error ); if ( !result.valid() ) { sol::error err = result; - uf::iostream << "Invalid call to Lua script: " << err.what() << "\n"; + uf::iostream << err.what() << "\n"; return false; } } else { @@ -225,20 +225,41 @@ bool ext::lua::run( const std::string& s, bool safe ) { pod::LuaScript ext::lua::script( const std::string& filename ) { pod::LuaScript script; - script.filename = filename; + script.file = filename; script.env = sol::environment( ext::lua::state, sol::create, ext::lua::state.globals() ); return script; } -bool ext::lua::run( const pod::LuaScript& s ) { - std::string script = s.header + "\n" + uf::io::readAsString( s.filename ); - auto result = state.safe_script( script, s.env, sol::script_pass_on_error ); - if ( !result.valid() ) { - sol::error err = result; - uf::iostream << "Invalid call to Lua script: " << err.what() << "\n"; - return false; +bool ext::lua::run( const pod::LuaScript& s, bool safe ) { + // is file + if ( uf::io::extension(s.file) == "lua" ) { + if ( safe ) { + auto result = state.safe_script_file( s.file, s.env, sol::script_pass_on_error ); + if ( !result.valid() ) { + sol::error err = result; + uf::iostream << err.what() << "\n"; + return false; + } + } else { + state.script_file( s.file ); + } + // is string with lua + } else { + if ( safe ) { + auto result = state.safe_script( s.file, s.env, sol::script_pass_on_error ); + if ( !result.valid() ) { + sol::error err = result; + uf::iostream << err.what() << "\n"; + return false; + } + } else { + state.script( s.file ); + } } return true; } void ext::lua::terminate() { - + if ( ext::lua::onInitializationFunctions ) { + delete ext::lua::onInitializationFunctions; + ext::lua::onInitializationFunctions = NULL; + } } \ No newline at end of file diff --git a/engine/src/ext/lua/usertypes/asset.cpp b/engine/src/ext/lua/usertypes/asset.cpp new file mode 100644 index 00000000..fd6bbe29 --- /dev/null +++ b/engine/src/ext/lua/usertypes/asset.cpp @@ -0,0 +1,19 @@ +#include + +#include + +UF_LUA_REGISTER_USERTYPE(uf::Asset, + UF_LUA_REGISTER_USERTYPE_DEFINE( load, []( uf::Asset& asset, const std::string& uri, const std::string& callback = "" ) { + if ( callback == "" ) + asset.load( uri ); + else + asset.load( uri, callback ); + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( cache, []( uf::Asset& asset, const std::string& uri, const std::string& callback = "" ) { + if ( callback == "" ) + asset.cache( uri ); + else + asset.cache( uri, callback ); + }), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Asset::getOriginal ) +) \ No newline at end of file diff --git a/engine/src/ext/lua/usertypes/audio.cpp b/engine/src/ext/lua/usertypes/audio.cpp new file mode 100644 index 00000000..ad514d12 --- /dev/null +++ b/engine/src/ext/lua/usertypes/audio.cpp @@ -0,0 +1,33 @@ +#include + +#include + +UF_LUA_REGISTER_USERTYPE(uf::Audio, + sol::call_constructor, sol::initializers( []( uf::Audio& self ){}, + []( uf::Audio& self, const std::string& filename = "", double volume = 1 ){ + if ( filename != "" ) self.load(filename); + self.setVolume(volume); + }), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::initialized ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::playing ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::destroy ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::load ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::play ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::stop ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::getTime ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::setTime ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::getDuration ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::setPosition ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::setOrientation ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::setVolume ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::getPitch ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::setPitch ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::getGain ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::setGain ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::getRolloffFactor ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::setRolloffFactor ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::getMaxDistance ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::setMaxDistance ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::getVolume ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::getFilename ) +) \ No newline at end of file diff --git a/engine/src/ext/lua/usertypes/camera.cpp b/engine/src/ext/lua/usertypes/camera.cpp new file mode 100644 index 00000000..ae07f734 --- /dev/null +++ b/engine/src/ext/lua/usertypes/camera.cpp @@ -0,0 +1,7 @@ +#include + +#include + +UF_LUA_REGISTER_USERTYPE(uf::Camera, + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Camera::update ) +) diff --git a/engine/src/ext/lua/usertypes/matrix.cpp b/engine/src/ext/lua/usertypes/matrix.cpp new file mode 100644 index 00000000..c7fb0f13 --- /dev/null +++ b/engine/src/ext/lua/usertypes/matrix.cpp @@ -0,0 +1,9 @@ +#include + +#include + +UF_LUA_REGISTER_USERTYPE(pod::Matrix4f, + UF_LUA_REGISTER_USERTYPE_DEFINE( m, []( pod::Matrix4f& self, const size_t& index ) { + return self[index]; + }) +) diff --git a/engine/src/ext/lua/usertypes/object.cpp b/engine/src/ext/lua/usertypes/object.cpp new file mode 100644 index 00000000..0b4b5d49 --- /dev/null +++ b/engine/src/ext/lua/usertypes/object.cpp @@ -0,0 +1,163 @@ +#include + +#include +#include +#include +#include +#include +#include + +UF_LUA_REGISTER_USERTYPE(uf::Object, + sol::call_constructor, sol::initializers( []( uf::Object& self, sol::object arg, bool init = true ){ + if ( arg.is() ) { + self.load( arg.as() ); + } else if ( arg.is() ) { + auto encoded = ext::lua::encode( arg.as() ); + if ( encoded ) { + uf::Serializer json = encoded.value(); + self.load(json); + } + } + if ( init ) { + self.initialize(); + } + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( uid, &uf::Object::getUid ), + UF_LUA_REGISTER_USERTYPE_DEFINE( name, &uf::Object::getName ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Object::formatHookName ), + UF_LUA_REGISTER_USERTYPE_DEFINE( getComponent, [](uf::Object& self, const std::string& type )->sol::object{ + #define UF_LUA_RETRIEVE_COMPONENT( T )\ + if ( type == UF_NS_GET_LAST(T) ) return sol::make_object( ext::lua::state, &self.getComponent() ); + + if ( type == "Metadata" ) { + auto& metadata = self.getComponent(); + auto decoded = ext::lua::decode( metadata ); + if ( decoded ) { + sol::table table = decoded.value(); + return sol::make_object( ext::lua::state, table ); + } + } + UF_LUA_RETRIEVE_COMPONENT(pod::Transform<>) + UF_LUA_RETRIEVE_COMPONENT(uf::Audio) + UF_LUA_RETRIEVE_COMPONENT(uf::Asset) + UF_LUA_RETRIEVE_COMPONENT(uf::Camera) + return sol::make_object( ext::lua::state, sol::lua_nil ); + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( setComponent, [](uf::Object& self, const std::string& type, sol::object value ) { + #define UF_LUA_UPDATE_COMPONENT( T )\ + else if ( type == UF_NS_GET_LAST(T) ) self.getComponent() = std::move(value.as()); + + if ( type == "Metadata" ) { + auto encoded = ext::lua::encode( value.as() ); + if ( encoded ) { + auto& metadata = self.getComponent(); + std::string str = encoded.value(); + uf::Serializer hooks = metadata["system"]["hooks"]; + metadata.merge( str, false ); + metadata["system"]["hooks"] = hooks; + } + } + UF_LUA_UPDATE_COMPONENT(pod::Transform<>) + UF_LUA_UPDATE_COMPONENT(uf::Audio) + UF_LUA_UPDATE_COMPONENT(uf::Asset) + UF_LUA_UPDATE_COMPONENT(uf::Camera) + /* + } else if ( type == "Transform" ) { + self.getComponent>() = value.as>(); + } + */ + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( bind, [](uf::Object& self, const std::string& type, sol::protected_function fun ) { + if ( !self.hasBehavior() ) uf::instantiator::bind( "LuaBehavior", self ); + pod::Behavior* behaviorPointer = NULL; + auto& behaviors = self.getBehaviors(); + for ( auto& b : behaviors ) { + if ( b.type != self.getType() ) continue; + behaviorPointer = &b; + break; + } + if ( !behaviorPointer ) return false; + pod::Behavior& behavior = *behaviorPointer; + + pod::Behavior::function_t* functionPointer = NULL; + if ( type == "initialize" ) functionPointer = &behavior.initialize; + else if ( type == "tick" ) functionPointer = &behavior.tick; + else if ( type == "render" ) functionPointer = &behavior.render; + else if ( type == "destroy" ) functionPointer = &behavior.destroy; + + if ( !functionPointer ) return false; + pod::Behavior::function_t& function = *functionPointer; + + function = [fun]( uf::Object& s ) { + auto result = fun(s); + if ( !result.valid() ) { + sol::error err = result; + uf::iostream << err.what() << "\n"; + } + }; + return true; + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( findByUid, []( uf::Object& self, const size_t& index )->uf::Object&{ + auto* pointer = self.findByUid( index ); + if ( pointer ) return pointer->as(); + static uf::Object null; + return null; + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( findByName, []( uf::Object& self, const std::string& index )->uf::Object&{ + auto* pointer = self.findByName( index ); + if ( pointer ) return pointer->as(); + static uf::Object null; + return null; + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( addChild, []( uf::Object& self, uf::Object& child )->uf::Object&{ + self.addChild( child ); + return self; + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( removeChild, []( uf::Object& self, uf::Object& child )->uf::Object&{ + self.removeChild( child ); + return self; + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( loadChild, []( uf::Object& self, const std::string& filename, bool init = true )->uf::Object&{ + auto* pointer = self.loadChildPointer( filename, init ); + if ( pointer ) return pointer->as(); + static uf::Object null; + return null; + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( getChildren, []( uf::Object& self )->sol::table{ + sol::table table = ext::lua::createTable(); + for ( auto* child : self.getChildren() ) { + table.add(&child->as()); + } + return table; + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( getParent, []( uf::Object& self )->uf::Object&{ + return self.getParent().as(); + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( addHook, []( uf::Object& self, const std::string& name, const sol::function& function ) { + self.addHook( name, [function]( const std::string& payload )->std::string{ + auto decoded = ext::lua::decode( payload ); + if ( decoded ) { + sol::table table = decoded.value(); + auto result = function( table ); + if ( !result.valid() ) { + sol::error err = result; + uf::iostream << err.what() << "\n"; + return "false"; + } + return "true"; + } + return "false"; + }); + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( callHook, []( uf::Object& self, const std::string& name, sol::table table = ext::lua::createTable() ) { + uf::Serializer payload = table; + self.callHook( name, payload ); + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( queueHook, []( uf::Object& self, const std::string& name, sol::table table, float delay = 0.0f ) { + uf::Serializer payload = table; + self.queueHook( name, payload, delay ); + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( __tostring, []( uf::Object& self ) { + return self.getName() + ": " + std::to_string( self.getUid() ); + }) +) diff --git a/engine/src/ext/lua/usertypes/quaternion.cpp b/engine/src/ext/lua/usertypes/quaternion.cpp new file mode 100644 index 00000000..18911fbc --- /dev/null +++ b/engine/src/ext/lua/usertypes/quaternion.cpp @@ -0,0 +1,35 @@ +#include + +#include + +UF_LUA_REGISTER_USERTYPE(pod::Quaternion<>, + sol::call_constructor, sol::initializers( + []( pod::Quaternion<>& self, const pod::Quaternion<>& copy = {} ) { + self = copy; + }, + []( pod::Quaternion<>& self, float x, float y, float z, float w ) { + self = uf::vector::create(x, y, z, w); + } + ), + UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Quaternion<>::x), + UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Quaternion<>::y), + UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Quaternion<>::z), + UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Quaternion<>::w), + UF_LUA_REGISTER_USERTYPE_DEFINE(v, []( pod::Quaternion<>& self, const size_t& index ) { + return self[index]; + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( __tostring, []( pod::Quaternion<>& self ) { + std::stringstream ss; + ss << "Quaterion(" << self.x << ", " << self.y << ", " << self.z << ", " << self.w << ")"; + return ss.str(); + }), + UF_LUA_REGISTER_USERTYPE_DEFINE(axisAngle, []( sol::object arg, float angle ){ + if ( arg.is() ) { + return uf::quaternion::axisAngle( arg.as(), angle ); + } else if ( arg.is() ) { + sol::table table = arg.as(); + return uf::quaternion::axisAngle( pod::Vector3f{ table[0], table[1], table[2] }, angle ); + } + return pod::Quaternion<>{}; + }) +) \ No newline at end of file diff --git a/engine/src/ext/lua/usertypes/timer.cpp b/engine/src/ext/lua/usertypes/timer.cpp new file mode 100644 index 00000000..e29cf34a --- /dev/null +++ b/engine/src/ext/lua/usertypes/timer.cpp @@ -0,0 +1,14 @@ +#include + +#include + +UF_LUA_REGISTER_USERTYPE(uf::Timer<>, + UF_LUA_REGISTER_USERTYPE_DEFINE( elapsed, []( uf::Timer<>& self ) { + return self.elapsed().asDouble(); + }), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Timer<>::start ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Timer<>::stop ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Timer<>::reset ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Timer<>::update ), + UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Timer<>::running ) +) \ No newline at end of file diff --git a/engine/src/ext/lua/usertypes/transform.cpp b/engine/src/ext/lua/usertypes/transform.cpp new file mode 100644 index 00000000..a4b4c2a6 --- /dev/null +++ b/engine/src/ext/lua/usertypes/transform.cpp @@ -0,0 +1,35 @@ +#include + +#include + +UF_LUA_REGISTER_USERTYPE(pod::Transform<>, + UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Transform<>::position), + UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Transform<>::scale), + UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Transform<>::up), + UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Transform<>::right), + UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Transform<>::forward), + UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Transform<>::orientation), + UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Transform<>::model), + UF_LUA_REGISTER_USERTYPE_DEFINE(move, []( pod::Transform<>& self, sol::variadic_args va ) { + auto it = va.begin(); + if ( va.size() == 1 ) { + pod::Vector3f delta = *it++; + self = uf::transform::move( self, delta ); + } else if ( va.size() == 2 ) { + pod::Vector3f axis = *it++; + double delta = *it++; + self = uf::transform::move( self, axis, delta ); + } + }), + UF_LUA_REGISTER_USERTYPE_DEFINE(rotate, []( pod::Transform<>& self, sol::variadic_args va ) { + auto it = va.begin(); + if ( va.size() == 1 ) { + pod::Quaternion<> delta = *it++; + self = uf::transform::rotate( self, delta ); + } else if ( va.size() == 2 ) { + pod::Vector3f axis = *it++; + double delta = *it++; + self = uf::transform::rotate( self, axis, delta ); + } + }) +) \ No newline at end of file diff --git a/engine/src/ext/lua/usertypes/vector.cpp b/engine/src/ext/lua/usertypes/vector.cpp new file mode 100644 index 00000000..e42b019a --- /dev/null +++ b/engine/src/ext/lua/usertypes/vector.cpp @@ -0,0 +1,59 @@ +#include + +#include + +UF_LUA_REGISTER_USERTYPE(pod::Vector3f, + sol::call_constructor, sol::initializers( + []( pod::Vector3f& self, const pod::Vector3f& copy = {} ) { + self = copy; + }, + []( pod::Vector3f& self, float x, float y, float z ) { + self = uf::vector::create(x, y, z); + } + ), + UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Vector3f::x), + UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Vector3f::y), + UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Vector3f::z), + UF_LUA_REGISTER_USERTYPE_DEFINE( v, []( pod::Vector3f& self, const size_t& index ) { + return self[index]; + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( distance, []( pod::Vector3f& self, const pod::Vector3f& other ) { + return uf::vector::distance( self, other ); + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( lerp, []( const pod::Vector3f& start, const pod::Vector3f& end, double delta ) { + return uf::vector::lerp( start, end, delta ); + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( __tostring, []( pod::Vector3f& self ) { + std::stringstream ss; + ss << "Vector(" << self.x << ", " << self.y << ", " << self.z << ")"; + return ss.str(); + }) +) +UF_LUA_REGISTER_USERTYPE(pod::Vector4f, + sol::call_constructor, sol::initializers( + []( pod::Vector4f& self, const pod::Vector4f& copy = {} ) { + self = copy; + }, + []( pod::Vector4f& self, float x, float y, float z, float w ) { + self = uf::vector::create(x, y, z, w); + } + ), + UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Vector4f::x), + UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Vector4f::y), + UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Vector4f::z), + UF_LUA_REGISTER_USERTYPE_MEMBER(pod::Vector4f::w), + UF_LUA_REGISTER_USERTYPE_DEFINE( v, []( pod::Vector4f& self, const size_t& index ) { + return self[index]; + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( distance, []( pod::Vector4f& self, const pod::Vector4f& other ) { + return uf::vector::distance( self, other ); + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( lerp, []( const pod::Vector4f& start, const pod::Vector4f& end, double delta ) { + return uf::vector::lerp( start, end, delta ); + }), + UF_LUA_REGISTER_USERTYPE_DEFINE( __tostring, []( pod::Vector4f& self ) { + std::stringstream ss; + ss << "Vector(" << self.x << ", " << self.y << ", " << self.z << ", " << self.w << ")"; + return ss.str(); + }) +) \ No newline at end of file diff --git a/engine/src/ext/oal/oal.cpp b/engine/src/ext/oal/oal.cpp index 0323115f..408ac029 100644 --- a/engine/src/ext/oal/oal.cpp +++ b/engine/src/ext/oal/oal.cpp @@ -70,7 +70,7 @@ void UF_API_CALL ext::AL::listener( ALenum name, std::vector parameters case 3: alListener3f( name, parameters[0], parameters[1], parameters[2] ); break; default: alListenerfv( name, ¶meters[0] ); break; } - ext::oal.checkError(__FUNCTION__, __LINE__); + AL_CHECK_ERROR(); } void UF_API_CALL ext::AL::listener( const std::string string, std::vector parameters ) { if ( string == "GAIN" ) return this->listener( AL_GAIN, parameters ); @@ -90,12 +90,13 @@ ext::al::Source::~Source() { void UF_API_CALL ext::al::Source::generate() { if ( this->m_index ) this->destroy(); - alGenSources(1, &this->m_index); ext::oal.checkError(__FUNCTION__, __LINE__); + AL_CHECK_ERROR(alGenSources(1, &this->m_index)); } void UF_API_CALL ext::al::Source::destroy() { if ( this->m_index && alIsSource(this->m_index) ) { if ( this->playing() ) this->stop(); - alDeleteSources(1, &this->m_index); ext::oal.checkError(__FUNCTION__, __LINE__); + AL_CHECK_ERROR(alSourcei(this->m_index, AL_BUFFER, 0)); + AL_CHECK_ERROR(alDeleteSources(1, &this->m_index)); } this->m_index = 0; } @@ -109,7 +110,8 @@ void UF_API_CALL ext::al::Source::source( ALenum name, std::vector para case 3: alSource3f( this->m_index, name, parameters[0], parameters[1], parameters[2] ); break; default: alSourcefv( this->m_index, name, ¶meters[0] ); break; } - ext::oal.checkError(__FUNCTION__, __LINE__, std::to_string(name)); + AL_CHECK_ERROR(); + //ext::oal.checkError(__FUNCTION__, __LINE__, std::to_string(name)); } void UF_API_CALL ext::al::Source::source( const std::string string, std::vector parameters ) { // alSourcef @@ -137,7 +139,7 @@ void UF_API_CALL ext::al::Source::source( ALenum name, std::vector parame case 3: alSource3i( this->m_index, name, parameters[0], parameters[1], parameters[2] ); break; default: alSourceiv( this->m_index, name, ¶meters[0] ); break; } - ext::oal.checkError(__FUNCTION__, __LINE__); + AL_CHECK_ERROR(); } void UF_API_CALL ext::al::Source::source( const std::string string, std::vector parameters ) { // alSourcei @@ -154,13 +156,14 @@ void UF_API_CALL ext::al::Source::source( const std::string string, std::vector< if ( string == "DIRECTION" ) return this->source( AL_DIRECTION, parameters ); } void UF_API_CALL ext::al::Source::play() { - alSourcePlay(this->m_index); ext::oal.checkError(__FUNCTION__, __LINE__, std::to_string(this->m_index)); + AL_CHECK_ERROR(alSourcePlay(this->m_index)); } void UF_API_CALL ext::al::Source::stop() { - alSourceStop(this->m_index); ext::oal.checkError(__FUNCTION__, __LINE__, std::to_string(this->m_index)); + AL_CHECK_ERROR(alSourceStop(this->m_index)); } bool UF_API_CALL ext::al::Source::playing() { - ALCenum state; alGetSourcei(this->m_index, AL_SOURCE_STATE, &state); + ALCenum state; + AL_CHECK_ERROR(alGetSourcei(this->m_index, AL_SOURCE_STATE, &state)); return state == AL_PLAYING; } @@ -173,11 +176,11 @@ ext::al::Buffer::~Buffer() { void UF_API_CALL ext::al::Buffer::generate() { if ( this->m_index ) this->destroy(); - alGenBuffers(1, &this->m_index); ext::oal.checkError(__FUNCTION__, __LINE__); + AL_CHECK_ERROR(alGenBuffers(1, &this->m_index)); } void UF_API_CALL ext::al::Buffer::destroy() { if ( this->m_index && alIsBuffer(this->m_index) ) { - alDeleteBuffers(1, &this->m_index); ext::oal.checkError(__FUNCTION__, __LINE__); + AL_CHECK_ERROR(alDeleteBuffers(1, &this->m_index)); } this->m_index = 0; } @@ -186,7 +189,7 @@ ALuint UF_API_CALL ext::al::Buffer::getIndex() const { return this->m_index; } void UF_API_CALL ext::al::Buffer::buffer(ALenum format, const ALvoid* data, ALsizei size, ALsizei frequency) { if ( !this->m_index ) this->generate(); - alBufferData(this->m_index, format, data, size, frequency); ext::oal.checkError(__FUNCTION__, __LINE__, std::to_string(format) + " @ " + std::to_string(size) + " @ " + std::to_string(frequency)); + AL_CHECK_ERROR(alBufferData(this->m_index, format, data, size, frequency)); } diff --git a/engine/src/ext/openvr/openvr.cpp b/engine/src/ext/openvr/openvr.cpp index 9b108423..a8421bd8 100644 --- a/engine/src/ext/openvr/openvr.cpp +++ b/engine/src/ext/openvr/openvr.cpp @@ -164,7 +164,7 @@ bool ext::openvr::initialize( int stage ) { if ( DEBUG_MARKER ) std::cout << ext::openvr::driver.manifest << std::endl; for ( auto i = 0; i < manifest["action_sets"].size(); ++i ) { if ( DEBUG_MARKER ) std::cout << manifest["action_sets"][i] << std::endl; - std::string name = manifest["action_sets"][i]["name"].asString(); + std::string name = manifest["action_sets"][i]["name"].as(); vr::VRActionSetHandle_t handle; VR_CHECK_INPUT_RESULT( vr::VRInput()->GetActionSetHandle( name.c_str(), &handle ) ); handles.actionSets[name] = handle; @@ -172,7 +172,7 @@ bool ext::openvr::initialize( int stage ) { // handles.actionSets.push_back(handle); } for ( auto i = 0; i < manifest["actions"].size(); ++i ) { - std::string name = manifest["actions"][i]["name"].asString(); + std::string name = manifest["actions"][i]["name"].as(); vr::VRActionHandle_t handle; VR_CHECK_INPUT_RESULT( vr::VRInput()->GetActionHandle( name.c_str(), &handle ) ); handles.actions[name] = handle; @@ -188,7 +188,7 @@ bool ext::openvr::initialize( int stage ) { if ( DEBUG_MARKER ) std::cout << "Registered hook for haptic: " << ("VR:Haptics."+split.back()) << std::endl; uf::hooks.addHook( "VR:Haptics."+split.back(), [&](const std::string& event)->std::string{ uf::Serializer json = event; - if ( vr::VRInputError_None != vr::VRInput()->TriggerHapticVibrationAction( handle, json["delay"].asFloat(), json["duration"].asFloat(), json["frequency"].asFloat(), json["amplitude"].asFloat(), vr::k_ulInvalidInputValueHandle ) ) + if ( vr::VRInputError_None != vr::VRInput()->TriggerHapticVibrationAction( handle, json["delay"].as(), json["duration"].as(), json["frequency"].as(), json["amplitude"].as(), vr::k_ulInvalidInputValueHandle ) ) return "false"; return "true"; }); diff --git a/engine/src/ext/vulkan/buffer.cpp b/engine/src/ext/vulkan/buffer.cpp index aec03530..d6b142e3 100644 --- a/engine/src/ext/vulkan/buffer.cpp +++ b/engine/src/ext/vulkan/buffer.cpp @@ -213,9 +213,14 @@ void ext::vulkan::Buffers::updateBuffer( void* data, VkDeviceSize length, Buffer // assert(buffer.allocationInfo.size == length); if ( buffer.allocationInfo.size != length ) { -// std::cout << "Mismatch buffer update: " << buffer.allocationInfo.size << " vs " << length << ", resetting for safety..." << std::endl; + if ( true ) { + VK_VALIDATION_MESSAGE("Mismatch buffer update: Requesting " << buffer.allocationInfo.size << ", got " << length); + } else { + length = buffer.allocationInfo.size; + VK_VALIDATION_MESSAGE("Mismatch buffer update: Requesting " << buffer.allocationInfo.size << ", got " << length << ", resetting for safety"); + } + uf::iostream << "\n"; // assert(buffer.allocationInfo.size > length); - length = buffer.allocationInfo.size; } diff --git a/engine/src/ext/vulkan/device.cpp b/engine/src/ext/vulkan/device.cpp index cc13cf04..f8e7d929 100644 --- a/engine/src/ext/vulkan/device.cpp +++ b/engine/src/ext/vulkan/device.cpp @@ -20,7 +20,7 @@ namespace { vr::VRCompositor()->GetVulkanInstanceExtensionsRequired( pExtensionStr, nBufferSize ); std::vector extensions = uf::string::split( pExtensionStr, " " ); for ( auto& str : extensions ) { - // std::cout << str << std::endl; + // uf::iostream << str << "\n"; requested.push_back(str); } // requested.insert( requested.end(), extensions.begin(), extensions.end() ); @@ -53,7 +53,7 @@ namespace { break; } if ( !found ) { - std::cout << "Vulkan missing requested extension: " << requestedExtension << std::endl; + uf::iostream << "Vulkan missing requested extension: " << requestedExtension << "\n"; } } } @@ -65,8 +65,8 @@ namespace { if ( feature == #NAME ) {\ if ( device.features.NAME == VK_TRUE ) {\ device.enabledFeatures.NAME = true;\ - if ( ext::vulkan::settings::validation ) std::cout << "Enabled feature: " << feature << std::endl;\ - } else if ( ext::vulkan::settings::validation ) std::cout << "Failed to enable feature: " << feature << std::endl;\ + if ( ext::vulkan::settings::validation ) uf::iostream << "Enabled feature: " << feature << "\n";\ + } else if ( ext::vulkan::settings::validation ) uf::iostream << "Failed to enable feature: " << feature << "\n";\ } for ( auto& feature : ext::vulkan::settings::requestedDeviceFeatures ) { @@ -132,8 +132,8 @@ namespace { if ( feature == #NAME ) {\ if ( device.features2.NAME == VK_TRUE ) {\ device.enabledFeatures2.NAME = true;\ - if ( ext::vulkan::settings::validation ) std::cout << "Enabled feature: " << feature << std::endl;\ - } else if ( ext::vulkan::settings::validation ) std::cout << "Failed to enable feature: " << feature << std::endl;\ + if ( ext::vulkan::settings::validation ) uf::iostream << "Enabled feature: " << feature << "\n";\ + } else if ( ext::vulkan::settings::validation ) uf::iostream << "Failed to enable feature: " << feature << "\n";\ } #undef CHECK_FEATURE2 } @@ -536,7 +536,7 @@ void ext::vulkan::Device::initialize() { { if ( ext::vulkan::settings::validation ) for ( auto ext : requestedExtensions ) - std::cout << "Requested instance extension: " << ext << std::endl; + uf::iostream << "Requested instance extension: " << ext << "\n"; uint32_t extensionsCount = 0; uint32_t enabledExtensionsCount = 0; @@ -552,7 +552,7 @@ void ext::vulkan::Device::initialize() { std::vector instanceExtensions; for ( auto& s : supportedExtensions.instance ) { if ( ext::vulkan::settings::validation ) - std::cout << "Enabled instance extension: " << s << std::endl; + uf::iostream << "Enabled instance extension: " << s << "\n"; instanceExtensions.push_back( s.c_str() ); } @@ -665,7 +665,7 @@ void ext::vulkan::Device::initialize() { { // Allocate enough ExtensionProperties to support all extensions being enabled if ( ext::vulkan::settings::validation ) - for ( auto ext : requestedExtensions ) std::cout << "Requested device extension: " << ext << std::endl; + for ( auto ext : requestedExtensions ) uf::iostream << "Requested device extension: " << ext << "\n"; uint32_t extensionsCount = 0; uint32_t enabledExtensionsCount = 0; @@ -680,7 +680,7 @@ void ext::vulkan::Device::initialize() { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; for ( auto& s : supportedExtensions.device ) { - if ( ext::vulkan::settings::validation ) std::cout << "Enabled device extension: " << s << std::endl; + if ( ext::vulkan::settings::validation ) uf::iostream << "Enabled device extension: " << s << "\n"; deviceExtensions.push_back( s.c_str() ); } @@ -759,7 +759,7 @@ void ext::vulkan::Device::initialize() { throw std::runtime_error("failed to create logical device!"); if ( ext::vulkan::settings::validation ) - std::cout << retrieveDeviceFeatures( *this ) << std::endl; + uf::iostream << retrieveDeviceFeatures( *this ) << "\n"; } // Create command pool getCommandPool( QueueEnum::GRAPHICS ); diff --git a/engine/src/ext/vulkan/graphic.cpp b/engine/src/ext/vulkan/graphic.cpp index a95cfd4f..b4edbe31 100644 --- a/engine/src/ext/vulkan/graphic.cpp +++ b/engine/src/ext/vulkan/graphic.cpp @@ -25,7 +25,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const std::st { std::ifstream is(this->filename = filename, std::ios::binary | std::ios::in | std::ios::ate); if ( !is.is_open() ) { - uf::iostream << "Error: Could not open shader file \"" << filename << "\"" << "\n"; + VK_DEBUG_MESSAGE("Error: Could not open shader file \"" << filename << "\""); return; } is.seekg(0, std::ios::end); spirv.reserve(is.tellg()); is.seekg(0, std::ios::beg); @@ -66,6 +66,15 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const std::st case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { size_t size = comp.get_declared_struct_size(base_type); if ( size <= 0 ) break; + if ( size > device.properties.limits.maxUniformBufferRange ) { + VK_DEBUG_MESSAGE("Invalid uniform buffer length of " << size << " for shader " << filename); + size = device.properties.limits.maxUniformBufferRange; + } + size_t misalignment = size % device.properties.limits.minStorageBufferOffsetAlignment; + if ( misalignment != 0 ) { + VK_DEBUG_MESSAGE("Invalid uniform buffer alignmnet of " << misalignment << " for shader " << filename << ", correcting..."); + size += misalignment; + } auto& uniform = uniforms.emplace_back(); uniform.create( size ); } break; @@ -82,20 +91,20 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const std::st if ( !type.array.empty() ) { size = type.array[0]; /* - std::cout << "ARRAY: " << filename << ":\t"; + uf::iostream << "ARRAY: " << filename << ":\t"; for ( auto v : type.array ) - std::cout << v << " "; - std::cout << std::endl; - std::cout << "ARRAY: " << filename << ":\t"; + uf::iostream << v << " "; + uf::iostream << "\n"; + uf::iostream << "ARRAY: " << filename << ":\t"; for ( auto v : type.array_size_literal ) - std::cout << v << " "; - std::cout << std::endl; + uf::iostream << v << " "; + uf::iostream << "\n"; */ } descriptorSetLayoutBindings.push_back( ext::vulkan::initializers::descriptorSetLayoutBinding( descriptorType, stage, comp.get_decoration(resource.id, spv::DecorationBinding), size ) ); }; - // std::cout << "["< device.properties.limits.maxPushConstantsSize ) { + VK_DEBUG_MESSAGE("Invalid push constant length of " << size << " for shader " << filename); + size = device.properties.limits.maxPushConstantsSize; + } auto& pushConstant = pushConstants.emplace_back(); pushConstant.create( size ); } @@ -219,7 +232,7 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic, GraphicDescriptor& des this->device = graphic.device; Device& device = *graphic.device; - // std::cout << &graphic << ": Shaders: " << graphic.material.shaders.size() << " Textures: " << graphic.material.textures.size() << std::endl; + // VK_DEBUG_MESSAGE(&graphic << ": Shaders: " << graphic.material.shaders.size() << " Textures: " << graphic.material.textures.size()); assert( graphic.material.shaders.size() > 0 ); RenderMode& renderMode = ext::vulkan::getRenderMode( descriptor.renderMode, true); @@ -237,8 +250,9 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic, GraphicDescriptor& des for ( auto& pushConstant : shader.pushConstants ) { size_t len = pushConstant.data().len; if ( len <= 0 || len > device.properties.limits.maxPushConstantsSize ) { - std::cout << "INVALID PUSH CONSTANT LEN OF : " << len << " FOR " << shader.filename << std::endl; - len = 4; + VK_DEBUG_MESSAGE("Invalid push constent length of " << len << " for shader " << shader.filename); + // goto PIPELINE_INITIALIZATION_INVALID; + len = device.properties.limits.maxPushConstantsSize; } pushConstantRanges.push_back(ext::vulkan::initializers::pushConstantRange( shader.descriptor.stage, @@ -348,8 +362,8 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic, GraphicDescriptor& des blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; - blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; } blendAttachmentStates.push_back(blendAttachmentState); @@ -442,6 +456,16 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic, GraphicDescriptor& des VK_CHECK_RESULT(vkCreateGraphicsPipelines( device, device.pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipeline)); } + + graphic.process = true; + return; +PIPELINE_INITIALIZATION_INVALID: + graphic.process = false; + VK_DEBUG_MESSAGE("Pipeline initialization invalid, updating next tick..."); + uf::thread::add( uf::thread::get("Main"), [&]() -> int { + this->initialize( graphic, descriptor ); + return 0;}, true ); + return; } void ext::vulkan::Pipeline::record( Graphic& graphic, VkCommandBuffer commandBuffer ) { auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; @@ -481,68 +505,181 @@ void ext::vulkan::Pipeline::update( Graphic& graphic ) { return this->update( graphic, graphic.descriptor ); } void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descriptor ) { + // + if ( descriptorSet == VK_NULL_HANDLE ) return; // generate fallback empty texture auto& emptyTexture = Texture2D::empty; RenderMode& renderMode = ext::vulkan::getRenderMode(descriptor.renderMode, true); auto& renderTarget = renderMode.getRenderTarget(descriptor.renderTarget ); - std::vector writeDescriptorSets; std::vector descriptorSetLayoutBindings; - std::vector inputDescriptors; - std::vector imageInfos; - for ( auto& shader : graphic.material.shaders ) { descriptorSetLayoutBindings.insert( descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.end() ); } + struct { + std::vector uniform; + std::vector storage; + std::vector image; + std::vector sampler; + std::vector input; + } infos; + if ( descriptor.subpass < renderTarget.passes.size() ) { auto& subpass = renderTarget.passes[descriptor.subpass]; for ( auto& input : subpass.inputs ) { - inputDescriptors.push_back(ext::vulkan::initializers::descriptorImageInfo( + infos.input.push_back(ext::vulkan::initializers::descriptorImageInfo( renderTarget.attachments[input.attachment].view, // input.layout input.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : input.layout )); } } + + { + for ( auto& texture : graphic.material.textures ) { + infos.image.emplace_back(texture.descriptor); + } + for ( auto& sampler : graphic.material.samplers ) { + infos.sampler.emplace_back(sampler.descriptor.info); + } + } + + for ( auto& shader : graphic.material.shaders ) { + #define PARSE_BUFFER( buffers ) for ( auto& buffer : buffers ) {\ + if ( buffer.usageFlags & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) {\ + infos.uniform.emplace_back(buffer.descriptor);\ + }\ + if ( buffer.usageFlags & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ) {\ + infos.storage.emplace_back(buffer.descriptor);\ + }\ + } + + PARSE_BUFFER(shader.buffers) + PARSE_BUFFER(graphic.buffers) + + // check if we can even consume that many infos + size_t consumes = 0; + for ( auto& layout : shader.descriptorSetLayoutBindings ) { + switch ( layout.descriptorType ) { + // consume an texture image info + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: { + consumes += layout.descriptorCount; + } break; + } + } + for ( size_t i = infos.image.size(); i < consumes; ++i ) { + infos.image.push_back(emptyTexture.descriptor); + } + } + + auto uniformBufferInfo = infos.uniform.begin(); + auto storageBufferInfo = infos.storage.begin(); + auto imageInfo = infos.image.begin(); + auto samplerInfo = infos.sampler.begin(); + auto inputInfo = infos.input.begin(); + + #define BREAK_ASSERT(condition, ...) if ( condition ) { VK_DEBUG_MESSAGE(#condition << "\t" << __VA_ARGS__); break; } + + std::vector writeDescriptorSets; + for ( auto& shader : graphic.material.shaders ) { + for ( auto& layout : shader.descriptorSetLayoutBindings ) { + // VK_DEBUG_MESSAGE(shader.filename << "\tType: " << layout.descriptorType << "\tConsuming: " << layout.descriptorCount); + switch ( layout.descriptorType ) { + // consume an texture image info + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: { + BREAK_ASSERT( imageInfo == infos.image.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet( + descriptorSet, + layout.descriptorType, + layout.binding, + &(*imageInfo), + layout.descriptorCount + )); + imageInfo += layout.descriptorCount; + } break; + case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: { + BREAK_ASSERT( inputInfo == infos.input.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet( + descriptorSet, + layout.descriptorType, + layout.binding, + &(*inputInfo), + layout.descriptorCount + )); + inputInfo += layout.descriptorCount; + } break; + case VK_DESCRIPTOR_TYPE_SAMPLER: { + BREAK_ASSERT( samplerInfo == infos.sampler.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet( + descriptorSet, + layout.descriptorType, + layout.binding, + &(*samplerInfo), + layout.descriptorCount + )); + samplerInfo += layout.descriptorCount; + } break; + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { + BREAK_ASSERT( uniformBufferInfo == infos.uniform.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet( + descriptorSet, + layout.descriptorType, + layout.binding, + &(*uniformBufferInfo), + layout.descriptorCount + )); + uniformBufferInfo += layout.descriptorCount; + } break; + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: { + BREAK_ASSERT( storageBufferInfo == infos.storage.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet( + descriptorSet, + layout.descriptorType, + layout.binding, + &(*storageBufferInfo), + layout.descriptorCount + )); + storageBufferInfo += layout.descriptorCount; + } break; + } + + } + } + +/* + std::vector writeDescriptorSets; + std::vector imageInfos; { for ( auto& shader : graphic.material.shaders ) { std::vector buffersStorageVector; std::vector buffersUniformsVector; - for ( auto& buffer : shader.buffers ) { - if ( buffer.usageFlags & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ) { - auto& descriptor = buffersStorageVector.emplace_back(buffer.descriptor); - if ( descriptor.offset % device->properties.limits.minStorageBufferOffsetAlignment != 0 ) { - // std::cout << "Unaligned offset! Expecting " << device->properties.limits.minUniformBufferOffsetAlignment << ", got " << descriptor.pBufferInfo->offset << std::endl; - descriptor.offset = 0; - } - } - if ( buffer.usageFlags & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) { - auto& descriptor = buffersUniformsVector.emplace_back(buffer.descriptor); - if ( descriptor.offset % device->properties.limits.minUniformBufferOffsetAlignment != 0 ) { - // std::cout << "Unaligned offset! Expecting " << device->properties.limits.minUniformBufferOffsetAlignment << ", got " << descriptor.pBufferInfo->offset << std::endl; - descriptor.offset = 0; - } - } - } - for ( auto& buffer : graphic.buffers ) { - if ( buffer.usageFlags & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ) { - auto& descriptor = buffersStorageVector.emplace_back(buffer.descriptor); - if ( descriptor.offset % device->properties.limits.minStorageBufferOffsetAlignment != 0 ) { - std::cout << "[" << __LINE__ << "] Unaligned offset! Expecting " << device->properties.limits.minUniformBufferOffsetAlignment << ", got " << descriptor.offset << std::endl; - descriptor.offset = 0; - } - } - if ( buffer.usageFlags & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) { - auto& descriptor = buffersUniformsVector.emplace_back(buffer.descriptor); - if ( descriptor.offset % device->properties.limits.minUniformBufferOffsetAlignment != 0 ) { - std::cout << "[" << __LINE__ << "] Unaligned offset! Expecting " << device->properties.limits.minUniformBufferOffsetAlignment << ", got " << descriptor.offset << std::endl; - descriptor.offset = 0; - } - } + + #define PARSE_BUFFER( buffers ) for ( auto& buffer : buffers ) {\ + if ( buffer.usageFlags & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ) {\ + auto& descriptor = buffersStorageVector.emplace_back(buffer.descriptor);\ + if ( descriptor.offset % device->properties.limits.minStorageBufferOffsetAlignment != 0 ) {\ + VK_DEBUG_MESSAGE("Unaligned offset! Expecting " << device->properties.limits.minUniformBufferOffsetAlignment << ", got " << descriptor.offset);\ + goto PIPELINE_UPDATE_INVALID;\ + }\ + }\ + if ( buffer.usageFlags & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) {\ + auto& descriptor = buffersUniformsVector.emplace_back(buffer.descriptor);\ + if ( descriptor.offset % device->properties.limits.minUniformBufferOffsetAlignment != 0 ) {\ + VK_DEBUG_MESSAGE("Unaligned offset! Expecting " << device->properties.limits.minUniformBufferOffsetAlignment << ", got " << descriptor.offset);\ + goto PIPELINE_UPDATE_INVALID;\ + }\ + }\ } + PARSE_BUFFER(shader.buffers) + PARSE_BUFFER(graphic.buffers) + auto textures = graphic.material.textures.begin(); auto samplers = graphic.material.samplers.begin(); auto attachments = inputDescriptors.begin(); @@ -569,7 +706,7 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip if ( d.imageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ) d.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; } else { - // std::cout << "textures == graphic.material.textures.end()" << std::endl; + // VK_DEBUG_MESSAGE("textures == graphic.material.textures.end()"); } imageInfos.push_back( d ); } @@ -603,21 +740,17 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip } break; case VK_DESCRIPTOR_TYPE_SAMPLER: { if ( samplers == graphic.material.samplers.end() ) { - std::cout << "samplers == graphic.material.samplers.end()" << std::endl; + VK_DEBUG_MESSAGE("samplers == graphic.material.samplers.end()"); break; } imageInfo = &((samplers++)->descriptor.info); } break; case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { if ( buffersUniforms == buffersUniformsVector.end() ) { - std::cout << "buffersUniforms == buffersUniformsVector.end()" << std::endl; + VK_DEBUG_MESSAGE("buffersUniforms == buffersUniformsVector.end()"); break; } auto* descriptor = &(*(buffersUniforms++)); - if ( descriptor->offset % device->properties.limits.minUniformBufferOffsetAlignment != 0 ) { - std::cout << __LINE__ << ": Unaligned offset! Expecting " << device->properties.limits.minUniformBufferOffsetAlignment << ", got " << descriptor->offset << std::endl; - descriptor->offset = 0; - } writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet( descriptorSet, layout.descriptorType, @@ -627,15 +760,10 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip } break; case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: { if ( buffersStorage == buffersStorageVector.end() ) { - std::cout << "buffersStorage == buffersStorageVector.end()" << std::endl; + VK_DEBUG_MESSAGE("buffersStorage == buffersStorageVector.end()"); break; } auto* descriptor = &(*(buffersStorage++)); - if ( descriptor->offset % device->properties.limits.minStorageBufferOffsetAlignment != 0 ) { - std::cout << __LINE__ << ": Unaligned offset! Expecting " << device->properties.limits.minUniformBufferOffsetAlignment << ", got " << descriptor->offset << std::endl; - descriptor->offset = 0; - } - writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet( descriptorSet, layout.descriptorType, @@ -645,7 +773,7 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip } break; case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: { if ( attachments == inputDescriptors.end() ) { - std::cout << "attachments == inputDescriptors.end()" << std::endl; + VK_DEBUG_MESSAGE("attachments == inputDescriptors.end()"); break; } imageInfo = &(*(attachments++)); @@ -673,40 +801,34 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip } } } - - bool invalid = false; +*/ for ( auto& descriptor : writeDescriptorSets ) { for ( size_t i = 0; i < descriptor.descriptorCount; ++i ) { if ( descriptor.pBufferInfo ) { if ( descriptor.pBufferInfo[i].offset % device->properties.limits.minUniformBufferOffsetAlignment != 0 ) { - std::cout << "[" << __LINE__ << "] Invalid descriptor for buffer: " << descriptor.pBufferInfo[i].buffer << " (Offset: " << descriptor.pBufferInfo[i].offset << ", Range: " << descriptor.pBufferInfo[i].range << "), invalidating..." << std::endl; + VK_DEBUG_MESSAGE("Invalid descriptor for buffer: " << descriptor.pBufferInfo[i].buffer << " (Offset: " << descriptor.pBufferInfo[i].offset << ", Range: " << descriptor.pBufferInfo[i].range << "), invalidating..."); + goto PIPELINE_UPDATE_INVALID; + /* auto pointer = const_cast(&descriptor.pBufferInfo[i]); pointer->offset = 0; pointer->range = 0; pointer->buffer = VK_NULL_HANDLE; invalid = true; break; + */ } } + /* if ( descriptor.pImageInfo ) { if ( descriptor.pImageInfo[i].imageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ) { - // auto pointer = const_cast(&descriptor.pImageInfo[i]); - // pointer->imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + auto pointer = const_cast(&descriptor.pImageInfo[i]); + pointer->imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; } } + */ } } - renderMode.rebuild = true; - - if ( invalid ) { - graphic.process = false; - std::cout << "[" << __LINE__ << "] Pipeline invalid, updating next tick..." << std::endl; - uf::thread::add( uf::thread::has("Main") ? uf::thread::get("Main") : uf::thread::create( "Main", false, true ), [&]() -> int { - this->update( graphic, descriptor ); - return 0;}, true ); - return; - } graphic.process = true; vkUpdateDescriptorSets( @@ -716,6 +838,15 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip 0, NULL ); + return; + +PIPELINE_UPDATE_INVALID: + graphic.process = false; + VK_DEBUG_MESSAGE("Pipeline update invalid, updating next tick..."); + uf::thread::add( uf::thread::get("Main"), [&]() -> int { + this->update( graphic, descriptor ); + return 0;}, true ); + return; } void ext::vulkan::Pipeline::destroy() { if ( aliased ) return; @@ -816,13 +947,14 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer ) { return this->record( commandBuffer, descriptor ); } void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, GraphicDescriptor& descriptor ) { + if ( !process ) return; if ( !this->hasPipeline( descriptor ) ) { - std::cout << this << ": has no valid pipeline" << std::endl; + VK_DEBUG_MESSAGE(this << ": has no valid pipeline"); return; } auto& pipeline = this->getPipeline( descriptor ); - + if ( pipeline.descriptorSet == VK_NULL_HANDLE ) return; assert( buffers.size() >= 2 ); Buffer& vertexBuffer = buffers.at(0); Buffer& indexBuffer = buffers.at(1); @@ -883,6 +1015,6 @@ std::string ext::vulkan::GraphicDescriptor::hash() const { serializer["depthTest"]["write"] = depthTest.write; serializer["depthTest"]["operation"] = depthTest.operation; -// if ( renderMode != "Gui" ) std::cout << this << ": " << indices << ": " << renderMode << ": " << subpass << ": " << serializer << std::endl; +// if ( renderMode != "Gui" ) uf::iostream << this << ": " << indices << ": " << renderMode << ": " << subpass << ": " << serializer << "\n"; return uf::string::sha256( serializer.serialize() ); } \ No newline at end of file diff --git a/engine/src/ext/vulkan/rendermode.cpp b/engine/src/ext/vulkan/rendermode.cpp index c7d171ca..88cf7afe 100644 --- a/engine/src/ext/vulkan/rendermode.cpp +++ b/engine/src/ext/vulkan/rendermode.cpp @@ -35,7 +35,7 @@ void ext::vulkan::RenderMode::createCommandBuffers() { if ( !graphic.initialized || !graphic.process ) return; graphics.push_back(&graphic); }; - for ( uf::Scene* scene : ext::vulkan::scenes ) { + for ( uf::Scene* scene : uf::scene::scenes ) { if ( !scene ) continue; scene->process(filter); } @@ -79,7 +79,7 @@ void ext::vulkan::RenderMode::bindPipelines() { if ( !graphic.process ) return; graphics.push_back(&graphic); }; - for ( uf::Scene* scene : ext::vulkan::scenes ) { + for ( uf::Scene* scene : uf::scene::scenes ) { if ( !scene ) continue; scene->process(filter); } diff --git a/engine/src/ext/vulkan/rendermodes/compute.cpp b/engine/src/ext/vulkan/rendermodes/compute.cpp index 6d827b8f..0898d534 100644 --- a/engine/src/ext/vulkan/rendermodes/compute.cpp +++ b/engine/src/ext/vulkan/rendermodes/compute.cpp @@ -50,7 +50,7 @@ void ext::vulkan::ComputeRenderMode::initialize( Device& device ) { uint32_t eyes = 2; }; auto* specializationConstants = (SpecializationConstant*) &shader.specializationConstants[0]; - specializationConstants->maxLights = metadata["system"]["config"]["engine"]["scenes"]["max lights"].asUInt64(); + specializationConstants->maxLights = metadata["system"]["config"]["engine"]["scenes"]["max lights"].as(); specializationConstants->eyes = ext::openvr::context ? 2 : 1; for ( auto& binding : shader.descriptorSetLayoutBindings ) { if ( binding.descriptorCount > 1 ) { diff --git a/engine/src/ext/vulkan/rendermodes/deferred.cpp b/engine/src/ext/vulkan/rendermodes/deferred.cpp index 856c3c5c..0312dd97 100644 --- a/engine/src/ext/vulkan/rendermodes/deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/deferred.cpp @@ -34,10 +34,10 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { } attachments; attachments.albedo = renderTarget.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true ); // albedo - attachments.normals = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true ); // normals + attachments.normals = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, false ); // normals if ( !settings::experimental::deferredReconstructPosition ) - attachments.position = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true ); // position - attachments.depth = renderTarget.attach( device.formats.depth, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, true ); // depth + attachments.position = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, false ); // position + attachments.depth = renderTarget.attach( device.formats.depth, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false ); // depth // attachments.ping = renderTarget.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ); // albedo // attachments.pong = renderTarget.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ); // albedo @@ -144,7 +144,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { uint32_t maxLights = 16; }; auto* specializationConstants = (SpecializationConstant*) &shader.specializationConstants[0]; - specializationConstants->maxLights = metadata["system"]["config"]["engine"]["scenes"]["max lights"].asUInt64(); + specializationConstants->maxLights = metadata["system"]["config"]["engine"]["scenes"]["max lights"].as(); for ( auto& binding : shader.descriptorSetLayoutBindings ) { if ( binding.descriptorCount > 1 ) binding.descriptorCount = specializationConstants->maxLights; @@ -152,8 +152,8 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { /* std::vector palette; // size of palette - if ( metadata["system"]["config"]["engine"]["scenes"]["palette"].isNumeric() ) { - size_t size = metadata["system"]["config"]["engine"]["scenes"]["palette"].asUInt64(); + if ( metadata["system"]["config"]["engine"]["scenes"]["palette"].is() ) { + size_t size = metadata["system"]["config"]["engine"]["scenes"]["palette"].as(); for ( size_t x = 0; x < size; ++x ) { palette.push_back(pod::Vector4f{ (128.0f + 128.0f * sin(3.1415f * x / 16.0f)) / 256.0f, @@ -163,14 +163,14 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { }); } // palette array - } else if ( metadata["system"]["config"]["engine"]["scenes"]["palette"].isArray() ) { + } else if ( ext::json::isArray( metadata["system"]["config"]["engine"]["scenes"]["palette"] ) ) { for ( int i = 0; i < metadata["system"]["config"]["engine"]["scenes"]["palette"].size(); ++i ) { auto& color = palette.emplace_back(); palette.push_back(pod::Vector4f{ - metadata["system"]["config"]["engine"]["scenes"]["palette"][i][0].asFloat(), - metadata["system"]["config"]["engine"]["scenes"]["palette"][i][1].asFloat(), - metadata["system"]["config"]["engine"]["scenes"]["palette"][i][2].asFloat(), - metadata["system"]["config"]["engine"]["scenes"]["palette"][i][3].asFloat(), + metadata["system"]["config"]["engine"]["scenes"]["palette"][i][0].as(), + metadata["system"]["config"]["engine"]["scenes"]["palette"][i][1].as(), + metadata["system"]["config"]["engine"]["scenes"]["palette"][i][2].as(), + metadata["system"]["config"]["engine"]["scenes"]["palette"][i][3].as(), }); } } @@ -234,13 +234,13 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const std::vector(), + v[1].as(), + v[2].as(), + v[3].as(), } }; } else { clearValue.color = { { 0, 0, 0, 0 } }; diff --git a/engine/src/ext/vulkan/rendermodes/multiview_stereoscopic_deferred.cpp b/engine/src/ext/vulkan/rendermodes/multiview_stereoscopic_deferred.cpp index 05aeb569..b7b3cea3 100644 --- a/engine/src/ext/vulkan/rendermodes/multiview_stereoscopic_deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/multiview_stereoscopic_deferred.cpp @@ -121,7 +121,7 @@ void ext::vulkan::MultiviewStereoscopicDeferredRenderMode::initialize( Device& d uint32_t maxLights = 16; }; auto* specializationConstants = (SpecializationConstant*) &shader.specializationConstants[0]; - specializationConstants->maxLights = metadata["system"]["config"]["engine"]["scenes"]["max lights"].asUInt64(); + specializationConstants->maxLights = metadata["system"]["config"]["engine"]["scenes"]["max lights"].as(); for ( auto& binding : shader.descriptorSetLayoutBindings ) { if ( binding.descriptorCount > 1 ) @@ -180,13 +180,13 @@ void ext::vulkan::MultiviewStereoscopicDeferredRenderMode::createCommandBuffers( for ( auto& attachment : renderTarget.attachments ) { VkClearValue clearValue; if ( attachment.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ) { - if ( !metadata["system"]["renderer"]["clear values"][(int) clearValues.size()].isNull() ) { + if ( !ext::json::isNull( metadata["system"]["renderer"]["clear values"][(int) clearValues.size()] ) ) { auto& v = metadata["system"]["renderer"]["clear values"][(int) clearValues.size()]; clearValue.color = { { - v[0].asFloat(), - v[1].asFloat(), - v[2].asFloat(), - v[3].asFloat(), + v[0].as(), + v[1].as(), + v[2].as(), + v[3].as(), } }; } else { clearValue.color = { { 0, 0, 0, 0 } }; diff --git a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp index 8f9b1800..2d2fa522 100644 --- a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp @@ -24,10 +24,10 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { } attachments; attachments.albedo = renderTarget.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true ); // albedo - attachments.normals = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true ); // normals + attachments.normals = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, false ); // normals if ( !settings::experimental::deferredReconstructPosition ) - attachments.position = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true ); // position - attachments.depth = renderTarget.attach( device.formats.depth, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, true ); // depth + attachments.position = renderTarget.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, false ); // position + attachments.depth = renderTarget.attach( device.formats.depth, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false ); // depth // Attach swapchain's image as output if ( !false ) { attachments.output = renderTarget.attach( device.formats.color, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, true ); // output @@ -49,8 +49,8 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; - blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; } swapchainAttachment.blendState = blendAttachmentState; diff --git a/engine/src/ext/vulkan/rendermodes/stereoscopic_deferred.cpp b/engine/src/ext/vulkan/rendermodes/stereoscopic_deferred.cpp index eccbffc0..568c4239 100644 --- a/engine/src/ext/vulkan/rendermodes/stereoscopic_deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/stereoscopic_deferred.cpp @@ -162,13 +162,13 @@ void ext::vulkan::StereoscopicDeferredRenderMode::initialize( Device& device ) { int32_t maxLights = 16; }; auto& specializationConstants = shader.specializationConstants.get(); - specializationConstants.maxLights = metadata["system"]["config"]["engine"]["scenes"]["max lights"].asUInt64(); + specializationConstants.maxLights = metadata["system"]["config"]["engine"]["scenes"]["max lights"].as(); */ struct SpecializationConstant { uint32_t maxLights = 16; }; auto* specializationConstants = (SpecializationConstant*) &shader.specializationConstants[0]; - specializationConstants->maxLights = metadata["system"]["config"]["engine"]["scenes"]["max lights"].asUInt64(); + specializationConstants->maxLights = metadata["system"]["config"]["engine"]["scenes"]["max lights"].as(); for ( auto& binding : shader.descriptorSetLayoutBindings ) { if ( binding.descriptorCount > 1 ) @@ -252,13 +252,13 @@ void ext::vulkan::StereoscopicDeferredRenderMode::createCommandBuffers( const st for ( auto& attachment : renderTarget.attachments ) { VkClearValue clearValue; if ( attachment.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ) { - if ( !metadata["system"]["renderer"]["clear values"][(int) clearValues.size()].isNull() ) { + if ( !ext::json::isNull( metadata["system"]["renderer"]["clear values"][(int) clearValues.size()] ) ) { auto& v = metadata["system"]["renderer"]["clear values"][(int) clearValues.size()]; clearValue.color = { { - v[0].asFloat(), - v[1].asFloat(), - v[2].asFloat(), - v[3].asFloat(), + v[0].as(), + v[1].as(), + v[2].as(), + v[3].as(), } }; } else { clearValue.color = { { 0, 0, 0, 0 } }; diff --git a/engine/src/ext/vulkan/rendertarget.cpp b/engine/src/ext/vulkan/rendertarget.cpp index 0e13c88f..828f76be 100644 --- a/engine/src/ext/vulkan/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendertarget.cpp @@ -125,12 +125,36 @@ size_t ext::vulkan::RenderTarget::attach( VkFormat format, VkImageUsageFlags usa blendEnabled ); if ( blendEnabled == VK_TRUE ) { + /* blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; + */ + /* + blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; + blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE; + blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; + blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_DST_ALPHA; + */ + /* + blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; + blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; + */ + blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; + blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; } attachment->blendState = blendAttachmentState; } diff --git a/engine/src/ext/vulkan/vulkan.cpp b/engine/src/ext/vulkan/vulkan.cpp index 41478acb..24078586 100644 --- a/engine/src/ext/vulkan/vulkan.cpp +++ b/engine/src/ext/vulkan/vulkan.cpp @@ -149,7 +149,7 @@ bool ext::vulkan::hasRenderMode( const std::string& name, bool isName ) { ext::vulkan::RenderMode& ext::vulkan::addRenderMode( ext::vulkan::RenderMode* mode, const std::string& name ) { mode->name = name; renderModes.push_back(mode); - std::cout << "Adding RenderMode: " << name << ": " << mode->getType() << std::endl; + if ( ext::vulkan::settings::validation ) uf::iostream << "Adding RenderMode: " << name << ": " << mode->getType() << "\n"; // reorder ext::vulkan::states::rebuild = true; return *mode; @@ -170,7 +170,7 @@ ext::vulkan::RenderMode& ext::vulkan::getRenderMode( const std::string& name, bo } } } -// std::cout << "Requesting RenderMode `" << name << "`, got `" << target->getName() << "` (" << target->getType() << ")" << std::endl; +// if ( ext::vulkan::settings::validation ) uf::iostream << "Requesting RenderMode `" << name << "`, got `" << target->getName() << "` (" << target->getType() << ")" << "\n"; return *target; } std::vector ext::vulkan::getRenderModes( const std::string& name, bool isName ) { @@ -181,7 +181,7 @@ std::vector ext::vulkan::getRenderModes( const std::ve for ( auto& renderMode: renderModes ) { if ( ( isName && std::find(names.begin(), names.end(), renderMode->getName()) != names.end() ) || std::find(names.begin(), names.end(), renderMode->getType()) != names.end() ) { targets.push_back(renderMode); -// std::cout << "Requestings RenderMode `" << name << "`, got `" << renderMode->getName() << "` (" << renderMode->getType() << ")" << std::endl; +// if ( ext::vulkan::settings::validation ) uf::iostream << "Requestings RenderMode `" << name << "`, got `" << renderMode->getName() << "` (" << renderMode->getType() << ")" << "\n"; } } return targets; @@ -250,7 +250,7 @@ void ext::vulkan::initialize( uint8_t stage ) { graphic.initializePipeline(); ext::vulkan::states::rebuild = true; }; - for ( uf::Scene* scene : ext::vulkan::scenes ) { + for ( uf::Scene* scene : uf::scene::scenes ) { if ( !scene ) continue; scene->process(filter); } @@ -297,7 +297,7 @@ void ext::vulkan::tick() { graphic.initializePipeline(); ext::vulkan::states::rebuild = true; }; - for ( uf::Scene* scene : ext::vulkan::scenes ) { + for ( uf::Scene* scene : uf::scene::scenes ) { if ( !scene ) continue; scene->process(filter); } @@ -350,7 +350,7 @@ void ext::vulkan::render() { if ( !renderMode ) continue; if ( !renderMode->execute ) continue; ext::vulkan::currentRenderMode = renderMode; - for ( uf::Scene* scene : ext::vulkan::scenes ) scene->render(); + for ( uf::Scene* scene : uf::scene::scenes ) scene->render(); renderMode->render(); } @@ -371,7 +371,7 @@ void ext::vulkan::destroy() { uf::Graphic& graphic = entity->getComponent(); graphic.destroy(); }; - for ( uf::Scene* scene : ext::vulkan::scenes ) { + for ( uf::Scene* scene : uf::scene::scenes ) { if ( !scene ) continue; scene->process(filter); } @@ -379,7 +379,7 @@ void ext::vulkan::destroy() { for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue; renderMode->destroy(); - delete renderMode; + // delete renderMode; renderMode = NULL; } diff --git a/engine/src/spec/window/universal.cpp b/engine/src/spec/window/universal.cpp index ce30d3e9..2b6d0814 100644 --- a/engine/src/spec/window/universal.cpp +++ b/engine/src/spec/window/universal.cpp @@ -25,8 +25,8 @@ void UF_API_CALL spec::uni::Window::pushEvent( const uf::OptimalHook::name_t& na void UF_API_CALL spec::uni::Window::pushEvent( const uf::ReadableHook::argument_t& serialized ) { if ( !uf::hooks.prefersReadable() ) return; uf::Serializer json = serialized; - if ( !uf::hooks.exists(json["type"].asString()) ) return; - this->m_events.readable.push({json["type"].asString(), serialized}); + if ( !uf::hooks.exists(json["type"].as()) ) return; + this->m_events.readable.push({json["type"].as(), serialized}); } void UF_API_CALL spec::uni::Window::pushEvent( const uf::OptimalHook::argument_t& userdata ) { if ( uf::hooks.prefersReadable() ) return; diff --git a/engine/src/utils/audio/audio.cpp b/engine/src/utils/audio/audio.cpp index 672089e6..28c2e44c 100644 --- a/engine/src/utils/audio/audio.cpp +++ b/engine/src/utils/audio/audio.cpp @@ -21,6 +21,9 @@ UF_API uf::Audio::Audio( const uf::Audio& copy ) : { } */ + +bool uf::Audio::mute = false; + uf::Audio::~Audio() { this->destroy(); } @@ -31,6 +34,10 @@ bool UF_API uf::Audio::initialized() { return true; } void UF_API uf::Audio::destroy() { + { + auto filename = this->getFilename(); + if ( filename != "" ) std::cout << "Audio::Destroy() Destroying " << filename << std::endl; + } this->m_source.destroy(); this->m_buffer.destroy(); } @@ -39,10 +46,14 @@ bool UF_API uf::Audio::playing() { if ( !this->m_source.playing() ) return false; return true; } -void UF_API uf::Audio::load( const std::string& filename ) { if ( filename != "" ) this->m_filename = filename; +void UF_API uf::Audio::load( const std::string& filename ) { + if ( uf::Audio::mute ) return; + if ( this->initialized() ) this->destroy(); + if ( filename != "" ) this->m_filename = filename; + ALenum format; + ALsizei frequency; + std::vector buffer; std::string extension = uf::io::extension( this->m_filename ); - - std::vector buffer; ALenum format; ALsizei frequency; if ( extension == "ogg" ) { ext::Vorbis vorbis; vorbis.load( this->m_filename ); @@ -50,17 +61,19 @@ void UF_API uf::Audio::load( const std::string& filename ) { if ( filename != "" format = vorbis.getFormat(); frequency = vorbis.getFrequency(); this->m_duration = vorbis.getDuration(); - - this->m_buffer.generate(); ext::oal.checkError(__FUNCTION__, __LINE__); - this->m_source.generate(); ext::oal.checkError(__FUNCTION__, __LINE__); - - this->m_buffer.buffer( format, &buffer[0], buffer.size(), frequency ); ext::oal.checkError(__FUNCTION__, __LINE__); - this->m_source.source( "BUFFER", std::vector{ this->m_buffer.getIndex() } ); ext::oal.checkError(__FUNCTION__, __LINE__); - - this->m_source.source( "PITCH", std::vector{ 1 } ); ext::oal.checkError(__FUNCTION__, __LINE__); - this->m_source.source( "GAIN", std::vector{ 1 } ); ext::oal.checkError(__FUNCTION__, __LINE__); - this->m_source.source( "LOOPING", std::vector{ AL_FALSE } ); ext::oal.checkError(__FUNCTION__, __LINE__); } + + if ( buffer.empty() ) return; + + AL_CHECK_ERROR(this->m_buffer.generate()); + AL_CHECK_ERROR(this->m_source.generate()); + + AL_CHECK_ERROR(this->m_buffer.buffer( format, &buffer[0], buffer.size(), frequency )); + AL_CHECK_ERROR(this->m_source.source( "BUFFER", std::vector{ this->m_buffer.getIndex() } )); + + AL_CHECK_ERROR(this->m_source.source( "PITCH", std::vector{ 1 } )); + AL_CHECK_ERROR(this->m_source.source( "GAIN", std::vector{ 1 } )); + AL_CHECK_ERROR(this->m_source.source( "LOOPING", std::vector{ AL_FALSE } )); } void UF_API uf::Audio::play() { @@ -81,7 +94,7 @@ float uf::Audio::getDuration() const { ALfloat UF_API uf::Audio::getTime() { if ( !this->playing() ) return 0; ALfloat pos; - alGetSourcef(this->m_source.getIndex(), AL_SEC_OFFSET, &pos ); ext::oal.checkError(__FUNCTION__, __LINE__); + AL_CHECK_ERROR(alGetSourcef(this->m_source.getIndex(), AL_SEC_OFFSET, &pos )); return pos; } void UF_API uf::Audio::setTime( ALfloat pos ) { @@ -92,7 +105,7 @@ void UF_API uf::Audio::setTime( ALfloat pos ) { ALfloat UF_API uf::Audio::getPitch() { if ( !this->initialized() ) return 0; ALfloat pitch; - alGetSourcef(this->m_source.getIndex(), AL_PITCH, &pitch ); ext::oal.checkError(__FUNCTION__, __LINE__); + AL_CHECK_ERROR(alGetSourcef(this->m_source.getIndex(), AL_PITCH, &pitch )); return pitch; } void UF_API uf::Audio::setPitch( ALfloat pitch ) { @@ -103,7 +116,7 @@ void UF_API uf::Audio::setPitch( ALfloat pitch ) { ALfloat UF_API uf::Audio::getGain() { if ( !this->initialized() ) return 0; ALfloat gain; - alGetSourcef(this->m_source.getIndex(), AL_GAIN, &gain ); ext::oal.checkError(__FUNCTION__, __LINE__); + AL_CHECK_ERROR(alGetSourcef(this->m_source.getIndex(), AL_GAIN, &gain )); return gain; } void UF_API uf::Audio::setGain( ALfloat gain ) { @@ -114,7 +127,7 @@ void UF_API uf::Audio::setGain( ALfloat gain ) { ALfloat UF_API uf::Audio::getRolloffFactor() { if ( !this->initialized() ) return 0; ALfloat rolloffFactor; - alGetSourcef(this->m_source.getIndex(), AL_ROLLOFF_FACTOR, &rolloffFactor ); ext::oal.checkError(__FUNCTION__, __LINE__); + AL_CHECK_ERROR(alGetSourcef(this->m_source.getIndex(), AL_ROLLOFF_FACTOR, &rolloffFactor )); return rolloffFactor; } void UF_API uf::Audio::setRolloffFactor( ALfloat rolloffFactor ) { @@ -125,7 +138,7 @@ void UF_API uf::Audio::setRolloffFactor( ALfloat rolloffFactor ) { ALfloat UF_API uf::Audio::getMaxDistance() { if ( !this->initialized() ) return 0; ALfloat maxDistance; - alGetSourcef(this->m_source.getIndex(), AL_MAX_DISTANCE, &maxDistance ); ext::oal.checkError(__FUNCTION__, __LINE__); + AL_CHECK_ERROR(alGetSourcef(this->m_source.getIndex(), AL_MAX_DISTANCE, &maxDistance )); return maxDistance; } void UF_API uf::Audio::setMaxDistance( ALfloat maxDistance ) { @@ -146,10 +159,14 @@ void UF_API uf::Audio::setVolume( float volume ) { } float UF_API uf::Audio::getVolume() const { ALfloat pos; - alGetSourcef(this->m_source.getIndex(), AL_GAIN, &pos ); ext::oal.checkError(__FUNCTION__, __LINE__); + AL_CHECK_ERROR(alGetSourcef(this->m_source.getIndex(), AL_GAIN, &pos )); return pos; } +uf::SoundEmitter::~SoundEmitter() { + this->cleanup(true); +} + uf::Audio& UF_API uf::SoundEmitter::add( const std::string& filename ) { if ( this->m_container.find( filename ) != this->m_container.end() ) return this->get(filename); uf::Audio& sound = this->m_container[filename]; @@ -176,7 +193,9 @@ const uf::SoundEmitter::container_t& UF_API uf::SoundEmitter::get() const { void UF_API uf::SoundEmitter::cleanup( bool purge ) { for ( auto& pair : this->m_container ) { - if ( !pair.second.playing() ) { + if ( purge || !pair.second.playing() ) { + pair.second.stop(); + pair.second.destroy(); this->m_container.erase(pair.first); } } diff --git a/engine/src/utils/component/component.cpp b/engine/src/utils/component/component.cpp index b53c24c8..8324e3c4 100644 --- a/engine/src/utils/component/component.cpp +++ b/engine/src/utils/component/component.cpp @@ -2,17 +2,15 @@ UF_API uf::MemoryPool uf::component::memoryPool; uf::Component::~Component() { + this->destroyComponents(); +} + +void uf::Component::destroyComponents() { for ( auto& kv : this->m_container ) { pod::Component& component = kv.second; uf::userdata::destroy(uf::component::memoryPool, component.userdata); - /* - if ( uf::component::memoryPool.size() > 0 ) { - uf::userdata::destroy(uf::component::memoryPool, component.userdata); - } else { - uf::userdata::destroy(component.userdata); - } - */ } + this->m_container.clear(); } #include diff --git a/engine/src/utils/hook/hook.cpp b/engine/src/utils/hook/hook.cpp index 4a0d0985..efa70aaa 100644 --- a/engine/src/utils/hook/hook.cpp +++ b/engine/src/utils/hook/hook.cpp @@ -125,20 +125,32 @@ bool uf::HookHandler::isAliasToOptimal( const Readable::alias_t::name_t& name ) } // Calls a hook in either readable or optimal format (no argument is passed unless it's aliased) -void uf::HookHandler::call( const Readable::name_t& name ) { - if ( !this->exists(name) ) return; - this->call(name, Readable::argument_t()); - this->call(name, Optimal::argument_t()); +std::vector uf::HookHandler::call( const Readable::name_t& name ) { + struct { + std::vector readable; + std::vector optimal; + } returns; + if ( !this->exists(name) ) return returns.readable; + + returns.readable = this->call(name, Readable::argument_t()); + returns.optimal = this->call(name, Optimal::argument_t()); +/* + if ( typeid(Readable::return_t) == typeid(Optimal::return_t) ) { + returns.readable.insert( returns.readable.end(), returns.optimal.begin(), returns.optimal.end() ); + } +*/ + return returns.readable; } // Calls a hook in readable format std::vector uf::HookHandler::call( const Readable::name_t& name, const Readable::argument_t& argument ) { - std::vector returns; + std::vector returns; if ( !this->exists(name) ) return returns; if ( !this->isReadable(name) ) { if ( !this->isAliasToReadable(name) ) return returns; auto& aliases = this->m_readable.aliases.at(name); for ( auto& alias : aliases ) { - this->call( alias.name, (argument != "" ? argument : alias.argument) ); + auto result = this->call( alias.name, (argument != "" ? argument : alias.argument) ); + returns.insert( returns.end(), result.begin(), result.end() ); } return returns; } @@ -155,36 +167,25 @@ std::vector uf::HookHandler::call( const Re return returns; } // Calls a hook in optimal format -void uf::HookHandler::call( const Optimal::name_t& name, const Optimal::argument_t& argument ) { - if ( !this->exists(name) ) return; +std::vector uf::HookHandler::call( const Optimal::name_t& name, const Optimal::argument_t& argument ) { + std::vector returns; + if ( !this->exists(name) ) return returns; if ( !this->isOptimal(name) ) { - if ( !this->isAliasToOptimal(name) ) return; + if ( !this->isAliasToOptimal(name) ) return returns; auto& aliases = this->m_optimal.aliases.at(name); for ( auto& alias : aliases ) { - this->call( alias.name, (argument ? argument : alias.argument) ); + auto result = this->call( alias.name, (argument ? argument : alias.argument) ); + returns.insert( returns.end(), result.begin(), result.end() ); } - return; + return returns; } auto& hooks = this->m_optimal.hooks.at(name); for ( auto& hook : hooks ) { - hook( argument ); - /* - try { - hook( argument ); - } catch ( std::exception& e ) { - uf::iostream << "ERROR: Exception thrown while calling hook `" << name << "`!" << "\n" - << "\twhat(): " << e.what() << "\n"; - // throw; - } catch ( bool handled ) { - if ( !handled ) throw; - } catch ( ... ) { - uf::iostream << "ERROR: Exception thrown while calling hook `" << name << "`!" << "\n" - << "\twhat(): " << "???" << "\n"; - // throw; - } - */ + auto result = hook( argument ); + returns.push_back(result); } + return returns; } /* diff --git a/engine/src/utils/serialize/serializer.cpp b/engine/src/utils/serialize/serializer.cpp index 42c9aa51..d2f01d4d 100644 --- a/engine/src/utils/serialize/serializer.cpp +++ b/engine/src/utils/serialize/serializer.cpp @@ -8,30 +8,54 @@ #include #include -uf::Serializer::Serializer( const std::string& str ) { - this->deserialize(str); -} -uf::Serializer::Serializer( const Json::Value& json ) { - try { - *this = json; - } catch (...) { - // ignore parse errors +namespace { + std::string encode( const Json::Value& json, bool pretty = true ) { +/* + std::stringstream ss; + if ( pretty ) { + ss << json; + } else { + Json::StreamWriterBuilder builder; + builder["commentStyle"] = "None"; + builder["indentation"] = ""; + std::unique_ptr writer( builder.newStreamWriter() ); + writer->write(json, &ss); + } + return ss.str(); +*/ + Json::FastWriter fast; + Json::StyledWriter styled; + std::string output = pretty ? styled.write(json) : fast.write(json); + if ( output.back() == '\n' ) output.pop_back(); + return output; + } + std::string encode( const sol::table& table ) { + return ext::lua::state["json"]["encode"]( table ); + } + + void decode( Json::Value& json, const std::string& str ) { + Json::Reader reader; + if ( !reader.parse(str, json) ) { + uf::iostream << "JSON Error: " << reader.getFormattedErrorMessages() << "\n"; + } } } -uf::Serializer::output_t uf::Serializer::serialize() const { - std::stringstream ss; - ss << *this; - return ss.str(); + +uf::Serializer::Serializer( const std::string& str ) { //: sol::table(ext::lua::state, sol::create) { + this->deserialize(str); +} +uf::Serializer::Serializer( const sol::table& table ) { //: sol::table(ext::lua::state, sol::create) { + this->deserialize( encode( table ) ); +} +uf::Serializer::Serializer( const Json::Value& json ) { //: sol::table(ext::lua::state, sol::create) { + this->deserialize( encode( json ) ); +} +uf::Serializer::output_t uf::Serializer::serialize( bool pretty ) const { + return encode( *this, pretty ); } void uf::Serializer::deserialize( const std::string& str ) { - if ( str != "" ) - try { - std::stringstream(str) >> *this; - } catch ( const std::exception& e ) { - uf::iostream << "Error: " << e.what() << "\n"; - } catch (...) { - // ignore parse errors - } + if ( str == "" ) return; + decode( *this, str ); } bool uf::Serializer::readFromFile( const std::string& from ) { @@ -68,13 +92,21 @@ bool uf::Serializer::writeToFile( const std::string& to ) const { } void uf::Serializer::merge( const uf::Serializer& other, bool priority ) { - if ( !this->isObject() || !other.isObject() ) return; + if ( !ext::json::isObject( *this ) || !ext::json::isObject( other ) ) return; std::function update = [&]( Json::Value& a, const Json::Value& b ) { - if ( !b.isObject() ) return; + if ( !ext::json::isObject( b ) ) return; for ( const auto& key : b.getMemberNames() ) { - if ( !a.isObject() || !priority ) a[key] = b[key]; + /* + if ( !ext::json::isObject( a ) || !priority ) + a[key] = b[key]; update(a[key], b[key]); + */ + if( a[key].type() == Json::objectValue && b[key].type() == Json::objectValue ) { + update(a[key], b[key]); + } + if ( !priority ) + a[key] = b[key]; } }; @@ -92,8 +124,12 @@ uf::Serializer& uf::Serializer::operator=( const std::string& str ) { this->deserialize(str); return *this; } +uf::Serializer& uf::Serializer::operator=( const sol::table& table ) { + this->deserialize( encode( table ) ); + return *this; +} uf::Serializer& uf::Serializer::operator=( const Json::Value& json ) { - Value::operator=(json); + this->deserialize( encode( json ) ); return *this; } uf::Serializer& uf::Serializer::operator<<( const std::string& str ) { diff --git a/engine/src/utils/string/ext.cpp b/engine/src/utils/string/ext.cpp index e9640f0e..703af954 100644 --- a/engine/src/utils/string/ext.cpp +++ b/engine/src/utils/string/ext.cpp @@ -15,15 +15,29 @@ std::string UF_API uf::string::uppercase( const std::string& str ) { std::transform(upper.begin(), upper.end(), upper.begin(), ::toupper); return upper; } -std::vector UF_API uf::string::split( const std::string& haystack, const std::string& needle ) { +#include +std::vector UF_API uf::string::split( const std::string& str, const std::string& delim ) { + std::vector tokens; + size_t prev = 0, pos = 0; + do { + pos = str.find(delim, prev); + if (pos == std::string::npos) pos = str.length(); + std::string token = str.substr(prev, pos-prev); + if (!token.empty()) tokens.push_back(token); + prev = pos + delim.length(); + } while (pos < str.length() && prev < str.length()); + if ( tokens.empty() ) tokens.emplace_back(str); + return tokens; +/* std::vector cont; size_t last = 0, next = 0; - while ((next = haystack.find(needle, last)) != std::string::npos) { - cont.push_back(haystack.substr(last, next-last)); + while ((next = str.find(needle, last)) != std::string::npos) { + cont.push_back(str.substr(last, next-last)); last = next + 1; } - cont.push_back( haystack.substr(last) ); + cont.push_back( str.substr(last) ); return cont; +*/ } std::string UF_API uf::string::replace( const std::string& string, const std::string& search, const std::string& replace ) { std::string result = string; diff --git a/engine/src/utils/userdata/userdata.cpp b/engine/src/utils/userdata/userdata.cpp index eca20f28..d0fd7eb7 100644 --- a/engine/src/utils/userdata/userdata.cpp +++ b/engine/src/utils/userdata/userdata.cpp @@ -51,22 +51,29 @@ void UF_API uf::userdata::destroy( pod::Userdata* userdata ) { */ } +size_t uf::userdata::size( size_t len, size_t padding ) { + padding = 0; + // return sizeof(pod::Userdata) + len + ( sizeof(uint8_t) * padding ); + return sizeof(size_t) + len + ( sizeof(uint8_t) * padding ); +} + // pod::Userdata* UF_API uf::userdata::create( uf::MemoryPool& requestedMemoryPool, std::size_t len, void* data ) { if ( len <= 0 ) return NULL; + size_t requestedLen = size( len ); // uf::MemoryPool& memoryPool = uf::MemoryPool::global.size() > 0 ? uf::MemoryPool::global : requestedMemoryPool; #if UF_MEMORYPOOL_INVALID_MALLOC uf::MemoryPool& memoryPool = requestedMemoryPool.size() > 0 ? requestedMemoryPool : uf::MemoryPool::global; - pod::Userdata* userdata = (pod::Userdata*) memoryPool.alloc( data, sizeof(pod::Userdata) + len ); + pod::Userdata* userdata = (pod::Userdata*) memoryPool.alloc( data, requestedLen ); #else uf::MemoryPool* memoryPool = NULL; if ( requestedMemoryPool.size() > 0 ) memoryPool = &requestedMemoryPool; else if ( uf::MemoryPool::global.size() > 0 ) memoryPool = &uf::MemoryPool::global; pod::Userdata* userdata = NULL; if ( memoryPool ) - userdata = (pod::Userdata*) memoryPool->alloc( data, sizeof(pod::Userdata) + len ); + userdata = (pod::Userdata*) memoryPool->alloc( data, requestedLen ); else { - userdata = (pod::Userdata*) operator new( sizeof(pod::Userdata) + len ); // allocate data for the userdata struct, and then some + userdata = (pod::Userdata*) operator new( requestedLen ); // allocate data for the userdata struct, and then some if ( data ) memcpy( userdata->data, data, len ); else memset( userdata->data, 0, len ); } @@ -75,7 +82,7 @@ pod::Userdata* UF_API uf::userdata::create( uf::MemoryPool& requestedMemoryPool, return userdata; /* if ( uf::userdata::memoryPool.size() > 0 ) { - auto allocation = uf::userdata::memoryPool.allocate( NULL, sizeof(pod::Userdata) + len ); + auto allocation = uf::userdata::memoryPool.allocate( NULL, requestedLen ); pod::Userdata* userdata = (pod::Userdata*) allocation.pointer; if ( data ) memcpy( userdata->data, data, len ); else memset( userdata->data, 0, len ); diff --git a/ext/behaviors/craeture/behavior.cpp b/ext/behaviors/craeture/behavior.cpp index b9088d87..91a58078 100644 --- a/ext/behaviors/craeture/behavior.cpp +++ b/ext/behaviors/craeture/behavior.cpp @@ -18,7 +18,7 @@ #include -EXT_BEHAVIOR_REGISTER_CPP(CraetureBehavior) +UF_BEHAVIOR_REGISTER_CPP(ext::CraetureBehavior) #define this (&self) void ext::CraetureBehavior::initialize( uf::Object& self ) { pod::Transform<>& transform = this->getComponent>(); @@ -36,11 +36,11 @@ void ext::CraetureBehavior::initialize( uf::Object& self ) { /* Gravity */ { if ( metadata["system"]["physics"]["gravity"] != Json::nullValue ) { - physics.linear.acceleration.x = metadata["system"]["physics"]["gravity"][0].asFloat(); - physics.linear.acceleration.y = metadata["system"]["physics"]["gravity"][1].asFloat(); - physics.linear.acceleration.z = metadata["system"]["physics"]["gravity"][2].asFloat(); + physics.linear.acceleration.x = metadata["system"]["physics"]["gravity"][0].as(); + physics.linear.acceleration.y = metadata["system"]["physics"]["gravity"][1].as(); + physics.linear.acceleration.z = metadata["system"]["physics"]["gravity"][2].as(); } - if ( !metadata["system"]["physics"]["collision"].asBool() ) { + if ( !metadata["system"]["physics"]["collision"].as() ) { physics.linear.acceleration.x = 0; physics.linear.acceleration.y = 0; physics.linear.acceleration.z = 0; @@ -69,18 +69,18 @@ void ext::CraetureBehavior::initialize( uf::Object& self ) { this->addHook( "world:Collision.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - size_t uid = json["uid"].asUInt64(); + size_t uid = json["uid"].as(); // do not collide with children // if ( this->findByUid(uid) ) return "false"; pod::Vector3 normal; - float scale = metadata["system"]["physics"]["collision"].asFloat(); - float depth = json["depth"].asFloat() * scale; + float scale = metadata["system"]["physics"]["collision"].as(); + float depth = json["depth"].as() * scale; // if ( fabs(depth) < 0.005 ) return "false"; //std::cout << "Collision depth: " << depth << std::endl; - normal.x = json["normal"][0].asFloat(); - normal.y = json["normal"][1].asFloat(); - normal.z = json["normal"][2].asFloat(); + normal.x = json["normal"][0].as(); + normal.y = json["normal"][1].as(); + normal.z = json["normal"][2].as(); pod::Vector3 correction = normal * depth; transform.position -= correction; @@ -97,13 +97,13 @@ void ext::CraetureBehavior::initialize( uf::Object& self ) { uf::Scene& world = uf::scene::getCurrentScene(); uf::Serializer& masterdata = world.getComponent(); - std::string filename = json["filename"].asString(); + std::string filename = json["filename"].as(); if ( uf::io::extension(filename) != "ogg" ) return "false"; if ( filename == "" ) return "false"; uf::Audio& sfx = this->getComponent().add(filename); - sfx.setVolume(masterdata["volumes"]["sfx"].asFloat()); + sfx.setVolume(masterdata["volumes"]["sfx"].as()); auto& pTransform = world.getController().getComponent>(); sfx.setPosition( transform.position ); sfx.play(); @@ -112,15 +112,15 @@ void ext::CraetureBehavior::initialize( uf::Object& self ) { }); this->addHook( "world:Craeture.OnHit.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - uint64_t phase = json["phase"].asUInt64(); + uint64_t phase = json["phase"].as(); // start color pod::Vector4f color = { 1, 1, 1, 0 }; if ( phase == 0 ) { color = pod::Vector4f{ - json["color"][0].asFloat(), - json["color"][1].asFloat(), - json["color"][2].asFloat(), - json["color"][3].asFloat(), + json["color"][0].as(), + json["color"][1].as(), + json["color"][2].as(), + json["color"][3].as(), }; } metadata["color"][0] = color[0]; @@ -128,7 +128,7 @@ void ext::CraetureBehavior::initialize( uf::Object& self ) { metadata["color"][2] = color[2]; metadata["color"][3] = color[3]; - if ( metadata["timers"]["hurt"].asFloat() < timer.elapsed().asDouble() ) { + if ( metadata["timers"]["hurt"].as() < timer.elapsed().asDouble() ) { metadata["timers"]["hurt"] = timer.elapsed().asDouble() + 1.0f; uf::Scene& scene = uf::scene::getCurrentScene(); @@ -140,7 +140,7 @@ void ext::CraetureBehavior::initialize( uf::Object& self ) { }); this->addHook( "world:Craeture.Hurt.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - if ( metadata["timers"]["flash"].asFloat() < timer.elapsed().asDouble() ) { + if ( metadata["timers"]["flash"].as() < timer.elapsed().asDouble() ) { metadata["timers"]["flash"] = timer.elapsed().asDouble() + 0.4f; for ( int i = 0; i < 16; ++i ) { uf::Serializer payload; @@ -162,18 +162,18 @@ void ext::CraetureBehavior::tick( uf::Object& self ) { uf::Serializer& sMetadata = scene.getComponent(); uf::Serializer& pMetadata = scene.getController().getComponent(); - if ( !pMetadata["system"]["control"].asBool() ) return; - if ( !sMetadata["system"]["physics"]["optimizations"]["entity-local update"].asBool() ) return; + if ( !pMetadata["system"]["control"].as() ) return; + if ( !sMetadata["system"]["physics"]["optimizations"]["entity-local update"].as() ) return; pod::Transform<>& transform = this->getComponent>(); pod::Physics& physics = this->getComponent(); /* Gravity */ { if ( metadata["system"]["physics"]["gravity"] != Json::nullValue ) { - physics.linear.acceleration.x = metadata["system"]["physics"]["gravity"][0].asFloat(); - physics.linear.acceleration.y = metadata["system"]["physics"]["gravity"][1].asFloat(); - physics.linear.acceleration.z = metadata["system"]["physics"]["gravity"][2].asFloat(); + physics.linear.acceleration.x = metadata["system"]["physics"]["gravity"][0].as(); + physics.linear.acceleration.y = metadata["system"]["physics"]["gravity"][1].as(); + physics.linear.acceleration.z = metadata["system"]["physics"]["gravity"][2].as(); } - if ( !metadata["system"]["physics"]["collision"].asBool() ) { + if ( !metadata["system"]["physics"]["collision"].as() ) { physics.linear.acceleration.x = 0; physics.linear.acceleration.y = 0; physics.linear.acceleration.z = 0; diff --git a/ext/behaviors/hands/behavior.cpp b/ext/behaviors/hands/behavior.cpp index 3d6e822c..586f6b7f 100644 --- a/ext/behaviors/hands/behavior.cpp +++ b/ext/behaviors/hands/behavior.cpp @@ -25,7 +25,7 @@ namespace { } hands, lines, lights; } -EXT_BEHAVIOR_REGISTER_CPP(PlayerHandBehavior) +UF_BEHAVIOR_REGISTER_CPP(ext::PlayerHandBehavior) #define this (&self) void ext::PlayerHandBehavior::initialize( uf::Object& self ) { uf::Serializer& metadata = this->getComponent(); @@ -46,18 +46,18 @@ void ext::PlayerHandBehavior::initialize( uf::Object& self ) { { bool loaded = true; for ( auto it = metadata["hands"].begin(); it != metadata["hands"].end(); ++it ) { - std::string key = it.key().asString(); - if ( !ext::openvr::requestRenderModel(metadata["hands"][key]["controller"]["model"].asString()) ) loaded = false; + std::string key = it.key().as(); + if ( !ext::openvr::requestRenderModel(metadata["hands"][key]["controller"]["model"].as()) ) loaded = false; } if ( !loaded ) { this->addHook( "VR:Model.Loaded", [&](const std::string& event)->std::string{ uf::Serializer json = event; - std::string name = json["name"].asString(); + std::string name = json["name"].as(); std::string side = ""; - if ( name == metadata["hands"]["left"]["controller"]["model"].asString() ) { + if ( name == metadata["hands"]["left"]["controller"]["model"].as() ) { side = "left"; - } else if ( name == metadata["hands"]["right"]["controller"]["model"].asString() ) { + } else if ( name == metadata["hands"]["right"]["controller"]["model"].as() ) { side = "right"; }; if ( side == "" ) return "false"; @@ -77,22 +77,22 @@ void ext::PlayerHandBehavior::initialize( uf::Object& self ) { uf::instantiator::bind( "ObjectBehavior", hand ); hand.initialize(); } - if ( metadata["hands"][side]["pointer"]["length"].asFloat() > 0 ) { + if ( metadata["hands"][side]["pointer"]["length"].as() > 0 ) { line.addAlias(); pod::Transform<>& transform = line.getComponent>(); transform.orientation = uf::quaternion::axisAngle( { - metadata["hands"][side]["pointer"]["orientation"]["axis"][0].asFloat(), - metadata["hands"][side]["pointer"]["orientation"]["axis"][1].asFloat(), - metadata["hands"][side]["pointer"]["orientation"]["axis"][2].asFloat() + metadata["hands"][side]["pointer"]["orientation"]["axis"][0].as(), + metadata["hands"][side]["pointer"]["orientation"]["axis"][1].as(), + metadata["hands"][side]["pointer"]["orientation"]["axis"][2].as() }, - metadata["hands"][side]["pointer"]["orientation"]["angle"].asFloat() * 3.14159f / 180.0f + metadata["hands"][side]["pointer"]["orientation"]["angle"].as() * 3.14159f / 180.0f ); transform.position = { - metadata["hands"][side]["pointer"]["offset"][0].asFloat(), - metadata["hands"][side]["pointer"]["offset"][1].asFloat(), - metadata["hands"][side]["pointer"]["offset"][2].asFloat() + metadata["hands"][side]["pointer"]["offset"][0].as(), + metadata["hands"][side]["pointer"]["offset"][1].as(), + metadata["hands"][side]["pointer"]["offset"][2].as() }; auto& mesh = line.getComponent(); @@ -100,7 +100,7 @@ void ext::PlayerHandBehavior::initialize( uf::Object& self ) { mesh.vertices = { { {0.0f, 0.0f, 0.0f} }, - { {0.0f, 0.0f, metadata["hands"][side]["pointer"]["length"].asFloat()} }, + { {0.0f, 0.0f, metadata["hands"][side]["pointer"]["length"].as()} }, }; graphic.initialize(); graphic.initializeGeometry(mesh); @@ -109,11 +109,11 @@ void ext::PlayerHandBehavior::initialize( uf::Object& self ) { graphic.material.attachShader("./data/shaders/line.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); graphic.descriptor.topology = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; graphic.descriptor.fill = VK_POLYGON_MODE_LINE; - graphic.descriptor.lineWidth = metadata["hands"][side]["pointer"]["width"].asFloat(); + graphic.descriptor.lineWidth = metadata["hands"][side]["pointer"]["width"].as(); line.initialize(); } - if ( metadata["hands"][side]["light"]["should"].asBool() ){ + if ( metadata["hands"][side]["light"]["should"].as() ){ auto& child = hand.loadChild("/light.json", false); if (side == "left" ) lights.left = &child; @@ -124,11 +124,11 @@ void ext::PlayerHandBehavior::initialize( uf::Object& self ) { auto& light = side == "left" ? *lights.left : *lights.right; auto& metadata = light.getComponent(); - if ( !json["color"].isNull() ) metadata["light"]["color"] = json["color"]; - if ( !json["radius"].isNull() ) metadata["light"]["radius"] = json["radius"]; - if ( !json["power"].isNull() ) metadata["light"]["power"] = json["power"]; - if ( !json["type"].isNull() ) metadata["light"]["type"] = json["type"]; - if ( !json["shadows"].isNull() ) metadata["light"]["shadows"] = json["shadows"]; + if ( !ext::json::isNull( json["color"] ) ) metadata["light"]["color"] = json["color"]; + if ( !ext::json::isNull( json["radius"] ) ) metadata["light"]["radius"] = json["radius"]; + if ( !ext::json::isNull( json["power"] ) ) metadata["light"]["power"] = json["power"]; + if ( !ext::json::isNull( json["type"] ) ) metadata["light"]["type"] = json["type"]; + if ( !ext::json::isNull( json["shadows"] ) ) metadata["light"]["shadows"] = json["shadows"]; metadata["lights"]["external update"] = true; // light.initialize(); @@ -140,10 +140,10 @@ void ext::PlayerHandBehavior::initialize( uf::Object& self ) { auto& light = side == "left" ? *lights.left : *lights.right; auto& metadata = light.getComponent(); - if ( !json["color"].isNull() ) metadata["light"]["color"] = json["color"]; - if ( !json["radius"].isNull() ) metadata["light"]["radius"] = json["radius"]; - if ( !json["power"].isNull() ) metadata["light"]["power"] = json["power"]; - if ( !json["shadows"].isNull() ) metadata["light"]["shadows"] = json["shadows"]; + if ( !ext::json::isNull( json["color"] ) ) metadata["light"]["color"] = json["color"]; + if ( !ext::json::isNull( json["radius"] ) ) metadata["light"]["radius"] = json["radius"]; + if ( !ext::json::isNull( json["power"] ) ) metadata["light"]["power"] = json["power"]; + if ( !ext::json::isNull( json["shadows"] ) ) metadata["light"]["shadows"] = json["shadows"]; metadata["lights"]["external update"] = true; light.initialize(); @@ -161,22 +161,22 @@ void ext::PlayerHandBehavior::initialize( uf::Object& self ) { uf::Serializer json = event; std::string side = &hand == hands.left ? "left" : "right"; - if ( json["hand"].asString() != side ) return "false"; + if ( json["hand"].as() != side ) return "false"; // fire mouse click - if ( json["name"].asString() == "click" ) { + if ( json["name"].as() == "click" ) { uf::Serializer payload; payload["type"] = "window:Mouse.Click"; payload["invoker"] = "vr"; - payload["mouse"]["position"]["x"] = metadata["hands"][side]["cursor"]["position"][0].asFloat(); - payload["mouse"]["position"]["y"] = metadata["hands"][side]["cursor"]["position"][1].asFloat(); + payload["mouse"]["position"]["x"] = metadata["hands"][side]["cursor"]["position"][0].as(); + payload["mouse"]["position"]["y"] = metadata["hands"][side]["cursor"]["position"][1].as(); payload["mouse"]["delta"]["x"] = 0; payload["mouse"]["delta"]["y"] = 0; payload["mouse"]["button"] = side == "left" ? "Right" : "Left"; - payload["mouse"]["state"] = json["state"].asBool() ? "Down": "Up"; + payload["mouse"]["state"] = json["state"].as() ? "Down": "Up"; - uf::hooks.call( payload["type"].asString(), payload ); + uf::hooks.call( payload["type"].as(), payload ); } return "true"; @@ -186,7 +186,7 @@ void ext::PlayerHandBehavior::initialize( uf::Object& self ) { std::string side = &hand == hands.left ? "left" : "right"; - float mag = json["depth"].asFloat(); + float mag = json["depth"].as(); uf::Serializer payload; payload["delay"] = 0.0f; payload["duration"] = uf::physics::time::delta; @@ -312,24 +312,24 @@ void ext::PlayerHandBehavior::tick( uf::Object& self ) { pod::Transform<> gtransform; pod::Matrix4f mvp; uf::Serializer& cMetadata = controller.getComponent(); - if ( cMetadata["overlay"]["position"].isArray() ) + if ( ext::json::isArray( cMetadata["overlay"]["position"] ) ) gtransform.position = { - cMetadata["overlay"]["position"][0].asFloat(), - cMetadata["overlay"]["position"][1].asFloat(), - cMetadata["overlay"]["position"][2].asFloat(), + cMetadata["overlay"]["position"][0].as(), + cMetadata["overlay"]["position"][1].as(), + cMetadata["overlay"]["position"][2].as(), }; - if ( cMetadata["overlay"]["scale"].isArray() ) + if ( ext::json::isArray( cMetadata["overlay"]["scale"] ) ) gtransform.scale = { - cMetadata["overlay"]["scale"][0].asFloat(), - cMetadata["overlay"]["scale"][1].asFloat(), - cMetadata["overlay"]["scale"][2].asFloat(), + cMetadata["overlay"]["scale"][0].as(), + cMetadata["overlay"]["scale"][1].as(), + cMetadata["overlay"]["scale"][2].as(), }; - if ( cMetadata["overlay"]["orientation"].isArray() ) + if ( ext::json::isArray( cMetadata["overlay"]["orientation"] ) ) gtransform.orientation = { - cMetadata["overlay"]["orientation"][0].asFloat(), - cMetadata["overlay"]["orientation"][1].asFloat(), - cMetadata["overlay"]["orientation"][2].asFloat(), - cMetadata["overlay"]["orientation"][3].asFloat(), + cMetadata["overlay"]["orientation"][0].as(), + cMetadata["overlay"]["orientation"][1].as(), + cMetadata["overlay"]["orientation"][2].as(), + cMetadata["overlay"]["orientation"][3].as(), }; plane.center = gtransform.position; @@ -390,10 +390,10 @@ void ext::PlayerHandBehavior::render( uf::Object& self ){ uniforms.matrices.view[i] = camera.getView( i ); uniforms.matrices.projection[i] = camera.getProjection( i ); } - uniforms.color[0] = metadata["hands"]["left"]["controller"]["color"][0].asFloat(); - uniforms.color[1] = metadata["hands"]["left"]["controller"]["color"][1].asFloat(); - uniforms.color[2] = metadata["hands"]["left"]["controller"]["color"][2].asFloat(); - uniforms.color[3] = metadata["hands"]["left"]["controller"]["color"][3].asFloat(); + uniforms.color[0] = metadata["hands"]["left"]["controller"]["color"][0].as(); + uniforms.color[1] = metadata["hands"]["left"]["controller"]["color"][1].as(); + uniforms.color[2] = metadata["hands"]["left"]["controller"]["color"][2].as(); + uniforms.color[3] = metadata["hands"]["left"]["controller"]["color"][3].as(); // graphic.updateBuffer( uniforms, 0, false ); if ( uf::renderer::currentRenderMode ) { @@ -420,10 +420,10 @@ void ext::PlayerHandBehavior::render( uf::Object& self ){ uniforms.matrices.view[i] = camera.getView( i ); uniforms.matrices.projection[i] = camera.getProjection( i ); } - uniforms.color[0] = metadata["hands"]["right"]["controller"]["color"][0].asFloat(); - uniforms.color[1] = metadata["hands"]["right"]["controller"]["color"][1].asFloat(); - uniforms.color[2] = metadata["hands"]["right"]["controller"]["color"][2].asFloat(); - uniforms.color[3] = metadata["hands"]["right"]["controller"]["color"][3].asFloat(); + uniforms.color[0] = metadata["hands"]["right"]["controller"]["color"][0].as(); + uniforms.color[1] = metadata["hands"]["right"]["controller"]["color"][1].as(); + uniforms.color[2] = metadata["hands"]["right"]["controller"]["color"][2].as(); + uniforms.color[3] = metadata["hands"]["right"]["controller"]["color"][3].as(); // graphic.updateBuffer( uniforms, 0, false ); if ( uf::renderer::currentRenderMode ) { @@ -450,10 +450,10 @@ void ext::PlayerHandBehavior::render( uf::Object& self ){ uniforms.matrices.view[i] = camera.getView( i ); uniforms.matrices.projection[i] = camera.getProjection( i ); } - uniforms.color[0] = metadata["hands"]["left"]["pointer"]["color"][0].asFloat(); - uniforms.color[1] = metadata["hands"]["left"]["pointer"]["color"][1].asFloat(); - uniforms.color[2] = metadata["hands"]["left"]["pointer"]["color"][2].asFloat(); - uniforms.color[3] = metadata["hands"]["left"]["pointer"]["color"][3].asFloat(); + uniforms.color[0] = metadata["hands"]["left"]["pointer"]["color"][0].as(); + uniforms.color[1] = metadata["hands"]["left"]["pointer"]["color"][1].as(); + uniforms.color[2] = metadata["hands"]["left"]["pointer"]["color"][2].as(); + uniforms.color[3] = metadata["hands"]["left"]["pointer"]["color"][3].as(); // graphic.updateBuffer( uniforms, 0, false ); graphic.material.shaders.front().updateBuffer( uniforms, 0, false ); } @@ -471,10 +471,10 @@ void ext::PlayerHandBehavior::render( uf::Object& self ){ uniforms.matrices.view[i] = camera.getView( i ); uniforms.matrices.projection[i] = camera.getProjection( i ); } - uniforms.color[0] = metadata["hands"]["right"]["pointer"]["color"][0].asFloat(); - uniforms.color[1] = metadata["hands"]["right"]["pointer"]["color"][1].asFloat(); - uniforms.color[2] = metadata["hands"]["right"]["pointer"]["color"][2].asFloat(); - uniforms.color[3] = metadata["hands"]["right"]["pointer"]["color"][3].asFloat(); + uniforms.color[0] = metadata["hands"]["right"]["pointer"]["color"][0].as(); + uniforms.color[1] = metadata["hands"]["right"]["pointer"]["color"][1].as(); + uniforms.color[2] = metadata["hands"]["right"]["pointer"]["color"][2].as(); + uniforms.color[3] = metadata["hands"]["right"]["pointer"]["color"][3].as(); // graphic.updateBuffer( uniforms, 0, false ); graphic.material.shaders.front().updateBuffer( uniforms, 0, false ); } diff --git a/ext/behaviors/light/behavior.cpp b/ext/behaviors/light/behavior.cpp index 67631317..94e4c4b3 100644 --- a/ext/behaviors/light/behavior.cpp +++ b/ext/behaviors/light/behavior.cpp @@ -6,7 +6,7 @@ #include #include -EXT_BEHAVIOR_REGISTER_CPP(LightBehavior) +UF_BEHAVIOR_REGISTER_CPP(ext::LightBehavior) #define this (&self) void ext::LightBehavior::initialize( uf::Object& self ) { auto& metadata = this->getComponent(); @@ -15,7 +15,7 @@ void ext::LightBehavior::initialize( uf::Object& self ) { auto& scene = uf::scene::getCurrentScene(); auto& controller = scene.getController(); - if ( metadata["light"]["shadows"]["enabled"].asBool() ) { + if ( metadata["light"]["shadows"]["enabled"].as() ) { auto& renderMode = this->getComponent(); std::string name = "RT:" + std::to_string((int) this->getUid()); uf::renderer::addRenderMode( &renderMode, name ); @@ -23,39 +23,39 @@ void ext::LightBehavior::initialize( uf::Object& self ) { camera = controller.getComponent(); camera.getTransform() = {}; camera.setStereoscopic(false); - if ( metadata["light"]["shadows"]["fov"].isNumeric() ) { - camera.setFov( metadata["light"]["shadows"]["fov"].asFloat() ); + if ( metadata["light"]["shadows"]["fov"].is() ) { + camera.setFov( metadata["light"]["shadows"]["fov"].as() ); camera.updateProjection(); } - if ( metadata["light"]["radius"].isArray() ) { + if ( ext::json::isArray( metadata["light"]["radius"] ) ) { auto bounds = camera.getBounds(); - bounds.x = metadata["light"]["radius"][0].asFloat(); - bounds.y = metadata["light"]["radius"][1].asFloat(); + bounds.x = metadata["light"]["radius"][0].as(); + bounds.y = metadata["light"]["radius"][1].as(); camera.setBounds(bounds); } - if ( metadata["light"]["shadows"]["resolution"].isArray() ) { - renderMode.width = metadata["light"]["shadows"]["resolution"][0].asUInt64(); - renderMode.height = metadata["light"]["shadows"]["resolution"][1].asUInt64(); + if ( ext::json::isArray( metadata["light"]["shadows"]["resolution"] ) ) { + renderMode.width = metadata["light"]["shadows"]["resolution"][0].as(); + renderMode.height = metadata["light"]["shadows"]["resolution"][1].as(); auto size = camera.getSize(); size.x = renderMode.width; size.y = renderMode.height; camera.setSize(size); } else { - renderMode.width = metadata["light"]["shadows"]["resolution"].asUInt64(); - renderMode.height = metadata["light"]["shadows"]["resolution"].asUInt64(); + renderMode.width = metadata["light"]["shadows"]["resolution"].as(); + renderMode.height = metadata["light"]["shadows"]["resolution"].as(); auto size = camera.getSize(); size.x = renderMode.width; size.y = renderMode.height; camera.setSize(size); } } - if ( !metadata["light"]["shadows"]["bias"].isNumeric() ) { + if ( !metadata["light"]["shadows"]["bias"].is() ) { metadata["light"]["shadows"]["bias"] = 0.00005f; } - if ( !metadata["light"]["color"].isArray() ) { - metadata["light"]["color"][0] = 1; //metadata["light"]["color"]["random"].asBool() ? (rand() % 100) / 100.0 : 1; - metadata["light"]["color"][1] = 1; //metadata["light"]["color"]["random"].asBool() ? (rand() % 100) / 100.0 : 1; - metadata["light"]["color"][2] = 1; //metadata["light"]["color"]["random"].asBool() ? (rand() % 100) / 100.0 : 1; + if ( !ext::json::isArray( metadata["light"]["color"] ) ) { + metadata["light"]["color"][0] = 1; //metadata["light"]["color"]["random"].as() ? (rand() % 100) / 100.0 : 1; + metadata["light"]["color"][1] = 1; //metadata["light"]["color"]["random"].as() ? (rand() % 100) / 100.0 : 1; + metadata["light"]["color"][2] = 1; //metadata["light"]["color"]["random"].as() ? (rand() % 100) / 100.0 : 1; } } void ext::LightBehavior::tick( uf::Object& self ) { @@ -76,40 +76,40 @@ void ext::LightBehavior::tick( uf::Object& self ) { if ( parentMetadata["system"]["name"] == "Light" ) { metadata["light"] = parentMetadata["light"]; } else { - if ( metadata["light"]["fade"].isObject() ) { - if ( metadata["light"]["backup"]["power"].isNull() ) { + if ( ext::json::isObject( metadata["light"]["fade"] ) ) { + if ( ext::json::isNull( metadata["light"]["backup"]["power"] ) ) { metadata["light"]["backup"]["power"] = metadata["light"]["power"]; } - if ( metadata["light"]["backup"]["color"].isNull() ) { + if ( ext::json::isNull( metadata["light"]["backup"]["color"] ) ) { metadata["light"]["backup"]["color"] = metadata["light"]["color"]; } // fade towards - int direction = metadata["light"]["fade"]["increment"].asBool() ? 1 : -1; - metadata["light"]["fade"]["timer"] = metadata["light"]["fade"]["timer"].asFloat() + metadata["light"]["fade"]["rate"].asFloat() * uf::physics::time::delta * direction; + int direction = metadata["light"]["fade"]["increment"].as() ? 1 : -1; + metadata["light"]["fade"]["timer"] = metadata["light"]["fade"]["timer"].as() + metadata["light"]["fade"]["rate"].as() * uf::physics::time::delta * direction; // 0 .. delta .. 1 .. (1 + timeout * 0.5) - if ( direction == 1 && metadata["light"]["fade"]["timer"].asFloat() >= 0.5f * metadata["light"]["fade"]["timeout"].asFloat() + 1.0f ) { + if ( direction == 1 && metadata["light"]["fade"]["timer"].as() >= 0.5f * metadata["light"]["fade"]["timeout"].as() + 1.0f ) { metadata["light"]["fade"]["increment"] = false; - } else if ( direction == -1 && metadata["light"]["fade"]["timer"].asFloat() <= -0.5f * metadata["light"]["fade"]["timeout"].asFloat() ) { + } else if ( direction == -1 && metadata["light"]["fade"]["timer"].as() <= -0.5f * metadata["light"]["fade"]["timeout"].as() ) { metadata["light"]["fade"]["increment"] = true; } { - float delta = metadata["light"]["fade"]["timer"].asFloat(); + float delta = metadata["light"]["fade"]["timer"].as(); delta = std::clamp( delta, 0.f, 1.f ); - if ( metadata["light"]["fade"]["power"].isNumeric() ) { - metadata["light"]["power"] = uf::math::lerp( metadata["light"]["backup"]["power"].asFloat(), metadata["light"]["fade"]["power"].asFloat(), delta ); + if ( metadata["light"]["fade"]["power"].is() ) { + metadata["light"]["power"] = uf::math::lerp( metadata["light"]["backup"]["power"].as(), metadata["light"]["fade"]["power"].as(), delta ); } - if ( metadata["light"]["fade"]["color"].isArray() ) { + if ( ext::json::isArray( metadata["light"]["fade"]["color"] ) ) { pod::Vector3f fadeColor; { - fadeColor.x = metadata["light"]["fade"]["color"][0].asFloat(); - fadeColor.y = metadata["light"]["fade"]["color"][1].asFloat(); - fadeColor.z = metadata["light"]["fade"]["color"][2].asFloat(); + fadeColor.x = metadata["light"]["fade"]["color"][0].as(); + fadeColor.y = metadata["light"]["fade"]["color"][1].as(); + fadeColor.z = metadata["light"]["fade"]["color"][2].as(); } pod::Vector3f origColor; { - origColor.x = metadata["light"]["backup"]["color"][0].asFloat(); - origColor.y = metadata["light"]["backup"]["color"][1].asFloat(); - origColor.z = metadata["light"]["backup"]["color"][2].asFloat(); + origColor.x = metadata["light"]["backup"]["color"][0].as(); + origColor.y = metadata["light"]["backup"]["color"][1].as(); + origColor.z = metadata["light"]["backup"]["color"][2].as(); } pod::Vector3f color = uf::vector::lerp( origColor, fadeColor, delta ); @@ -119,16 +119,16 @@ void ext::LightBehavior::tick( uf::Object& self ) { } } } - if ( metadata["light"]["flicker"].isObject() ) { + if ( ext::json::isObject( metadata["light"]["flicker"] ) ) { float r = (rand() % 100) / 100.0; - float rate = metadata["light"]["flicker"]["rate"].asFloat(); - if ( metadata["light"]["backup"]["power"].isNull() ) { + float rate = metadata["light"]["flicker"]["rate"].as(); + if ( ext::json::isNull( metadata["light"]["backup"]["power"] ) ) { metadata["light"]["backup"]["power"] = metadata["light"]["power"]; } - metadata["light"]["flicker"]["timer"] = metadata["light"]["flicker"]["timer"].asFloat() + uf::physics::time::delta; - if ( metadata["light"]["flicker"]["timer"].asFloat() >= metadata["light"]["flicker"]["timeout"].asFloat() ) { + metadata["light"]["flicker"]["timer"] = metadata["light"]["flicker"]["timer"].as() + uf::physics::time::delta; + if ( metadata["light"]["flicker"]["timer"].as() >= metadata["light"]["flicker"]["timeout"].as() ) { metadata["light"]["flicker"]["timer"] = 0; - metadata["light"]["power"] = (r > rate) ? metadata["light"]["flicker"]["power"].asFloat() : metadata["light"]["backup"]["power"]; + metadata["light"]["power"] = (r > rate) ? metadata["light"]["flicker"]["power"].as() : metadata["light"]["backup"]["power"]; } } } @@ -142,7 +142,7 @@ void ext::LightBehavior::tick( uf::Object& self ) { auto& controllerTransform = scene.getController().getComponent>(); transform.position = controllerTransform.position + controllerCamera.position; } - if ( metadata["light"]["external update"].isNull() || (!metadata["light"]["external update"].isNull() && !metadata["light"]["external update"].asBool()) ) { + if ( ext::json::isNull( metadata["light"]["external update"] ) || (!ext::json::isNull( metadata["light"]["external update"] ) && !metadata["light"]["external update"].as()) ) { auto& camera = this->getComponent(); for ( std::size_t i = 0; i < 2; ++i ) { camera.setView( uf::matrix::inverse( uf::transform::model( transform ) ), i ); @@ -151,14 +151,14 @@ void ext::LightBehavior::tick( uf::Object& self ) { // render every other frame, maybe if ( false ) { - if ( metadata["system"]["renderer"]["limit rendering"]["limiter"].isNumeric() && this->hasComponent() ) { + if ( metadata["system"]["renderer"]["limit rendering"]["limiter"].is() && this->hasComponent() ) { auto& limiterMetadata = metadata["system"]["renderer"]["limit rendering"]; auto& renderMode = this->getComponent(); - if ( limiterMetadata["timer"].asFloat() > 1.0f / limiterMetadata["limiter"].asFloat() ) { + if ( limiterMetadata["timer"].as() > 1.0f / limiterMetadata["limiter"].as() ) { limiterMetadata["timer"] = 0; renderMode.execute = true; } else { - limiterMetadata["timer"] = limiterMetadata["timer"].asFloat() + uf::physics::time::delta; + limiterMetadata["timer"] = limiterMetadata["timer"].as() + uf::physics::time::delta; renderMode.execute = false; } } diff --git a/ext/behaviors/player/behavior.cpp b/ext/behaviors/player/behavior.cpp index a94e39bd..bea1ea9b 100644 --- a/ext/behaviors/player/behavior.cpp +++ b/ext/behaviors/player/behavior.cpp @@ -12,10 +12,6 @@ #include -#include "../../scenes/worldscape/gui/pause.h" -#include "../../scenes/worldscape/gui/battle.h" -#include "../../scenes/worldscape//.h" - namespace { uf::Serializer masterTableGet( const std::string& table ) { uf::Scene& scene = uf::scene::getCurrentScene(); @@ -36,7 +32,7 @@ namespace { } } -EXT_BEHAVIOR_REGISTER_CPP(PlayerBehavior) +UF_BEHAVIOR_REGISTER_CPP(ext::PlayerBehavior) #define this (&self) void ext::PlayerBehavior::initialize( uf::Object& self ) { this->addComponent(); { @@ -61,56 +57,56 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { } settings; uf::Camera& camera = this->getComponent(); - settings.mode = metadata["camera"]["ortho"].asBool() ? -1 : 1; - settings.perspective.size.x = metadata["camera"]["settings"]["size"]["x"].asDouble(); - settings.perspective.size.y = metadata["camera"]["settings"]["size"]["y"].asDouble(); + settings.mode = metadata["camera"]["ortho"].as() ? -1 : 1; + settings.perspective.size.x = metadata["camera"]["settings"]["size"]["x"].as(); + settings.perspective.size.y = metadata["camera"]["settings"]["size"]["y"].as(); camera.setSize(settings.perspective.size); if ( settings.mode < 0 ) { - settings.ortho.lr.x = metadata["camera"]["settings"]["left"].asDouble(); - settings.ortho.lr.y = metadata["camera"]["settings"]["right"].asDouble(); - settings.ortho.bt.x = metadata["camera"]["settings"]["bottom"].asDouble(); - settings.ortho.bt.y = metadata["camera"]["settings"]["top"].asDouble(); - settings.ortho.nf.x = metadata["camera"]["settings"]["near"].asDouble(); - settings.ortho.nf.y = metadata["camera"]["settings"]["far"].asDouble(); + settings.ortho.lr.x = metadata["camera"]["settings"]["left"].as(); + settings.ortho.lr.y = metadata["camera"]["settings"]["right"].as(); + settings.ortho.bt.x = metadata["camera"]["settings"]["bottom"].as(); + settings.ortho.bt.y = metadata["camera"]["settings"]["top"].as(); + settings.ortho.nf.x = metadata["camera"]["settings"]["near"].as(); + settings.ortho.nf.y = metadata["camera"]["settings"]["far"].as(); camera.ortho( settings.ortho.lr, settings.ortho.bt, settings.ortho.nf ); } else { - settings.perspective.fov = metadata["camera"]["settings"]["fov"].asDouble(); - settings.perspective.bounds.x = metadata["camera"]["settings"]["clip"]["near"].asDouble(); - settings.perspective.bounds.y = metadata["camera"]["settings"]["clip"]["far"].asDouble(); + settings.perspective.fov = metadata["camera"]["settings"]["fov"].as(); + settings.perspective.bounds.x = metadata["camera"]["settings"]["clip"]["near"].as(); + settings.perspective.bounds.y = metadata["camera"]["settings"]["clip"]["far"].as(); camera.setFov(settings.perspective.fov); camera.setBounds(settings.perspective.bounds); } camera.setStereoscopic(true); - settings.offset.x = metadata["camera"]["offset"][0].asDouble(); - settings.offset.y = metadata["camera"]["offset"][1].asDouble(); - settings.offset.z = metadata["camera"]["offset"][2].asDouble(); + settings.offset.x = metadata["camera"]["offset"][0].as(); + settings.offset.y = metadata["camera"]["offset"][1].as(); + settings.offset.z = metadata["camera"]["offset"][2].as(); pod::Transform<>& transform = camera.getTransform(); /* Transform initialization */ { - transform.position.x = metadata["camera"]["position"][0].asDouble(); - transform.position.y = metadata["camera"]["position"][1].asDouble(); - transform.position.z = metadata["camera"]["position"][2].asDouble(); + transform.position.x = metadata["camera"]["position"][0].as(); + transform.position.y = metadata["camera"]["position"][1].as(); + transform.position.z = metadata["camera"]["position"][2].as(); - transform.scale.x = metadata["camera"]["scale"][0].asDouble(); - transform.scale.y = metadata["camera"]["scale"][1].asDouble(); - transform.scale.z = metadata["camera"]["scale"][2].asDouble(); + transform.scale.x = metadata["camera"]["scale"][0].as(); + transform.scale.y = metadata["camera"]["scale"][1].as(); + transform.scale.z = metadata["camera"]["scale"][2].as(); } camera.setOffset(settings.offset); camera.update(true); // Update viewport - if ( metadata["camera"]["settings"]["size"]["auto"].asBool() ) { + if ( metadata["camera"]["settings"]["size"]["auto"].as() ) { this->addHook( "window:Resized", [&](const std::string& event)->std::string{ uf::Serializer json = event; // Update persistent window sized (size stored to JSON file) pod::Vector2ui size; { - size.x = json["window"]["size"]["x"].asUInt64(); - size.y = json["window"]["size"]["y"].asUInt64(); + size.x = json["window"]["size"]["x"].as(); + size.y = json["window"]["size"]["y"].as(); } /* Update camera's viewport */ { uf::Camera& camera = this->getComponent(); @@ -126,7 +122,7 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { this->addHook( "window:Mouse.CursorVisibility", [&](const std::string& event)->std::string{ uf::Serializer json = event; - metadata["system"]["control"] = !json["state"].asBool(); + metadata["system"]["control"] = !json["state"].as(); return "true"; }); @@ -137,12 +133,12 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { // discard events sent by os, only trust client now if ( json["invoker"] != "client" ) return "true"; - pod::Vector2i delta = { json["mouse"]["delta"]["x"].asInt(), json["mouse"]["delta"]["y"].asInt() }; - pod::Vector2i size = { json["mouse"]["size"]["x"].asInt(), json["mouse"]["size"]["y"].asInt() }; + pod::Vector2i delta = { json["mouse"]["delta"]["x"].as(), json["mouse"]["delta"]["y"].as() }; + pod::Vector2i size = { json["mouse"]["size"]["x"].as(), json["mouse"]["size"]["y"].as() }; pod::Vector2 relta = { (float) delta.x / size.x, (float) delta.y / size.y }; relta *= 2; if ( delta.x == 0 && delta.y == 0 ) return "true"; - if ( !metadata["system"]["control"].asBool() ) return "true"; + if ( !metadata["system"]["control"].as() ) return "true"; bool updateCamera = false; uf::Camera& camera = this->getComponent(); @@ -150,26 +146,26 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { pod::Transform<>& cameraTransform = camera.getTransform(); if ( delta.x != 0 ) { double current, minima, maxima; { - current = metadata["camera"]["limit"]["current"][0] != Json::nullValue ? metadata["camera"]["limit"]["current"][0].asDouble() : NAN; - minima = metadata["camera"]["limit"]["minima"][0] != Json::nullValue ? metadata["camera"]["limit"]["minima"][0].asDouble() : NAN; - maxima = metadata["camera"]["limit"]["maxima"][0] != Json::nullValue ? metadata["camera"]["limit"]["maxima"][0].asDouble() : NAN; + current = metadata["camera"]["limit"]["current"][0] != Json::nullValue ? metadata["camera"]["limit"]["current"][0].as() : NAN; + minima = metadata["camera"]["limit"]["minima"][0] != Json::nullValue ? metadata["camera"]["limit"]["minima"][0].as() : NAN; + maxima = metadata["camera"]["limit"]["maxima"][0] != Json::nullValue ? metadata["camera"]["limit"]["maxima"][0].as() : NAN; } - if ( metadata["camera"]["invert"][0].asBool() ) relta.x *= -1; + if ( metadata["camera"]["invert"][0].as() ) relta.x *= -1; current += relta.x; if ( current != current || ( current < maxima && current > minima ) ) uf::transform::rotate( transform, transform.up, relta.x ), updateCamera = true; else current -= relta.x; if ( metadata["camera"]["limit"]["current"][0] != Json::nullValue ) metadata["camera"]["limit"]["current"][0] = current; } if ( delta.y != 0 ) { double current, minima, maxima; { - current = metadata["camera"]["limit"]["current"][1] != Json::nullValue ? metadata["camera"]["limit"]["current"][1].asDouble() : NAN; - minima = metadata["camera"]["limit"]["minima"][1] != Json::nullValue ? metadata["camera"]["limit"]["minima"][1].asDouble() : NAN; - maxima = metadata["camera"]["limit"]["maxima"][1] != Json::nullValue ? metadata["camera"]["limit"]["maxima"][1].asDouble() : NAN; + current = metadata["camera"]["limit"]["current"][1] != Json::nullValue ? metadata["camera"]["limit"]["current"][1].as() : NAN; + minima = metadata["camera"]["limit"]["minima"][1] != Json::nullValue ? metadata["camera"]["limit"]["minima"][1].as() : NAN; + maxima = metadata["camera"]["limit"]["maxima"][1] != Json::nullValue ? metadata["camera"]["limit"]["maxima"][1].as() : NAN; } - if ( metadata["camera"]["invert"][1].asBool() ) relta.y *= -1; + if ( metadata["camera"]["invert"][1].as() ) relta.y *= -1; current += relta.y; if ( current != current || ( current < maxima && current > minima ) ) { uf::transform::rotate( cameraTransform, cameraTransform.right, relta.y ); - // uf::transform::rotate( this->m_animation.transforms[metadata["animation"]["names"]["head"].asString()], {0, 0, 0}, -relta.y ); + // uf::transform::rotate( this->m_animation.transforms[metadata["animation"]["names"]["head"].as()], {0, 0, 0}, -relta.y ); updateCamera = true; } else current -= relta.y; if ( metadata["camera"]["limit"]["current"][1] != Json::nullValue ) metadata["camera"]["limit"]["current"][1] = current; @@ -185,7 +181,7 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { for ( auto& member : json[""]["transients"] ) { if ( member["type"] != "player" ) continue; - std::string id = member["id"].asString(); + std::string id = member["id"].as(); metadata[""]["transients"][id]["hp"] = member["hp"]; metadata[""]["transients"][id]["mp"] = member["mp"]; } @@ -212,27 +208,27 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { // detect collision against transients, engage in battle this->addHook( "world:Collision.%UID%", [&](const std::string& event)->std::string{ - if ( metadata["system"]["cooldown"].asFloat() > uf::physics::time::current ) return "false"; - if ( !metadata["system"]["control"].asBool() ) return "false"; + if ( metadata["system"]["cooldown"].as() > uf::physics::time::current ) return "false"; + if ( !metadata["system"]["control"].as() ) return "false"; uf::Serializer json = event; - std::string state = metadata["system"]["state"].asString(); + std::string state = metadata["system"]["state"].as(); if ( state != "" && state != "null" ) return "false"; uf::Scene& scene = uf::scene::getCurrentScene(); - uf::Entity* entity = scene.findByUid(json["entity"].asUInt64()); + uf::Entity* entity = scene.findByUid(json["entity"].as()); if ( !entity ) return "false"; uf::Serializer& pMetadata = entity->getComponent(); - std::string onCollision = pMetadata["system"]["onCollision"].asString(); + std::string onCollision = pMetadata["system"]["onCollision"].as(); if ( onCollision == "battle" ) { uf::Serializer payload; payload["battle"]["enemy"] = pMetadata[""]; - payload["battle"]["enemy"]["uid"] = json["entity"].asUInt64(); + payload["battle"]["enemy"]["uid"] = json["entity"].as(); payload["battle"]["player"] = metadata[""]; payload["battle"]["player"]["uid"] = this->getUid(); payload["battle"]["music"] = pMetadata["music"]; @@ -242,7 +238,7 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { if ( !uf::Window::isKeyPressed("E") ) return "false"; uf::Serializer payload; payload["dialogue"] = pMetadata["dialogue"]; - payload["uid"] = json["entity"].asUInt64(); + payload["uid"] = json["entity"].as(); this->callHook("menu:Dialogue.Start", payload); } // metadata["system"]["cooldown"] = uf::physics::time::current + 5; @@ -278,10 +274,10 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { this->addHook( "discord.Activity.Update.%UID%", [&](const std::string& event)->std::string{ uf::Serializer payload; - std::string leaderId = metadata[""]["party"][0].asString(); + std::string leaderId = metadata[""]["party"][0].as(); uf::Serializer cardData = masterDataGet("Card", leaderId); - uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); - std::string leader = charaData["name"].asString(); + uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].as()); + std::string leader = charaData["name"].as(); payload["details"] = "Leader: " + leader; uf::hooks.call( "discord:Activity.Update", payload ); @@ -315,19 +311,19 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { } keys; if ( ext::openvr::context ) { - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "dpadUp" )["state"].asBool() ) keys.forward = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "dpadDown" )["state"].asBool() ) keys.backwards = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "dpadLeft" )["state"].asBool() ) keys.lookLeft = true; // keys.left = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "dpadRight" )["state"].asBool() ) keys.lookRight = true; // keys.right = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "thumbclick" )["state"].asBool() ) keys.running = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "a" )["state"].asBool() ) keys.jump = true; + if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "dpadUp" )["state"].as() ) keys.forward = true; + if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "dpadDown" )["state"].as() ) keys.backwards = true; + if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "dpadLeft" )["state"].as() ) keys.lookLeft = true; // keys.left = true; + if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "dpadRight" )["state"].as() ) keys.lookRight = true; // keys.right = true; + if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "thumbclick" )["state"].as() ) keys.running = true; + if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "a" )["state"].as() ) keys.jump = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "dpadUp" )["state"].asBool() ) keys.forward = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "dpadDown" )["state"].asBool() ) keys.backwards = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "dpadLeft" )["state"].asBool() ) keys.lookLeft = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "dpadRight" )["state"].asBool() ) keys.lookRight = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "thumbclick" )["state"].asBool() ) keys.crouch = true, keys.walk = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "a" )["state"].asBool() ) keys.paused = true; + if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "dpadUp" )["state"].as() ) keys.forward = true; + if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "dpadDown" )["state"].as() ) keys.backwards = true; + if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "dpadLeft" )["state"].as() ) keys.lookLeft = true; + if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "dpadRight" )["state"].as() ) keys.lookRight = true; + if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "thumbclick" )["state"].as() ) keys.crouch = true, keys.walk = true; + if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "a" )["state"].as() ) keys.paused = true; } struct { @@ -339,8 +335,8 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { std::string menu = ""; } stats; stats.floored = physics.linear.velocity.y == 0; - stats.menu = metadata["system"]["menu"].asString(); - stats.impulse = metadata["system"]["physics"]["impulse"].asBool(); + stats.menu = metadata["system"]["menu"].as(); + stats.impulse = metadata["system"]["physics"]["impulse"].as(); struct { float move = 4; float walk = 1; @@ -348,12 +344,12 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { float rotate = uf::physics::time::delta; float limitSquared = 4*4; } speed; { - speed.rotate *= metadata["system"]["physics"]["rotate"].asFloat(); - speed.move = metadata["system"]["physics"]["move"].asFloat(); - speed.run = metadata["system"]["physics"]["run"].asFloat() / metadata["system"]["physics"]["move"].asFloat(); - speed.walk = metadata["system"]["physics"]["walk"].asFloat() / metadata["system"]["physics"]["move"].asFloat(); + speed.rotate *= metadata["system"]["physics"]["rotate"].as(); + speed.move = metadata["system"]["physics"]["move"].as(); + speed.run = metadata["system"]["physics"]["run"].as() / metadata["system"]["physics"]["move"].as(); + speed.walk = metadata["system"]["physics"]["walk"].as() / metadata["system"]["physics"]["move"].as(); } - if ( !metadata["system"]["physics"]["collision"].asBool() ) { + if ( !metadata["system"]["physics"]["collision"].as() ) { stats.impulse = true; } @@ -362,15 +358,15 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { if ( keys.vee ) { if ( timer.elapsed().asDouble() >= 0.25 ) { timer.reset(); - if ( metadata["system"]["physics"]["backup"]["collision"].isNull() ) + if ( ext::json::isNull( metadata["system"]["physics"]["backup"]["collision"] ) ) metadata["system"]["physics"]["backup"]["collision"] = metadata["system"]["physics"]["collision"]; - if ( !metadata["system"]["physics"]["collision"].asBool() ) { + if ( !metadata["system"]["physics"]["collision"].as() ) { metadata["system"]["physics"]["collision"] = metadata["system"]["physics"]["backup"]["collision"]; } else { metadata["system"]["physics"]["collision"] = 0; } std::cout << "Toggling noclip: " << transform.position.x << ", " << transform.position.y << ", " << transform.position.z << std::endl; - // metadata["system"]["physics"]["collision"] = !metadata["system"]["physics"]["collision"].asBool(); + // metadata["system"]["physics"]["collision"] = !metadata["system"]["physics"]["collision"].as(); physics.linear.velocity = {0,0,0}; } } @@ -387,7 +383,7 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { metadata["system"]["control"] = false; uf::hooks.call("menu:Pause"); } - else if ( !metadata["system"]["control"].asBool() ) { + else if ( !metadata["system"]["control"].as() ) { stats.menu = "menu"; } else if ( stats.menu == "" ) { metadata["system"]["control"] = true; @@ -396,19 +392,19 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { } metadata["system"]["menu"] = stats.menu; - if ( metadata["system"]["physics"]["clamp"].isObject() ) { - if ( metadata["system"]["physics"]["clamp"]["x"].isArray() ) { - transform.position.x = std::clamp( transform.position.x, metadata["system"]["physics"]["clamp"]["x"][0].asFloat(), metadata["system"]["physics"]["clamp"]["x"][1].asFloat() ); + if ( ext::json::isObject( metadata["system"]["physics"]["clamp"] ) ) { + if ( ext::json::isArray( metadata["system"]["physics"]["clamp"]["x"] ) ) { + transform.position.x = std::clamp( transform.position.x, metadata["system"]["physics"]["clamp"]["x"][0].as(), metadata["system"]["physics"]["clamp"]["x"][1].as() ); } - if ( metadata["system"]["physics"]["clamp"]["y"].isArray() ) { - transform.position.y = std::clamp( transform.position.y, metadata["system"]["physics"]["clamp"]["y"][0].asFloat(), metadata["system"]["physics"]["clamp"]["y"][1].asFloat() ); + if ( ext::json::isArray( metadata["system"]["physics"]["clamp"]["y"] ) ) { + transform.position.y = std::clamp( transform.position.y, metadata["system"]["physics"]["clamp"]["y"][0].as(), metadata["system"]["physics"]["clamp"]["y"][1].as() ); } - if ( metadata["system"]["physics"]["clamp"]["z"].isArray() ) { - transform.position.z = std::clamp( transform.position.z, metadata["system"]["physics"]["clamp"]["z"][0].asFloat(), metadata["system"]["physics"]["clamp"]["z"][1].asFloat() ); + if ( ext::json::isArray( metadata["system"]["physics"]["clamp"]["z"] ) ) { + transform.position.z = std::clamp( transform.position.z, metadata["system"]["physics"]["clamp"]["z"][0].as(), metadata["system"]["physics"]["clamp"]["z"][1].as() ); } } - if ( metadata["system"]["control"].asBool() ) { + if ( metadata["system"]["control"].as() ) { if ( stats.floored ) { pod::Transform<> translator = transform; if ( ext::openvr::context ) { @@ -463,14 +459,14 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { stats.updateCamera = (stats.walking = true); } if ( keys.jump ) { - if ( !metadata["system"]["physics"]["collision"].asBool() ) { - if ( metadata["system"]["physics"]["jump"][0].asFloat() != 0 ) transform.position.x += metadata["system"]["physics"]["jump"][0].asFloat() * uf::physics::time::delta; - if ( metadata["system"]["physics"]["jump"][1].asFloat() != 0 ) transform.position.y += metadata["system"]["physics"]["jump"][1].asFloat() * uf::physics::time::delta; - if ( metadata["system"]["physics"]["jump"][2].asFloat() != 0 ) transform.position.z += metadata["system"]["physics"]["jump"][2].asFloat() * uf::physics::time::delta; + if ( !metadata["system"]["physics"]["collision"].as() ) { + if ( metadata["system"]["physics"]["jump"][0].as() != 0 ) transform.position.x += metadata["system"]["physics"]["jump"][0].as() * uf::physics::time::delta; + if ( metadata["system"]["physics"]["jump"][1].as() != 0 ) transform.position.y += metadata["system"]["physics"]["jump"][1].as() * uf::physics::time::delta; + if ( metadata["system"]["physics"]["jump"][2].as() != 0 ) transform.position.z += metadata["system"]["physics"]["jump"][2].as() * uf::physics::time::delta; } else { - if ( metadata["system"]["physics"]["jump"][0].asFloat() != 0 ) physics.linear.velocity.x = metadata["system"]["physics"]["jump"][0].asFloat(); - if ( metadata["system"]["physics"]["jump"][1].asFloat() != 0 ) physics.linear.velocity.y = metadata["system"]["physics"]["jump"][1].asFloat(); - if ( metadata["system"]["physics"]["jump"][2].asFloat() != 0 ) physics.linear.velocity.z = metadata["system"]["physics"]["jump"][2].asFloat(); + if ( metadata["system"]["physics"]["jump"][0].as() != 0 ) physics.linear.velocity.x = metadata["system"]["physics"]["jump"][0].as(); + if ( metadata["system"]["physics"]["jump"][1].as() != 0 ) physics.linear.velocity.y = metadata["system"]["physics"]["jump"][1].as(); + if ( metadata["system"]["physics"]["jump"][2].as() != 0 ) physics.linear.velocity.z = metadata["system"]["physics"]["jump"][2].as(); } } } @@ -483,22 +479,22 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { } if ( keys.crouch ) { - if ( !metadata["system"]["physics"]["collision"].asBool() ) { - if ( metadata["system"]["physics"]["jump"][0].asFloat() != 0 ) transform.position.x -= metadata["system"]["physics"]["jump"][0].asFloat() * uf::physics::time::delta; - if ( metadata["system"]["physics"]["jump"][1].asFloat() != 0 ) transform.position.y -= metadata["system"]["physics"]["jump"][1].asFloat() * uf::physics::time::delta; - if ( metadata["system"]["physics"]["jump"][2].asFloat() != 0 ) transform.position.z -= metadata["system"]["physics"]["jump"][2].asFloat() * uf::physics::time::delta; + if ( !metadata["system"]["physics"]["collision"].as() ) { + if ( metadata["system"]["physics"]["jump"][0].as() != 0 ) transform.position.x -= metadata["system"]["physics"]["jump"][0].as() * uf::physics::time::delta; + if ( metadata["system"]["physics"]["jump"][1].as() != 0 ) transform.position.y -= metadata["system"]["physics"]["jump"][1].as() * uf::physics::time::delta; + if ( metadata["system"]["physics"]["jump"][2].as() != 0 ) transform.position.z -= metadata["system"]["physics"]["jump"][2].as() * uf::physics::time::delta; } else { - if ( !metadata["system"]["crouching"].asBool() ) stats.deltaCrouch = true; + if ( !metadata["system"]["crouching"].as() ) stats.deltaCrouch = true; metadata["system"]["crouching"] = true; } } else { - if ( metadata["system"]["crouching"].asBool() ) stats.deltaCrouch = true; + if ( metadata["system"]["crouching"].as() ) stats.deltaCrouch = true; metadata["system"]["crouching"] = false; } } if ( stats.deltaCrouch ) { - float delta = metadata["system"]["physics"]["crouch"].asFloat(); - if ( metadata["system"]["crouching"].asBool() ) camera.getTransform().position.y -= delta; + float delta = metadata["system"]["physics"]["crouch"].as(); + if ( metadata["system"]["crouching"].as() ) camera.getTransform().position.y -= delta; else camera.getTransform().position.y += delta; stats.updateCamera = true; } @@ -507,17 +503,17 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { if ( stats.walking ) { uf::SoundEmitter& emitter = this->getComponent(); int cycle = rand() % metadata["audio"]["footstep"]["list"].size(); - std::string filename = metadata["audio"]["footstep"]["list"][cycle].asString(); + std::string filename = metadata["audio"]["footstep"]["list"][cycle].as(); uf::Audio& footstep = emitter.add(filename); bool playing = false; for ( uint i = 0; i < metadata["audio"]["footstep"]["list"].size(); ++i ) { - uf::Audio& audio = emitter.add(metadata["audio"]["footstep"]["list"][i].asString()); + uf::Audio& audio = emitter.add(metadata["audio"]["footstep"]["list"][i].as()); if ( audio.playing() ) playing = true; } if ( !playing ) { footstep.play(); - footstep.setVolume(metadata["audio"]["footstep"]["volume"].asFloat()); + footstep.setVolume(metadata["audio"]["footstep"]["volume"].as()); footstep.setPosition( transform.position ); // [0, 1] diff --git a/ext/behaviors/portal/behavior.cpp b/ext/behaviors/portal/behavior.cpp index 6ec46f07..93f56994 100644 --- a/ext/behaviors/portal/behavior.cpp +++ b/ext/behaviors/portal/behavior.cpp @@ -16,8 +16,8 @@ #include -EXT_BEHAVIOR_REGISTER_CPP(PortalsBehavior) -EXT_BEHAVIOR_REGISTER_AS_OBJECT(PortalsBehavior, Portals) +UF_BEHAVIOR_REGISTER_CPP(ext::PortalsBehavior) +UF_BEHAVIOR_REGISTER_AS_OBJECT(ext::PortalsBehavior, Portals) #define this (&self) void ext::PortalsBehavior::initialize( uf::Object& self ) { auto& metadata = this->getComponent(); @@ -43,8 +43,8 @@ void ext::PortalsBehavior::render( uf::Object& self ){} void ext::PortalsBehavior::destroy( uf::Object& self ){} #undef this -EXT_BEHAVIOR_REGISTER_CPP(PortalBehavior) -EXT_BEHAVIOR_REGISTER_AS_OBJECT(PortalBehavior, Portal) +UF_BEHAVIOR_REGISTER_CPP(ext::PortalBehavior) +UF_BEHAVIOR_REGISTER_AS_OBJECT(ext::PortalBehavior, Portal) #define this (&self) void ext::PortalBehavior::initialize( uf::Object& self ) { auto& metadata = this->getComponent(); @@ -97,7 +97,7 @@ void ext::PortalBehavior::tick( uf::Object& self ) { { auto& conCamera = controller.getComponent(); auto& prtTransform = this->getComponent>(); - auto& otherSideTransform = this->getParent().findByUid( metadata["target"].asUInt() )->getComponent>(); + auto& otherSideTransform = this->getParent().findByUid( metadata["target"].as() )->getComponent>(); for ( std::size_t i = 0; i < 2; ++i ) { pod::Matrix4f controllerCameraToWorldMatrix = uf::matrix::inverse( conCamera.getView(i) ); diff --git a/ext/behaviors/scene/behavior.cpp b/ext/behaviors/scene/behavior.cpp index 915be431..b33bfed4 100644 --- a/ext/behaviors/scene/behavior.cpp +++ b/ext/behaviors/scene/behavior.cpp @@ -24,7 +24,7 @@ #include "../../ext.h" #include "../../gui/gui.h" -EXT_BEHAVIOR_REGISTER_CPP(ExtSceneBehavior) +UF_BEHAVIOR_REGISTER_CPP(ext::ExtSceneBehavior) #define this ((uf::Scene*) &self) void ext::ExtSceneBehavior::initialize( uf::Object& self ) { uf::Asset& assetLoader = this->getComponent(); @@ -41,8 +41,8 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { if ( metadata["previous bgm"]["filename"] == "" ) return "false"; - std::string filename = metadata["previous bgm"]["filename"].asString(); - float timestamp = metadata["previous bgm"]["timestamp"].asFloat(); + std::string filename = metadata["previous bgm"]["filename"].as(); + float timestamp = metadata["previous bgm"]["timestamp"].as(); // std::cout << metadata["previous bgm"] << std::endl; @@ -53,7 +53,7 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { audio.stop(); } audio.load(filename); - audio.setVolume(metadata["volumes"]["bgm"].asFloat()); + audio.setVolume(metadata["volumes"]["bgm"].as()); audio.setTime(timestamp); audio.play(); @@ -61,7 +61,7 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { }); this->addHook( "asset:Load.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - std::string filename = json["filename"].asString(); + std::string filename = json["filename"].as(); if ( uf::io::extension(filename) != "ogg" ) return "false"; const uf::Audio* audioPointer = NULL; @@ -72,7 +72,7 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { if ( audio.playing() ) audio.stop(); audio.load(filename); - audio.setVolume(metadata["volumes"]["bgm"].asFloat()); + audio.setVolume(metadata["volumes"]["bgm"].as()); audio.play(); return "true"; @@ -88,8 +88,8 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { uf::Object* manager = (uf::Object*) this->globalFindByName("Gui Manager"); if ( !manager ) return "false"; uf::Serializer payload; - // uf::Object* gui = (uf::Object*) manager->findByUid( (payload["uid"] = manager->loadChildUid("/scenes/worldscape/gui/pause/menu.json", false)).asUInt64() ); - uf::Object& gui = manager->loadChild("/scenes/worldscape/gui/pause/menu.json", false); + std::string config = metadata["menus"]["pause"].is() ? metadata["menus"]["pause"].as() : "/scenes/worldscape/gui/pause/menu.json"; + uf::Object& gui = manager->loadChild(config, false); payload["uid"] = gui.getUid(); uf::Serializer& metadata = gui.getComponent(); @@ -101,13 +101,22 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { this->addHook( "world:Entity.LoadAsset", [&](const std::string& event)->std::string{ uf::Serializer json = event; - std::string asset = json["asset"].asString(); - std::string uid = json["uid"].asString(); + std::string asset = json["asset"].as(); + std::string uid = json["uid"].as(); assetLoader.load(asset, "asset:Load." + uid); return "true"; }); + this->addHook( "shader:Update.%UID%", [&](const std::string& event)->std::string{ + uf::Serializer json = event; + + json["mode"] = json["mode"].as() | metadata["system"]["renderer"]["shader"]["mode"].as(); + metadata["system"]["renderer"]["shader"]["mode"] = json["mode"]; + metadata["system"]["renderer"]["shader"]["parameters"] = json["parameters"]; + + return "true"; + }); /* store viewport size */ { metadata["system"]["window"]["size"]["x"] = uf::renderer::settings::width; metadata["system"]["window"]["size"]["y"] = uf::renderer::settings::height; @@ -118,8 +127,8 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { uf::Serializer json = event; pod::Vector2ui size; { - size.x = json["window"]["size"]["x"].asUInt64(); - size.y = json["window"]["size"]["y"].asUInt64(); + size.x = json["window"]["size"]["x"].as(); + size.y = json["window"]["size"]["y"].as(); } metadata["system"]["window"] = json["system"]["window"]; @@ -141,8 +150,9 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { uf::Serializer& metadata = this->getComponent(); uf::Asset& assetLoader = this->getComponent(); - /* check if audio needs to loop */ try { - uf::Audio& bgm = this->getComponent(); + /* check if audio needs to loop */ { + /* + auto& bgm = this->getComponent(); float current = bgm.getTime(); float end = bgm.getDuration(); float epsilon = 0.005f; @@ -151,15 +161,14 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { std::string filename = bgm.getFilename(); filename = assetLoader.getOriginal(filename); if ( filename.find("_intro") != std::string::npos ) { - assetLoader.load(uf::string::replace( filename, "_intro", "" ), "asset:Load." + std::to_string(this->getUid())); + assetLoader.load(uf::string::replace( filename, "_intro", "" ), this->formatHookName("asset:Load.%UID%")); // loop } else { bgm.setTime(0); if ( !bgm.playing() ) bgm.play(); } } - } catch ( ... ) { - + */ } /* Regain control if nothing requests it */ { @@ -180,15 +189,15 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { static uf::Timer timer(false); if ( !timer.running() ) timer.start(); if ( uf::Window::isKeyPressed("U") && timer.elapsed().asDouble() >= 1 ) { timer.reset(); - auto& allocations = uf::Entity::memoryPool.allocations(); - uf::iostream << "Current size: " << allocations.size() << "\n"; //" | UIDs: " << uf::Entity::uids << "\n"; uint orphans = 0; uint empty = 0; + auto& allocations = uf::Entity::memoryPool.allocations(); + uf::iostream << "Current size: " << allocations.size() << "\n"; //" | UIDs: " << uf::Entity::uids << "\n"; for ( auto& allocation : allocations ) { uf::Entity* e = (uf::Entity*) allocation.pointer; - if ( !e->hasParent() ) { + if ( !e->hasParent() && e != this ) { ++orphans; - uf::iostream << "Orphan: " << e->getName() << ": " << e << "\n"; + uf::iostream << "Orphan: " << e->getName() << ": " << e->getUid() << ": " << e << "\n"; } } uf::iostream << "Orphans: " << orphans << "\n"; @@ -212,7 +221,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { } if ( uf::scene::getCurrentScene().getUid() == this->getUid() ) { - /* Update lights */ if ( metadata["light"]["should"].asBool() ) { + /* Update lights */ if ( metadata["light"]["should"].as() ) { // if ( !uf::renderer::currentRenderMode || uf::renderer::currentRenderMode->name != "" ) return; auto& scene = uf::scene::getCurrentScene(); @@ -294,7 +303,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { { uf::Serializer& metadata = controller.getComponent(); - if ( metadata["light"]["should"].asBool() ) entities.push_back(&controller); + if ( metadata["light"]["should"].as() ) entities.push_back(&controller); } } for ( size_t _ = 0; _ < blitters.size(); ++_ ) { @@ -321,30 +330,30 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { uniforms->matrices.projection[i] = camera.getProjection( i ); } { - uniforms->ambient.x = metadata["light"]["ambient"][0].asFloat(); - uniforms->ambient.y = metadata["light"]["ambient"][1].asFloat(); - uniforms->ambient.z = metadata["light"]["ambient"][2].asFloat(); - uniforms->ambient.w = metadata["light"]["kexp"].asFloat(); + uniforms->ambient.x = metadata["light"]["ambient"][0].as(); + uniforms->ambient.y = metadata["light"]["ambient"][1].as(); + uniforms->ambient.z = metadata["light"]["ambient"][2].as(); + uniforms->ambient.w = metadata["light"]["kexp"].as(); } { - uniforms->fog.color.x = metadata["light"]["fog"]["color"][0].asFloat(); - uniforms->fog.color.y = metadata["light"]["fog"]["color"][1].asFloat(); - uniforms->fog.color.z = metadata["light"]["fog"]["color"][2].asFloat(); + uniforms->fog.color.x = metadata["light"]["fog"]["color"][0].as(); + uniforms->fog.color.y = metadata["light"]["fog"]["color"][1].as(); + uniforms->fog.color.z = metadata["light"]["fog"]["color"][2].as(); - uniforms->fog.range.x = metadata["light"]["fog"]["range"][0].asFloat(); - uniforms->fog.range.y = metadata["light"]["fog"]["range"][1].asFloat(); + uniforms->fog.range.x = metadata["light"]["fog"]["range"][0].as(); + uniforms->fog.range.y = metadata["light"]["fog"]["range"][1].as(); } { - uniforms->mode.type.x = metadata["system"]["renderer"]["shader"]["mode"].asUInt(); - uniforms->mode.type.y = metadata["system"]["renderer"]["shader"]["scalar"].asUInt(); - uniforms->mode.parameters.x = metadata["system"]["renderer"]["shader"]["parameters"][0].asFloat(); - uniforms->mode.parameters.y = metadata["system"]["renderer"]["shader"]["parameters"][1].asFloat(); - uniforms->mode.parameters.z = metadata["system"]["renderer"]["shader"]["parameters"][2].asFloat(); + uniforms->mode.type.x = metadata["system"]["renderer"]["shader"]["mode"].as(); + uniforms->mode.type.y = metadata["system"]["renderer"]["shader"]["scalar"].as(); + uniforms->mode.parameters.x = metadata["system"]["renderer"]["shader"]["parameters"][0].as(); + uniforms->mode.parameters.y = metadata["system"]["renderer"]["shader"]["parameters"][1].as(); + uniforms->mode.parameters.z = metadata["system"]["renderer"]["shader"]["parameters"][2].as(); - if ( metadata["system"]["renderer"]["shader"]["parameters"][3].asString() == "time" ) { + if ( metadata["system"]["renderer"]["shader"]["parameters"][3].as() == "time" ) { uniforms->mode.parameters.w = uf::physics::time::current; } else { - uniforms->mode.parameters.w = metadata["system"]["renderer"]["shader"]["parameters"][3].asFloat(); + uniforms->mode.parameters.w = metadata["system"]["renderer"]["shader"]["parameters"][3].as(); } } { @@ -380,16 +389,16 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { if ( entity == &controller ) light.position.y += 2; - light.position.w = metadata["light"]["radius"][1].asFloat(); + light.position.w = metadata["light"]["radius"][1].as(); - light.color.x = metadata["light"]["color"][0].asFloat(); - light.color.y = metadata["light"]["color"][1].asFloat(); - light.color.z = metadata["light"]["color"][2].asFloat(); + light.color.x = metadata["light"]["color"][0].as(); + light.color.y = metadata["light"]["color"][1].as(); + light.color.z = metadata["light"]["color"][2].as(); - light.color.w = metadata["light"]["power"].asFloat(); + light.color.w = metadata["light"]["power"].as(); - light.type = metadata["light"]["type"].asUInt64(); - light.depthBias = metadata["light"]["shadows"]["bias"].asFloat(); + light.type = metadata["light"]["type"].as(); + light.depthBias = metadata["light"]["shadows"]["bias"].as(); if ( !hasCompute && entity->hasComponent() ) { auto& renderMode = entity->getComponent(); diff --git a/ext/behaviors/scene/collision/behavior.cpp b/ext/behaviors/scene/collision/behavior.cpp index 53e44bfd..e470429a 100644 --- a/ext/behaviors/scene/collision/behavior.cpp +++ b/ext/behaviors/scene/collision/behavior.cpp @@ -22,7 +22,7 @@ #include -EXT_BEHAVIOR_REGISTER_CPP(SceneCollisionBehavior) +UF_BEHAVIOR_REGISTER_CPP(ext::SceneCollisionBehavior) #define this ((uf::Scene*) &self) void ext::SceneCollisionBehavior::initialize( uf::Object& self ) { @@ -35,18 +35,18 @@ void ext::SceneCollisionBehavior::tick( uf::Object& self ) { auto& metadata = this->getComponent(); - if ( !metadata["system"]["physics"]["collision"].asBool() ) return; + if ( !metadata["system"]["physics"]["collision"].as() ) return; auto& mutex = *(this->getComponent()); mutex.lock(); - bool threaded = !metadata["system"]["physics"]["single threaded"].asBool(); - bool sort = metadata["system"]["physics"]["sort"].asBool(); - bool useStrongest = metadata["system"]["physics"]["use"]["strongest"].asBool(); - bool queued = metadata["system"]["physics"]["use"]["queue"].asBool(); - bool updatePhysics = !metadata["system"]["physics"]["optimizations"]["entity-local update"].asBool(); - bool ignoreStaticEntities = metadata["system"]["physics"]["optimizations"]["ignore static entities"].asBool(); - bool ignoreDuplicateTests = metadata["system"]["physics"]["optimizations"]["ignore duplicate tests"].asBool(); - bool useWorkers = metadata["system"]["physics"]["use"]["worker"].asBool(); + bool threaded = !metadata["system"]["physics"]["single threaded"].as(); + bool sort = metadata["system"]["physics"]["sort"].as(); + bool useStrongest = metadata["system"]["physics"]["use"]["strongest"].as(); + bool queued = metadata["system"]["physics"]["use"]["queue"].as(); + bool updatePhysics = !metadata["system"]["physics"]["optimizations"]["entity-local update"].as(); + bool ignoreStaticEntities = metadata["system"]["physics"]["optimizations"]["ignore static entities"].as(); + bool ignoreDuplicateTests = metadata["system"]["physics"]["optimizations"]["ignore duplicate tests"].as(); + bool useWorkers = metadata["system"]["physics"]["use"]["worker"].as(); pod::Thread& thread = uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true, false ); auto function = [&]() -> int { std::vector entities; @@ -58,11 +58,11 @@ void ext::SceneCollisionBehavior::tick( uf::Object& self ) { auto& transform = entity->getComponent>(); auto& physics = entity->getComponent(); if ( metadata["system"]["physics"]["gravity"] != Json::nullValue ) { - physics.linear.acceleration.x = metadata["system"]["physics"]["gravity"][0].asFloat(); - physics.linear.acceleration.y = metadata["system"]["physics"]["gravity"][1].asFloat(); - physics.linear.acceleration.z = metadata["system"]["physics"]["gravity"][2].asFloat(); + physics.linear.acceleration.x = metadata["system"]["physics"]["gravity"][0].as(); + physics.linear.acceleration.y = metadata["system"]["physics"]["gravity"][1].as(); + physics.linear.acceleration.z = metadata["system"]["physics"]["gravity"][2].as(); } - if ( !metadata["system"]["physics"]["collision"].asBool() ) { + if ( !metadata["system"]["physics"]["collision"].as() ) { physics.linear.acceleration.x = 0; physics.linear.acceleration.y = 0; physics.linear.acceleration.z = 0; @@ -73,14 +73,17 @@ void ext::SceneCollisionBehavior::tick( uf::Object& self ) { } { std::function filter = [&]( uf::Entity* entity ) { + if ( !entity ) return; auto& metadata = entity->getComponent(); - if ( !metadata["system"]["physics"]["collision"].isNull() && !metadata["system"]["physics"]["collision"].asBool() ) return; + if ( !ext::json::isNull( metadata["system"]["physics"]["collision"] ) && !metadata["system"]["physics"]["collision"].as() ) return; if ( entity->hasComponent() ) entities.push_back((uf::Object*) entity); }; this->process(filter); } - auto onCollision = []( pod::Collider::Manifold& manifold, uf::Object* a, uf::Object* b, bool queued ){ + auto onCollision = []( pod::Collider::Manifold& manifold, uf::Object* a, uf::Object* b, bool queued ){ + if ( !a || !b ) return; + uf::Serializer payload; payload["normal"][0] = manifold.normal.x; payload["normal"][1] = manifold.normal.y; diff --git a/ext/behaviors/soundemitter/behavior.cpp b/ext/behaviors/soundemitter/behavior.cpp index 89bd4516..a26035e2 100644 --- a/ext/behaviors/soundemitter/behavior.cpp +++ b/ext/behaviors/soundemitter/behavior.cpp @@ -8,7 +8,7 @@ #include -EXT_BEHAVIOR_REGISTER_CPP(SoundEmitterBehavior) +UF_BEHAVIOR_REGISTER_CPP(ext::SoundEmitterBehavior) #define this ((uf::Scene*) &self) void ext::SoundEmitterBehavior::initialize( uf::Object& self ) { @@ -21,7 +21,7 @@ void ext::SoundEmitterBehavior::initialize( uf::Object& self ) { this->addHook( "asset:Load.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - std::string filename = json["filename"].asString(); + std::string filename = json["filename"].as(); if ( uf::io::extension(filename) != "ogg" ) return "false"; const uf::Audio* audioPointer = NULL; @@ -31,20 +31,20 @@ void ext::SoundEmitterBehavior::initialize( uf::Object& self ) { uf::Audio& audio = this->getComponent(); //emitter.add(filename); audio.load(filename); { - float volume = metadata["audio"]["volume"].isNumeric() ? metadata["audio"]["volume"].asFloat() : sMetadata["volumes"]["sfx"].asFloat(); + float volume = metadata["audio"]["volume"].is() ? metadata["audio"]["volume"].as() : sMetadata["volumes"]["sfx"].as(); audio.setVolume(volume); } - if ( metadata["audio"]["pitch"].isNumeric() ) { - audio.setPitch(metadata["audio"]["pitch"].asFloat()); + if ( metadata["audio"]["pitch"].is() ) { + audio.setPitch(metadata["audio"]["pitch"].as()); } - if ( metadata["audio"]["gain"].isNumeric() ) { - audio.setGain(metadata["audio"]["gain"].asFloat()); + if ( metadata["audio"]["gain"].is() ) { + audio.setGain(metadata["audio"]["gain"].as()); } - if ( metadata["audio"]["rolloffFactor"].isNumeric() ) { - audio.setRolloffFactor(metadata["audio"]["rolloffFactor"].asFloat()); + if ( metadata["audio"]["rolloffFactor"].is() ) { + audio.setRolloffFactor(metadata["audio"]["rolloffFactor"].as()); } - if ( metadata["audio"]["maxDistance"].isNumeric() ) { - audio.setMaxDistance(metadata["audio"]["maxDistance"].asFloat()); + if ( metadata["audio"]["maxDistance"].is() ) { + audio.setMaxDistance(metadata["audio"]["maxDistance"].as()); } audio.play(); @@ -63,7 +63,7 @@ void ext::SoundEmitterBehavior::tick( uf::Object& self ) { audio.setPosition( transform.position ); audio.setOrientation( transform.orientation ); - if ( metadata["audio"]["loop"].asBool() ) { + if ( metadata["audio"]["loop"].as() ) { float current = audio.getTime(); float end = audio.getDuration(); float epsilon = 0.005f; diff --git a/ext/behaviors/sprite/behavior.cpp b/ext/behaviors/sprite/behavior.cpp index 3e68d30c..efa3c13c 100644 --- a/ext/behaviors/sprite/behavior.cpp +++ b/ext/behaviors/sprite/behavior.cpp @@ -33,7 +33,7 @@ namespace { } } -EXT_BEHAVIOR_REGISTER_CPP(HousamoSpriteBehavior) +UF_BEHAVIOR_REGISTER_CPP(ext::HousamoSpriteBehavior) #define this (&self) void ext::HousamoSpriteBehavior::initialize( uf::Object& self ) { uf::Scene& scene = uf::scene::getCurrentScene(); @@ -43,7 +43,7 @@ void ext::HousamoSpriteBehavior::initialize( uf::Object& self ) { this->addHook( "graphics:Assign.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - std::string filename = json["filename"].asString(); + std::string filename = json["filename"].as(); metadata["system"]["control"] = false; if ( uf::io::extension(filename) != "png" ) return "false"; @@ -92,17 +92,17 @@ void ext::HousamoSpriteBehavior::initialize( uf::Object& self ) { }); { - std::string id = metadata[""]["party"][0].asString(); + std::string id = metadata[""]["party"][0].as(); uf::Serializer member = metadata[""]["transients"][id]; uf::Serializer cardData = masterDataGet("Card", id); - std::string name = cardData["filename"].asString(); - if ( member["skin"].isString() ) name += "_" + member["skin"].asString(); + std::string name = cardData["filename"].as(); + if ( member["skin"].is() ) name += "_" + member["skin"].as(); std::string filename = "https://cdn..xyz//unity/Android/fg/fg_" + name + ".png"; - if ( cardData["internal"].asBool() ) { + if ( cardData["internal"].as() ) { filename = "./data/smtsamo/fg/fg_" + name + ".png"; } - metadata["orientation"] = cardData["orientation"].asString() == "" ? "portrait" : "landscape"; + metadata["orientation"] = cardData["orientation"].as() == "" ? "portrait" : "landscape"; assetLoader.load(filename, "asset:Load." + std::to_string(this->getUid()) ); } @@ -110,7 +110,7 @@ void ext::HousamoSpriteBehavior::initialize( uf::Object& self ) { void ext::HousamoSpriteBehavior::tick( uf::Object& self ) {} void ext::HousamoSpriteBehavior::render( uf::Object& self ){ uf::Serializer& metadata = this->getComponent(); - if ( !metadata["system"]["loaded"].asBool() ) return; + if ( !metadata["system"]["loaded"].as() ) return; /* Update uniforms */ if ( this->hasComponent() ) { auto& mesh = this->getComponent(); @@ -126,10 +126,10 @@ void ext::HousamoSpriteBehavior::render( uf::Object& self ){ uniforms.matrices.projection[i] = camera.getProjection( i ); } - uniforms.color[0] = metadata["color"][0].asFloat(); - uniforms.color[1] = metadata["color"][1].asFloat(); - uniforms.color[2] = metadata["color"][2].asFloat(); - uniforms.color[3] = metadata["color"][3].asFloat(); + uniforms.color[0] = metadata["color"][0].as(); + uniforms.color[1] = metadata["color"][1].as(); + uniforms.color[2] = metadata["color"][2].as(); + uniforms.color[3] = metadata["color"][3].as(); graphic.material.shaders.front().updateBuffer( uniforms, 0, false ); }; } diff --git a/ext/behaviors/staticemitter/behavior.cpp b/ext/behaviors/staticemitter/behavior.cpp deleted file mode 100644 index d6b2bdcd..00000000 --- a/ext/behaviors/staticemitter/behavior.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "behavior.h" - -#include - -#include -#include -#include -#include - -EXT_BEHAVIOR_REGISTER_CPP(StaticEmitterBehavior) -#define this ((uf::Object*) &self) -void ext::StaticEmitterBehavior::initialize( uf::Object& self ) { - auto& metadata = this->getComponent(); - if ( metadata["distance"].asBool() ) { - // this->addHook( "system:Load.Finished.%UID%", [&](const std::string& event)->std::string{ - // uf::Serializer json = event; - auto* hud = this->loadChildPointer("/hud.json", true); - metadata["hud"]["uid"] = hud->getUid(); - // return "true"; - // }); - } -} -void ext::StaticEmitterBehavior::tick( uf::Object& self ) { - auto& scene = uf::scene::getCurrentScene(); - auto& controller = scene.getController(); - - auto& cTransform = controller.getComponent>(); - auto& transform = this->getComponent>(); - - float distanceSquared = uf::vector::distanceSquared( transform.position, cTransform.position ); - - auto& metadata = this->getComponent(); - auto& sMetadata = scene.getComponent(); - if ( metadata["static"]["scale"].isNumeric() ) { - distanceSquared *= metadata["static"]["scale"].asFloat(); - } - { - float lo = metadata["static"]["range"][0].isNumeric() ? metadata["static"]["range"][0].asFloat() : 0.1f; - float hi = metadata["static"]["range"][1].isNumeric() ? metadata["static"]["range"][1].asFloat() : 0.5f; - float staticBlend = std::clamp( distanceSquared > 1 ? 1.0f / distanceSquared : 1.0f, lo, hi ); - - float flicker = metadata["static"]["flicker"].isNumeric() ? metadata["static"]["flicker"].asFloat() : 0.001; - float pieces = metadata["static"]["pieces"].isNumeric() ? metadata["static"]["pieces"].asFloat() : 1000; - - uint32_t mode = sMetadata["system"]["renderer"]["shader"]["mode"].asUInt(); - mode |= (0x1 << 1); - - sMetadata["system"]["renderer"]["shader"]["mode"] = mode; - sMetadata["system"]["renderer"]["shader"]["parameters"][0] = flicker; - sMetadata["system"]["renderer"]["shader"]["parameters"][1] = pieces; - sMetadata["system"]["renderer"]["shader"]["parameters"][2] = staticBlend; - sMetadata["system"]["renderer"]["shader"]["parameters"][3] = "time"; - } - - static uf::Timer timer(false); - if ( !timer.running() ) timer.start(); - if ( metadata["hud"]["uid"].isNumeric() && timer.elapsed().asDouble() > 0.125 ) { - timer.reset(); - auto* hud = this->findByUid( metadata["hud"]["uid"].asUInt64() ); - auto& hMetadata = hud->getComponent(); - double d = uf::vector::distance( cTransform.position, transform.position ); - std::string string = uf::string::si( d, "m" ); - hMetadata["text settings"]["alpha"] = 0.5f; - if ( hMetadata["text settings"]["string"].asString() != string ) { - uf::Serializer payload; - payload["string"] = string; - hud->as().callHook("gui:UpdateString.%UID%", payload); - } - } -} - -void ext::StaticEmitterBehavior::render( uf::Object& self ){} -void ext::StaticEmitterBehavior::destroy( uf::Object& self ){} -#undef this \ No newline at end of file diff --git a/ext/behaviors/staticemitter/behavior.h b/ext/behaviors/staticemitter/behavior.h deleted file mode 100644 index 6265c86d..00000000 --- a/ext/behaviors/staticemitter/behavior.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace ext { - class EXT_API StaticEmitterBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; -} \ No newline at end of file diff --git a/ext/gui/behavior.cpp b/ext/gui/behavior.cpp index 11d68023..90a79ae2 100644 --- a/ext/gui/behavior.cpp +++ b/ext/gui/behavior.cpp @@ -48,12 +48,12 @@ std::vector ext::Gui::generateGlyphs( const std::string& _string uf::Object& gui = *this; std::string string = _string; uf::Serializer& metadata = gui.getComponent(); - std::string font = "./data/fonts/" + metadata["text settings"]["font"].asString(); + std::string font = "./data/fonts/" + metadata["text settings"]["font"].as(); if ( ::glyphs.cache[font].empty() ) { ext::freetype::initialize( ::glyphs.glyph, font ); } if ( string == "" ) { - string = metadata["text settings"]["string"].asString(); + string = metadata["text settings"]["string"].as(); } pod::Transform<>& transform = gui.getComponent>(); std::vector gs; @@ -89,13 +89,13 @@ std::vector ext::Gui::generateGlyphs( const std::string& _string } colors; } stat; - float scale = metadata["text settings"]["scale"].asFloat(); + float scale = metadata["text settings"]["scale"].as(); { pod::Vector3f color = { - metadata["text settings"]["color"][0].asFloat(), - metadata["text settings"]["color"][1].asFloat(), - metadata["text settings"]["color"][2].asFloat(), + metadata["text settings"]["color"][0].as(), + metadata["text settings"]["color"][1].as(), + metadata["text settings"]["color"][2].as(), }; stat.colors.container.push_back(color); } @@ -144,20 +144,20 @@ std::vector ext::Gui::generateGlyphs( const std::string& _string unsigned long c = *it; if ( c == '\n' ) continue; if ( c == '\t' ) continue; if ( c == 0x01 ) continue; std::string key = ""; { key += std::to_string(c) + ";"; - key += metadata["text settings"]["padding"][0].asString() + ","; - key += metadata["text settings"]["padding"][1].asString() + ";"; - key += metadata["text settings"]["spread"].asString() + ";"; - key += metadata["text settings"]["size"].asString() + ";"; - key += metadata["text settings"]["font"].asString() + ";"; - key += metadata["text settings"]["sdf"].asString(); + key += metadata["text settings"]["padding"][0].as() + ","; + key += metadata["text settings"]["padding"][1].as() + ";"; + key += metadata["text settings"]["spread"].as() + ";"; + key += metadata["text settings"]["size"].as() + ";"; + key += metadata["text settings"]["font"].as() + ";"; + key += metadata["text settings"]["sdf"].as(); } uf::Glyph& glyph = ::glyphs.cache[font][key]; if ( !glyph.generated() ) { - glyph.setPadding( { metadata["text settings"]["padding"][0].asUInt(), metadata["text settings"]["padding"][1].asUInt() } ); - glyph.setSpread( metadata["text settings"]["spread"].asUInt() ); - if ( metadata["text settings"]["sdf"].asBool() ) glyph.useSdf(true); - glyph.generate( ::glyphs.glyph, c, metadata["text settings"]["size"].asInt() ); + glyph.setPadding( { metadata["text settings"]["padding"][0].as(), metadata["text settings"]["padding"][1].as() } ); + glyph.setSpread( metadata["text settings"]["spread"].as() ); + if ( metadata["text settings"]["sdf"].as() ) glyph.useSdf(true); + glyph.generate( ::glyphs.glyph, c, metadata["text settings"]["size"].as() ); } stat.biggest.x = std::max( (float) stat.biggest.x, (float) glyph.getSize().x); @@ -193,12 +193,12 @@ std::vector ext::Gui::generateGlyphs( const std::string& _string } std::string key = ""; { key += std::to_string(c) + ";"; - key += metadata["text settings"]["padding"][0].asString() + ","; - key += metadata["text settings"]["padding"][1].asString() + ";"; - key += metadata["text settings"]["spread"].asString() + ";"; - key += metadata["text settings"]["size"].asString() + ";"; - key += metadata["text settings"]["font"].asString() + ";"; - key += metadata["text settings"]["sdf"].asString(); + key += metadata["text settings"]["padding"][0].as() + ","; + key += metadata["text settings"]["padding"][1].as() + ";"; + key += metadata["text settings"]["spread"].as() + ";"; + key += metadata["text settings"]["size"].as() + ";"; + key += metadata["text settings"]["font"].as() + ";"; + key += metadata["text settings"]["sdf"].as(); } uf::Glyph& glyph = ::glyphs.cache[font][key]; pod::GlyphBox g; @@ -212,13 +212,13 @@ std::vector ext::Gui::generateGlyphs( const std::string& _string stat.cursor.x += (glyph.getAdvance().x); } - stat.origin.x = ( !metadata["text settings"]["world"].asBool() && transform.position.x != (int) transform.position.x ) ? transform.position.x * ext::gui::size.current.x : transform.position.x; - stat.origin.y = ( !metadata["text settings"]["world"].asBool() && transform.position.y != (int) transform.position.y ) ? transform.position.y * ext::gui::size.current.y : transform.position.y; + stat.origin.x = ( !metadata["text settings"]["world"].as() && transform.position.x != (int) transform.position.x ) ? transform.position.x * ext::gui::size.current.x : transform.position.x; + stat.origin.y = ( !metadata["text settings"]["world"].as() && transform.position.y != (int) transform.position.y ) ? transform.position.y * ext::gui::size.current.y : transform.position.y; - if ( metadata["text settings"]["origin"].isArray() ) { - stat.origin.x = metadata["text settings"]["origin"][0].asInt(); - stat.origin.y = metadata["text settings"]["origin"][1].asInt(); + if ( ext::json::isArray( metadata["text settings"]["origin"] ) ) { + stat.origin.x = metadata["text settings"]["origin"][0].as(); + stat.origin.y = metadata["text settings"]["origin"][1].as(); } else if ( metadata["text settings"]["origin"] == "top" ) stat.origin.y = ext::gui::size.current.y - stat.origin.y - stat.biggest.y;// else stat.origin.y = stat.origin.y; if ( metadata["text settings"]["align"] == "right" ) stat.origin.x = ext::gui::size.current.x - stat.origin.x - stat.box.w;// else stat.origin.x = stat.origin.x; @@ -251,12 +251,12 @@ std::vector ext::Gui::generateGlyphs( const std::string& _string } std::string key = ""; { key += std::to_string(c) + ";"; - key += metadata["text settings"]["padding"][0].asString() + ","; - key += metadata["text settings"]["padding"][1].asString() + ";"; - key += metadata["text settings"]["spread"].asString() + ";"; - key += metadata["text settings"]["size"].asString() + ";"; - key += metadata["text settings"]["font"].asString() + ";"; - key += metadata["text settings"]["sdf"].asString(); + key += metadata["text settings"]["padding"][0].as() + ","; + key += metadata["text settings"]["padding"][1].as() + ";"; + key += metadata["text settings"]["spread"].as() + ";"; + key += metadata["text settings"]["size"].as() + ";"; + key += metadata["text settings"]["font"].as() + ";"; + key += metadata["text settings"]["sdf"].as(); } uf::Glyph& glyph = ::glyphs.cache[font][key]; @@ -276,9 +276,9 @@ std::vector ext::Gui::generateGlyphs( const std::string& _string } catch ( ... ) { std::cout << "Invalid color index `" << stat.colors.index << "` for string: " << string << ": (" << stat.colors.container.size() << ")" << std::endl; g.color = { - metadata["text settings"]["color"][0].asFloat(), - metadata["text settings"]["color"][1].asFloat(), - metadata["text settings"]["color"][2].asFloat(), + metadata["text settings"]["color"][0].as(), + metadata["text settings"]["color"][1].as(), + metadata["text settings"]["color"][2].as(), }; } @@ -307,15 +307,15 @@ void ext::Gui::load( uf::Image& image ) { } std::string suffix = ""; { - std::string _ = gui.getRootParent().getComponent()["shaders"]["gui"]["suffix"].asString(); + std::string _ = gui.getRootParent().getComponent()["shaders"]["gui"]["suffix"].as(); if ( _ != "" ) suffix = _ + "."; } if ( gui.getName() == "Gui: Text" ) { pod::GlyphBox g; - g.box.x = metadata["text settings"]["box"][0].asFloat(); - g.box.y = metadata["text settings"]["box"][1].asFloat(); - g.box.w = metadata["text settings"]["box"][2].asFloat(); - g.box.h = metadata["text settings"]["box"][3].asFloat(); + g.box.x = metadata["text settings"]["box"][0].as(); + g.box.y = metadata["text settings"]["box"][1].as(); + g.box.w = metadata["text settings"]["box"][2].as(); + g.box.h = metadata["text settings"]["box"][3].as(); mesh.vertices = { {{ g.box.x, g.box.y + g.box.h }, { 0.0f, 0.0f }}, @@ -337,8 +337,8 @@ void ext::Gui::load( uf::Image& image ) { std::string vertex = "./data/shaders/gui.text.vert.spv"; std::string fragment = "./data/shaders/gui.text.frag.spv"; } filenames; - if ( metadata["shaders"]["vertex"].isString() ) filenames.vertex = metadata["shaders"]["vertex"].asString(); - if ( metadata["shaders"]["fragment"].isString() ) filenames.fragment = metadata["shaders"]["fragment"].asString(); + if ( metadata["shaders"]["vertex"].is() ) filenames.vertex = metadata["shaders"]["vertex"].as(); + if ( metadata["shaders"]["fragment"].is() ) filenames.fragment = metadata["shaders"]["fragment"].as(); else if ( suffix != "" ) filenames.fragment = "./data/shaders/gui.text."+suffix+"frag.spv"; graphic.material.initializeShaders({ @@ -361,8 +361,8 @@ void ext::Gui::load( uf::Image& image ) { std::string vertex = "./data/shaders/gui.vert.spv"; std::string fragment = "./data/shaders/gui.frag.spv"; } filenames; - if ( metadata["shaders"]["vertex"].isString() ) filenames.vertex = metadata["shaders"]["vertex"].asString(); - if ( metadata["shaders"]["fragment"].isString() ) filenames.fragment = metadata["shaders"]["fragment"].asString(); + if ( metadata["shaders"]["vertex"].is() ) filenames.vertex = metadata["shaders"]["vertex"].as(); + if ( metadata["shaders"]["fragment"].is() ) filenames.fragment = metadata["shaders"]["fragment"].as(); else if ( suffix != "" ) filenames.fragment = "./data/shaders/gui."+suffix+"frag.spv"; graphic.material.initializeShaders({ @@ -381,39 +381,39 @@ void ext::Gui::load( uf::Image& image ) { auto& texture = graphic.material.textures.front(); pod::Vector2f textureSize = { - metadata["original size"]["x"].asFloat(), - metadata["original size"]["y"].asFloat() + metadata["original size"]["x"].as(), + metadata["original size"]["y"].as() }; - if ( metadata["scaling"].asString() == "fixed" ) { + if ( metadata["scaling"].as() == "fixed" ) { transform.scale = pod::Vector3{ (float) textureSize.x / ext::gui::size.current.x, (float) textureSize.y / ext::gui::size.current.y, 1 }; - } else if ( metadata["scaling"].asString() == "fixed-1080p" ) { + } else if ( metadata["scaling"].as() == "fixed-1080p" ) { transform.scale = pod::Vector3{ (float) textureSize.x / 1920, (float) textureSize.y / 1080, 1 }; } } } -EXT_OBJECT_REGISTER_BEGIN(Gui) - UF_OBJECT_REGISTER_BEHAVIOR(EntityBehavior) - UF_OBJECT_REGISTER_BEHAVIOR(ObjectBehavior) - EXT_OBJECT_REGISTER_BEHAVIOR(GuiBehavior) -EXT_OBJECT_REGISTER_END() +UF_OBJECT_REGISTER_BEGIN(ext::Gui) + UF_OBJECT_REGISTER_BEHAVIOR(uf::EntityBehavior) + UF_OBJECT_REGISTER_BEHAVIOR(uf::ObjectBehavior) + UF_OBJECT_REGISTER_BEHAVIOR(ext::GuiBehavior) +UF_OBJECT_REGISTER_END() #define this (&self) void ext::GuiBehavior::initialize( uf::Object& self ) { auto& metadata = this->getComponent(); this->addHook( "glyph:Load.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - unsigned long c = json["glyph"].asUInt64(); - std::string font = "./data/fonts/" + metadata["text settings"]["font"].asString(); + unsigned long c = json["glyph"].as(); + std::string font = "./data/fonts/" + metadata["text settings"]["font"].as(); std::string key = ""; { key += std::to_string(c) + ";"; - key += metadata["text settings"]["padding"][0].asString() + ","; - key += metadata["text settings"]["padding"][1].asString() + ";"; - key += metadata["text settings"]["spread"].asString() + ";"; - key += metadata["text settings"]["size"].asString() + ";"; - key += metadata["text settings"]["font"].asString() + ";"; - key += metadata["text settings"]["sdf"].asString(); + key += metadata["text settings"]["padding"][0].as() + ","; + key += metadata["text settings"]["padding"][1].as() + ";"; + key += metadata["text settings"]["spread"].as() + ";"; + key += metadata["text settings"]["size"].as() + ";"; + key += metadata["text settings"]["font"].as() + ";"; + key += metadata["text settings"]["sdf"].as(); } uf::Glyph& glyph = ::glyphs.cache[font][key]; @@ -429,7 +429,7 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { }); this->addHook( "asset:Load.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - std::string filename = json["filename"].asString(); + std::string filename = json["filename"].as(); if ( uf::io::extension(filename) != "png" ) return "false"; @@ -449,50 +449,50 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { if ( !this->hasComponent() ) return "false"; pod::Vector2ui size; { - size.x = json["window"]["size"]["x"].asUInt64(); - size.y = json["window"]["size"]["y"].asUInt64(); + size.x = json["window"]["size"]["x"].as(); + size.y = json["window"]["size"]["y"].as(); } pod::Transform<>& transform = this->getComponent>(); // uf::Graphic& graphic = this->getComponent(); // auto& texture = graphic.material.textures.front(); pod::Vector2f textureSize = { - metadata["original size"]["x"].asFloat(), - metadata["original size"]["y"].asFloat() + metadata["original size"]["x"].as(), + metadata["original size"]["y"].as() }; - if ( metadata["text settings"].isObject() ) { - } else if ( metadata["scaling"].asString() == "fixed" ) { + if ( ext::json::isObject( metadata["text settings"] ) ) { + } else if ( metadata["scaling"].as() == "fixed" ) { transform.scale = pod::Vector3{ (float) textureSize.x / size.x, (float) textureSize.y / size.y, 1 }; - } else if ( metadata["scaling"].asString() == "fixed-1080p" ) { + } else if ( metadata["scaling"].as() == "fixed-1080p" ) { transform.scale = pod::Vector3{ (float) textureSize.x / 1920, (float) textureSize.y / 1080, 1 }; } return "true"; } ); - if ( metadata["system"]["clickable"].asBool() ) { + if ( metadata["system"]["clickable"].as() ) { uf::Timer clickTimer(false); // clickTimer.start( uf::Time<>(-1000000) ); if ( !clickTimer.running() ) clickTimer.start(); this->addHook( "gui:Clicked.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - if ( metadata["events"]["click"].isObject() ) { + if ( ext::json::isObject( metadata["events"]["click"] ) ) { uf::Serializer event = metadata["events"]["click"]; metadata["events"]["click"] = Json::arrayValue; metadata["events"]["click"][0] = event; - } else if ( !metadata["events"]["click"].isArray() ) { + } else if ( !ext::json::isArray( metadata["events"]["click"] ) ) { this->getParent().as().callHook("gui:Clicked.%UID%", event); return "false"; } for ( int i = 0; i < metadata["events"]["click"].size(); ++i ) { uf::Serializer event = metadata["events"]["click"][i]; uf::Serializer payload = event["payload"]; - float delay = event["delay"].asFloat(); - if ( event["delay"].isNumeric() ) { - this->queueHook(event["name"].asString(), payload, event["delay"].asFloat()); + float delay = event["delay"].as(); + if ( event["delay"].is() ) { + this->queueHook(event["name"].as(), payload, event["delay"].as()); } else { - this->callHook(event["name"].asString(), payload ); + this->callHook(event["name"].as(), payload ); } } return "true"; @@ -502,15 +502,15 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { // if ( !this->hasComponent() ) return "false"; uf::Serializer& metadata = this->getComponent(); - if ( metadata["world"].asBool() ) return "true"; + if ( metadata["world"].as() ) return "true"; if ( metadata["box"] == Json::nullValue ) return "true"; - bool down = json["mouse"]["state"].asString() == "Down"; + bool down = json["mouse"]["state"].as() == "Down"; bool clicked = false; if ( down ) { pod::Vector2ui position; { - position.x = json["mouse"]["position"]["x"].asInt() > 0 ? json["mouse"]["position"]["x"].asUInt() : 0; - position.y = json["mouse"]["position"]["y"].asInt() > 0 ? json["mouse"]["position"]["y"].asUInt() : 0; + position.x = json["mouse"]["position"]["x"].as() > 0 ? json["mouse"]["position"]["x"].as() : 0; + position.y = json["mouse"]["position"]["y"].as() > 0 ? json["mouse"]["position"]["y"].as() : 0; } pod::Vector2f click; { click.x = (float) position.x / (float) ext::gui::size.current.x; @@ -524,12 +524,12 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { if (json["invoker"] == "vr" ) { - x = json["mouse"]["position"]["x"].asFloat(); - y = json["mouse"]["position"]["y"].asFloat(); + x = json["mouse"]["position"]["x"].as(); + y = json["mouse"]["position"]["y"].as(); } - pod::Vector2f min = { metadata["box"]["min"]["x"].asFloat(), metadata["box"]["min"]["y"].asFloat() }; - pod::Vector2f max = { metadata["box"]["max"]["x"].asFloat(), metadata["box"]["max"]["y"].asFloat() }; + pod::Vector2f min = { metadata["box"]["min"]["x"].as(), metadata["box"]["min"]["y"].as() }; + pod::Vector2f max = { metadata["box"]["max"]["x"].as(), metadata["box"]["max"]["y"].as() }; clicked = ( min.x <= x && min.y <= y && max.x >= x && max.y >= y ); } @@ -541,28 +541,28 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { return "true"; } ); } - if ( metadata["system"]["hoverable"].asBool() ) { + if ( metadata["system"]["hoverable"].as() ) { uf::Timer hoverTimer(false); hoverTimer.start( uf::Time<>(-1000000) ); this->addHook( "gui:Hovered.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - if ( metadata["events"]["hover"].isObject() ) { + if ( ext::json::isObject( metadata["events"]["hover"] ) ) { uf::Serializer event = metadata["events"]["hover"]; metadata["events"]["hover"] = Json::arrayValue; metadata["events"]["hover"][0] = event; - } else if ( !metadata["events"]["hover"].isArray() ) { + } else if ( !ext::json::isArray( metadata["events"]["hover"] ) ) { this->getParent().as().callHook("gui:Clicked.%UID%", event); return "false"; } for ( int i = 0; i < metadata["events"]["hover"].size(); ++i ) { uf::Serializer event = metadata["events"]["hover"][i]; uf::Serializer payload = event["payload"]; - float delay = event["delay"].asFloat(); - if ( event["delay"].isNumeric() ) { - this->queueHook(event["name"].asString(), payload, event["delay"].asFloat()); + float delay = event["delay"].as(); + if ( event["delay"].is() ) { + this->queueHook(event["name"].as(), payload, event["delay"].as()); } else { - this->callHook(event["name"].asString(), payload ); + this->callHook(event["name"].as(), payload ); } } return "true"; @@ -572,14 +572,14 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { if ( this->getUid() == 0 ) return "false"; if ( !this->hasComponent() ) return "false"; uf::Serializer& metadata = this->getComponent(); - if ( metadata["world"].asBool() ) return "true"; + if ( metadata["world"].as() ) return "true"; if ( metadata["box"] == Json::nullValue ) return "true"; - bool down = json["mouse"]["state"].asString() == "Down"; + bool down = json["mouse"]["state"].as() == "Down"; bool clicked = false; pod::Vector2ui position; { - position.x = json["mouse"]["position"]["x"].asInt() > 0 ? json["mouse"]["position"]["x"].asUInt() : 0; - position.y = json["mouse"]["position"]["y"].asInt() > 0 ? json["mouse"]["position"]["y"].asUInt() : 0; + position.x = json["mouse"]["position"]["x"].as() > 0 ? json["mouse"]["position"]["x"].as() : 0; + position.y = json["mouse"]["position"]["y"].as() > 0 ? json["mouse"]["position"]["y"].as() : 0; } pod::Vector2f click; { click.x = (float) position.x / (float) ext::gui::size.current.x; @@ -590,8 +590,8 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { float x = click.x; float y = click.y; - pod::Vector2f min = { metadata["box"]["min"]["x"].asFloat(), metadata["box"]["min"]["y"].asFloat() }; - pod::Vector2f max = { metadata["box"]["max"]["x"].asFloat(), metadata["box"]["max"]["y"].asFloat() }; + pod::Vector2f min = { metadata["box"]["min"]["x"].as(), metadata["box"]["min"]["y"].as() }; + pod::Vector2f max = { metadata["box"]["max"]["x"].as(), metadata["box"]["max"]["y"].as() }; clicked = ( min.x <= x && min.y <= y && max.x >= x && max.y >= y ); } metadata["hovered"] = clicked; @@ -604,19 +604,19 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { return "true"; } ); } - if ( metadata["text settings"]["string"].isString() ) { - if ( ::defaultSettings["metadata"].isNull() ) { + if ( metadata["text settings"]["string"].is() ) { + if ( ext::json::isNull( ::defaultSettings["metadata"] ) ) { ::defaultSettings.readFromFile("./data/entities/gui/text/string.json"); } for ( auto it = ::defaultSettings["metadata"]["text settings"].begin(); it != ::defaultSettings["metadata"]["text settings"].end(); ++it ) { - std::string key = it.key().asString(); - if ( metadata["text settings"][key].isNull() ) { + std::string key = it.key().as(); + if ( ext::json::isNull( metadata["text settings"][key] ) ) { metadata["text settings"][key] = ::defaultSettings["metadata"]["text settings"][key]; } } - if ( metadata["text settings"]["legacy"].asBool() ) { + if ( metadata["text settings"]["legacy"].as() ) { float delay = 0.0f; - float scale = metadata["text settings"]["scale"].asFloat(); + float scale = metadata["text settings"]["scale"].as(); std::vector glyphs = this->as().generateGlyphs(); for ( auto& glyph : glyphs ) { uf::Object& glyphElement = this->loadChild("/gui/text/letter.json", false); @@ -650,9 +650,9 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { uf::Serializer payload; payload["glyph"] = (uint64_t) glyph.code; - if ( metadata["text settings"]["scroll speed"].isNumeric() ) { + if ( metadata["text settings"]["scroll speed"].is() ) { glyphElement.queueHook("glyph:Load.%UID%", payload, delay); - delay += metadata["text settings"]["scroll speed"].asFloat(); + delay += metadata["text settings"]["scroll speed"].as(); } else { glyphElement.callHook("glyph:Load.%UID%", payload); } @@ -661,21 +661,21 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { } { float delay = 0.0f; - float scale = metadata["text settings"]["scale"].asFloat(); + float scale = metadata["text settings"]["scale"].as(); auto& transform = this->getComponent>(); transform.scale.x = scale; transform.scale.y = scale; std::vector glyphs = this->as().generateGlyphs(); - std::string font = "./data/fonts/" + metadata["text settings"]["font"].asString(); + std::string font = "./data/fonts/" + metadata["text settings"]["font"].as(); std::string key = ""; { - key += metadata["text settings"]["padding"][0].asString() + ","; - key += metadata["text settings"]["padding"][1].asString() + ";"; - key += metadata["text settings"]["spread"].asString() + ";"; - key += metadata["text settings"]["size"].asString() + ";"; - key += metadata["text settings"]["font"].asString() + ";"; - key += metadata["text settings"]["sdf"].asString(); + key += metadata["text settings"]["padding"][0].as() + ","; + key += metadata["text settings"]["padding"][1].as() + ";"; + key += metadata["text settings"]["spread"].as() + ";"; + key += metadata["text settings"]["size"].as() + ";"; + key += metadata["text settings"]["font"].as() + ";"; + key += metadata["text settings"]["sdf"].as(); } auto& scene = uf::scene::getCurrentScene(); auto& atlas = this->getComponent(); @@ -722,15 +722,15 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { graphic.initializeGeometry( mesh ); std::string suffix = ""; { - std::string _ = scene.getComponent()["shaders"]["gui"]["suffix"].asString(); + std::string _ = scene.getComponent()["shaders"]["gui"]["suffix"].as(); if ( _ != "" ) suffix = _ + "."; } struct { std::string vertex = "./data/shaders/gui.text.vert.spv"; std::string fragment = "./data/shaders/gui.text.frag.spv"; } filenames; - if ( metadata["shaders"]["vertex"].isString() ) filenames.vertex = metadata["shaders"]["vertex"].asString(); - if ( metadata["shaders"]["fragment"].isString() ) filenames.fragment = metadata["shaders"]["fragment"].asString(); + if ( metadata["shaders"]["vertex"].is() ) filenames.vertex = metadata["shaders"]["vertex"].as(); + if ( metadata["shaders"]["fragment"].is() ) filenames.fragment = metadata["shaders"]["fragment"].as(); else if ( suffix != "" ) filenames.fragment = "./data/shaders/gui.text."+suffix+"frag.spv"; graphic.material.initializeShaders({ @@ -749,28 +749,28 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { this->addHook( "gui:UpdateString.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; for ( auto it = ::defaultSettings["metadata"]["text settings"].begin(); it != ::defaultSettings["metadata"]["text settings"].end(); ++it ) { - std::string key = it.key().asString(); - if ( metadata["text settings"][key].isNull() ) { + std::string key = it.key().as(); + if ( ext::json::isNull( metadata["text settings"][key] ) ) { metadata["text settings"][key] = ::defaultSettings["metadata"]["text settings"][key]; } } - if ( json["string"].isString() ) { + if ( json["string"].is() ) { metadata["text settings"]["string"] = json["string"]; } - std::string string = metadata["text settings"]["string"].asString(); + std::string string = metadata["text settings"]["string"].as(); float delay = 0.0f; - float scale = metadata["text settings"]["scale"].asFloat(); + float scale = metadata["text settings"]["scale"].as(); std::vector glyphs = this->as().generateGlyphs( string ); - std::string font = "./data/fonts/" + metadata["text settings"]["font"].asString(); + std::string font = "./data/fonts/" + metadata["text settings"]["font"].as(); std::string key = ""; { - key += metadata["text settings"]["padding"][0].asString() + ","; - key += metadata["text settings"]["padding"][1].asString() + ";"; - key += metadata["text settings"]["spread"].asString() + ";"; - key += metadata["text settings"]["size"].asString() + ";"; - key += metadata["text settings"]["font"].asString() + ";"; - key += metadata["text settings"]["sdf"].asString(); + key += metadata["text settings"]["padding"][0].as() + ","; + key += metadata["text settings"]["padding"][1].as() + ";"; + key += metadata["text settings"]["spread"].as() + ";"; + key += metadata["text settings"]["size"].as() + ";"; + key += metadata["text settings"]["font"].as() + ";"; + key += metadata["text settings"]["sdf"].as(); } auto& transform = this->getComponent>(); auto& scene = uf::scene::getCurrentScene(); @@ -838,15 +838,15 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { graphic.initializeGeometry( mesh ); std::string suffix = ""; { - std::string _ = scene.getComponent()["shaders"]["gui"]["suffix"].asString(); + std::string _ = scene.getComponent()["shaders"]["gui"]["suffix"].as(); if ( _ != "" ) suffix = _ + "."; } struct { std::string vertex = "./data/shaders/gui.text.vert.spv"; std::string fragment = "./data/shaders/gui.text.frag.spv"; } filenames; - if ( metadata["shaders"]["vertex"].isString() ) filenames.vertex = metadata["shaders"]["vertex"].asString(); - if ( metadata["shaders"]["fragment"].isString() ) filenames.fragment = metadata["shaders"]["fragment"].asString(); + if ( metadata["shaders"]["vertex"].is() ) filenames.vertex = metadata["shaders"]["vertex"].as(); + if ( metadata["shaders"]["fragment"].is() ) filenames.fragment = metadata["shaders"]["fragment"].as(); else if ( suffix != "" ) filenames.fragment = "./data/shaders/gui.text."+suffix+"frag.spv"; graphic.material.initializeShaders({ @@ -861,9 +861,9 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { } void ext::GuiBehavior::tick( uf::Object& self ) { uf::Serializer& metadata = this->getComponent(); - if ( metadata["text settings"]["fade in speed"].isNumeric() && !metadata["system"]["faded in"].asBool() ) { - float speed = metadata["text settings"]["fade in speed"].asFloat(); - float alpha = metadata["text settings"]["color"][3].asFloat(); + if ( metadata["text settings"]["fade in speed"].is() && !metadata["system"]["faded in"].as() ) { + float speed = metadata["text settings"]["fade in speed"].as(); + float alpha = metadata["text settings"]["color"][3].as(); speed *= uf::physics::time::delta; if ( alpha < 1 && alpha + speed > 1 ) { alpha = 1; @@ -888,15 +888,15 @@ void ext::GuiBehavior::render( uf::Object& self ){ if ( !graphic.initialized ) return; pod::Vector4 offset = { - metadata["uv"][0].asFloat(), - metadata["uv"][1].asFloat(), - metadata["uv"][2].asFloat(), - metadata["uv"][3].asFloat() + metadata["uv"][0].as(), + metadata["uv"][1].as(), + metadata["uv"][2].as(), + metadata["uv"][3].as() }; int mode = 0; - if ( !metadata["shader"].isNull() ) mode = metadata["shader"].asInt(); + if ( !ext::json::isNull( metadata["shader"] ) ) mode = metadata["shader"].as(); - if ( !metadata["text settings"]["legacy"].isNull() && ((metadata["text settings"]["legacy"].asBool() && this->getName() == "Gui: Text") || (!metadata["text settings"]["legacy"].asBool() && metadata["text settings"]["string"].isString())) ) { + if ( !ext::json::isNull( metadata["text settings"]["legacy"] ) && ((metadata["text settings"]["legacy"].as() && this->getName() == "Gui: Text") || (!metadata["text settings"]["legacy"].as() && metadata["text settings"]["string"].is())) ) { struct GlyphDescriptor { struct { alignas(16) pod::Matrix4f model[2]; @@ -917,49 +917,49 @@ void ext::GuiBehavior::render( uf::Object& self ){ }; auto& uniforms = graphic.material.shaders.front().uniforms.front().get(); - if ( !metadata["text settings"]["color"].isArray() ) { + if ( !ext::json::isArray( metadata["text settings"]["color"] ) ) { metadata["text settings"]["color"][0] = 1.0f; metadata["text settings"]["color"][1] = 1.0f; metadata["text settings"]["color"][2] = 1.0f; metadata["text settings"]["color"][3] = 1.0f; } - if ( !metadata["text settings"]["stroke"].isArray() ) { + if ( !ext::json::isArray( metadata["text settings"]["stroke"] ) ) { metadata["text settings"]["stroke"][0] = 0.0f; metadata["text settings"]["stroke"][1] = 0.0f; metadata["text settings"]["stroke"][2] = 0.0f; metadata["text settings"]["stroke"][3] = 1.0f; } pod::Vector4 color = { - metadata["text settings"]["color"][0].asFloat(), - metadata["text settings"]["color"][1].asFloat(), - metadata["text settings"]["color"][2].asFloat(), - metadata["text settings"]["color"][3].asFloat() + metadata["text settings"]["color"][0].as(), + metadata["text settings"]["color"][1].as(), + metadata["text settings"]["color"][2].as(), + metadata["text settings"]["color"][3].as() }; - if ( metadata["alpha"].isNumeric() ) { - color[3] *= metadata["alpha"].asFloat(); + if ( metadata["alpha"].is() ) { + color[3] *= metadata["alpha"].as(); } pod::Vector4 stroke = { - metadata["text settings"]["stroke"][0].asFloat(), - metadata["text settings"]["stroke"][1].asFloat(), - metadata["text settings"]["stroke"][2].asFloat(), - metadata["text settings"]["stroke"][3].asFloat() + metadata["text settings"]["stroke"][0].as(), + metadata["text settings"]["stroke"][1].as(), + metadata["text settings"]["stroke"][2].as(), + metadata["text settings"]["stroke"][3].as() }; uniforms.gui.offset = offset; uniforms.gui.color = color; uniforms.gui.stroke = stroke; uniforms.gui.mode = mode; - uniforms.gui.sdf = metadata["text settings"]["sdf"].asBool(); - uniforms.gui.shadowbox = metadata["text settings"]["shadowbox"].asBool(); - uniforms.gui.weight = metadata["text settings"]["weight"].asFloat(); // float - uniforms.gui.spread = metadata["text settings"]["spread"].asInt(); // int - uniforms.gui.scale = metadata["text settings"]["scale"].asFloat(); // float - if ( !metadata["text settings"]["depth"].isNull() ) - uniforms.gui.depth = metadata["text settings"]["depth"].asFloat(); + uniforms.gui.sdf = metadata["text settings"]["sdf"].as(); + uniforms.gui.shadowbox = metadata["text settings"]["shadowbox"].as(); + uniforms.gui.weight = metadata["text settings"]["weight"].as(); // float + uniforms.gui.spread = metadata["text settings"]["spread"].as(); // int + uniforms.gui.scale = metadata["text settings"]["scale"].as(); // float + if ( !ext::json::isNull( metadata["text settings"]["depth"] ) ) + uniforms.gui.depth = metadata["text settings"]["depth"].as(); else uniforms.gui.depth = 0.0f; for ( std::size_t i = 0; i < 2; ++i ) { - if ( metadata["text settings"]["world"].asBool() ) { + if ( metadata["text settings"]["world"].as() ) { auto& scene = uf::scene::getCurrentScene(); auto& controller = scene.getController(); auto& camera = controller.getComponent(); @@ -1034,20 +1034,20 @@ void ext::GuiBehavior::render( uf::Object& self ){ } */ } else { - if ( !metadata["color"].isArray() ) { + if ( !ext::json::isArray( metadata["color"] ) ) { metadata["color"][0] = 1.0f; metadata["color"][1] = 1.0f; metadata["color"][2] = 1.0f; metadata["color"][3] = 1.0f; } pod::Vector4 color = { - metadata["color"][0].asFloat(), - metadata["color"][1].asFloat(), - metadata["color"][2].asFloat(), - metadata["color"][3].asFloat() + metadata["color"][0].as(), + metadata["color"][1].as(), + metadata["color"][2].as(), + metadata["color"][3].as() }; - if ( metadata["alpha"].isNumeric() ) { - color[3] *= metadata["alpha"].asFloat(); + if ( metadata["alpha"].is() ) { + color[3] *= metadata["alpha"].as(); } struct UniformDescriptor { struct { @@ -1065,13 +1065,13 @@ void ext::GuiBehavior::render( uf::Object& self ){ uniforms.gui.offset = offset; uniforms.gui.color = color; uniforms.gui.mode = mode; - if ( !metadata["depth"].isNull() ) - uniforms.gui.depth = metadata["depth"].asFloat(); + if ( !ext::json::isNull( metadata["depth"] ) ) + uniforms.gui.depth = metadata["depth"].as(); else uniforms.gui.depth = 0; for ( std::size_t i = 0; i < 2; ++i ) { - if ( metadata["world"].asBool() ) { + if ( metadata["world"].as() ) { /* pod::Transform<> flatten = uf::transform::flatten(camera.getTransform(), true); pod::Matrix4 rotation = uf::quaternion::matrix( uf::vector::multiply( { 1, 1, 1, -1 }, flatten.orientation) ); diff --git a/ext/gui/manager/behavior.cpp b/ext/gui/manager/behavior.cpp index 96d33c06..d1e6ad81 100644 --- a/ext/gui/manager/behavior.cpp +++ b/ext/gui/manager/behavior.cpp @@ -42,8 +42,8 @@ ext::gui::Size ext::gui::size = { }; -EXT_BEHAVIOR_REGISTER_CPP(GuiManagerBehavior) -EXT_BEHAVIOR_REGISTER_AS_OBJECT(GuiManagerBehavior, GuiManager) +UF_BEHAVIOR_REGISTER_CPP(ext::GuiManagerBehavior) +UF_BEHAVIOR_REGISTER_AS_OBJECT(ext::GuiManagerBehavior, ext::GuiManager) #define this (&self) void ext::GuiManagerBehavior::initialize( uf::Object& self ) { { @@ -65,8 +65,8 @@ void ext::GuiManagerBehavior::initialize( uf::Object& self ) { uf::Serializer json = event; pod::Vector2ui size; { - size.x = json["window"]["size"]["x"].asUInt64(); - size.y = json["window"]["size"]["y"].asUInt64(); + size.x = json["window"]["size"]["x"].as(); + size.y = json["window"]["size"]["y"].as(); } ext::gui::size.current = size; // ext::gui::size.reference = size; @@ -76,11 +76,11 @@ void ext::GuiManagerBehavior::initialize( uf::Object& self ) { this->addHook( "window:Mouse.Moved", [&](const std::string& event)->std::string{ uf::Serializer json = event; - bool down = json["mouse"]["state"].asString() == "Down"; + bool down = json["mouse"]["state"].as() == "Down"; bool clicked = false; pod::Vector2ui position; { - position.x = json["mouse"]["position"]["x"].asInt() > 0 ? json["mouse"]["position"]["x"].asUInt() : 0; - position.y = json["mouse"]["position"]["y"].asInt() > 0 ? json["mouse"]["position"]["y"].asUInt() : 0; + position.x = json["mouse"]["position"]["x"].as() > 0 ? json["mouse"]["position"]["x"].as() : 0; + position.y = json["mouse"]["position"]["y"].as() > 0 ? json["mouse"]["position"]["y"].as() : 0; } pod::Vector2f click; { click.x = (float) position.x / (float) ext::gui::size.current.x; @@ -96,7 +96,7 @@ void ext::GuiManagerBehavior::initialize( uf::Object& self ) { auto& controller = scene.getController(); auto& metadata = controller.getComponent(); - if ( metadata["overlay"]["cursor"]["type"].asString() == "mouse" ) { + if ( metadata["overlay"]["cursor"]["type"].as() == "mouse" ) { metadata["overlay"]["cursor"]["position"][0] = click.x; metadata["overlay"]["cursor"]["position"][1] = click.y; } @@ -139,27 +139,27 @@ void ext::GuiManagerBehavior::render( uf::Object& self ){ for ( size_t i = 0; i < 2; ++i ) { pod::Transform<> transform; - if ( metadata["overlay"]["position"].isArray() ) + if ( ext::json::isArray( metadata["overlay"]["position"] ) ) transform.position = { - metadata["overlay"]["position"][0].asFloat(), - metadata["overlay"]["position"][1].asFloat(), - metadata["overlay"]["position"][2].asFloat(), + metadata["overlay"]["position"][0].as(), + metadata["overlay"]["position"][1].as(), + metadata["overlay"]["position"][2].as(), }; - if ( metadata["overlay"]["scale"].isArray() ) + if ( ext::json::isArray( metadata["overlay"]["scale"] ) ) transform.scale = { - metadata["overlay"]["scale"][0].asFloat(), - metadata["overlay"]["scale"][1].asFloat(), - metadata["overlay"]["scale"][2].asFloat(), + metadata["overlay"]["scale"][0].as(), + metadata["overlay"]["scale"][1].as(), + metadata["overlay"]["scale"][2].as(), }; - if ( metadata["overlay"]["orientation"].isArray() ) + if ( ext::json::isArray( metadata["overlay"]["orientation"] ) ) transform.orientation = { - metadata["overlay"]["orientation"][0].asFloat(), - metadata["overlay"]["orientation"][1].asFloat(), - metadata["overlay"]["orientation"][2].asFloat(), - metadata["overlay"]["orientation"][3].asFloat(), + metadata["overlay"]["orientation"][0].as(), + metadata["overlay"]["orientation"][1].as(), + metadata["overlay"]["orientation"][2].as(), + metadata["overlay"]["orientation"][3].as(), }; - if ( ext::openvr::enabled && (metadata["overlay"]["enabled"].asBool() || uf::renderer::getRenderMode("Stereoscopic Deferred", true).getType() == "Stereoscopic Deferred" )) { - if ( metadata["overlay"]["floating"].asBool() ) { + if ( ext::openvr::enabled && (metadata["overlay"]["enabled"].as() || uf::renderer::getRenderMode("Stereoscopic Deferred", true).getType() == "Stereoscopic Deferred" )) { + if ( metadata["overlay"]["floating"].as() ) { pod::Matrix4f model = uf::transform::model( transform ); uniforms.matrices.models[i] = camera.getProjection(i) * ext::openvr::hmdEyePositionMatrix( i == 0 ? vr::Eye_Left : vr::Eye_Right ) * model; } else { @@ -173,24 +173,24 @@ void ext::GuiManagerBehavior::render( uf::Object& self ){ pod::Matrix4t<> model = uf::matrix::translate( uf::matrix::identity(), { 0, 0, 1 } ); uniforms.matrices.models[i] = model; } - // uniforms.alpha.x = metadata["overlay"]["alpha"].asFloat(); + // uniforms.alpha.x = metadata["overlay"]["alpha"].as(); // uniforms.alpha.y = 0; - uniforms.cursor.position.x = (metadata["overlay"]["cursor"]["position"][0].asFloat() + 1.0f) * 0.5f; //(::mouse.position.x + 1.0f) * 0.5f; - uniforms.cursor.position.y = (metadata["overlay"]["cursor"]["position"][1].asFloat() + 1.0f) * 0.5f; //(::mouse.position.y + 1.0f) * 0.5f; + uniforms.cursor.position.x = (metadata["overlay"]["cursor"]["position"][0].as() + 1.0f) * 0.5f; //(::mouse.position.x + 1.0f) * 0.5f; + uniforms.cursor.position.y = (metadata["overlay"]["cursor"]["position"][1].as() + 1.0f) * 0.5f; //(::mouse.position.y + 1.0f) * 0.5f; pod::Vector3f cursorSize; - cursorSize.x = metadata["overlay"]["cursor"]["radius"].asFloat(); - cursorSize.y = metadata["overlay"]["cursor"]["radius"].asFloat(); + cursorSize.x = metadata["overlay"]["cursor"]["radius"].as(); + cursorSize.y = metadata["overlay"]["cursor"]["radius"].as(); cursorSize = uf::matrix::multiply( uf::matrix::inverse( uf::matrix::scale( uf::matrix::identity() , transform.scale) ), cursorSize ); uniforms.cursor.radius.x = cursorSize.x; uniforms.cursor.radius.y = cursorSize.y; - uniforms.cursor.color.x = metadata["overlay"]["cursor"]["color"][0].asFloat(); - uniforms.cursor.color.y = metadata["overlay"]["cursor"]["color"][1].asFloat(); - uniforms.cursor.color.z = metadata["overlay"]["cursor"]["color"][2].asFloat(); - uniforms.cursor.color.w = metadata["overlay"]["cursor"]["color"][3].asFloat(); + uniforms.cursor.color.x = metadata["overlay"]["cursor"]["color"][0].as(); + uniforms.cursor.color.y = metadata["overlay"]["cursor"]["color"][1].as(); + uniforms.cursor.color.z = metadata["overlay"]["cursor"]["color"][2].as(); + uniforms.cursor.color.w = metadata["overlay"]["cursor"]["color"][3].as(); } shader.updateBuffer( (void*) &uniforms, sizeof(uniforms), 0 ); } diff --git a/ext/inits/persistence.inl b/ext/inits/persistence.inl index e0ac85a6..d9fa53eb 100644 --- a/ext/inits/persistence.inl +++ b/ext/inits/persistence.inl @@ -9,10 +9,10 @@ uf::Serializer file; } config; /* Read from file */ if (( file.exists = config.file.readFromFile(file.filename) )) { - persistent.window.size.x = config.file["window"]["size"]["x"].asUInt64(); - persistent.window.size.y = config.file["window"]["size"]["y"].asUInt64(); + persistent.window.size.x = config.file["window"]["size"]["x"].as(); + persistent.window.size.y = config.file["window"]["size"]["y"].as(); if ( config.file["window"]["title"] != "null" ) { - persistent.window.title = config.file["window"]["title"].asString(); + persistent.window.title = config.file["window"]["title"].as(); } /* Update window size */ { diff --git a/ext/main.cpp b/ext/main.cpp index 0f9c43f5..23b8929d 100644 --- a/ext/main.cpp +++ b/ext/main.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -61,6 +62,7 @@ namespace { double curTime = 0; double deltaTime = 0; size_t frames = 0; + double limiter = 1.0 / 144.0; } times; uf::Serializer config; @@ -117,16 +119,21 @@ void EXT_API ext::initialize() { // #include "./inits/persistence.inl" } /* Lua */ { + ext::lua::main = ::config["engine"]["ext"]["lua"]["main"].as(); + for ( auto it = ::config["engine"]["ext"]["lua"]["modules"].begin(); it != ::config["engine"]["ext"]["lua"]["modules"].end(); ++it ) { + std::string key = it.key().as(); + ext::lua::modules[key] = ::config["engine"]["ext"]["lua"]["modules"][key].as(); + } ext::lua::initialize(); } /* Parse config */ { // Set memory pool sizes { - auto deduceSize = []( auto& value )->size_t{ - if ( value.isNumeric() ) return value.asUInt64(); - if ( value.isString() ) { - std::string str = value.asString(); + auto deduceSize = []( const Json::Value& value )->size_t{ + if ( value.is() ) return value.as(); + if ( value.is() ) { + std::string str = value.as(); std::regex regex("^(\\d+) ?((?:K|M|G)?(?:i?B)?)$"); std::smatch match; if ( std::regex_search( str, match, regex ) ) { @@ -144,23 +151,23 @@ void EXT_API ext::initialize() { }; { size_t size = deduceSize( ::config["engine"]["memory pool"]["size"] ); - uf::MemoryPool::globalOverride = ::config["engine"]["memory pool"]["globalOverride"].asBool(); + uf::MemoryPool::globalOverride = ::config["engine"]["memory pool"]["globalOverride"].as(); uf::iostream << "Requesting " << (int) size << " bytes for global memory pool: " << &uf::MemoryPool::global << "\n"; uf::MemoryPool::global.initialize( size ); - uf::MemoryPool::subPool = ::config["engine"]["memory pool"]["subPools"].asBool(); + uf::MemoryPool::subPool = ::config["engine"]["memory pool"]["subPools"].as(); if ( size <= 0 || uf::MemoryPool::subPool ) { { - size_t size = deduceSize( ::config["engine"]["memory pools"]["component"] ); + size_t size = deduceSize( ::config["engine"]["memory pool"]["pools"]["component"] ); uf::iostream << "Requesting " << (int) size << " bytes for component memory pool: " << &uf::component::memoryPool << "\n"; uf::component::memoryPool.initialize( size ); } { - size_t size = deduceSize( ::config["engine"]["memory pools"]["userdata"] ); + size_t size = deduceSize( ::config["engine"]["memory pool"]["pools"]["userdata"] ); uf::iostream << "Requesting " << (int) size << " bytes for userdata memory pool: " << &uf::userdata::memoryPool << "\n"; uf::userdata::memoryPool.initialize( size ); } { - size_t size = deduceSize( ::config["engine"]["memory pools"]["entity"] ); + size_t size = deduceSize( ::config["engine"]["memory pool"]["pools"]["entity"] ); uf::iostream << "Requesting " << (int) size << " bytes for entity memory pool: " << &uf::Entity::memoryPool << "\n"; uf::Entity::memoryPool.initialize( size ); } @@ -168,74 +175,82 @@ void EXT_API ext::initialize() { } } /* Frame limiter */ { - double limit = ::config["engine"]["limiters"]["framerate"].asDouble(); + double limit = ::config["engine"]["limiters"]["framerate"].as(); if ( limit != 0 ) - uf::thread::limiter = 1.0 / ::config["engine"]["limiters"]["framerate"].asDouble(); - else uf::thread::limiter = 0; + ::times.limiter = 1.0 / ::config["engine"]["limiters"]["framerate"].as(); + else ::times.limiter = 0; } /* Max delta time */{ - double limit = ::config["engine"]["limiters"]["deltaTime"].asDouble(); + double limit = ::config["engine"]["limiters"]["deltaTime"].as(); if ( limit != 0 ) - uf::physics::time::clamp = 1.0 / ::config["engine"]["limiters"]["deltaTime"].asDouble(); + uf::physics::time::clamp = 1.0 / ::config["engine"]["limiters"]["deltaTime"].as(); else uf::physics::time::clamp = 0; } /* Thread frame limiter */ { - double limit = ::config["engine"]["threads"]["frame limiter"].asDouble(); + double limit = ::config["engine"]["threads"]["frame limiter"].as(); if ( limit != 0 ) - uf::thread::limiter = 1.0 / ::config["engine"]["threads"]["frame limiter"].asDouble(); + uf::thread::limiter = 1.0 / ::config["engine"]["threads"]["frame limiter"].as(); + else + uf::thread::limiter = 0; } + // Mute audio + if ( ::config["engine"]["audio"]["mute"].is() ) + uf::Audio::mute = ::config["engine"]["audio"]["mute"].as(); + // Set worker threads - if ( ::config["engine"]["threads"]["workers"].asString() == "auto" ) { + if ( ::config["engine"]["threads"]["workers"].as() == "auto" ) { auto threads = std::max( 1, (int) std::thread::hardware_concurrency() - 1 ); ::config["engine"]["threads"]["workers"] = threads; uf::iostream << "Using " << threads << " worker threads" << "\n"; } - uf::thread::workers = ::config["engine"]["threads"]["workers"].asUInt64(); + uf::thread::workers = ::config["engine"]["threads"]["workers"].as(); // Enable valiation layer - uf::renderer::settings::validation = ::config["engine"]["ext"]["vulkan"]["validation"]["enabled"].asBool(); + uf::renderer::settings::validation = ::config["engine"]["ext"]["vulkan"]["validation"]["enabled"].as(); - if ( ::config["engine"]["ext"]["vulkan"]["framebuffer"]["msaa"].isNumeric() ) - uf::renderer::settings::msaa = ::config["engine"]["ext"]["vulkan"]["framebuffer"]["msaa"].asUInt64(); + if ( ::config["engine"]["ext"]["vulkan"]["framebuffer"]["msaa"].is() ) + uf::renderer::settings::msaa = ::config["engine"]["ext"]["vulkan"]["framebuffer"]["msaa"].as(); - if ( ::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"].isNumeric() ) { - float scale = ::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"].asFloat(); + if ( ::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"].is() ) { + float scale = ::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"].as(); uf::renderer::settings::width *= scale; uf::renderer::settings::height *= scale; - } else if ( ::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"].isArray() ) { - uf::renderer::settings::width = ::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"][0].asFloat(); - uf::renderer::settings::height = ::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"][1].asFloat(); - std::string filter = ::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"][2].asString(); + } else if ( ext::json::isArray( ::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"] ) ) { + uf::renderer::settings::width = ::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"][0].as(); + uf::renderer::settings::height = ::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"][1].as(); + std::string filter = ::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"][2].as(); if ( uf::string::lowercase( filter ) == "nearest" ) uf::renderer::settings::swapchainUpscaleFilter = VK_FILTER_NEAREST; else if ( uf::string::lowercase( filter ) == "linear" ) uf::renderer::settings::swapchainUpscaleFilter = VK_FILTER_LINEAR; } + if ( ::config["engine"]["debug"]["entity"]["delete children on destroy"].is() ) uf::Entity::deleteChildrenOnDestroy = ::config["engine"]["debug"]["entity"]["delete children on destroy"].as(); + if ( ::config["engine"]["debug"]["entity"]["delete components on destroy"].is() ) uf::Entity::deleteComponentsOnDestroy = ::config["engine"]["debug"]["entity"]["delete components on destroy"].as(); for ( int i = 0; i < ::config["engine"]["ext"]["vulkan"]["validation"]["filters"].size(); ++i ) { - uf::renderer::settings::validationFilters.push_back( ::config["engine"]["ext"]["vulkan"]["validation"]["filters"][i].asString() ); + uf::renderer::settings::validationFilters.push_back( ::config["engine"]["ext"]["vulkan"]["validation"]["filters"][i].as() ); } for ( int i = 0; i < ::config["engine"]["ext"]["vulkan"]["extensions"]["device"].size(); ++i ) { - uf::renderer::settings::requestedDeviceExtensions.push_back( ::config["engine"]["ext"]["vulkan"]["extensions"]["device"][i].asString() ); + uf::renderer::settings::requestedDeviceExtensions.push_back( ::config["engine"]["ext"]["vulkan"]["extensions"]["device"][i].as() ); } for ( int i = 0; i < ::config["engine"]["ext"]["vulkan"]["extensions"]["instance"].size(); ++i ) { - uf::renderer::settings::requestedInstanceExtensions.push_back( ::config["engine"]["ext"]["vulkan"]["extensions"]["instance"][i].asString() ); + uf::renderer::settings::requestedInstanceExtensions.push_back( ::config["engine"]["ext"]["vulkan"]["extensions"]["instance"][i].as() ); } for ( int i = 0; i < ::config["engine"]["ext"]["vulkan"]["features"].size(); ++i ) { - uf::renderer::settings::requestedDeviceFeatures.push_back( ::config["engine"]["ext"]["vulkan"]["features"][i].asString() ); + uf::renderer::settings::requestedDeviceFeatures.push_back( ::config["engine"]["ext"]["vulkan"]["features"][i].as() ); } - uf::renderer::settings::experimental::rebuildOnTickBegin = ::config["engine"]["ext"]["vulkan"]["experimental"]["rebuild on tick begin"].asBool(); - uf::renderer::settings::experimental::waitOnRenderEnd = ::config["engine"]["ext"]["vulkan"]["experimental"]["wait on render end"].asBool(); - uf::renderer::settings::experimental::individualPipelines = ::config["engine"]["ext"]["vulkan"]["experimental"]["individual pipelines"].asBool(); - uf::renderer::settings::experimental::multithreadedCommandRecording = ::config["engine"]["ext"]["vulkan"]["experimental"]["multithreaded command recording"].asBool(); - uf::renderer::settings::experimental::deferredReconstructPosition = ::config["engine"]["ext"]["vulkan"]["experimental"]["deferred reconstruct position"].asBool(); - uf::renderer::settings::experimental::deferredAliasOutputToSwapchain = ::config["engine"]["ext"]["vulkan"]["experimental"]["deferred alias output to swapchain"].asBool(); + uf::renderer::settings::experimental::rebuildOnTickBegin = ::config["engine"]["ext"]["vulkan"]["experimental"]["rebuild on tick begin"].as(); + uf::renderer::settings::experimental::waitOnRenderEnd = ::config["engine"]["ext"]["vulkan"]["experimental"]["wait on render end"].as(); + uf::renderer::settings::experimental::individualPipelines = ::config["engine"]["ext"]["vulkan"]["experimental"]["individual pipelines"].as(); + uf::renderer::settings::experimental::multithreadedCommandRecording = ::config["engine"]["ext"]["vulkan"]["experimental"]["multithreaded command recording"].as(); + uf::renderer::settings::experimental::deferredReconstructPosition = ::config["engine"]["ext"]["vulkan"]["experimental"]["deferred reconstruct position"].as(); + uf::renderer::settings::experimental::deferredAliasOutputToSwapchain = ::config["engine"]["ext"]["vulkan"]["experimental"]["deferred alias output to swapchain"].as(); - ext::openvr::enabled = ::config["engine"]["ext"]["vr"]["enable"].asBool(); - ext::openvr::swapEyes = ::config["engine"]["ext"]["vr"]["swap eyes"].asBool(); - if ( ::config["engine"]["ext"]["vr"]["dominatEye"].isNumeric() ) - ext::openvr::dominantEye = ::config["engine"]["ext"]["vr"]["dominatEye"].asUInt64(); - else if ( ::config["engine"]["ext"]["vr"]["dominatEye"].asString() == "left" ) ext::openvr::dominantEye = 0; - else if ( ::config["engine"]["ext"]["vr"]["dominatEye"].asString() == "right" ) ext::openvr::dominantEye = 1; - ext::openvr::driver.manifest = ::config["engine"]["ext"]["vr"]["manifest"].asString(); + ext::openvr::enabled = ::config["engine"]["ext"]["vr"]["enable"].as(); + ext::openvr::swapEyes = ::config["engine"]["ext"]["vr"]["swap eyes"].as(); + if ( ::config["engine"]["ext"]["vr"]["dominatEye"].is() ) + ext::openvr::dominantEye = ::config["engine"]["ext"]["vr"]["dominatEye"].as(); + else if ( ::config["engine"]["ext"]["vr"]["dominatEye"].as() == "left" ) ext::openvr::dominantEye = 0; + else if ( ::config["engine"]["ext"]["vr"]["dominatEye"].as() == "right" ) ext::openvr::dominantEye = 1; + ext::openvr::driver.manifest = ::config["engine"]["ext"]["vr"]["manifest"].as(); if ( ext::openvr::enabled ) { ::config["engine"]["render modes"]["stereo deferred"] = true; } @@ -250,20 +265,20 @@ void EXT_API ext::initialize() { } /* Initialize Vulkan */ { - // uf::renderer::width = ::config["window"]["size"]["x"].asInt(); - // uf::renderer::height = ::config["window"]["size"]["y"].asInt(); + // uf::renderer::width = ::config["window"]["size"]["x"].as(); + // uf::renderer::height = ::config["window"]["size"]["y"].as(); // setup render mode - if ( ::config["engine"]["render modes"]["gui"].asBool() ) { + if ( ::config["engine"]["render modes"]["gui"].as() ) { auto* renderMode = new uf::renderer::RenderTargetRenderMode; uf::renderer::addRenderMode( renderMode, "Gui" ); renderMode->blitter.descriptor.subpass = 1; } - if ( ::config["engine"]["render modes"]["multiview stereo deferred"].asBool() ) + if ( ::config["engine"]["render modes"]["multiview stereo deferred"].as() ) uf::renderer::addRenderMode( new uf::renderer::MultiviewStereoscopicDeferredRenderMode, "" ); - else if ( ::config["engine"]["render modes"]["stereo deferred"].asBool() ) + else if ( ::config["engine"]["render modes"]["stereo deferred"].as() ) uf::renderer::addRenderMode( new uf::renderer::StereoscopicDeferredRenderMode, "" ); - else if ( ::config["engine"]["render modes"]["deferred"].asBool() ) + else if ( ::config["engine"]["render modes"]["deferred"].as() ) uf::renderer::addRenderMode( new uf::renderer::DeferredRenderMode, "" ); if ( ext::openvr::enabled ) { @@ -278,8 +293,8 @@ void EXT_API ext::initialize() { uf::iostream << "Recommended VR Resolution: " << renderMode.width << ", " << renderMode.height << "\n"; - if ( ::config["engine"]["ext"]["vr"]["scale"].isNumeric() ) { - float scale = ::config["engine"]["ext"]["vr"]["scale"].asFloat(); + if ( ::config["engine"]["ext"]["vr"]["scale"].is() ) { + float scale = ::config["engine"]["ext"]["vr"]["scale"].as(); renderMode.width *= scale; renderMode.height *= scale; @@ -294,42 +309,63 @@ void EXT_API ext::initialize() { pod::Thread& threadPhysics = uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true ); } - /* Discord */ if ( ::config["engine"]["ex"]["discord"]["enabled"].asBool() ) { + /* Discord */ if ( ::config["engine"]["ex"]["discord"]["enabled"].as() ) { ext::discord::initialize(); } - /* Initialize root scene*/ { - uf::scene::unloadScene(); - auto& scene = uf::scene::loadScene( ::config["engine"]["scenes"]["start"].asString() ); - auto& metadata = scene.getComponent(); - metadata["system"]["config"] = ::config; - } /* Add hooks */ { - uf::hooks.addHook( "game:LoadScene", [&](const std::string& event)->std::string{ + uf::hooks.addHook( "game:Scene.Load", [&](const std::string& event)->std::string{ + auto function = [event]() -> int { + uf::Serializer json = event; + uf::renderer::synchronize(); + + // uf::hooks.call("game:Scene.Cleanup"); + uf::scene::unloadScene(); + + auto& scene = uf::scene::loadScene( json["scene"].as() ); + auto& metadata = scene.getComponent(); + metadata["system"]["config"] = ::config; + + return 0; + }; + uf::Serializer json = event; - uf::iostream << "SCENE CHANGE: " << event << "\n"; - uf::renderer::synchronize(); - uf::scene::unloadScene(); - auto& scene = uf::scene::loadScene( json["scene"].asString() ); - auto& metadata = scene.getComponent(); - metadata["system"]["config"] = ::config; + if ( json["immediate"].as() ) + function(); + else + uf::thread::add( uf::thread::get("Main"), function, true ); return "true"; }); + uf::hooks.addHook( "game:Scene.Cleanup", [&](const std::string& event)->std::string{ + for ( auto* scene : uf::scene::scenes ) { + scene->destroy(); + delete scene; + } + uf::scene::scenes.clear(); + return "true"; + }); uf::hooks.addHook( "system:Quit", [&](const std::string& event)->std::string{ uf::iostream << "system:Quit: " << event << "\n"; ext::ready = false; return "true"; }); } + /* Initialize root scene*/ { + uf::Serializer payload; + payload["scene"] = ::config["engine"]["scenes"]["start"]; + payload["immediate"] = true; + uf::hooks.call("game:Scene.Load", payload); + } ext::ready = true; uf::iostream << "EXT took " << times.sys.elapsed().asDouble() << " seconds to initialize!" << "\n"; { uf::thread::add( uf::thread::fetchWorker(), [&]() -> int { - uf::Asset& assetLoader = uf::scene::getCurrentScene().getComponent(); + auto& scene = uf::scene::getCurrentScene(); + auto& assetLoader = scene.getComponent(); assetLoader.processQueue(); return 0;}, false ); } @@ -354,7 +390,7 @@ void EXT_API ext::tick() { } uf::iostream << "\n"; }; - for ( uf::Scene* scene : uf::renderer::scenes ) { + for ( uf::Scene* scene : uf::scene::scenes ) { if ( !scene ) continue; uf::iostream << "Scene: " << scene->getName() << ": " << scene << "\n"; scene->process(filter, 1); @@ -373,7 +409,7 @@ void EXT_API ext::tick() { } uf::iostream << "]\n"; }; - for ( uf::Scene* scene : uf::renderer::scenes ) { + for ( uf::Scene* scene : uf::scene::scenes ) { if ( !scene ) continue; uf::iostream << "Scene: " << scene->getName() << ": " << scene << "\n"; scene->process(filter, 1); @@ -429,7 +465,7 @@ void EXT_API ext::tick() { auto& lMetadata = light.getComponent(); lTransform.position = t.position; lTransform.orientation = t.orientation; - if ( !lMetadata["light"].isArray() ) { + if ( !ext::json::isArray( lMetadata["light"] ) ) { lMetadata["light"]["color"][0] = (rand() % 100) / 100.0; lMetadata["light"]["color"][1] = (rand() % 100) / 100.0; lMetadata["light"]["color"][2] = (rand() % 100) / 100.0; @@ -459,21 +495,34 @@ void EXT_API ext::tick() { uf::thread::process( thread ); } + /* Garbage collection */ if ( ::config["engine"]["debug"]["garbage collection"]["enabled"].as() ) { + static uf::Timer timer(false); + if ( !timer.running() ) timer.start(); + double every = ::config["engine"]["debug"]["framerate"]["every"].as(); + uint8_t mode = ::config["engine"]["debug"]["framerate"]["mode"].as(); + if ( timer.elapsed().asDouble() >= every ) { timer.reset(); + size_t collected = uf::instantiator::collect( mode ); + if ( collected > 0 ) { + uf::iostream << "GC collected " << (int) collected << " unused entities" << "\n"; + } + } + } + /* Update vulkan */ { uf::renderer::tick(); } - /* Discord */ if ( ::config["engine"]["ext"]["discord"]["enable"].asBool() ) { + /* Discord */ if ( ::config["engine"]["ext"]["discord"]["enable"].as() ) { ext::discord::tick(); } /* OpenVR */ if ( ext::openvr::context ) { ext::openvr::tick(); } - /* FPS Print */ if ( ::config["engine"]["debug"]["framerate"]["print"].asBool() ) { + /* FPS Print */ if ( ::config["engine"]["debug"]["framerate"]["print"].as() ) { static uf::Timer timer(false); if ( !timer.running() ) timer.start(); ++::times.frames; - double every = ::config["engine"]["debug"]["framerate"]["every"].asDouble(); + double every = ::config["engine"]["debug"]["framerate"]["every"].as(); double time = 0; if ( (time = timer.elapsed().asDouble()) >= every ) { timer.reset(); // uf::iostream << "Framerate: " << (1.0/times.deltaTime) << " FPS | Frametime: " << (times.deltaTime * 1000) << "ms" << "\n"; @@ -482,16 +531,16 @@ void EXT_API ext::tick() { } } - /* Frame limiter of sorts I guess */ if ( uf::thread::limiter > 0 ) { + /* Frame limiter of sorts I guess */ if ( ::times.limiter > 0 ) { static uf::Timer timer(false); if ( !timer.running() ) timer.start(); auto elapsed = timer.elapsed().asMilliseconds(); - long long sleep = (uf::thread::limiter * 1000) - elapsed; + long long sleep = (::times.limiter * 1000) - elapsed; if ( sleep > 0 ) { - if ( ::config["engine"]["debug"]["framerate"]["print"].asBool() ) { - // uf::iostream << "Frame limiting: " << elapsed << "ms exceeds limit, sleeping for " << elapsed << "ms" << "\n"; + if ( ::config["engine"]["debug"]["framerate"]["print"].as() ) { + uf::iostream << "Frame limiting: " << elapsed << "ms exceeds limit, sleeping for " << elapsed << "ms" << "\n"; } - // std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); + std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); } timer.reset(); } diff --git a/ext/scenes/raytrace/behavior.cpp b/ext/scenes/raytrace/behavior.cpp index 6cbd9842..2e36417a 100644 --- a/ext/scenes/raytrace/behavior.cpp +++ b/ext/scenes/raytrace/behavior.cpp @@ -23,7 +23,7 @@ #include "../../ext.h" #include "../../gui/gui.h" -EXT_BEHAVIOR_REGISTER_CPP(RayTracingSceneBehavior) +UF_BEHAVIOR_REGISTER_CPP(ext::RayTracingSceneBehavior) #define this ((uf::Scene*) &self) void ext::RayTracingSceneBehavior::initialize( uf::Object& self ) { uf::Serializer& metadata = this->getComponent(); @@ -33,12 +33,12 @@ void ext::RayTracingSceneBehavior::initialize( uf::Object& self ) { auto& renderMode = this->getComponent(); std::string name = "C:RT:" + std::to_string((int) this->getUid()); uf::renderer::addRenderMode( &renderMode, name ); - if ( metadata["light"]["shadows"]["resolution"].isArray() ) { - renderMode.width = metadata["light"]["shadows"]["resolution"][0].asUInt64(); - renderMode.height = metadata["light"]["shadows"]["resolution"][1].asUInt64(); + if ( ext::json::isArray( metadata["light"]["shadows"]["resolution"] ) ) { + renderMode.width = metadata["light"]["shadows"]["resolution"][0].as(); + renderMode.height = metadata["light"]["shadows"]["resolution"][1].as(); } else { - renderMode.width = metadata["light"]["shadows"]["resolution"].asUInt64(); - renderMode.height = metadata["light"]["shadows"]["resolution"].asUInt64(); + renderMode.width = metadata["light"]["shadows"]["resolution"].as(); + renderMode.height = metadata["light"]["shadows"]["resolution"].as(); } { struct Shape { @@ -118,11 +118,11 @@ void ext::RayTracingSceneBehavior::tick( uf::Object& self ) { float reflectionFalloff; }; auto& pushConstant = shader.pushConstants.front().get(); - pushConstant.marchingSteps = metadata["rays"]["marching steps"].asUInt64(); - pushConstant.rayBounces = metadata["rays"]["ray bounces"].asUInt64(); - pushConstant.shadowFactor = metadata["rays"]["shadow factor"].asFloat(); - pushConstant.reflectionStrength = metadata["rays"]["reflection"]["strength"].asFloat(); - pushConstant.reflectionFalloff = metadata["rays"]["reflection"]["falloff"].asFloat(); + pushConstant.marchingSteps = metadata["rays"]["marching steps"].as(); + pushConstant.rayBounces = metadata["rays"]["ray bounces"].as(); + pushConstant.shadowFactor = metadata["rays"]["shadow factor"].as(); + pushConstant.reflectionStrength = metadata["rays"]["reflection"]["strength"].as(); + pushConstant.reflectionFalloff = metadata["rays"]["reflection"]["falloff"].as(); auto& scene = uf::scene::getCurrentScene(); auto& controller = scene.getController(); @@ -138,18 +138,18 @@ void ext::RayTracingSceneBehavior::tick( uf::Object& self ) { } { - uniforms->ambient.x = metadata["light"]["ambient"][0].asFloat(); - uniforms->ambient.y = metadata["light"]["ambient"][1].asFloat(); - uniforms->ambient.z = metadata["light"]["ambient"][2].asFloat(); - uniforms->ambient.w = metadata["light"]["kexp"].asFloat(); + uniforms->ambient.x = metadata["light"]["ambient"][0].as(); + uniforms->ambient.y = metadata["light"]["ambient"][1].as(); + uniforms->ambient.z = metadata["light"]["ambient"][2].as(); + uniforms->ambient.w = metadata["light"]["kexp"].as(); } { - uniforms->fog.color.x = metadata["light"]["fog"]["color"][0].asFloat(); - uniforms->fog.color.y = metadata["light"]["fog"]["color"][1].asFloat(); - uniforms->fog.color.z = metadata["light"]["fog"]["color"][2].asFloat(); + uniforms->fog.color.x = metadata["light"]["fog"]["color"][0].as(); + uniforms->fog.color.y = metadata["light"]["fog"]["color"][1].as(); + uniforms->fog.color.z = metadata["light"]["fog"]["color"][2].as(); - uniforms->fog.range.x = metadata["light"]["fog"]["range"][0].asFloat(); - uniforms->fog.range.y = metadata["light"]["fog"]["range"][1].asFloat(); + uniforms->fog.range.x = metadata["light"]["fog"]["range"][0].as(); + uniforms->fog.range.y = metadata["light"]["fog"]["range"][1].as(); } std::vector entities; @@ -171,7 +171,7 @@ void ext::RayTracingSceneBehavior::tick( uf::Object& self ) { { uf::Serializer& metadata = controller.getComponent(); - // if ( metadata["light"]["should"].asBool() ) + // if ( metadata["light"]["should"].as() ) entities.push_back(&controller); } UniformDescriptor::Light* lights = (UniformDescriptor::Light*) &uniforms_buffer[sizeof(UniformDescriptor) - sizeof(UniformDescriptor::Light)]; @@ -189,13 +189,13 @@ void ext::RayTracingSceneBehavior::tick( uf::Object& self ) { if ( entity == &controller ) light.position.y += 2; - light.position.w = metadata["light"]["radius"][1].asFloat(); + light.position.w = metadata["light"]["radius"][1].as(); - light.color.x = metadata["light"]["color"][0].asFloat(); - light.color.y = metadata["light"]["color"][1].asFloat(); - light.color.z = metadata["light"]["color"][2].asFloat(); + light.color.x = metadata["light"]["color"][0].as(); + light.color.y = metadata["light"]["color"][1].as(); + light.color.z = metadata["light"]["color"][2].as(); - light.color.w = metadata["light"]["power"].asFloat(); + light.color.w = metadata["light"]["power"].as(); } shader.updateBuffer( (void*) uniforms_buffer, uniforms_len, 0, false ); diff --git a/ext/scenes/start/behavior.cpp b/ext/scenes/start/behavior.cpp deleted file mode 100644 index d96b12bd..00000000 --- a/ext/scenes/start/behavior.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include "behavior.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../../ext.h" -#include "../../gui/gui.h" - -#include -#include - -namespace { - uf::Object* circleIn; - uf::Object* circleOut; -} - -EXT_BEHAVIOR_REGISTER_CPP(StartMenuBehavior) -EXT_BEHAVIOR_REGISTER_AS_OBJECT(StartMenuBehavior, StartMenu) -#define this ((uf::Scene*) &self) -void ext::StartMenuBehavior::initialize( uf::Object& self ) { - uf::Serializer& metadata = this->getComponent(); - uf::Asset& assetLoader = this->getComponent(); - - /* Magic Circle Outter */ { - // circleOut = (uf::Object*) this->findByUid( this->loadChildUid("./gui/mainmenu/circle-out.json", true) ); - circleOut = this->loadChildPointer("./gui/mainmenu/circle-out.json", true); - } - /* Magic Circle Inner */ { - // circleIn = (uf::Object*) this->findByUid( this->loadChildUid("./gui/mainmenu/circle-in.json", true) ); - circleIn = this->loadChildPointer("./gui/mainmenu/circle-in.json", true); - } - // update camera - { - auto& controller = this->getController(); - controller.getComponent().update(true); - pod::Transform<>& transform = controller.getComponent>(); - - uf::Serializer json; - json.readFromFile("./data/entities/player.json"); - controller.getComponent()["overlay"] = json["metadata"]["overlay"]; - } -} -void ext::StartMenuBehavior::tick( uf::Object& self ) { - uf::Serializer& metadata = this->getComponent(); - uf::Asset& assetLoader = this->getComponent(); - - if ( circleIn ) { - pod::Transform<>& transform = circleIn->getComponent>(); - static float time = 0.0f; - float speed = 0.0125f; - uf::Serializer& metadata = circleIn->getComponent(); - if ( metadata["hovered"].asBool() ) speed = 0.25f; - time += uf::physics::time::delta * -speed; - transform.orientation = uf::quaternion::axisAngle( { 0.0f, 0.0f, 1.0f }, time ); - - static pod::Vector3f start = { transform.position.x, -2.0f, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - // metadata["color"][3] = alpha; - } - if ( circleOut ) { - pod::Transform<>& transform = circleOut->getComponent>(); - uf::Serializer& metadata = circleOut->getComponent(); - static float time = 0.0f; - float speed = 0.0125f; - if ( metadata["hovered"].asBool() ) speed = 0.25f; - time += uf::physics::time::delta * speed; - transform.orientation = uf::quaternion::axisAngle( { 0.0f, 0.0f, 1.0f }, time ); - - static pod::Vector3f start = { transform.position.x, 2.0f, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - // metadata["color"][3] = alpha; - } - - { - auto& controller = this->getController(); - auto& camera = controller.getComponent(); - camera.updateView(); - } -} -void ext::StartMenuBehavior::render( uf::Object& self ) { -} -void ext::StartMenuBehavior::destroy( uf::Object& self ) { -} -#undef this \ No newline at end of file diff --git a/ext/scenes/start/behavior.h b/ext/scenes/start/behavior.h deleted file mode 100644 index 9e2a2092..00000000 --- a/ext/scenes/start/behavior.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace ext { - class EXT_API StartMenuBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; -} \ No newline at end of file diff --git a/ext/scenes/worldscape/behavior.cpp b/ext/scenes/worldscape/behavior.cpp index 299a3365..7093321e 100644 --- a/ext/scenes/worldscape/behavior.cpp +++ b/ext/scenes/worldscape/behavior.cpp @@ -15,18 +15,10 @@ #include "../../ext.h" -#include "./gui/battle.h" -#include "./gui/dialogue.h" -#include "./gui/pause.h" - -#include ".//battle.h" -#include ".//dialogue.h" - #include #include -EXT_BEHAVIOR_REGISTER_CPP(WorldScapeSceneBehavior) -EXT_BEHAVIOR_REGISTER_AS_OBJECT(WorldScapeSceneBehavior, WorldScapeScene) +UF_BEHAVIOR_REGISTER_CPP(ext::WorldScapeSceneBehavior) #define this ((uf::Scene*) &self) void ext::WorldScapeSceneBehavior::initialize( uf::Object& self ) { uf::Serializer& metadata = this->getComponent(); @@ -48,7 +40,7 @@ void ext::WorldScapeSceneBehavior::initialize( uf::Object& self ) { static uf::Timer timer(false); if ( !timer.running() ) timer.start(); - +/* this->addHook( "world:Battle.Prepare", [&](const std::string& event)->std::string{ uf::Serializer json = event; @@ -121,6 +113,7 @@ void ext::WorldScapeSceneBehavior::initialize( uf::Object& self ) { return "true"; }); +*/ } void ext::WorldScapeSceneBehavior::tick( uf::Object& self ) { } diff --git a/ext/scenes/worldscape/gui/battle.cpp b/ext/scenes/worldscape/gui/battle.cpp index 641e09b5..dd01d325 100644 --- a/ext/scenes/worldscape/gui/battle.cpp +++ b/ext/scenes/worldscape/gui/battle.cpp @@ -66,13 +66,13 @@ namespace { uf::Serializer& masterdata = scene.getComponent(); uf::Serializer cardData = masterDataGet("Card", id); - uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); - std::string name = charaData["filename"].asString(); + uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].as()); + std::string name = charaData["filename"].as(); if ( name == "none" ) return; std::string url = "https://cdn..xyz//unity/Android/voice/voice_" + name + "_"+key+".ogg"; - if ( charaData["internal"].asBool() ) { + if ( charaData["internal"].as() ) { url = "/smtsamo/voice/voice_" + name + "_" + key + ".ogg"; } @@ -87,7 +87,7 @@ namespace { uf::Entity* = scene.findByUid(uid); if ( ! ) return; uf::Serializer& metadata = ->getComponent(); - std::string id = metadata[""]["id"].asString(); + std::string id = metadata[""]["id"].as(); playSound( entity, id, key ); } void playSound( ext::GuiBattle& entity, const std::string& key ) { @@ -111,7 +111,7 @@ namespace { uint64_t i = 0; std::string key = ""; for ( auto it = object.begin(); it != object.end(); ++it ) { - if ( i++ == index ) key = it.key().asString(); + if ( i++ == index ) key = it.key().as(); } return key; } @@ -158,7 +158,7 @@ void ext::GuiBattle::initialize() { this->addHook( "asset:Cache.SFX." + std::to_string(this->getUid()), [&](const std::string& event)->std::string{ uf::Serializer json = event; - std::string filename = json["filename"].asString(); + std::string filename = json["filename"].as(); if ( uf::io::extension(filename) != "ogg" ) return "false"; @@ -171,7 +171,7 @@ void ext::GuiBattle::initialize() { sfx = uf::Audio(); sfx.load(filename); */ - sfx.setVolume(masterdata["volumes"]["sfx"].asFloat()); + sfx.setVolume(masterdata["volumes"]["sfx"].as()); sfx.play(); return "true"; @@ -180,7 +180,7 @@ void ext::GuiBattle::initialize() { this->addHook( "asset:Cache.Voice." + std::to_string(this->getUid()), [&](const std::string& event)->std::string{ uf::Serializer json = event; - std::string filename = json["filename"].asString(); + std::string filename = json["filename"].as(); if ( uf::io::extension(filename) != "ogg" ) return "false"; @@ -190,7 +190,7 @@ void ext::GuiBattle::initialize() { if ( voice.playing() ) voice.stop(); voice = uf::Audio(); voice.load(filename); - voice.setVolume(masterdata["volumes"]["voice"].asFloat()); + voice.setVolume(masterdata["volumes"]["voice"].as()); voice.play(); return "true"; @@ -245,7 +245,7 @@ void ext::GuiBattle::initialize() { // turn start, play sfx - if ( json["battle"]["turn"]["start of turn"].asBool() ) { + if ( json["battle"]["turn"]["start of turn"].as() ) { playSound(*this, "turn"); } @@ -254,8 +254,8 @@ void ext::GuiBattle::initialize() { this->addHook("world:Battle.Damage.%UID%", [&](const std::string& event) -> std::string { uf::Serializer json = event; - std::string uid = json["target"]["uid"].asString(); - std::string damage = json["target"]["damage"].asString(); + std::string uid = json["target"]["uid"].as(); + std::string damage = json["target"]["damage"].as(); pod::Transform<> pTransform; pTransform.position = { 0, 0, 0 }; @@ -268,7 +268,7 @@ void ext::GuiBattle::initialize() { if ( pointer->getUid() == 0 ) continue; if ( pointer->getName() == "Menu: Party Member Icon" ) { uf::Serializer& pMetadata = pointer->getComponent(); - if ( pMetadata[""]["uid"].asString() != uid ) continue; + if ( pMetadata[""]["uid"].as() != uid ) continue; pTransform = pointer->getComponent>(); pTransform.position.y -= (0.1); } @@ -278,7 +278,7 @@ void ext::GuiBattle::initialize() { this->addChild(*particle); uf::Serializer& pMetadata = particle->getComponent(); particle->as().load("./damageText.json", true); - std::string color = json["color"].isString() ? json["color"].asString() : "FF0000"; + std::string color = json["color"].is() ? json["color"].as() : "FF0000"; pMetadata["text settings"]["string"] = "%#"+color+"%" + damage; pod::Transform<>& transform = particle->getComponent>(); transform = pTransform; @@ -290,7 +290,7 @@ void ext::GuiBattle::initialize() { }); this->addHook("world:Battle.Message.%UID%", [&](const std::string& event) -> std::string { uf::Serializer json = event; - std::string message = json["message"].asString(); + std::string message = json["message"].as(); if ( battleMessage ) { battleMessage->destroy(); @@ -348,9 +348,9 @@ void ext::GuiBattle::initialize() { this->addChild(*critCutIn); uf::Serializer& pMetadata = critCutIn->getComponent(); - uf::Serializer cardData = masterDataGet("Card", json["id"].asString()); - pMetadata["system"]["assets"][0] = "/smtsamo/ci/ci_"+ cardData["filename"].asString() +".png"; - if ( !uf::io::exists( pMetadata["system"]["assets"][0].asString() ) ) pMetadata["system"]["assets"][0] = Json::nullValue; + uf::Serializer cardData = masterDataGet("Card", json["id"].as()); + pMetadata["system"]["assets"][0] = "/smtsamo/ci/ci_"+ cardData["filename"].as() +".png"; + if ( !uf::io::exists( pMetadata["system"]["assets"][0].as() ) ) pMetadata["system"]["assets"][0] = Json::nullValue; critCutIn->as().load("./critCutIn.json", true); critCutIn->initialize(); } @@ -364,7 +364,7 @@ void ext::GuiBattle::initialize() { uf::Serializer json = event; { - float turns = json["battle"]["turn"]["counter"].asFloat(); + float turns = json["battle"]["turn"]["counter"].as(); if ( turnCounters && turnCounters->getUid() != 0 ) { this->removeChild(*turnCounters); turnCounters->destroy(); @@ -422,15 +422,15 @@ void ext::GuiBattle::initialize() { int i = 0; for ( auto& member : json["battle"]["transients"] ) { - if ( member["uid"].isNull() ) continue; + if ( ext::json::isNull( member["uid"] ) ) continue; if ( member["type"] == "enemy" ) continue; - if ( member["hp"].asFloat() <= 0 ) continue; + if ( member["hp"].as() <= 0 ) continue; if ( i >= 4 ) break; - uf::Serializer cardData = masterDataGet("Card", member["id"].asString()); - std::string name = cardData["filename"].asString(); - if ( member["skin"].isString() ) name += "_" + member["skin"].asString(); + uf::Serializer cardData = masterDataGet("Card", member["id"].as()); + std::string name = cardData["filename"].as(); + if ( member["skin"].is() ) name += "_" + member["skin"].as(); std::string filename = "https://cdn..xyz//unity/Android/icon/icon_" + name + ".png"; - if ( cardData["internal"].asBool() ) { + if ( cardData["internal"].as() ) { filename = "/smtsamo/icon/icon_" + name + ".png"; } @@ -466,7 +466,7 @@ void ext::GuiBattle::initialize() { partyMemberButton->addChild(*partyMemberText); uf::Serializer& pMetadata = partyMemberText->getComponent(); partyMemberText->as().load("./partyMemberText.json", true); - pMetadata["text settings"]["string"] = "" + colorString("00FF00") + "" + member["hp"].asString() + "\n" + colorString("0000FF") + "" + member["mp"].asString(); + pMetadata["text settings"]["string"] = "" + colorString("00FF00") + "" + member["hp"].as() + "\n" + colorString("0000FF") + "" + member["mp"].as(); pMetadata[""] = member; pod::Transform<>& transform = partyMemberText->getComponent>(); transform.position = bTransform.position; @@ -478,7 +478,7 @@ void ext::GuiBattle::initialize() { if ( partyMemberHP ) { uf::Serializer& pMetadata = partyMemberHP->getComponent(); float percentage = 1.0f; - percentage = member["hp"].asFloat() / member["max hp"].asFloat(); + percentage = member["hp"].as() / member["max hp"].as(); // uv[0, 0] -> uv[09.43, 23.81] // uv[1, 1] -> uv[84.91, 68.25] pMetadata["uv"][2] = (percentage * 0.8491) + 0.0660; @@ -488,7 +488,7 @@ void ext::GuiBattle::initialize() { if ( partyMemberMP ) { uf::Serializer& pMetadata = partyMemberMP->getComponent(); float percentage = 1.0f; - percentage = member["mp"].asFloat() / member["max mp"].asFloat(); + percentage = member["mp"].as() / member["max mp"].as(); // uv[0, 0] -> uv[09.43, 23.81] // uv[1, 1] -> uv[84.91, 68.25] pMetadata["uv"][2] = (percentage * 0.8491) + 0.0943; @@ -545,7 +545,7 @@ void ext::GuiBattle::initialize() { partyMemberButton->addChild(*partyMemberText); uf::Serializer& pMetadata = partyMemberText->getComponent(); partyMemberText->as().load("./partyMemberText.json", true); - pMetadata["text settings"]["string"] = "" + colorString("FF0000") + "" + member["hp"].asString() + "\n" + colorString("0000FF") + "" + member["mp"].asString(); + pMetadata["text settings"]["string"] = "" + colorString("FF0000") + "" + member["hp"].as() + "\n" + colorString("0000FF") + "" + member["mp"].as(); pMetadata[""] = member; pod::Transform<>& transform = partyMemberText->getComponent>(); transform.position = bTransform.position; @@ -574,7 +574,7 @@ void ext::GuiBattle::initialize() { uf::Serializer& pMetadata = partyMemberHP->getComponent(); float percentage = 1.0f; - percentage = member["hp"].asFloat() / member["max hp"].asFloat(); + percentage = member["hp"].as() / member["max hp"].as(); // uv[0, 0] -> uv[09.43, 23.81] // uv[1, 1] -> uv[84.91, 68.25] pMetadata["uv"][2] = (percentage * 0.8491) + 0.0660; @@ -592,7 +592,7 @@ void ext::GuiBattle::initialize() { uf::Serializer& pMetadata = partyMemberMP->getComponent(); float percentage = 1.0f; - percentage = member["mp"].asFloat() / member["max mp"].asFloat(); + percentage = member["mp"].as() / member["max mp"].as(); // uv[0, 0] -> uv[09.43, 23.81] // uv[1, 1] -> uv[84.91, 68.25] pMetadata["uv"][2] = (percentage * 0.8491) + 0.0943; @@ -637,12 +637,12 @@ void ext::GuiBattle::tick() { static std::string queuedAction; std::function postParseResult = [&]( uf::Serializer& result ) { - if ( result["end"].asBool() ) bMetadata["system"]["closing"] = true; - if ( !result["timeout"].isNull() ) timeout = result["timeout"].asFloat(); + if ( result["end"].as() ) bMetadata["system"]["closing"] = true; + if ( !ext::json::isNull( result["timeout"] ) ) timeout = result["timeout"].as(); else timeout = 1; // modify timeout based on string length - if ( result["message"].isString() && !result["target"].isNull() ) { - uint64_t size = result["message"].asString().size(); + if ( result["message"].is() && !ext::json::isNull( result["target"] ) ) { + uint64_t size = result["message"].as().size(); float modified = size * 0.025f; if ( timeout < modified ) timeout = modified; } @@ -661,7 +661,7 @@ void ext::GuiBattle::tick() { delete battleOptions; battleOptions = NULL; } - if ( member["uid"].isNull() ) { + if ( ext::json::isNull( member["uid"] ) ) { stats.previousMember = stats.currentMember; return; } @@ -672,25 +672,25 @@ void ext::GuiBattle::tick() { stats.actions.invalids.clear(); stats.currentMember["skills"] = Json::arrayValue; for ( int i = 0; i < member["skills"].size(); ++i ) { - std::string id = member["skills"][i].asString(); + std::string id = member["skills"][i].as(); uf::Serializer skillData = masterDataGet("Skill", id); bool add = false; - if ( skillData["type"].asInt() > 0 && skillData["type"].asInt() < 16 ) add = true; + if ( skillData["type"].as() > 0 && skillData["type"].as() < 16 ) add = true; if ( add ) stats.currentMember["skills"].append(id); } std::string skillDescription = ""; for ( int i = start; i < stats.currentMember["skills"].size(); ++i ) { - std::string id = stats.currentMember["skills"][i].asString(); + std::string id = stats.currentMember["skills"][i].as(); std::string text = ""; if ( std::find( stats.skill.invalids.begin(), stats.skill.invalids.end(), id ) != stats.skill.invalids.end() ) continue; if ( ++counter > stats.skill.selectionsMax ) break; - uf::Serializer cardData = masterDataGet("Card", member["id"].asString()); - uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); + uf::Serializer cardData = masterDataGet("Card", member["id"].as()); + uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].as()); uf::Serializer skillData = masterDataGet("Skill", id); if ( id != "0" ) { - text = skillData["name"].asString(); + text = skillData["name"].as(); } else { text = "攻撃"; } @@ -699,34 +699,34 @@ void ext::GuiBattle::tick() { } else { text = "" + colorString("FF0000") + "" + text; - skillDescription = skillData["effect"].asString(); - if ( skillData["mp"].isNumeric() ) { - int64_t cost = skillData["mp"].asInt64(); - skillDescription = skillData["effect"].asString() + "\nCost: " + colorString("0000FF") + ""+std::to_string(cost)+" MP" + colorString("FFFFFF") + ""; + skillDescription = skillData["effect"].as(); + if ( skillData["mp"].is() ) { + int64_t cost = skillData["mp"].as(); + skillDescription = skillData["effect"].as() + "\nCost: " + colorString("0000FF") + ""+std::to_string(cost)+" MP" + colorString("FFFFFF") + ""; } - if ( skillData["hp%"].isNumeric() ) { - int64_t cost = skillData["hp%"].asInt64(); - cost = member["max hp"].asFloat() * ( cost / 100.0f ); - skillDescription = skillData["effect"].asString() + "\nCost: " + colorString("00FF00") + ""+std::to_string(cost)+" HP" + colorString("FFFFFF") + ""; + if ( skillData["hp%"].is() ) { + int64_t cost = skillData["hp%"].as(); + cost = member["max hp"].as() * ( cost / 100.0f ); + skillDescription = skillData["effect"].as() + "\nCost: " + colorString("00FF00") + ""+std::to_string(cost)+" HP" + colorString("FFFFFF") + ""; } } string += "\n" + text; } if ( stats.currentMember["skills"].size() > stats.skill.selectionsMax ) { for ( int i = 0; i < stats.currentMember["skills"].size(); ++i ) { - std::string id = stats.currentMember["skills"][i].asString(); + std::string id = stats.currentMember["skills"][i].as(); std::string text = ""; if ( std::find( stats.skill.invalids.begin(), stats.skill.invalids.end(), id ) != stats.skill.invalids.end() ) continue; if ( ++counter > stats.skill.selectionsMax ) break; if ( id != "0" ) { - uf::Serializer cardData = masterDataGet("Card", member["id"].asString()); - uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); + uf::Serializer cardData = masterDataGet("Card", member["id"].as()); + uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].as()); uf::Serializer skillData = masterDataGet("Skill", id); - text = skillData["name"].asString(); + text = skillData["name"].as(); } else { - uf::Serializer cardData = masterDataGet("Card", member["id"].asString()); - uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); + uf::Serializer cardData = masterDataGet("Card", member["id"].as()); + uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].as()); text = "攻撃"; } @@ -758,7 +758,7 @@ void ext::GuiBattle::tick() { delete commandOptions; commandOptions = NULL; } - if ( actions.isNull() ) { + if ( ext::json::isNull( actions ) ) { stats.actions.selection = 0; queuedAction = ""; return; @@ -770,7 +770,7 @@ void ext::GuiBattle::tick() { auto keys = actions.getMemberNames(); for ( int i = start; i < keys.size(); ++i ) { std::string key = getKeyFromIndex( actions, i ); - std::string text = actions[key].asString(); + std::string text = actions[key].as(); if ( std::find( stats.actions.invalids.begin(), stats.actions.invalids.end(), key ) != stats.actions.invalids.end() ) continue; if ( ++counter > stats.actions.selectionsMax ) break; if ( i != stats.actions.selection ) text = "" + colorString("FFFFFF") + "" + text; @@ -780,7 +780,7 @@ void ext::GuiBattle::tick() { if ( keys.size() > stats.actions.selectionsMax ) { for ( int i = 0; i < keys.size(); ++i ) { std::string key = getKeyFromIndex( actions, i ); - std::string text = actions[key].asString(); + std::string text = actions[key].as(); if ( std::find( stats.actions.invalids.begin(), stats.actions.invalids.end(), key ) != stats.actions.invalids.end() ) continue; if ( ++counter > stats.actions.selectionsMax ) break; if ( i != stats.actions.selection ) text = "" + colorString("FFFFFF") + "" + text; @@ -806,7 +806,7 @@ void ext::GuiBattle::tick() { delete targetOptions; targetOptions = NULL; } - if ( actions.isNull() ) { + if ( ext::json::isNull( actions ) ) { stats.skill.selection = 0; stats.targets.selection = 0; return; @@ -819,9 +819,9 @@ void ext::GuiBattle::tick() { stats.actions.invalids.clear(); std::string targetDescription = ""; for ( int i = start; i < actions.size(); ++i ) { - uf::Serializer cardData = masterDataGet("Card", actions[i]["id"].asString()); - uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); - std::string text = charaData["name"].asString(); + uf::Serializer cardData = masterDataGet("Card", actions[i]["id"].as()); + uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].as()); + std::string text = charaData["name"].as(); if ( std::find( stats.targets.invalids.begin(), stats.targets.invalids.end(), text ) != stats.targets.invalids.end() ) continue; if ( ++counter > stats.targets.selectionsMax ) break; if ( i != stats.targets.selection ) text = "" + colorString("FFFFFF") + "" + text; @@ -830,9 +830,9 @@ void ext::GuiBattle::tick() { } if ( actions.size() > stats.targets.selectionsMax ) { for ( int i = 0; i < actions.size(); ++i ) { - uf::Serializer cardData = masterDataGet("Card", actions[i]["id"].asString()); - uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); - std::string text = charaData["name"].asString(); + uf::Serializer cardData = masterDataGet("Card", actions[i]["id"].as()); + uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].as()); + std::string text = charaData["name"].as(); if ( std::find( stats.targets.invalids.begin(), stats.targets.invalids.end(), text ) != stats.targets.invalids.end() ) continue; if ( ++counter > stats.targets.selectionsMax ) break; if ( i != stats.targets.selection ) text = "" + colorString("FFFFFF") + "" + text; @@ -852,12 +852,12 @@ void ext::GuiBattle::tick() { } if ( queuedAction == "analyze" ) { uf::Serializer payload; - payload["uid"] = stats.targets.current[stats.targets.selection]["uid"].asString(); - // if ( payload["uid"].asString() == "") + payload["uid"] = stats.targets.current[stats.targets.selection]["uid"].as(); + // if ( payload["uid"].as() == "") payload["action"] = "analyze"; uf::Serializer result = battleManager->callHook("world:Battle.Action.%UID%", payload)[0]; - targetDescription = result["message"].asString(); + targetDescription = result["message"].as(); } if ( targetDescription != "" ) { uf::Serializer payload; @@ -874,7 +874,7 @@ void ext::GuiBattle::tick() { uf::Serializer json = event; uf::Serializer payload; payload["action"] = "turn-start"; - if ( !stats.previousMember["uid"].isNull() ) payload["uid"] = stats.previousMember["uid"].asUInt64() + 1; + if ( !ext::json::isNull( stats.previousMember["uid"] ) ) payload["uid"] = stats.previousMember["uid"].as() + 1; auto hookCall = battleManager->callHook("world:Battle.Action.%UID%", payload); if ( hookCall.empty() ) { metadata["system"]["closing"] = true; @@ -882,14 +882,14 @@ void ext::GuiBattle::tick() { } uf::Serializer result = hookCall[0]; - if ( result["end"].asBool() ) { - if ( metadata.isObject() ) metadata["system"]["closing"] = true; + if ( result["end"].as() ) { + if ( ext::json::isObject( metadata ) ) metadata["system"]["closing"] = true; return "false"; } postParseResult(result); - if ( result["uid"].isNull() ) return "false"; - uint64_t uid = result["uid"].asUInt64(); + if ( ext::json::isNull( result["uid"] ) ) return "false"; + uint64_t uid = result["uid"].as(); renderCommandOptions(std::string("")); renderSkillOptions(std::string("")); @@ -899,7 +899,7 @@ void ext::GuiBattle::tick() { payload["uid"] = uid; if ( result[""]["type"] == "enemy" ) { payload["action"] = "enemy-attack"; - } else if ( result["skipped"].asBool() ) { + } else if ( result["skipped"].as() ) { payload["action"] = "forced-pass"; } else { stats.currentMember = result[""]; @@ -919,12 +919,12 @@ void ext::GuiBattle::tick() { { uf::Serializer& metadata = this->getComponent(); - if ( metadata["system"]["closing"].asBool() ) { + if ( metadata["system"]["closing"].as() ) { if ( alpha >= 1.0f ) { uf::Asset assetLoader; std::string canonical = assetLoader.load("./data/audio/ui/menu close.ogg"); uf::Audio& sfx = assetLoader.get(canonical); - sfx.setVolume(masterdata["volumes"]["sfx"].asFloat()); + sfx.setVolume(masterdata["volumes"]["sfx"].as()); sfx.play(); } if ( alpha <= 0.0f ) { @@ -933,13 +933,13 @@ void ext::GuiBattle::tick() { metadata["system"]["closed"] = true; } else alpha -= uf::physics::time::delta; metadata["color"][3] = alpha; - } else if ( metadata["system"]["closed"].asBool() ) { + } else if ( metadata["system"]["closed"].as() ) { uf::Object& parent = this->getParent(); parent.getComponent()["system"]["closed"] = true; this->destroy(); parent.removeChild(*this); } else { - if ( !metadata["initialized"].asBool() ) alpha = 0.0f; + if ( !metadata["initialized"].as() ) alpha = 0.0f; metadata["initialized"] = true; if ( alpha >= 1.0f ) alpha = 1.0f; else alpha += uf::physics::time::delta * 1.5f; @@ -952,14 +952,14 @@ void ext::GuiBattle::tick() { static float time = 0.0f; float speed = 0.0125f; uf::Serializer& metadata = circleIn->getComponent(); - if ( metadata["hovered"].asBool() ) speed = -0.25f; + if ( metadata["hovered"].as() ) speed = -0.25f; time += uf::physics::time::delta * speed; transform.orientation = uf::quaternion::axisAngle( { 0.0f, 0.0f, 1.0f }, time ); static pod::Vector3f start = { transform.position.x, -2.0f, 0.0f }; static pod::Vector3f end = transform.position; static float delta = 0.0f; - if ( !metadata["initialized"].asBool() ) delta = 0.0f; + if ( !metadata["initialized"].as() ) delta = 0.0f; metadata["initialized"] = true; if ( delta >= 1 ) delta = 1; else { @@ -973,14 +973,14 @@ void ext::GuiBattle::tick() { uf::Serializer& metadata = circleOut->getComponent(); static float time = 0.0f; float speed = 0.0125f; - if ( metadata["hovered"].asBool() ) speed = 0.25f; + if ( metadata["hovered"].as() ) speed = 0.25f; time += uf::physics::time::delta * speed; transform.orientation = uf::quaternion::axisAngle( { 0.0f, 0.0f, 1.0f }, time ); static pod::Vector3f start = { transform.position.x, 2.0f, 0.0f }; static pod::Vector3f end = transform.position; static float delta = 0.0f; - if ( !metadata["initialized"].asBool() ) delta = 0.0f; + if ( !metadata["initialized"].as() ) delta = 0.0f; metadata["initialized"] = true; if ( delta >= 1 ) delta = 1; else { @@ -995,7 +995,7 @@ void ext::GuiBattle::tick() { for ( uf::Entity* pointer : turnCounters->getChildren() ) { uf::Serializer& pMetadata = pointer->getComponent(); float coeff = 2.0f; - // if ( pMetadata["half counter"].asBool() ) coeff = 4.0f; + // if ( pMetadata["half counter"].as() ) coeff = 4.0f; // pMetadata["color"][3] = sin(time * coeff) * 0.25f + 0.75f; pMetadata["color"][3] = std::min( 1.0f, (float) sin(time * coeff) * 0.5f + 1.0f ); } @@ -1007,7 +1007,7 @@ void ext::GuiBattle::tick() { static pod::Vector3f start = { transform.position.x, 2.0f, 0.0f }; static pod::Vector3f end = transform.position; static float delta = 0.0f; - if ( !metadata["initialized"].asBool() ) delta = 0.0f; + if ( !metadata["initialized"].as() ) delta = 0.0f; metadata["initialized"] = true; if ( delta >= 1 ) delta = 1; else { @@ -1030,7 +1030,7 @@ void ext::GuiBattle::tick() { pod::Transform<>& transform = pointer->getComponent>(); uf::Serializer& metadata = pointer->getComponent(); metadata["color"][3] = alpha; - if ( metadata["clicked"].asBool() && timer.elapsed().asDouble() >= timeout ) { + if ( metadata["clicked"].as() && timer.elapsed().asDouble() >= timeout ) { } static float color = 0.0f; // std::cout << pointer << ": " << metadata << ": " << stats.currentMember << std::endl; @@ -1065,7 +1065,7 @@ void ext::GuiBattle::tick() { pod::Transform<>& transform = pointer->getComponent>(); uf::Serializer& metadata = pointer->getComponent(); metadata["color"][3] = alpha; - if ( metadata["clicked"].asBool() && timer.elapsed().asDouble() >= timeout ) { + if ( metadata["clicked"].as() && timer.elapsed().asDouble() >= timeout ) { } static float color = 0.0f; // std::cout << pointer << ": " << metadata << ": " << stats.currentMember << std::endl; @@ -1093,7 +1093,7 @@ void ext::GuiBattle::tick() { // std::cout << particle << ": " << metadata["system"]["percent"] << ": " << metadata["text settings"]["string"] << std::endl; // std::cout << transform.position.x << ", " << transform.position.y << ", " << transform.position.z << std::endl; try { - if ( !metadata["system"].isObject() ) { + if ( !ext::json::isObject( metadata["system"] ) ) { this->removeChild(*particle); particle->destroy(); delete particle; @@ -1112,7 +1112,7 @@ void ext::GuiBattle::tick() { *it = NULL; continue; } - metadata["system"]["percent"] = metadata["system"]["percent"].asFloat() + uf::physics::time::delta; + metadata["system"]["percent"] = metadata["system"]["percent"].as() + uf::physics::time::delta; } catch ( ... ) { if ( particle ) { this->removeChild(*particle); @@ -1136,23 +1136,23 @@ void ext::GuiBattle::tick() { uf::Serializer& metadata = partyMemberCommandCircle->getComponent(); static float time = 0.0f; float speed = 0.5f; - if ( metadata["hovered"].asBool() ) speed = 0.75f; + if ( metadata["hovered"].as() ) speed = 0.75f; time += uf::physics::time::delta * speed; transform.orientation = uf::quaternion::axisAngle( { 0.0f, 0.0f, 1.0f }, time ); metadata["color"][3] = alpha; { pod::Vector3f start = { - metadata["system"]["lerp"]["start"][0].asFloat(), - metadata["system"]["lerp"]["start"][1].asFloat(), - metadata["system"]["lerp"]["start"][2].asFloat(), + metadata["system"]["lerp"]["start"][0].as(), + metadata["system"]["lerp"]["start"][1].as(), + metadata["system"]["lerp"]["start"][2].as(), }; pod::Vector3f end = { - metadata["system"]["lerp"]["end"][0].asFloat(), - metadata["system"]["lerp"]["end"][1].asFloat(), - metadata["system"]["lerp"]["end"][2].asFloat(), + metadata["system"]["lerp"]["end"][0].as(), + metadata["system"]["lerp"]["end"][1].as(), + metadata["system"]["lerp"]["end"][2].as(), }; - float delta = metadata["system"]["lerp"]["delta"].asFloat(); + float delta = metadata["system"]["lerp"]["delta"].as(); if ( delta >= 1 ) delta = 1; else { delta += uf::physics::time::delta * 8.0f; @@ -1194,7 +1194,7 @@ void ext::GuiBattle::tick() { do { --stats.targets.selection; if ( stats.targets.selection < 0 ) { stats.targets.selection = stats.targets.current.size() - 1; } - } while ( std::find( stats.targets.invalids.begin(), stats.targets.invalids.end(), stats.targets.current[stats.targets.selection]["id"].asString() ) != stats.targets.invalids.end() ); + } while ( std::find( stats.targets.invalids.begin(), stats.targets.invalids.end(), stats.targets.current[stats.targets.selection]["id"].as() ) != stats.targets.invalids.end() ); } } else if ( keys.down ) { @@ -1204,7 +1204,7 @@ void ext::GuiBattle::tick() { do { ++stats.targets.selection; if ( stats.targets.selection >= stats.targets.current.size() ) { stats.targets.selection = 0; } - } while ( std::find( stats.targets.invalids.begin(), stats.targets.invalids.end(), stats.targets.current[stats.targets.selection]["id"].asString() ) != stats.targets.invalids.end() ); + } while ( std::find( stats.targets.invalids.begin(), stats.targets.invalids.end(), stats.targets.current[stats.targets.selection]["id"].as() ) != stats.targets.invalids.end() ); } } else released = true; @@ -1245,7 +1245,7 @@ void ext::GuiBattle::tick() { timer.reset(); stats.state = "waiting"; - if ( result["invalid"].asBool() ) { + if ( result["invalid"].as() ) { // stats.actions.invalids.push_back(action); renderCommandOptions(stats.actions.current); // this->queueHook("world:Battle.Turn.%UID%", "", timeout); @@ -1271,7 +1271,7 @@ void ext::GuiBattle::tick() { do { --stats.skill.selection; if ( stats.skill.selection < 0 ) { stats.skill.selection = stats.currentMember["skills"].size()- 1; } - } while ( std::find( stats.skill.invalids.begin(), stats.skill.invalids.end(), stats.currentMember["skills"][stats.skill.selection].asString() ) != stats.skill.invalids.end() ); + } while ( std::find( stats.skill.invalids.begin(), stats.skill.invalids.end(), stats.currentMember["skills"][stats.skill.selection].as() ) != stats.skill.invalids.end() ); } } else if ( keys.down ) { @@ -1281,7 +1281,7 @@ void ext::GuiBattle::tick() { do { ++stats.skill.selection; if ( stats.skill.selection >= stats.currentMember["skills"].size()) { stats.skill.selection = 0; } - } while ( std::find( stats.skill.invalids.begin(), stats.skill.invalids.end(), stats.currentMember["skills"][stats.skill.selection].asString() ) != stats.skill.invalids.end() ); + } while ( std::find( stats.skill.invalids.begin(), stats.skill.invalids.end(), stats.currentMember["skills"][stats.skill.selection].as() ) != stats.skill.invalids.end() ); } } else released = true; @@ -1310,10 +1310,10 @@ void ext::GuiBattle::tick() { payload["skill"] = stats.currentMember["skills"][stats.skill.selection]; uf::Serializer result = battleManager->callHook("world:Battle.Action.%UID%", payload)[0]; - std::string skillId = stats.currentMember["skills"][stats.skill.selection].asString(); + std::string skillId = stats.currentMember["skills"][stats.skill.selection].as(); uf::Serializer skillData = masterDataGet("Skill", skillId); - if ( result["range"].isNumeric() ) skillData["range"] = result["range"]; - if ( skillData["range"].asInt64() > 1 ) { + if ( result["range"].is() ) skillData["range"] = result["range"]; + if ( skillData["range"].as() > 1 ) { uf::Serializer payload; payload["action"] = "member-attack"; payload["uid"] = stats.currentMember["uid"]; @@ -1322,7 +1322,7 @@ void ext::GuiBattle::tick() { postParseResult(result); timer.reset(); stats.state = "waiting"; - if ( result["invalid"].asBool() ) { + if ( result["invalid"].as() ) { // stats.actions.invalids.push_back(action); renderCommandOptions(stats.actions.current); // this->queueHook("world:Battle.Turn.%UID%", "", timeout); @@ -1353,7 +1353,7 @@ void ext::GuiBattle::tick() { do { --stats.actions.selection; if ( stats.actions.selection < 0 ) { stats.actions.selection = stats.actions.current.size() - 1; } - } while ( std::find( stats.actions.invalids.begin(), stats.actions.invalids.end(), stats.actions.current[stats.actions.selection].asString() ) != stats.actions.invalids.end() ); + } while ( std::find( stats.actions.invalids.begin(), stats.actions.invalids.end(), stats.actions.current[stats.actions.selection].as() ) != stats.actions.invalids.end() ); } } else if ( keys.down ) { @@ -1363,7 +1363,7 @@ void ext::GuiBattle::tick() { do { ++stats.actions.selection; if ( stats.actions.selection >= stats.actions.current.size() ) { stats.actions.selection = 0; } - } while ( std::find( stats.actions.invalids.begin(), stats.actions.invalids.end(), stats.actions.current[stats.actions.selection].asString() ) != stats.actions.invalids.end() ); + } while ( std::find( stats.actions.invalids.begin(), stats.actions.invalids.end(), stats.actions.current[stats.actions.selection].as() ) != stats.actions.invalids.end() ); } } else released = true; @@ -1382,7 +1382,7 @@ void ext::GuiBattle::tick() { } else if ( keys.select && timer.elapsed().asDouble() >= timeout ) { playSound(*this, "menu close"); uf::Serializer payload; - std::string action = stats.actions.current[stats.actions.selection].asString(); + std::string action = stats.actions.current[stats.actions.selection].as(); payload["action"] = action; if ( payload["action"] == "member-attack" ) { payload["uid"] = stats.currentMember["uid"]; @@ -1396,7 +1396,7 @@ void ext::GuiBattle::tick() { renderCommandOptions(std::string("")); stats.state = "waiting"; - if ( result["invalid"].asBool() ) { + if ( result["invalid"].as() ) { stats.actions.invalids.push_back(action); renderCommandOptions(stats.actions.current); // this->queueHook("world:Battle.Turn.%UID%", "", timeout); @@ -1484,7 +1484,7 @@ void ext::GuiBattle::tick() { queuedAction = action; stats.state = "waiting"; - if ( result["invalid"].asBool() ) { + if ( result["invalid"].as() ) { stats.actions.invalids.push_back(action); renderCommandOptions(stats.actions.current); } else if ( payload["action"] == "member-attack" ) { diff --git a/ext/scenes/worldscape/gui/dialogue.cpp b/ext/scenes/worldscape/gui/dialogue.cpp index 9ed04d48..1e8e4360 100644 --- a/ext/scenes/worldscape/gui/dialogue.cpp +++ b/ext/scenes/worldscape/gui/dialogue.cpp @@ -50,10 +50,10 @@ namespace { uf::Serializer& masterdata = scene.getComponent(); uf::Serializer cardData = masterDataGet("Card", id); - uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); - std::string name = charaData["filename"].asString(); + uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].as()); + std::string name = charaData["filename"].as(); std::string url = "https://cdn..xyz//unity/Android/voice/voice_" + name + "_"+key+".ogg"; - if ( charaData["internal"].asBool() ) { + if ( charaData["internal"].as() ) { url = "/smtsamo/voice/voice_" + name + "_" + key + ".ogg"; } @@ -68,7 +68,7 @@ namespace { uf::Entity* = scene.findByUid(uid); if ( ! ) return; uf::Serializer& metadata = ->getComponent(); - std::string id = metadata[""]["id"].asString(); + std::string id = metadata[""]["id"].as(); playSound( entity, id, key ); } void playSound( ext::GuiDialogue& entity, const std::string& key ) { @@ -92,7 +92,7 @@ namespace { uint64_t i = 0; std::string key = ""; for ( auto it = object.begin(); it != object.end(); ++it ) { - if ( i++ == index ) key = it.key().asString(); + if ( i++ == index ) key = it.key().as(); } return key; } @@ -125,7 +125,7 @@ void ext::GuiDialogue::initialize() { this->addHook( "asset:Cache.SFX." + std::to_string(this->getUid()), [&](const std::string& event)->std::string{ uf::Serializer json = event; - std::string filename = json["filename"].asString(); + std::string filename = json["filename"].as(); if ( uf::io::extension(filename) != "ogg" ) return "false"; @@ -135,7 +135,7 @@ void ext::GuiDialogue::initialize() { if ( sfx.playing() ) sfx.stop(); sfx = uf::Audio(); sfx.load(filename); - sfx.setVolume(masterdata["volumes"]["sfx"].asFloat()); + sfx.setVolume(masterdata["volumes"]["sfx"].as()); sfx.play(); return "true"; @@ -144,7 +144,7 @@ void ext::GuiDialogue::initialize() { this->addHook( "asset:Cache.Voice." + std::to_string(this->getUid()), [&](const std::string& event)->std::string{ uf::Serializer json = event; - std::string filename = json["filename"].asString(); + std::string filename = json["filename"].as(); if ( uf::io::extension(filename) != "ogg" ) return "false"; @@ -154,7 +154,7 @@ void ext::GuiDialogue::initialize() { if ( voice.playing() ) voice.stop(); voice = uf::Audio(); voice.load(filename); - voice.setVolume(masterdata["volumes"]["voice"].asFloat()); + voice.setVolume(masterdata["volumes"]["voice"].as()); voice.play(); return "true"; @@ -191,10 +191,10 @@ void ext::GuiDialogue::tick() { if ( !timer.running() ) timer.start(); std::function postParseResult = [&]( uf::Serializer& result ) { - if ( result["end"].asBool() ) bMetadata["system"]["closing"] = true; - if ( !result["timeout"].isNull() ) timeout = result["timeout"].asFloat(); + if ( result["end"].as() ) bMetadata["system"]["closing"] = true; + if ( !ext::json::isNull( result["timeout"] ) ) timeout = result["timeout"].as(); else timeout = 1; - if ( result["message"].asString() != "" ) { + if ( result["message"].as() != "" ) { if ( dialogueMessage ) { dialogueMessage->destroy(); this->removeChild(*dialogueMessage); @@ -204,7 +204,7 @@ void ext::GuiDialogue::tick() { this->addChild(*dialogueMessage); uf::Serializer& pMetadata = dialogueMessage->getComponent(); dialogueMessage->as().load("./dialogue-text.json", true); - pMetadata["text settings"]["string"] = result["message"].asString(); + pMetadata["text settings"]["string"] = result["message"].as(); dialogueMessage->initialize(); } timer.reset(); @@ -217,7 +217,7 @@ void ext::GuiDialogue::tick() { delete dialogueOptions; dialogueOptions = NULL; } - if ( actions.isNull() ) { + if ( ext::json::isNull( actions ) ) { stats.actions.selection = 0; return; } @@ -228,7 +228,7 @@ void ext::GuiDialogue::tick() { auto keys = actions.getMemberNames(); for ( int i = start; i < keys.size(); ++i ) { std::string key = getKeyFromIndex( actions, i ); - std::string text = actions[key].asString(); + std::string text = actions[key].as(); if ( std::find( stats.actions.invalids.begin(), stats.actions.invalids.end(), key ) != stats.actions.invalids.end() ) continue; if ( ++counter > stats.actions.selectionsMax ) break; if ( i != stats.actions.selection ) text = "%#FFFFFF%" + text; @@ -238,7 +238,7 @@ void ext::GuiDialogue::tick() { if ( keys.size() > stats.actions.selectionsMax ) { for ( int i = 0; i < keys.size(); ++i ) { std::string key = getKeyFromIndex( actions, i ); - std::string text = actions[key].asString(); + std::string text = actions[key].as(); if ( std::find( stats.actions.invalids.begin(), stats.actions.invalids.end(), key ) != stats.actions.invalids.end() ) continue; if ( ++counter > stats.actions.selectionsMax ) break; if ( i != stats.actions.selection ) text = "%#FFFFFF%" + text; @@ -278,12 +278,12 @@ void ext::GuiDialogue::tick() { { uf::Serializer& metadata = this->getComponent(); - if ( metadata["system"]["closing"].asBool() ) { + if ( metadata["system"]["closing"].as() ) { if ( alpha >= 1.0f ) { uf::Asset assetLoader; std::string canonical = assetLoader.load("./data/audio/ui/menu close.ogg"); uf::Audio& sfx = assetLoader.get(canonical); - sfx.setVolume(masterdata["volumes"]["sfx"].asFloat()); + sfx.setVolume(masterdata["volumes"]["sfx"].as()); sfx.play(); } if ( alpha <= 0.0f ) { @@ -292,13 +292,13 @@ void ext::GuiDialogue::tick() { metadata["system"]["closed"] = true; } else alpha -= uf::physics::time::delta; metadata["color"][3] = alpha; - } else if ( metadata["system"]["closed"].asBool() ) { + } else if ( metadata["system"]["closed"].as() ) { uf::Object& parent = this->getParent(); parent.getComponent()["system"]["closed"] = true; this->destroy(); parent.removeChild(*this); } else { - if ( !metadata["initialized"].asBool() ) alpha = 0.0f; + if ( !metadata["initialized"].as() ) alpha = 0.0f; metadata["initialized"] = true; if ( alpha >= 1.0f ) alpha = 1.0f; else alpha += uf::physics::time::delta * 1.5f; diff --git a/ext/scenes/worldscape/gui/pause.cpp b/ext/scenes/worldscape/gui/pause.cpp deleted file mode 100644 index 37406c92..00000000 --- a/ext/scenes/worldscape/gui/pause.cpp +++ /dev/null @@ -1,578 +0,0 @@ -#include "pause.h" - -#include -#include -#include -#include -#include -#include -#include -// #include -#include -#include - -#include - -#include - -#include -#include -#include -#include - -namespace { - uf::Object* mainText; - uf::Object* commandText; - uf::Object* transientSprite; - uf::Object* transientSpriteShadow; - uf::Object* circleIn; - uf::Object* circleOut; - uf::Object* coverBar; - uf::Object* tenkouseiOption; - uf::Object* closeOption; - uf::Object* quitOption; -} - -namespace { - void playSound( ext::GuiWorldPauseMenu& entity, const std::string& key ) { - uf::Scene& scene = uf::scene::getCurrentScene(); - uf::Serializer& metadata = entity.getComponent(); - uf::Serializer& masterdata = scene.getComponent(); - - std::string url = "./data/audio/ui/" + key + ".ogg"; - - uf::Asset& assetLoader = scene.getComponent(); - assetLoader.cache(url, "asset:Cache." + std::to_string(entity.getUid())); - } - - uf::Serializer masterTableGet( const std::string& table ) { - uf::Scene& scene = uf::scene::getCurrentScene(); - uf::Serializer& mastertable = scene.getComponent(); - return mastertable["system"]["mastertable"][table]; - } - uf::Serializer masterDataGet( const std::string& table, const std::string& key ) { - uf::Scene& scene = uf::scene::getCurrentScene(); - uf::Serializer& mastertable = scene.getComponent(); - return mastertable["system"]["mastertable"][table][key]; - } - inline int64_t parseInt( const std::string& str ) { - return atoi(str.c_str()); - } -} - - -EXT_OBJECT_REGISTER_CPP(GuiWorldPauseMenu) -void ext::GuiWorldPauseMenu::initialize() { - uf::Object::initialize(); - - uf::Scene& scene = uf::scene::getCurrentScene(); - uf::Serializer& masterdata = scene.getComponent(); - uf::Serializer& metadata = this->getComponent(); - - // asset loading - this->addHook( "asset:Cache." + std::to_string(this->getUid()), [&](const std::string& event)->std::string{ - uf::Serializer json = event; - - std::string filename = json["filename"].asString(); - - if ( uf::io::extension(filename) != "ogg" ) return "false"; - - if ( filename == "" ) return "false"; - uf::Audio& sfx = this->getComponent(); - if ( sfx.playing() ) sfx.stop(); - sfx = uf::Audio(); - sfx.load(filename); - sfx.setVolume(masterdata["volumes"]["sfx"].asFloat()); - sfx.play(); - - return "true"; - }); - - // release control - { - uf::Serializer payload; - payload["state"] = true; - uf::hooks.call("window:Mouse.CursorVisibility", payload); - uf::hooks.call("window:Mouse.Lock"); - } - - // opened - playSound(*this, "menu open"); - - /* Magic Circle Outter */ { - // circleOut = (uf::Object*) this->findByUid(this->loadChildUid("./circle-out.json", true)); - circleOut = this->loadChildPointer("./circle-out.json", true); - /* - circleOut = new uf::Object; - this->addChild(*circleOut); - circleOut->load("./circle-out.json"); - circleOut->initialize(); - */ - } - /* Magic Circle Inner */ { - // circleIn = (uf::Object*) this->findByUid(this->loadChildUid("./circle-in.json", true)); - circleIn = this->loadChildPointer("./circle-in.json", true); - /* - circleIn = new uf::Object; - this->addChild(*circleIn); - circleIn->load("./circle-in.json"); - circleIn->initialize(); - */ - } - /* set sprite order */ { - metadata["portraits"]["i"] = 0; - uf::Serializer& pMetadata = scene.getController().getComponent(); - int i = 0; - for ( auto& k : pMetadata[""]["party"] ) { - std::string id = k.asString(); - uf::Serializer member = pMetadata[""]["transients"][id]; - uf::Serializer cardData = masterDataGet("Card", id); - std::string name = cardData["filename"].asString(); - if ( member["skin"].isString() ) name += "_" + member["skin"].asString(); - std::string filename = "https://cdn..xyz//unity/Android/fg/fg_" + name + ".png"; - if ( cardData["internal"].asBool() ) { - filename = "/smtsamo/fg/fg_" + name + ".png"; - } - metadata["portraits"]["list"][i++] = filename; - } - } - { - std::string portrait = metadata["portraits"]["list"][0].asString(); - /* Transient shadow background */ { - transientSpriteShadow = new uf::Object; - uf::Asset& assetLoader = transientSpriteShadow->getComponent(); - this->addChild(*transientSpriteShadow); - uf::Serializer& pMetadata = transientSpriteShadow->getComponent(); - pMetadata["system"]["assets"][0] = portrait; - - transientSpriteShadow->load("./transient-shadow.json", true); - transientSpriteShadow->initialize(); - - } - /* Transient transientSprite */ { - transientSprite = new uf::Object; - uf::Asset& assetLoader = transientSprite->getComponent(); - this->addChild(*transientSprite); - uf::Serializer& pMetadata = transientSprite->getComponent(); - pMetadata["system"]["assets"][0] = portrait; - - transientSprite->load("./transient-portrait.json", true); - transientSprite->initialize(); - - } - } - /* Main Text (the one that scrolls) */ { - // mainText = (uf::Object*) this->findByUid(this->loadChildUid("./main-text.json", true)); - mainText = this->loadChildPointer("./main-text.json", true); - /* - mainText = new uf::Object; - this->addChild(*mainText); - mainText->load("./main-text.json"); - mainText->initialize(); - */ - } - /* Command text */ { - // commandText = (uf::Object*) this->findByUid(this->loadChildUid("./command-text.json", true)); - commandText = this->loadChildPointer("./command-text.json", true); - /* - commandText = new uf::Object; - this->addChild(*commandText); - commandText->load("./command-text.json"); - commandText->initialize(); - */ - } - /* Cover bar */ { - // coverBar = (uf::Object*) this->findByUid(this->loadChildUid("./yellow-box.json", true)); - coverBar = this->loadChildPointer("./yellow-box.json", true); - /* - coverBar = new uf::Object; - this->addChild(*coverBar); - coverBar->load("./yellow-box.json"); - coverBar->initialize(); - */ - } - /* Option 1 */ { - // tenkouseiOption = (uf::Object*) this->findByUid(this->loadChildUid("./tenkousei.json", true)); - tenkouseiOption = this->loadChildPointer("./tenkousei.json", true); - /* - tenkouseiOption = new uf::Object; - this->addChild(*tenkouseiOption); - tenkouseiOption->load("./tenkousei.json"); - tenkouseiOption->initialize(); - */ - } - /* Option 2 */ { - // closeOption = (uf::Object*) this->findByUid(this->loadChildUid("./close.json", true)); - closeOption = this->loadChildPointer("./close.json", true); - /* - closeOption = new uf::Object; - this->addChild(*closeOption); - closeOption->load("./close.json"); - closeOption->initialize(); - */ - } - /* Option 3 */ { - // quitOption = (uf::Object*) this->findByUid(this->loadChildUid("./quit.json", true)); - quitOption = this->loadChildPointer("./quit.json", true); - /* - quitOption = new uf::Object; - this->addChild(*quitOption); - quitOption->load("./quit.json"); - quitOption->initialize(); - */ - } - - this->addHook("menu:Close.%UID%", [&]( const std::string& event ) -> std::string { - /* - // kill - this->getParent().removeChild(*this); - this->destroy(); - delete this; - return "true"; - */ - metadata["system"]["closing"] = true; - return "true"; - }); -} -void ext::GuiWorldPauseMenu::tick() { - uf::Object::tick(); - - uf::Scene& scene = this->getRootParent(); - uf::Serializer& masterdata = scene.getComponent(); - static uf::Timer timer(false); - static uf::Audio sfx; - if ( !timer.running() ) timer.start(); - - static float alpha = 0.0f; - { - uf::Serializer& metadata = this->getComponent(); - /* - if ( uf::Window::isKeyPressed("Escape") && !metadata["system"]["closing"].asBool() ) { - metadata["system"]["closing"] = true; - playSound(*this, "menu close"); - } - */ - if ( metadata["system"]["closing"].asBool() ) { - if ( alpha <= 0.0f ) { - alpha = 0.0f; - metadata["system"]["closing"] = false; - metadata["system"]["closed"] = true; - } else alpha -= uf::physics::time::delta; - metadata["color"][3] = alpha; - } else if ( metadata["system"]["closed"].asBool() ) { - // kill - timer.stop(); - this->destroy(); - delete this; - return; - } else { - if ( !metadata["initialized"].asBool() ) alpha = 0.0f; - metadata["initialized"] = true; - if ( alpha >= 1.0f ) alpha = 1.0f; - else alpha += uf::physics::time::delta * 1.5f; - metadata["color"][3] = alpha; - } - } - - if ( mainText ) { - pod::Transform<>& transform = mainText->getComponent>(); - uf::Serializer& metadata = mainText->getComponent(); - float speed = 0.5f; - if ( metadata["hovered"].asBool() ) speed = 0.75f; - transform.position.y += uf::physics::time::delta * speed; - if ( transform.position.y > 2 ) transform.position.y = -2; - - transform.orientation = uf::quaternion::axisAngle( { 0.0f, 0.0f, 1.0f }, -1.5707963f ); - if ( alpha < 0.6f ) metadata["color"][3] = alpha; - } - if ( circleIn ) { - pod::Transform<>& transform = circleIn->getComponent>(); - static float time = 0.0f; - float speed = 0.0125f; - uf::Serializer& metadata = circleIn->getComponent(); - if ( metadata["hovered"].asBool() ) speed = 0.25f; - time += uf::physics::time::delta * -speed; - transform.orientation = uf::quaternion::axisAngle( { 0.0f, 0.0f, 1.0f }, time ); - - static pod::Vector3f start = { transform.position.x, -2.0f, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - metadata["color"][3] = alpha; - } - if ( circleOut ) { - pod::Transform<>& transform = circleOut->getComponent>(); - uf::Serializer& metadata = circleOut->getComponent(); - static float time = 0.0f; - float speed = 0.0125f; - if ( metadata["hovered"].asBool() ) speed = 0.25f; - time += uf::physics::time::delta * speed; - transform.orientation = uf::quaternion::axisAngle( { 0.0f, 0.0f, 1.0f }, time ); - - static pod::Vector3f start = { transform.position.x, 2.0f, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - metadata["color"][3] = alpha; - } - if ( coverBar ) { - pod::Transform<>& transform = coverBar->getComponent>(); - static pod::Vector3f start = { -1.5f, transform.position.y, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - uf::Serializer& metadata = coverBar->getComponent(); - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - metadata["color"][3] = alpha; - } - if ( transientSprite ) { - pod::Transform<>& transform = transientSprite->getComponent>(); - static pod::Vector3f start = { 2.0f, transform.position.y, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - uf::Serializer& metadata = transientSprite->getComponent(); - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - metadata["color"][3] = alpha; - - // cycle transients - if ( metadata["clicked"].asBool() && timer.elapsed().asDouble() >= 1 ) { - timer.reset(); - - playSound(*this, "menu flip"); - - uf::Serializer& master = this->getComponent(); - int index = master["portraits"]["i"].asInt() + 1; - if ( index >= master["portraits"]["list"].size() ) index = 0; - master["portraits"]["i"] = index; - std::string filename = master["portraits"]["list"][index].asString(); - - { - std::string portrait = master["portraits"]["list"][index].asString(); - /* Transient shadow background */ if ( transientSpriteShadow ) { - transientSpriteShadow->destroy(); - this->removeChild(*transientSpriteShadow); - delete transientSpriteShadow; - - transientSpriteShadow = new uf::Object; - uf::Serializer& pMetadata = transientSpriteShadow->getComponent(); - pMetadata["system"]["assets"][0] = portrait; - - this->addChild(*transientSpriteShadow); - transientSpriteShadow->load("./transient-shadow.json", true); - transientSpriteShadow->initialize(); - } - /* Transient transientSprite */ if ( transientSprite ) { - transientSprite->destroy(); - this->removeChild(*transientSprite); - delete transientSprite; - - transientSprite = new uf::Object; - uf::Serializer& pMetadata = transientSprite->getComponent(); - pMetadata["system"]["assets"][0] = portrait; - - this->addChild(*transientSprite); - transientSprite->load("./transient-portrait.json", true); - transientSprite->initialize(); - } - } - if ( mainText ) { - pod::Transform cTransform = mainText->getComponent>(); - mainText->destroy(); - this->removeChild(*mainText); - delete mainText; - mainText = new uf::Object; - this->addChild(*mainText); - mainText->load("./main-text.json"); - mainText->getComponent>() = cTransform; - mainText->initialize(); - } - } - } - if ( transientSpriteShadow ) { - pod::Transform<>& transform = transientSpriteShadow->getComponent>(); - static pod::Vector3f start = { 2.0f, transform.position.y, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - uf::Serializer& metadata = transientSpriteShadow->getComponent(); - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - metadata["color"][3] = alpha; - } - - if ( commandText ) { - pod::Transform<>& transform = commandText->getComponent>(); - static pod::Vector3f start = { -1.5f, transform.position.y, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - uf::Serializer& metadata = commandText->getComponent(); - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - metadata["color"][3] = alpha; - - for ( uf::Entity* pointer : commandText->getChildren() ) { - uf::Serializer& cMetadata = pointer->getComponent(); - // std::cout << pointer->getName() << ": " << cMetadata["text settings"]["color"] << std::endl; - cMetadata["text settings"]["color"][3] = alpha; - } - } - if ( tenkouseiOption ) { - pod::Transform<>& transform = tenkouseiOption->getComponent>(); - static pod::Vector3f start = { -1.5f, transform.position.y, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - uf::Serializer& metadata = tenkouseiOption->getComponent(); - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - - - if ( metadata["clicked"].asBool() && timer.elapsed().asDouble() >= 1 ) { - timer.reset(); - - playSound(*this, "invalid select"); - } - metadata["color"][3] = alpha; - - for ( uf::Entity* pointer : tenkouseiOption->getChildren() ) { - uf::Serializer& cMetadata = pointer->getComponent(); - cMetadata["text settings"]["color"][3] = alpha; - if ( metadata["hovered"].asBool() ) { - cMetadata["color"][0] = 0; - cMetadata["color"][1] = 0; - cMetadata["color"][2] = 0; - } else { - cMetadata["color"][0] = 1; - cMetadata["color"][1] = 1; - cMetadata["color"][2] = 1; - } - } - } - if ( closeOption ) { - pod::Transform<>& transform = closeOption->getComponent>(); - static pod::Vector3f start = { -1.5f, transform.position.y, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - uf::Serializer& metadata = closeOption->getComponent(); - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - - - if ( metadata["clicked"].asBool() && timer.elapsed().asDouble() >= 1 ) { - timer.reset(); - this->callHook("menu:Close.%UID%"); - playSound(*this, "menu close"); - } - metadata["color"][3] = alpha; - - for ( uf::Entity* pointer : closeOption->getChildren() ) { - uf::Serializer& cMetadata = pointer->getComponent(); - cMetadata["text settings"]["color"][3] = alpha; - if ( metadata["hovered"].asBool() ) { - cMetadata["color"][0] = 0; - cMetadata["color"][1] = 0; - cMetadata["color"][2] = 0; - } else { - cMetadata["color"][0] = 1; - cMetadata["color"][1] = 1; - cMetadata["color"][2] = 1; - } - } - } - if ( quitOption ) { - pod::Transform<>& transform = quitOption->getComponent>(); - static pod::Vector3f start = { -1.5f, transform.position.y, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - uf::Serializer& metadata = quitOption->getComponent(); - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - - - if ( metadata["clicked"].asBool() && timer.elapsed().asDouble() >= 1 ) { - timer.reset(); - this->callHook("menu:Close.%UID%"); - playSound(*this, "menu close"); - /* - uf::Scene& scene = this->getRootParent(); - scene.queueHook("system:Quit.%UID%", "", 1.0f); - */ - } - metadata["color"][3] = alpha; - - for ( uf::Entity* pointer : quitOption->getChildren() ) { - uf::Serializer& cMetadata = pointer->getComponent(); - cMetadata["text settings"]["color"][3] = alpha; - if ( metadata["hovered"].asBool() ) { - cMetadata["color"][0] = 0; - cMetadata["color"][1] = 0; - cMetadata["color"][2] = 0; - } else { - cMetadata["color"][0] = 1; - cMetadata["color"][1] = 1; - cMetadata["color"][2] = 1; - } - } - } - - // Close menu - if ( uf::Window::isKeyPressed("Escape") && timer.elapsed().asDouble() >= 1 ) { - timer.reset(); - this->callHook("menu:Close.%UID%"); - playSound(*this, "menu close"); - } -} -void ext::GuiWorldPauseMenu::render() { - uf::Object::render(); -} - -void ext::GuiWorldPauseMenu::destroy() { - uf::Serializer& metadata = this->getComponent(); - uf::Object::destroy(); -} \ No newline at end of file diff --git a/ext/scenes/worldscape/gui/pause.h b/ext/scenes/worldscape/gui/pause.h deleted file mode 100644 index db58c2c3..00000000 --- a/ext/scenes/worldscape/gui/pause.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "../../../gui/gui.h" - -namespace ext { - class EXT_API GuiWorldPauseMenu : public ext::Gui { - public: - virtual void initialize(); - virtual void tick(); - virtual void render(); - virtual void destroy(); - }; -} \ No newline at end of file diff --git a/ext/scenes/worldscape/gui/pause/behavior.cpp b/ext/scenes/worldscape/gui/pause/behavior.cpp deleted file mode 100644 index f17ce0db..00000000 --- a/ext/scenes/worldscape/gui/pause/behavior.cpp +++ /dev/null @@ -1,590 +0,0 @@ -#include "behavior.h" - -#include -#include -#include -#include -#include -#include -#include -// #include -#include -#include - -#include - -#include - -#include -#include -#include -#include - -namespace { - uf::Object* mainText; - uf::Object* commandText; - uf::Object* transientSprite; - uf::Object* transientSpriteShadow; - uf::Object* circleIn; - uf::Object* circleOut; - uf::Object* coverBar; - uf::Object* tenkouseiOption; - uf::Object* closeOption; - uf::Object* quitOption; -} - -namespace { - void playSound( uf::Object& entity, const std::string& key ) { - uf::Scene& scene = uf::scene::getCurrentScene(); - uf::Serializer& metadata = entity.getComponent(); - uf::Serializer& masterdata = scene.getComponent(); - - std::string url = "./data/audio/ui/" + key + ".ogg"; - - uf::Asset& assetLoader = scene.getComponent(); - assetLoader.cache(url, "asset:Cache." + std::to_string(entity.getUid())); - } - - uf::Serializer masterTableGet( const std::string& table ) { - uf::Scene& scene = uf::scene::getCurrentScene(); - uf::Serializer& mastertable = scene.getComponent(); - return mastertable["system"]["mastertable"][table]; - } - uf::Serializer masterDataGet( const std::string& table, const std::string& key ) { - uf::Scene& scene = uf::scene::getCurrentScene(); - uf::Serializer& mastertable = scene.getComponent(); - return mastertable["system"]["mastertable"][table][key]; - } - inline int64_t parseInt( const std::string& str ) { - return atoi(str.c_str()); - } -} - -EXT_BEHAVIOR_REGISTER_CPP(GuiWorldPauseMenuBehavior) -EXT_BEHAVIOR_REGISTER_AS_OBJECT(GuiWorldPauseMenuBehavior, GuiWorldPauseMenu) -#define this (&self) -void ext::GuiWorldPauseMenuBehavior::initialize( uf::Object& self ) { - uf::Scene& scene = uf::scene::getCurrentScene(); - uf::Serializer& masterdata = scene.getComponent(); - uf::Serializer& metadata = this->getComponent(); - - // asset loading - this->addHook( "asset:Cache." + std::to_string(this->getUid()), [&](const std::string& event)->std::string{ - uf::Serializer json = event; - - std::string filename = json["filename"].asString(); - - if ( uf::io::extension(filename) != "ogg" ) return "false"; - - if ( filename == "" ) return "false"; - uf::Audio& sfx = this->getComponent(); - if ( sfx.playing() ) sfx.stop(); - sfx = uf::Audio(); - sfx.load(filename); - sfx.setVolume(masterdata["volumes"]["sfx"].asFloat()); - sfx.play(); - - return "true"; - }); - - // release control - { - uf::Serializer payload; - payload["state"] = true; - uf::hooks.call("window:Mouse.CursorVisibility", payload); - uf::hooks.call("window:Mouse.Lock"); - } - - // opened - playSound(self, "menu open"); - - /* Magic Circle Outter */ { - // circleOut = (uf::Object*) this->findByUid(this->loadChildUid("./circle-out.json", true)); - circleOut = (uf::Object*) this->loadChildPointer("./circle-out.json", true); - /* - circleOut = new uf::Object; - this->addChild(*circleOut); - circleOut->load("./circle-out.json"); - circleOut->initialize(); - */ - } - /* Magic Circle Inner */ { - // circleIn = (uf::Object*) this->findByUid(this->loadChildUid("./circle-in.json", true)); - circleIn = (uf::Object*) this->loadChildPointer("./circle-in.json", true); - /* - circleIn = new uf::Object; - this->addChild(*circleIn); - circleIn->load("./circle-in.json"); - circleIn->initialize(); - */ - } - /* set sprite order */ { - metadata["portraits"]["i"] = 0; - uf::Serializer& pMetadata = scene.getController().getComponent(); - int i = 0; - for ( auto& k : pMetadata[""]["party"] ) { - std::string id = k.asString(); - uf::Serializer member = pMetadata[""]["transients"][id]; - uf::Serializer cardData = masterDataGet("Card", id); - std::string name = cardData["filename"].asString(); - if ( name == "" ) continue; - if ( member["skin"].isString() ) name += "_" + member["skin"].asString(); - std::string filename = "https://cdn..xyz//unity/Android/fg/fg_" + name + ".png"; - if ( cardData["internal"].asBool() ) { - filename = "/smtsamo/fg/fg_" + name + ".png"; - } - metadata["portraits"]["list"][i++] = filename; - } - } - { - std::string portrait = metadata["portraits"]["list"][0].asString(); - /* Transient shadow background */ if ( portrait != "" ) { - transientSpriteShadow = new uf::Object; - uf::Asset& assetLoader = transientSpriteShadow->getComponent(); - this->addChild(*transientSpriteShadow); - uf::Serializer& pMetadata = transientSpriteShadow->getComponent(); - pMetadata["system"]["assets"][0] = portrait; - - transientSpriteShadow->load("./transient-shadow.json", true); - transientSpriteShadow->initialize(); - - } - /* Transient transientSprite */ if ( portrait != "" ) { - transientSprite = new uf::Object; - uf::Asset& assetLoader = transientSprite->getComponent(); - this->addChild(*transientSprite); - uf::Serializer& pMetadata = transientSprite->getComponent(); - pMetadata["system"]["assets"][0] = portrait; - - transientSprite->load("./transient-portrait.json", true); - transientSprite->initialize(); - - } - } - /* Main Text (the one that scrolls) */ { - // mainText = (uf::Object*) this->findByUid(this->loadChildUid("./main-text.json", true)); - mainText = (uf::Object*) this->loadChildPointer("./main-text.json", true); - /* - mainText = new uf::Object; - this->addChild(*mainText); - mainText->load("./main-text.json"); - mainText->initialize(); - */ - } - /* Command text */ { - // commandText = (uf::Object*) this->findByUid(this->loadChildUid("./command-text.json", true)); - commandText = (uf::Object*) this->loadChildPointer("./command-text.json", true); - /* - commandText = new uf::Object; - this->addChild(*commandText); - commandText->load("./command-text.json"); - commandText->initialize(); - */ - } - /* Cover bar */ { - // coverBar = (uf::Object*) this->findByUid(this->loadChildUid("./yellow-box.json", true)); - coverBar = (uf::Object*) this->loadChildPointer("./yellow-box.json", true); - /* - coverBar = new uf::Object; - this->addChild(*coverBar); - coverBar->load("./yellow-box.json"); - coverBar->initialize(); - */ - } - /* Option 1 */ { - // tenkouseiOption = (uf::Object*) this->findByUid(this->loadChildUid("./tenkousei.json", true)); - tenkouseiOption = (uf::Object*) this->loadChildPointer("./tenkousei.json", true); - /* - tenkouseiOption = new uf::Object; - this->addChild(*tenkouseiOption); - tenkouseiOption->load("./tenkousei.json"); - tenkouseiOption->initialize(); - */ - } - /* Option 2 */ { - // closeOption = (uf::Object*) this->findByUid(this->loadChildUid("./close.json", true)); - closeOption = (uf::Object*) this->loadChildPointer("./close.json", true); - /* - closeOption = new uf::Object; - this->addChild(*closeOption); - closeOption->load("./close.json"); - closeOption->initialize(); - */ - } - /* Option 3 */ { - // quitOption = (uf::Object*) this->findByUid(this->loadChildUid("./quit.json", true)); - quitOption = (uf::Object*) this->loadChildPointer("./quit.json", true); - /* - quitOption = new uf::Object; - this->addChild(*quitOption); - quitOption->load("./quit.json"); - quitOption->initialize(); - */ - } - - this->addHook("menu:Close.%UID%", [&]( const std::string& event ) -> std::string { - /* - // kill - this->getParent().removeChild(*this); - this->destroy(); - delete this; - return "true"; - */ - uf::Serializer json = event; - - metadata["system"]["hooks"]["onClose"] = json["callback"]; - - metadata["system"]["closing"] = true; - playSound(*this, "menu close"); - - return "true"; - }); -} -void ext::GuiWorldPauseMenuBehavior::tick( uf::Object& self ) { - uf::Scene& scene = this->getRootParent(); - uf::Serializer& masterdata = scene.getComponent(); - static uf::Timer timer(false); - static uf::Audio sfx; -// if ( !timer.running() ) timer.start( uf::Time<>(-1000000) ); - if ( !timer.running() ) timer.start(); - - static float alpha = 0.0f; - { - uf::Serializer& metadata = this->getComponent(); - /* - if ( uf::Window::isKeyPressed("Escape") && !metadata["system"]["closing"].asBool() ) { - metadata["system"]["closing"] = true; - playSound(*this, "menu close"); - } - */ - if ( metadata["system"]["closing"].asBool() ) { - if ( alpha <= 0.0f ) { - alpha = 0.0f; - metadata["system"]["closing"] = false; - metadata["system"]["closed"] = true; - } else alpha -= uf::physics::time::delta; - metadata["color"][3] = alpha; - } else if ( metadata["system"]["closed"].asBool() ) { - // kill - timer.stop(); - - uf::Serializer callback = metadata["system"]["hooks"]["onClose"]; - uf::Serializer payload = callback["payload"]; - uf::Object* target = this; - if ( callback["scope"].asString() == "parent" ) { - target = &this->getParent().as(); - } else if ( callback["scope"].asString() == "scene" ) { - target = &uf::scene::getCurrentScene(); - } - if ( callback["delay"].isNumeric() ) { - target->queueHook( callback["name"].asString(), payload, callback["delay"].asFloat() ); - } else { - target->callHook( callback["name"].asString(), payload ); - } - - this->destroy(); - this->getParent().removeChild(*this); - delete this; - return; - } else { - if ( !metadata["initialized"].asBool() ) alpha = 0.0f; - metadata["initialized"] = true; - if ( alpha >= 1.0f ) alpha = 1.0f; - else alpha += uf::physics::time::delta * 1.5f; - metadata["color"][3] = alpha; - } - } - - if ( mainText ) { - pod::Transform<>& transform = mainText->getComponent>(); - uf::Serializer& metadata = mainText->getComponent(); - float speed = 0.5f; - if ( metadata["hovered"].asBool() ) speed = 0.75f; - transform.position.y += uf::physics::time::delta * speed; - if ( transform.position.y > 2 ) transform.position.y = -2; - - transform.orientation = uf::quaternion::axisAngle( { 0.0f, 0.0f, 1.0f }, -1.5707963f ); - if ( alpha < 0.6f ) metadata["color"][3] = alpha; - } - if ( circleIn ) { - pod::Transform<>& transform = circleIn->getComponent>(); - static float time = 0.0f; - float speed = 0.0125f; - uf::Serializer& metadata = circleIn->getComponent(); - if ( metadata["hovered"].asBool() ) speed = 0.25f; - time += uf::physics::time::delta * -speed; - transform.orientation = uf::quaternion::axisAngle( { 0.0f, 0.0f, 1.0f }, time ); - - static pod::Vector3f start = { transform.position.x, -2.0f, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - metadata["color"][3] = alpha; - } - if ( circleOut ) { - pod::Transform<>& transform = circleOut->getComponent>(); - uf::Serializer& metadata = circleOut->getComponent(); - static float time = 0.0f; - float speed = 0.0125f; - if ( metadata["hovered"].asBool() ) speed = 0.25f; - time += uf::physics::time::delta * speed; - transform.orientation = uf::quaternion::axisAngle( { 0.0f, 0.0f, 1.0f }, time ); - - static pod::Vector3f start = { transform.position.x, 2.0f, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - metadata["color"][3] = alpha; - } - if ( coverBar ) { - pod::Transform<>& transform = coverBar->getComponent>(); - static pod::Vector3f start = { -1.5f, transform.position.y, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - uf::Serializer& metadata = coverBar->getComponent(); - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - metadata["color"][3] = alpha; - } - if ( transientSprite ) { - pod::Transform<>& transform = transientSprite->getComponent>(); - static pod::Vector3f start = { 2.0f, transform.position.y, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - uf::Serializer& metadata = transientSprite->getComponent(); - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - metadata["color"][3] = alpha; - - // cycle transients - if ( metadata["clicked"].asBool() && timer.elapsed().asDouble() >= 1 ) { - timer.reset(); - - playSound(*this, "menu flip"); - - uf::Serializer& master = this->getComponent(); - int index = master["portraits"]["i"].asInt() + 1; - if ( index >= master["portraits"]["list"].size() ) index = 0; - master["portraits"]["i"] = index; - std::string filename = master["portraits"]["list"][index].asString(); - - { - std::string portrait = master["portraits"]["list"][index].asString(); - /* Transient shadow background */ if ( transientSpriteShadow ) { - transientSpriteShadow->destroy(); - this->removeChild(*transientSpriteShadow); - delete transientSpriteShadow; - - transientSpriteShadow = new uf::Object; - uf::Serializer& pMetadata = transientSpriteShadow->getComponent(); - pMetadata["system"]["assets"][0] = portrait; - - this->addChild(*transientSpriteShadow); - transientSpriteShadow->load("./transient-shadow.json", true); - transientSpriteShadow->initialize(); - } - /* Transient transientSprite */ if ( transientSprite ) { - transientSprite->destroy(); - this->removeChild(*transientSprite); - delete transientSprite; - - transientSprite = new uf::Object; - uf::Serializer& pMetadata = transientSprite->getComponent(); - pMetadata["system"]["assets"][0] = portrait; - - this->addChild(*transientSprite); - transientSprite->load("./transient-portrait.json", true); - transientSprite->initialize(); - } - } - if ( mainText ) { - pod::Transform cTransform = mainText->getComponent>(); - mainText->destroy(); - this->removeChild(*mainText); - delete mainText; - mainText = new uf::Object; - this->addChild(*mainText); - mainText->load("./main-text.json"); - mainText->getComponent>() = cTransform; - mainText->initialize(); - } - } - } - if ( transientSpriteShadow ) { - pod::Transform<>& transform = transientSpriteShadow->getComponent>(); - static pod::Vector3f start = { 2.0f, transform.position.y, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - uf::Serializer& metadata = transientSpriteShadow->getComponent(); - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - metadata["color"][3] = alpha; - } - - if ( commandText ) { - pod::Transform<>& transform = commandText->getComponent>(); - static pod::Vector3f start = { -1.5f, transform.position.y, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - uf::Serializer& metadata = commandText->getComponent(); - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - metadata["color"][3] = alpha; - - for ( uf::Entity* pointer : commandText->getChildren() ) { - uf::Serializer& cMetadata = pointer->getComponent(); - // std::cout << pointer->getName() << ": " << cMetadata["text settings"]["color"] << std::endl; - cMetadata["text settings"]["color"][3] = alpha; - } - } - if ( tenkouseiOption ) { - pod::Transform<>& transform = tenkouseiOption->getComponent>(); - static pod::Vector3f start = { -1.5f, transform.position.y, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - uf::Serializer& metadata = tenkouseiOption->getComponent(); - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - - - if ( metadata["clicked"].asBool() && timer.elapsed().asDouble() >= 1 ) { - timer.reset(); - - playSound(*this, "invalid select"); - } - metadata["color"][3] = alpha; - - for ( uf::Entity* pointer : tenkouseiOption->getChildren() ) { - uf::Serializer& cMetadata = pointer->getComponent(); - cMetadata["text settings"]["color"][3] = alpha; - if ( metadata["hovered"].asBool() ) { - cMetadata["color"][0] = 0; - cMetadata["color"][1] = 0; - cMetadata["color"][2] = 0; - } else { - cMetadata["color"][0] = 1; - cMetadata["color"][1] = 1; - cMetadata["color"][2] = 1; - } - } - } - if ( closeOption ) { - pod::Transform<>& transform = closeOption->getComponent>(); - static pod::Vector3f start = { -1.5f, transform.position.y, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - uf::Serializer& metadata = closeOption->getComponent(); - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - /* - if ( metadata["clicked"].asBool() && timer.elapsed().asDouble() >= 1 ) { - timer.reset(); - this->callHook("menu:Close.%UID%"); - playSound(*this, "menu close"); - } - */ - metadata["color"][3] = alpha; - - for ( uf::Entity* pointer : closeOption->getChildren() ) { - uf::Serializer& cMetadata = pointer->getComponent(); - cMetadata["text settings"]["color"][3] = alpha; - if ( metadata["hovered"].asBool() ) { - cMetadata["color"][0] = 0; - cMetadata["color"][1] = 0; - cMetadata["color"][2] = 0; - } else { - cMetadata["color"][0] = 1; - cMetadata["color"][1] = 1; - cMetadata["color"][2] = 1; - } - } - } - if ( quitOption ) { - pod::Transform<>& transform = quitOption->getComponent>(); - static pod::Vector3f start = { -1.5f, transform.position.y, 0.0f }; - static pod::Vector3f end = transform.position; - static float delta = 0.0f; - uf::Serializer& metadata = quitOption->getComponent(); - if ( !metadata["initialized"].asBool() ) delta = 0.0f; - metadata["initialized"] = true; - if ( delta >= 1 ) delta = 1; - else { - delta += uf::physics::time::delta * 1.5f; - transform.position = uf::vector::lerp( start, end, delta ); - } - /* - if ( metadata["clicked"].asBool() && timer.elapsed().asDouble() >= 1 ) { - timer.reset(); - this->callHook("menu:Close.%UID%"); - playSound(*this, "menu close"); - } - */ - metadata["color"][3] = alpha; - - for ( uf::Entity* pointer : quitOption->getChildren() ) { - uf::Serializer& cMetadata = pointer->getComponent(); - cMetadata["text settings"]["color"][3] = alpha; - if ( metadata["hovered"].asBool() ) { - cMetadata["color"][0] = 0; - cMetadata["color"][1] = 0; - cMetadata["color"][2] = 0; - } else { - cMetadata["color"][0] = 1; - cMetadata["color"][1] = 1; - cMetadata["color"][2] = 1; - } - } - } - - // Close menu - if ( uf::Window::isKeyPressed("Escape") && timer.elapsed().asDouble() >= 1 ) { - timer.reset(); - this->callHook("menu:Close.%UID%"); - playSound(*this, "menu close"); - } -} -void ext::GuiWorldPauseMenuBehavior::render( uf::Object& self ){} -void ext::GuiWorldPauseMenuBehavior::destroy( uf::Object& self ){} -#undef this \ No newline at end of file diff --git a/ext/scenes/worldscape/gui/pause/behavior.h b/ext/scenes/worldscape/gui/pause/behavior.h deleted file mode 100644 index ea1bfec9..00000000 --- a/ext/scenes/worldscape/gui/pause/behavior.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace ext { - class EXT_API GuiWorldPauseMenuBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; -} \ No newline at end of file diff --git a/ext/scenes/worldscape/housamo/battle.cpp b/ext/scenes/worldscape/housamo/battle.cpp index 44b67f71..68153817 100644 --- a/ext/scenes/worldscape/housamo/battle.cpp +++ b/ext/scenes/worldscape/housamo/battle.cpp @@ -49,13 +49,13 @@ namespace { uf::Serializer& masterdata = scene.getComponent(); uf::Serializer cardData = masterDataGet("Card", id); - uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); - std::string name = charaData["filename"].asString(); + uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].as()); + std::string name = charaData["filename"].as(); if ( name == "none" ) return; std::string url = "https://cdn..xyz//unity/Android/voice/voice_" + name + "_"+key+".ogg"; - if ( charaData["internal"].asBool() ) { + if ( charaData["internal"].as() ) { url = "./data/smtsamo/voice/voice_" + name + "_" + key + ".ogg"; } @@ -70,7 +70,7 @@ namespace { uf::Entity* = scene.findByUid(uid); if ( ! ) return; uf::Serializer& metadata = ->getComponent(); - std::string id = metadata[""]["id"].asString(); + std::string id = metadata[""]["id"].as(); playSound( entity, id, key ); } void playSound( ext::HousamoBattle& entity, const std::string& key ) { @@ -121,7 +121,7 @@ void ext::HousamoBattle::initialize() { uf::Serializer& metadata = this->getComponent(); uf::Serializer& masterdata = scene.getComponent(); - std::string filename = json["filename"].asString(); + std::string filename = json["filename"].as(); if ( uf::io::extension(filename) != "ogg" ) return "false"; @@ -129,7 +129,7 @@ void ext::HousamoBattle::initialize() { if ( voice.playing() ) voice.stop(); voice = uf::Audio(); voice.load(filename); - voice.setVolume(masterdata["volumes"]["voice"].asFloat()); + voice.setVolume(masterdata["volumes"]["voice"].as()); voice.play(); return "true"; @@ -140,7 +140,7 @@ void ext::HousamoBattle::initialize() { uf::Scene& scene = uf::scene::getCurrentScene(); uf::Serializer& masterdata = scene.getComponent(); - std::string filename = json["filename"].asString(); + std::string filename = json["filename"].as(); if ( uf::io::extension(filename) != "ogg" ) return "false"; @@ -148,7 +148,7 @@ void ext::HousamoBattle::initialize() { if ( sfx.playing() ) sfx.stop(); sfx = uf::Audio(); sfx.load(filename); - sfx.setVolume(masterdata["volumes"]["sfx"].asFloat()); + sfx.setVolume(masterdata["volumes"]["sfx"].as()); sfx.play(); return "true"; @@ -156,11 +156,11 @@ void ext::HousamoBattle::initialize() { this->addHook( "asset:Music.Load.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; std::string filename = ""; - if ( json["music"].isArray() ) { + if ( ext::json::isArray( json["music"] ) ) { int ri = floor(rand() % json["music"].size()); - filename = json["music"][ri].asString(); - } else if ( json["music"].isString() ) { - filename = json["music"].asString(); + filename = json["music"][ri].as(); + } else if ( json["music"].is() ) { + filename = json["music"].as(); } if ( filename != "" ) playMusic(*this, filename); return "true"; @@ -181,7 +181,7 @@ void ext::HousamoBattle::initialize() { uf::Serializer actions; actions.readFromFile("./data/entities/gui/battle/actions.json"); metadata["actions"] = actions; - if ( metadata["actions"].isNull() ) { + if ( ext::json::isNull( metadata["actions"] ) ) { metadata["actions"]["00.member-attack"] = "攻撃"; metadata["actions"]["01.member-skill"] = "スキル"; metadata["actions"]["02.inventory"] = "アイテム"; @@ -195,7 +195,7 @@ void ext::HousamoBattle::initialize() { // spawn transients accordingly for ( auto& id : metadata["battle"]["player"]["party"] ) { uint64_t uid = transients.size(); - auto& member = metadata["battle"]["player"]["transients"][id.asString()]; + auto& member = metadata["battle"]["player"]["transients"][id.as()]; member["uid"] = uid; ext::Housamo* transient = new ext::Housamo; @@ -212,7 +212,7 @@ void ext::HousamoBattle::initialize() { } for ( auto& id : metadata["battle"]["enemy"]["party"] ) { uint64_t uid = transients.size(); - auto& member = metadata["battle"]["enemy"]["transients"][id.asString()]; + auto& member = metadata["battle"]["enemy"]["transients"][id.as()]; member["uid"] = uid; ext::Housamo* transient = new ext::Housamo; @@ -233,33 +233,33 @@ void ext::HousamoBattle::initialize() { uf::Serializer payload; for ( auto& member : metadata["battle"]["transients"] ) { for ( auto& skillId : member["skills"] ) { - uf::Serializer skillData = masterDataGet("Skill", skillId.asString()); - if ( skillData["type"].asInt64() != 16 ) continue; + uf::Serializer skillData = masterDataGet("Skill", skillId.as()); + if ( skillData["type"].as() != 16 ) continue; for ( auto& status : skillData["statuses"] ) { - std::string target = status["target"].asString(); - std::string statusId = status["id"].asString(); + std::string target = status["target"].as(); + std::string statusId = status["id"].as(); uf::Serializer statusData = masterDataGet("Status", statusId); float r = (rand() % 100) / 100.0; - if ( statusData["proc"].isNumeric() ) { + if ( statusData["proc"].is() ) { // failed - if ( r > statusData["proc"].asFloat() / 100.0f ) { + if ( r > statusData["proc"].as() / 100.0f ) { target = ""; } } // apply status uf::Serializer targets; if ( target == "self" ) { - targets.append(member["uid"].asString()); + targets.append(member["uid"].as()); } else if ( target == "enemy" ) { for ( auto& tmember : metadata["battle"]["transients"] ) { if ( tmember["type"] == member["type"] ) continue; - targets.append(tmember["uid"].asString()); + targets.append(tmember["uid"].as()); } } else if ( target == "ally" ) { for ( auto& tmember : metadata["battle"]["transients"] ) { if ( tmember["type"] != member["type"] ) continue; - targets.append(tmember["uid"].asString()); + targets.append(tmember["uid"].as()); } } for ( auto& target : targets ) { @@ -267,13 +267,13 @@ void ext::HousamoBattle::initialize() { statusPayload["id"] = statusId; statusPayload["modifier"] = status["modifier"]; - statusPayload["turns"] = status["turns"].isNumeric() ? status["turns"] : statusData["turns"]; - metadata["battle"]["transients"][target.asString()]["statuses"].append(statusPayload); + statusPayload["turns"] = status["turns"].is() ? status["turns"] : statusData["turns"]; + metadata["battle"]["transients"][target.as()]["statuses"].append(statusPayload); - uf::Serializer cardData = masterDataGet( "Card", metadata["battle"]["transients"][target.asString()]["id"].asString() ); - uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); + uf::Serializer cardData = masterDataGet( "Card", metadata["battle"]["transients"][target.as()]["id"].as() ); + uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].as()); - payload["message"] = payload["message"].asString() + "\nApplied "+colorString("FF0000") + "" + statusData["name"].asString() + ""+colorString("FFFFFF") + " to " + charaData["name"].asString(); + payload["message"] = payload["message"].as() + "\nApplied "+colorString("FF0000") + "" + statusData["name"].as() + ""+colorString("FFFFFF") + " to " + charaData["name"].as(); } } } @@ -304,7 +304,7 @@ void ext::HousamoBattle::initialize() { std::string hookName = ""; uf::Serializer payload; - std::string action = json["action"].asString(); + std::string action = json["action"].as(); // dead check struct { @@ -314,7 +314,7 @@ void ext::HousamoBattle::initialize() { } player, enemy; } counts; for ( auto& member : metadata["battle"]["transients"] ) { - bool dead = member["hp"].asInt64() <= 0; + bool dead = member["hp"].as() <= 0; if ( member["type"] == "player" ) { ++counts.player.total; if ( dead ) ++counts.player.dead; @@ -382,22 +382,22 @@ void ext::HousamoBattle::initialize() { { auto& turnState = metadata["battle"]["turn"]; - float decrement = turnState["decrement"].asFloat(); - turnState["counter"] = turnState["counter"].asFloat() - decrement; + float decrement = turnState["decrement"].as(); + turnState["counter"] = turnState["counter"].as() - decrement; turnState["decrement"] = 0; } { for ( auto it = metadata["battle"]["transients"].begin(); it != metadata["battle"]["transients"].end(); ++it ) { - std::string key = it.key().asString(); - if ( key == "" || (*it)["type"].isNull() ) metadata["battle"].removeMember(key); + std::string key = it.key().as(); + if ( key == "" || ext::json::isNull( (*it)["type"] ) ) metadata["battle"].removeMember(key); } } /* remove dead */ if ( false ) { for ( auto it = metadata["battle"]["transients"].begin(); it != metadata["battle"]["transients"].end(); ++it ) { - std::string key = it.key().asString(); - if ( metadata["battle"]["transients"][key]["hp"].asInt64() > 0 ) continue; + std::string key = it.key().as(); + if ( metadata["battle"]["transients"][key]["hp"].as() > 0 ) continue; // metadata["battle"]["transients"].removeMember(key); } // std::cout << metadata["battle"]["transients"] << std::endl; @@ -424,7 +424,7 @@ void ext::HousamoBattle::initialize() { json["skill"] = "0"; return json; } - auto& member = metadata["battle"]["transients"][json["uid"].asString()]; + auto& member = metadata["battle"]["transients"][json["uid"].as()]; // deduce member state struct { std::vector ailments; @@ -432,7 +432,7 @@ void ext::HousamoBattle::initialize() { float factor = 0.0f; } stats; for ( auto& status : member["statuses"] ) { - std::string id = status["id"].asString(); + std::string id = status["id"].as(); if ( id == "0" ) continue; stats.ailments.push_back(id); if ( id == "6" ) ++stats.ndas; @@ -441,7 +441,7 @@ void ext::HousamoBattle::initialize() { uf::Serializer possibilities; possibilities = Json::arrayValue; for ( auto& skillId : member["skills"] ) { - uf::Serializer skillData = masterDataGet("Skill", skillId.asString()); + uf::Serializer skillData = masterDataGet("Skill", skillId.as()); // not recarms std::cout << skillData["name"] << ": "; if ( skillId == "81" || skillId == "82" ) { @@ -449,42 +449,42 @@ void ext::HousamoBattle::initialize() { continue; } // invalid skill type - if ( skillData["type"].asInt() < 1 || skillData["type"].asInt() > 15 ) { + if ( skillData["type"].as() < 1 || skillData["type"].as() > 15 ) { std::cout << "\tBad skill type" << std::endl; continue; } // no MP - if ( skillData["mp"].asFloat() > member["mp"].asFloat() ) { + if ( skillData["mp"].as() > member["mp"].as() ) { std::cout << "\tNot enough MP" << std::endl; continue; } // no HP - if ( skillData["hp%"].asFloat() / 100.0f * member["max hp"].asFloat() >= member["hp"].asFloat() ) { + if ( skillData["hp%"].as() / 100.0f * member["max hp"].as() >= member["hp"].as() ) { std::cout << "\tNot enough HP" << std::endl; continue; } // do not use same skills - if ( std::find(member["used skills"].begin(), member["used skills"].end(), skillId.asString()) != member["used skills"].end() ) { + if ( std::find(member["used skills"].begin(), member["used skills"].end(), skillId.as()) != member["used skills"].end() ) { std::cout << "\tRecently Used" << std::endl; continue; } // grants additional turns - if ( skillData["turns+"].isNumeric() ) { - queuedSkillId = skillId.asString(); + if ( skillData["turns+"].is() ) { + queuedSkillId = skillId.as(); std::cout << "\tCan gain turns" << std::endl; break; // try and heal if under 30% - } else if ( member["hp"].asFloat() / member["max hp"].asFloat() < 0.3f ) { + } else if ( member["hp"].as() / member["max hp"].as() < 0.3f ) { if ( skillData["type"] != "14" ) continue; - if ( stats.factor < skillData["power"].asFloat() ) { - queuedSkillId = skillId.asString(); - stats.factor = skillData["power"].asFloat(); + if ( stats.factor < skillData["power"].as() ) { + queuedSkillId = skillId.as(); + stats.factor = skillData["power"].as(); std::cout << "\tCan heal" << std::endl; } // remove debuffs } else if ( skillId == "200" ) { if ( stats.ndas * 75.0f > stats.factor ) { - queuedSkillId = skillId.asString(); + queuedSkillId = skillId.as(); stats.factor = stats.ndas * 75.0f; std::cout << "\tCan Dekunda" << std::endl; } @@ -492,14 +492,14 @@ void ext::HousamoBattle::initialize() { } else { // remove negative ailment (fear, etc) for ( auto& status : skillData["statuses"] ) { - std::string statusId = status["id"].asString(); + std::string statusId = status["id"].as(); uf::Serializer statusData = masterDataGet("Status", statusId); for ( auto it = status["modifier"].begin(); it != status["modifier"].end(); ++it ) { - statusData[it.key().asString()] = *it; + statusData[it.key().as()] = *it; } // remove statuses if ( statusData["type"] == "remove" && std::find( stats.ailments.begin(), stats.ailments.end(), statusId ) != stats.ailments.end() ) { - queuedSkillId = skillId.asString(); + queuedSkillId = skillId.as(); stats.factor = 150.0f; std::cout << "\tCan remove status " << statusData["name"] << std::endl; } @@ -516,9 +516,9 @@ void ext::HousamoBattle::initialize() { if ( queuedSkillId == "0" && possibilities.size() > 0 ) { possibilities.append("0"); int ri = floor(rand() % possibilities.size()); - queuedSkillId = possibilities[ri].asString(); + queuedSkillId = possibilities[ri].as(); auto queuedSkillData = masterDataGet( "Skill", queuedSkillId ); - std::cout << "Picked " << queuedSkillData["name"].asString() << std::endl; + std::cout << "Picked " << queuedSkillData["name"].as() << std::endl; } json["skill"] = queuedSkillId; return json; @@ -528,31 +528,31 @@ void ext::HousamoBattle::initialize() { uf::Serializer payload; payload["targets"] = Json::arrayValue; - auto& member = metadata["battle"]["transients"][json["uid"].asString()]; - if ( json["skill"].isString() ) { - std::string skillId = json["skill"].asString(); + auto& member = metadata["battle"]["transients"][json["uid"].as()]; + if ( json["skill"].is() ) { + std::string skillId = json["skill"].as(); if ( json["skill"] == "0" ) { for ( auto& status : member["statuses"] ) { - std::string statusId = status["id"].asString(); + std::string statusId = status["id"].as(); uf::Serializer statusData = masterDataGet("Status", statusId); for ( auto it = status["modifier"].begin(); it != status["modifier"].end(); ++it ) { - statusData[it.key().asString()] = *it; + statusData[it.key().as()] = *it; } if ( statusData["skill"] != skillId ) continue; - if ( statusData["range"].isNumeric() ) json["range"] = statusData["range"]; + if ( statusData["range"].is() ) json["range"] = statusData["range"]; } - } else if ( !json["type"].isString() ) { + } else if ( !json["type"].is() ) { uf::Serializer skillData = masterDataGet( "Skill", skillId ); - json["type"] = skillData["target"].asString(); + json["type"] = skillData["target"].as(); if ( json["type"] == "" ) json["type"] = "enemy"; } } else { json["type"] = "all"; } - if ( json["type"].isString() ) { + if ( json["type"].is() ) { if ( json["type"] == "self" ) { - payload["targets"].append( metadata["battle"]["transients"][json["uid"].asString()] ); + payload["targets"].append( metadata["battle"]["transients"][json["uid"].as()] ); } else { for ( auto& m : metadata["battle"]["transients"] ) { if ( json["type"] == "ally" && m["type"] != member["type"] ) continue; @@ -590,14 +590,14 @@ void ext::HousamoBattle::initialize() { for ( auto& member : metadata["battle"]["transients"] ) { if ( member["type"] != "enemy" ) continue; target = member; - size_t uid = member["uid"].asUInt64(); - uf::Serializer cardData = masterDataGet("Card", member["id"].asString()); - uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); - name = charaData["name"].asString(); + size_t uid = member["uid"].as(); + uf::Serializer cardData = masterDataGet("Card", member["id"].as()); + uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].as()); + name = charaData["name"].as(); break; } if ( target ) { - playSound(*this, target["id"].asString(), r > 0.5 ? "turn" : "battlestart"); + playSound(*this, target["id"].as(), r > 0.5 ? "turn" : "battlestart"); payload["message"] = ""+colorString("FF0000") + "" + name + ""+colorString("FFFFFF") + " speaks."; } @@ -605,15 +605,15 @@ void ext::HousamoBattle::initialize() { }); this->addHook( "world:Battle.OnHit.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - uint64_t uid = json["uid"].asUInt64(); + uint64_t uid = json["uid"].as(); ext::Housamo* transient = transients.at(uid); uf::Serializer& member = transient->getComponent(); - uint64_t entid = metadata["battle"]["enemy"]["uid"].asUInt64(); + uint64_t entid = metadata["battle"]["enemy"]["uid"].as(); uf::Entity* = scene.findByUid(entid); if ( ! ) return "false"; uf::Serializer& hMetadata = ->getComponent(); - uint64_t phase = json["phase"].asUInt64(); + uint64_t phase = json["phase"].as(); // start color pod::Vector4f color = { 1, 1, 1, 0 }; if ( phase == 0 ) { @@ -629,11 +629,11 @@ void ext::HousamoBattle::initialize() { uf::Serializer json = event; bool found = false; - uint64_t turnPlayer = json["uid"].asUInt64(); + uint64_t turnPlayer = json["uid"].as(); std::string name = ""; auto& turnState = metadata["battle"]["turn"]; { - if ( turnState["counter"].asFloat() <= 0 ) { + if ( turnState["counter"].as() <= 0 ) { if ( turnState["phase"] == "player" ) turnState["phase"] = "enemy"; else turnState["phase"] = "player"; int counter = 0; @@ -642,13 +642,13 @@ void ext::HousamoBattle::initialize() { bool locked = false; for ( auto& status : member["statuses"] ) { - std::string statusId = status["id"].asString(); + std::string statusId = status["id"].as(); uf::Serializer statusData = masterDataGet("Status", statusId); for ( auto it = status["modifier"].begin(); it != status["modifier"].end(); ++it ) { - statusData[it.key().asString()] = *it; + statusData[it.key().as()] = *it; } - if ( statusData["lock"].asBool() ) locked = true; + if ( statusData["lock"].as() ) locked = true; } if ( locked ) continue; @@ -669,23 +669,23 @@ void ext::HousamoBattle::initialize() { std::function getTurnPlayer = [&]()->bool{ for ( auto& member : metadata["battle"]["transients"] ) { - if ( member["hp"].asInt64() <= 0 ) continue; + if ( member["hp"].as() <= 0 ) continue; bool locked = false; for ( auto& status : member["statuses"] ) { - std::string statusId = status["id"].asString(); + std::string statusId = status["id"].as(); uf::Serializer statusData = masterDataGet("Status", statusId); for ( auto it = status["modifier"].begin(); it != status["modifier"].end(); ++it ) { - statusData[it.key().asString()] = *it; + statusData[it.key().as()] = *it; } - if ( statusData["lock"].asBool() ) locked = true; + if ( statusData["lock"].as() ) locked = true; } if ( locked ) continue; - if ( turnPlayer > member["uid"].asUInt64() ) continue; + if ( turnPlayer > member["uid"].as() ) continue; if ( member["type"] != turnState["phase"] ) continue; - turnPlayer = member["uid"].asUInt64(); + turnPlayer = member["uid"].as(); return true; } return false; @@ -704,10 +704,10 @@ void ext::HousamoBattle::initialize() { } payload["uid"] = turnPlayer; - auto& member = metadata["battle"]["transients"][payload["uid"].asString()]; - uf::Serializer cardData = masterDataGet("Card", member["id"].asString()); - uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); - name = charaData["name"].asString(); + auto& member = metadata["battle"]["transients"][payload["uid"].as()]; + uf::Serializer cardData = masterDataGet("Card", member["id"].as()); + uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].as()); + name = charaData["name"].as(); payload["message"] = "What will "+colorString("FF0000") + "" + name + ""+colorString("FFFFFF") + " do?"; // @@ -718,11 +718,11 @@ void ext::HousamoBattle::initialize() { bool skipped = false; // tick down statuses - if ( turnState["start of turn"].asBool() ) { + if ( turnState["start of turn"].as() ) { /* remove dead */ if ( false ) { for ( auto it = metadata["battle"]["transients"].begin(); it != metadata["battle"]["transients"].end(); ++it ) { - std::string key = it.key().asString(); - if ( metadata["battle"]["transients"][key]["hp"].asInt64() > 0 ) continue; + std::string key = it.key().as(); + if ( metadata["battle"]["transients"][key]["hp"].as() > 0 ) continue; // metadata["battle"]["transients"].removeMember(key); } // std::cout << metadata["battle"]["transients"] << std::endl; @@ -732,46 +732,46 @@ void ext::HousamoBattle::initialize() { member["used skills"] = Json::arrayValue; if ( member["type"] != turnState["phase"] ) continue; auto& statuses = member["statuses"]; -// std::cout << "Before: " << member["uid"].asString() << ": " << statuses << std::endl; +// std::cout << "Before: " << member["uid"].as() << ": " << statuses << std::endl; for ( int i = 0; i < statuses.size(); ++i ) { auto& status = statuses[i]; - uf::Serializer statusData = masterDataGet("Status", status["id"].asString()); + uf::Serializer statusData = masterDataGet("Status", status["id"].as()); for ( auto it = status["modifier"].begin(); it != status["modifier"].end(); ++it ) { - statusData[it.key().asString()] = *it; + statusData[it.key().as()] = *it; } - uf::Serializer cardData = masterDataGet( "Card", member["id"].asString() ); - uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); + uf::Serializer cardData = masterDataGet( "Card", member["id"].as() ); + uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].as()); - if ( statusData["hp"].isNumeric() ) { - int64_t hp = statusData["hp"].asInt64(); - member["hp"] = member["hp"].asInt64() + hp; - payload["message"] = payload["message"].asString() + "\n"+colorString("FF0000") + "" + charaData["name"].asString() + ""+colorString("FFFFFF") + " gained "+colorString("00FF00") + ""+ std::to_string(hp) +" HP"+colorString("FFFFFF") + " from "+colorString("FF0000") + "" + statusData["name"].asString() + ""+colorString("FFFFFF") + ""; + if ( statusData["hp"].is() ) { + int64_t hp = statusData["hp"].as(); + member["hp"] = member["hp"].as() + hp; + payload["message"] = payload["message"].as() + "\n"+colorString("FF0000") + "" + charaData["name"].as() + ""+colorString("FFFFFF") + " gained "+colorString("00FF00") + ""+ std::to_string(hp) +" HP"+colorString("FFFFFF") + " from "+colorString("FF0000") + "" + statusData["name"].as() + ""+colorString("FFFFFF") + ""; } - if ( statusData["hp%"].isNumeric() ) { - int64_t hp = member["max hp"].asFloat() * (statusData["hp%"].asInt64() / 100.0f); - if ( member["max hp"].asInt64() < member["hp"].asInt64() + hp ) hp = member["max hp"].asInt64() - member["hp"].asInt64(); - member["hp"] = member["hp"].asInt64() + hp; - if ( hp > 0 ) payload["message"] = payload["message"].asString() + "\n"+colorString("FF0000") + "" + charaData["name"].asString() + ""+colorString("FFFFFF") + " gained "+colorString("00FF00") + ""+ std::to_string(hp) +" HP"+colorString("FFFFFF") + " from "+colorString("FF0000") + "" + statusData["name"].asString() + ""+colorString("FFFFFF") + ""; + if ( statusData["hp%"].is() ) { + int64_t hp = member["max hp"].as() * (statusData["hp%"].as() / 100.0f); + if ( member["max hp"].as() < member["hp"].as() + hp ) hp = member["max hp"].as() - member["hp"].as(); + member["hp"] = member["hp"].as() + hp; + if ( hp > 0 ) payload["message"] = payload["message"].as() + "\n"+colorString("FF0000") + "" + charaData["name"].as() + ""+colorString("FFFFFF") + " gained "+colorString("00FF00") + ""+ std::to_string(hp) +" HP"+colorString("FFFFFF") + " from "+colorString("FF0000") + "" + statusData["name"].as() + ""+colorString("FFFFFF") + ""; } - if ( statusData["mp"].isNumeric() ) { - int64_t mp = statusData["mp"].asInt64(); - member["mp"] = member["mp"].asInt64() + mp; - if ( member["max mp"].asInt64() < member["mp"].asInt64() + mp ) mp = member["max mp"].asInt64() - member["mp"].asInt64(); - payload["message"] = payload["message"].asString() + "\n"+colorString("FF0000") + "" + charaData["name"].asString() + ""+colorString("FFFFFF") + " gained "+colorString("0000FF") + ""+ std::to_string(mp) +" MP"+colorString("FFFFFF") + " from "+colorString("FF0000") + "" + statusData["name"].asString() + ""+colorString("FFFFFF") + ""; + if ( statusData["mp"].is() ) { + int64_t mp = statusData["mp"].as(); + member["mp"] = member["mp"].as() + mp; + if ( member["max mp"].as() < member["mp"].as() + mp ) mp = member["max mp"].as() - member["mp"].as(); + payload["message"] = payload["message"].as() + "\n"+colorString("FF0000") + "" + charaData["name"].as() + ""+colorString("FFFFFF") + " gained "+colorString("0000FF") + ""+ std::to_string(mp) +" MP"+colorString("FFFFFF") + " from "+colorString("FF0000") + "" + statusData["name"].as() + ""+colorString("FFFFFF") + ""; } - if ( statusData["lock"].isNumeric() ) { + if ( statusData["lock"].is() ) { skipped = true; } } uf::Serializer newStatuses; for ( int i = statuses.size() - 1; i >= 0; --i ) { auto& status = statuses[i]; - uf::Serializer statusData = masterDataGet("Status", status["id"].asString()); - if ( !status["turns"].isNull() ) { - status["turns"] = status["turns"].asInt64() - 1; - if ( status["turns"].asInt64() < 0 ) { - if ( statusData["id"] != "0" ) payload["message"] = payload["message"].asString() + "\n"+colorString("FF0000") + "" + statusData["name"].asString() + ""+colorString("FFFFFF") + " wore off."; + uf::Serializer statusData = masterDataGet("Status", status["id"].as()); + if ( !ext::json::isNull( status["turns"] ) ) { + status["turns"] = status["turns"].as() - 1; + if ( status["turns"].as() < 0 ) { + if ( statusData["id"] != "0" ) payload["message"] = payload["message"].as() + "\n"+colorString("FF0000") + "" + statusData["name"].as() + ""+colorString("FFFFFF") + " wore off."; } else { newStatuses.append(status); } @@ -780,14 +780,14 @@ void ext::HousamoBattle::initialize() { } } statuses = newStatuses; -// std::cout << "After: " << member["uid"].asString() << ": " << statuses << std::endl; +// std::cout << "After: " << member["uid"].as() << ": " << statuses << std::endl; } } { for ( auto it = metadata["battle"]["transients"].begin(); it != metadata["battle"]["transients"].end(); ++it ) { - std::string key = it.key().asString(); - if ( key == "" || (*it)["type"].isNull() ) metadata["battle"].removeMember(key); + std::string key = it.key().as(); + if ( key == "" || ext::json::isNull( (*it)["type"] ) ) metadata["battle"].removeMember(key); } } @@ -827,42 +827,42 @@ void ext::HousamoBattle::initialize() { this->addHook( "world:Battle.Attack.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - std::string skillId = json["skill"].asString(); + std::string skillId = json["skill"].as(); uf::Serializer skillData = masterDataGet("Skill", skillId); // ext::Housamo* transient = transients.at(uid); - auto& member = metadata["battle"]["transients"][json["uid"].asString()]; + auto& member = metadata["battle"]["transients"][json["uid"].as()]; uf::Serializer payload; payload["message"] = ""; // modify skill data based on statuses for ( auto& status : member["statuses"] ) { - std::string statusId = status["id"].asString(); + std::string statusId = status["id"].as(); uf::Serializer statusData = masterDataGet("Status", statusId); for ( auto it = status["modifier"].begin(); it != status["modifier"].end(); ++it ) { - statusData[it.key().asString()] = *it; + statusData[it.key().as()] = *it; } if ( statusData["skill"] != skillId ) continue; - if ( statusData["range"].isNumeric() ) skillData["range"] = statusData["range"]; + if ( statusData["range"].is() ) skillData["range"] = statusData["range"]; } // select random target - if ( json["target"].isNull() ) { - if ( skillData["target"].isNull() ) skillData["target"] = "enemy"; + if ( ext::json::isNull( json["target"] ) ) { + if ( ext::json::isNull( skillData["target"] ) ) skillData["target"] = "enemy"; if ( skillData["target"] == "self" ) { - json["target"].append( member["uid"].asUInt64() ); - } else if ( skillData["range"].isNumeric() && skillData["range"].asInt64() > 1 ) { + json["target"].append( member["uid"].as() ); + } else if ( skillData["range"].is() && skillData["range"].as() > 1 ) { json["target"] = Json::arrayValue; for ( auto& m : metadata["battle"]["transients"] ) { if ( skillData["target"] == "ally" && m["type"] != member["type"] ) continue; if ( skillData["target"] != "ally" && m["type"] == member["type"] ) continue; - json["target"].append( m["uid"].asUInt64() ); + json["target"].append( m["uid"].as() ); } } else { std::vector targets; for ( auto& m : metadata["battle"]["transients"] ) { if ( skillData["target"] == "ally" && m["type"] != member["type"] ) continue; if ( skillData["target"] != "ally" && m["type"] == member["type"] ) continue; - targets.push_back( m["uid"].asUInt64() ); + targets.push_back( m["uid"].as() ); } int ri = floor(rand() % targets.size()); json["target"] = Json::arrayValue; @@ -871,19 +871,19 @@ void ext::HousamoBattle::initialize() { } uf::Serializer elementData; - uf::Serializer cardData = masterDataGet("Card", member["id"].asString()); - uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); + uf::Serializer cardData = masterDataGet("Card", member["id"].as()); + uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].as()); std::string elementId; float basePower = member["type"] == "enemy" ? 1.2f : 1.0f; if ( skillId != "0" ) { - payload["message"] = payload["message"].asString() + "\n"+colorString("FF0000") + "" + charaData["name"].asString() + ""+colorString("FFFFFF") + ": "+colorString("7777FF") + "" + skillData["name"].asString() + colorString("FFFFFF"); + payload["message"] = payload["message"].as() + "\n"+colorString("FF0000") + "" + charaData["name"].as() + ""+colorString("FFFFFF") + ": "+colorString("7777FF") + "" + skillData["name"].as() + colorString("FFFFFF"); - elementId = skillData["type"].asString(); + elementId = skillData["type"].as(); elementData = masterDataGet("Element", elementId); } else { - payload["message"] = payload["message"].asString() + "\n"+colorString("FF0000") + "" + charaData["name"].asString() + ""+colorString("FFFFFF") + ": "+colorString("7777FF") + "攻撃" + colorString("FFFFFF"); + payload["message"] = payload["message"].as() + "\n"+colorString("FF0000") + "" + charaData["name"].as() + ""+colorString("FFFFFF") + ": "+colorString("7777FF") + "攻撃" + colorString("FFFFFF"); elementId = "0"; if ( cardData["weapon_type"] == "1" ) elementId = "1"; // slash @@ -911,20 +911,20 @@ void ext::HousamoBattle::initialize() { }; { - int64_t mp = member["mp"].asInt64(); - int64_t hp = member["hp"].asInt64(); - int64_t mpCost = skillData["mp"].asInt64(); - int64_t hpCost = skillData["hp%"].asInt64(); + int64_t mp = member["mp"].as(); + int64_t hp = member["hp"].as(); + int64_t mpCost = skillData["mp"].as(); + int64_t hpCost = skillData["hp%"].as(); for ( auto& status : member["statuses"] ) { - std::string statusId = status["id"].asString(); + std::string statusId = status["id"].as(); uf::Serializer statusData = masterDataGet("Status", statusId); for ( auto it = status["modifier"].begin(); it != status["modifier"].end(); ++it ) { - statusData[it.key().asString()] = *it; + statusData[it.key().as()] = *it; } - if ( !statusData["type"].isNull() && elementData["type"] != statusData["type"] ) continue; - if ( !statusData["attributes"].isNull() ) { + if ( !ext::json::isNull( statusData["type"] ) && elementData["type"] != statusData["type"] ) continue; + if ( !ext::json::isNull( statusData["attributes"] ) ) { bool found = false; for ( auto& value : statusData["attributes"] ) { if ( value == elementData["id"] ) found = true; @@ -932,25 +932,25 @@ void ext::HousamoBattle::initialize() { if ( !found ) continue; } - if ( hpCost > 0 && statusData["cost"].isNumeric() ) { - hpCost -= statusData["cost"].asInt64(); + if ( hpCost > 0 && statusData["cost"].is() ) { + hpCost -= statusData["cost"].as(); } } - hpCost = member["max hp"].asFloat() * ( hpCost / 100.0f ); + hpCost = member["max hp"].as() * ( hpCost / 100.0f ); if ( mp < mpCost ) { - payload["message"] = "Not enough MP to use `"+colorString("FF0000") + ""+skillData["name"].asString()+""+colorString("FFFFFF") + "`."; + payload["message"] = "Not enough MP to use `"+colorString("FF0000") + ""+skillData["name"].as()+""+colorString("FFFFFF") + "`."; payload["timeout"] = 2.0f; if ( member["type"] != "enemy" ) { payload["invalid"] = true; } return payload; } else if ( mpCost > 0 ) { - metadata["battle"]["transients"][member["uid"].asString()]["mp"] = mp - mpCost; + metadata["battle"]["transients"][member["uid"].as()]["mp"] = mp - mpCost; } if ( hp < hpCost ) { - payload["message"] = "Not enough HP to use `"+colorString("FF0000") + ""+skillData["name"].asString()+""+colorString("FFFFFF") + "`."; + payload["message"] = "Not enough HP to use `"+colorString("FF0000") + ""+skillData["name"].as()+""+colorString("FFFFFF") + "`."; payload["timeout"] = 2.0f; if ( member["type"] != "enemy" ) { payload["invalid"] = true; @@ -960,7 +960,7 @@ void ext::HousamoBattle::initialize() { skillData = masterDataGet("Skill", skillId); } } else if ( hpCost > 0 ) { - metadata["battle"]["transients"][member["uid"].asString()]["hp"] = hp - hpCost; + metadata["battle"]["transients"][member["uid"].as()]["hp"] = hp - hpCost; { uf::Serializer payload; payload["uid"] = member["uid"]; @@ -971,28 +971,28 @@ void ext::HousamoBattle::initialize() { } } - if ( skillData["turns+"].isNumeric() ) { + if ( skillData["turns+"].is() ) { member["used skills"].append(skillId); - payload["message"] = payload["message"].asString() + "\nGained "+colorString("FF0000") + ""+skillData["turns+"].asString()+""+colorString("FFFFFF") + " additional turns!"; - metadata["battle"]["turn"]["counter"] = metadata["battle"]["turn"]["counter"].asFloat() + skillData["turns+"].asFloat(); + payload["message"] = payload["message"].as() + "\nGained "+colorString("FF0000") + ""+skillData["turns+"].as()+""+colorString("FFFFFF") + " additional turns!"; + metadata["battle"]["turn"]["counter"] = metadata["battle"]["turn"]["counter"].as() + skillData["turns+"].as(); } for ( auto& targetId : json["target"] ) { - uf::Serializer target = metadata["battle"]["transients"][targetId.asString()]; + uf::Serializer target = metadata["battle"]["transients"][targetId.as()]; float power = basePower; float morePower = 0; - float probability = skillData["proc"].isNumeric() ? skillData["proc"].asInt64() / 100.0f : 1.0f; + float probability = skillData["proc"].is() ? skillData["proc"].as() / 100.0f : 1.0f; // modify probability from statuses - for ( auto& status : metadata["battle"]["transients"][json["uid"].asString()]["statuses"] ) { - std::string statusId = status["id"].asString(); + for ( auto& status : metadata["battle"]["transients"][json["uid"].as()]["statuses"] ) { + std::string statusId = status["id"].as(); uf::Serializer statusData = masterDataGet("Status", statusId); for ( auto it = status["modifier"].begin(); it != status["modifier"].end(); ++it ) { - statusData[it.key().asString()] = *it; + statusData[it.key().as()] = *it; } - if ( !statusData["type"].isNull() && elementData["type"] != statusData["type"] ) continue; - if ( !statusData["attributes"].isNull() ) { + if ( !ext::json::isNull( statusData["type"] ) && elementData["type"] != statusData["type"] ) continue; + if ( !ext::json::isNull( statusData["attributes"] ) ) { bool found = false; for ( auto& value : statusData["attributes"] ) { if ( value == elementData["id"] ) found = true; @@ -1000,47 +1000,47 @@ void ext::HousamoBattle::initialize() { if ( !found ) continue; } - if ( statusData["proc+"].isNumeric() ) { - float moreProb = statusData["proc+"].asFloat() / 100.0f; + if ( statusData["proc+"].is() ) { + float moreProb = statusData["proc+"].as() / 100.0f; probability += moreProb; - payload["message"] = payload["message"].asString() + "\n"+colorString("FF00FF") + "" + std::to_string((int)(moreProb*100)) + "%"+colorString("FF0000") + " more probability"+colorString("FFFFFF") + ""; + payload["message"] = payload["message"].as() + "\n"+colorString("FF00FF") + "" + std::to_string((int)(moreProb*100)) + "%"+colorString("FF0000") + " more probability"+colorString("FFFFFF") + ""; } } // find attack modifying statuses on attacker - for ( auto& status : metadata["battle"]["transients"][json["uid"].asString()]["statuses"] ) { - std::string statusId = status["id"].asString(); + for ( auto& status : metadata["battle"]["transients"][json["uid"].as()]["statuses"] ) { + std::string statusId = status["id"].as(); uf::Serializer statusData = masterDataGet("Status", statusId); for ( auto it = status["modifier"].begin(); it != status["modifier"].end(); ++it ) { - statusData[it.key().asString()] = *it; + statusData[it.key().as()] = *it; } - if ( !statusData["type"].isNull() && elementData["type"] != statusData["type"] ) continue; - if ( !statusData["attributes"].isNull() ) { + if ( !ext::json::isNull( statusData["type"] ) && elementData["type"] != statusData["type"] ) continue; + if ( !ext::json::isNull( statusData["attributes"] ) ) { bool found = false; for ( auto& value : statusData["attributes"] ) { if ( value == elementData["id"] ) found = true; } if ( !found ) continue; } - if ( !statusData["ailments"].isNull() ) continue; + if ( !ext::json::isNull( statusData["ailments"] ) ) continue; - if ( statusData["power"].isNumeric() ) { - float adjust = statusData["power"].asFloat() / 100.0f; + if ( statusData["power"].is() ) { + float adjust = statusData["power"].as() / 100.0f; morePower += adjust; - // payload["message"] = payload["message"].asString() + "\n"+colorString("FF00FF") + "" + std::to_string((int)(adjust*100)) + "%"+colorString("FF0000") + " more power"+colorString("FFFFFF") + ""; + // payload["message"] = payload["message"].as() + "\n"+colorString("FF00FF") + "" + std::to_string((int)(adjust*100)) + "%"+colorString("FF0000") + " more power"+colorString("FFFFFF") + ""; } } // find defense modifying statuses on target - for ( auto& status : metadata["battle"]["transients"][targetId.asString()]["statuses"] ) { - std::string statusId = status["id"].asString(); + for ( auto& status : metadata["battle"]["transients"][targetId.as()]["statuses"] ) { + std::string statusId = status["id"].as(); uf::Serializer statusData = masterDataGet("Status", statusId); for ( auto it = status["modifier"].begin(); it != status["modifier"].end(); ++it ) { - statusData[it.key().asString()] = *it; + statusData[it.key().as()] = *it; } - if ( !statusData["type"].isNull() && elementData["type"] != statusData["type"] ) continue; - if ( !statusData["attributes"].isNull() ) { + if ( !ext::json::isNull( statusData["type"] ) && elementData["type"] != statusData["type"] ) continue; + if ( !ext::json::isNull( statusData["attributes"] ) ) { bool found = false; for ( auto& value : statusData["attributes"] ) { if ( value == elementData["id"] ) found = true; @@ -1048,13 +1048,13 @@ void ext::HousamoBattle::initialize() { if ( !found ) continue; } - if ( statusData["defense"].isNumeric() ) { - float adjust = statusData["defense"].asFloat() / 100.0f; + if ( statusData["defense"].is() ) { + float adjust = statusData["defense"].as() / 100.0f; morePower -= adjust; - // payload["message"] = payload["message"].asString() + "\n"+colorString("FF00FF") + "" + std::to_string((int)(adjust*100)) + "%"+colorString("FF0000") + " more defense"+colorString("FFFFFF") + ""; + // payload["message"] = payload["message"].as() + "\n"+colorString("FF00FF") + "" + std::to_string((int)(adjust*100)) + "%"+colorString("FF0000") + " more defense"+colorString("FFFFFF") + ""; } } - // if ( morePower != 0 ) payload["message"] = payload["message"].asString() + "\n"+colorString("FF00FF") + "" + std::to_string((int)(morePower*100)) + "%"+colorString("FF0000") + " power modifier"+colorString("FFFFFF") + ""; + // if ( morePower != 0 ) payload["message"] = payload["message"].as() + "\n"+colorString("FF00FF") + "" + std::to_string((int)(morePower*100)) + "%"+colorString("FF0000") + " power modifier"+colorString("FFFFFF") + ""; float r = (rand() % 100) / 100.0; // missed @@ -1069,18 +1069,18 @@ void ext::HousamoBattle::initialize() { bool repel = false; std::function affinityCheck = [&]( const std::string& targetId ) { auto& target = metadata["battle"]["transients"][targetId]; - uf::Serializer cardData = masterDataGet("Card", target["id"].asString()); + uf::Serializer cardData = masterDataGet("Card", target["id"].as()); uf::Serializer affinity = cardData["affinity"][elementId]; // affinity change check for ( auto& status : target["statuses"] ) { - std::string statusId = status["id"].asString(); + std::string statusId = status["id"].as(); uf::Serializer statusData = masterDataGet("Status", statusId); for ( auto it = status["modifier"].begin(); it != status["modifier"].end(); ++it ) { - statusData[it.key().asString()] = *it; + statusData[it.key().as()] = *it; } - if ( !statusData["type"].isNull() && elementData["type"] != statusData["type"] ) continue; - if ( !statusData["attributes"].isNull() ) { + if ( !ext::json::isNull( statusData["type"] ) && elementData["type"] != statusData["type"] ) continue; + if ( !ext::json::isNull( statusData["attributes"] ) ) { bool found = false; for ( auto& value : statusData["attributes"] ) { if ( value == elementData["id"] ) found = true; @@ -1088,21 +1088,21 @@ void ext::HousamoBattle::initialize() { if ( !found ) continue; } - if ( !statusData["affinity"].isNull() ) { - if ( !statusData["affinity"][elementId].isNull() ) affinity = statusData["affinity"][elementId]; - // payload["message"] = payload["message"].asString() + "\naffinity modifier."+colorString("FFFFFF") + ""; + if ( !ext::json::isNull( statusData["affinity"] ) ) { + if ( !ext::json::isNull( statusData["affinity"][elementId] ) ) affinity = statusData["affinity"][elementId]; + // payload["message"] = payload["message"].as() + "\naffinity modifier."+colorString("FFFFFF") + ""; } } - if ( !affinity.isNull() ) { - std::string affinityStr = affinity.asString(); + if ( !ext::json::isNull( affinity ) ) { + std::string affinityStr = affinity.as(); if ( repel && affinityStr == "repel" ) affinityStr = "null"; - if ( affinityStr == "weak" ) { payload["message"] = payload["message"].asString() + "\n"+colorString("FF0000") + "Weak!\n"; morePower *= 2.0f; } - else if ( affinityStr == "strong" ) { payload["message"] = payload["message"].asString() + "\n"+colorString("FF0000") + "Strong!\n"; morePower *= 0.5f; } - else if ( affinityStr == "drain" ) { turnEffects.endTurn = true; payload["message"] = payload["message"].asString() + "\n"+colorString("FF0000") + "Drain!\n"; morePower *= -1.0f; } - else if ( affinityStr == "null" ) { turnEffects.loseTurn = 2; payload["message"] = payload["message"].asString() + "\n"+colorString("FF0000") + "Nulled!\n"; morePower *= 0; } - else if ( affinityStr == "repel" ) { turnEffects.endTurn = true; payload["message"] = payload["message"].asString() + "\n"+colorString("FF0000") + "Repelled!\n"; repel = true; + if ( affinityStr == "weak" ) { payload["message"] = payload["message"].as() + "\n"+colorString("FF0000") + "Weak!\n"; morePower *= 2.0f; } + else if ( affinityStr == "strong" ) { payload["message"] = payload["message"].as() + "\n"+colorString("FF0000") + "Strong!\n"; morePower *= 0.5f; } + else if ( affinityStr == "drain" ) { turnEffects.endTurn = true; payload["message"] = payload["message"].as() + "\n"+colorString("FF0000") + "Drain!\n"; morePower *= -1.0f; } + else if ( affinityStr == "null" ) { turnEffects.loseTurn = 2; payload["message"] = payload["message"].as() + "\n"+colorString("FF0000") + "Nulled!\n"; morePower *= 0; } + else if ( affinityStr == "repel" ) { turnEffects.endTurn = true; payload["message"] = payload["message"].as() + "\n"+colorString("FF0000") + "Repelled!\n"; repel = true; // check again - affinityCheck(json["uid"].asString()); + affinityCheck(json["uid"].as()); } else { affinityStr = ""; } @@ -1114,7 +1114,7 @@ void ext::HousamoBattle::initialize() { showMessage( payload ); } } - }; affinityCheck(target["uid"].asString()); + }; affinityCheck(target["uid"].as()); power += morePower; @@ -1123,20 +1123,20 @@ void ext::HousamoBattle::initialize() { float calcDamage = 0.0f; // normal attack if ( elementData["type"] == "Physical" ) { - if ( skillData["hp%"].isNumeric() ) { + if ( skillData["hp%"].is() ) { // max hp * power - calcDamage = (member["max hp"].asFloat() * skillData["power"].asFloat() * 0.00114f ); + calcDamage = (member["max hp"].as() * skillData["power"].as() * 0.00114f ); } else { // ( lv + str ) * power / 15 - calcDamage = (member["lv"].asFloat() + member["str"].asFloat()) * skillData["power"].asFloat() / 15.0f; + calcDamage = (member["lv"].as() + member["str"].as()) * skillData["power"].as() / 15.0f; } } else if ( elementData["type"] == "Magic" ) { - if ( member["lv"].asFloat() < 30 ) { - calcDamage *= skillData["power"].asFloat() * member["lv"].asFloat() * ( 2 * member["mag"].asFloat() + 70.0f ) / 1000.0f; - } else if ( member["lv"].asFloat() < 160 ) { - calcDamage = 3.0f * skillData["power"].asFloat() * ( 2 * member["mag"].asFloat() + 70.0f - ( 0.4f * member["lv"].asFloat() ) ) / 100.0f; + if ( member["lv"].as() < 30 ) { + calcDamage *= skillData["power"].as() * member["lv"].as() * ( 2 * member["mag"].as() + 70.0f ) / 1000.0f; + } else if ( member["lv"].as() < 160 ) { + calcDamage = 3.0f * skillData["power"].as() * ( 2 * member["mag"].as() + 70.0f - ( 0.4f * member["lv"].as() ) ) / 100.0f; } else { - calcDamage = 3.0f * skillData["power"].asFloat() * ( 2 * member["mag"].asFloat() + 5 ) / 100.0f; + calcDamage = 3.0f * skillData["power"].as() * ( 2 * member["mag"].as() + 5 ) / 100.0f; } } else { std::cout << elementData << ": " << skillData << std::endl; @@ -1144,9 +1144,9 @@ void ext::HousamoBattle::initialize() { damage = (int) (calcDamage * power); } - if ( skillData["hits"].isArray() ) { - float low = skillData["hits"][0].asFloat(); - float high = skillData["hits"][1].asFloat(); + if ( ext::json::isArray( skillData["hits"] ) ) { + float low = skillData["hits"][0].as(); + float high = skillData["hits"][1].as(); int hits = low + r * (high - low); damage *= hits; } @@ -1160,9 +1160,9 @@ void ext::HousamoBattle::initialize() { bool critted = false; std::function applyDamage = [&]( const std::string& targetId ) { auto& target = metadata["battle"]["transients"][targetId]; - uf::Serializer cardData = masterDataGet("Card", target["id"].asString()); - uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); - int curHp = target["hp"].asFloat(); + uf::Serializer cardData = masterDataGet("Card", target["id"].as()); + uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].as()); + int curHp = target["hp"].as(); bool isCrit = ((rand() % 100) / 100.0) < 0.1; if ( damage == 0 ) isCrit = false; float oldDamage = damage; @@ -1173,14 +1173,14 @@ void ext::HousamoBattle::initialize() { // is a heal if ( elementId == "14" ) { - float power = skillData["power"].asFloat() / 100.0f * (morePower == 0 ? 1 : morePower); - std::cout << target["max hp"].asFloat() << ", " << power << std::endl; - damage = -1 * std::abs(target["max hp"].asFloat() * power); + float power = skillData["power"].as() / 100.0f * (morePower == 0 ? 1 : morePower); + std::cout << target["max hp"].as() << ", " << power << std::endl; + damage = -1 * std::abs(target["max hp"].as() * power); } if ( instakill ) damage = curHp; target["hp"] = (int) (curHp -= damage); - if ( target["hp"].asFloat() > target["max hp"].asFloat() ) target["hp"] = target["max hp"].asFloat(); + if ( target["hp"].as() > target["max hp"].as() ) target["hp"] = target["max hp"].as(); std::cout << power << ", " << damage << ", " << morePower << (isCrit ? " / crit" : "") << std::endl; @@ -1194,12 +1194,12 @@ void ext::HousamoBattle::initialize() { payload["color"] = "FF0000"; payload["message"] = (int) damage; - if ( skillData["drains"].asBool() ) { - float ratio = damage / target["max hp"].asFloat(); - int mpDrain = target["max mp"].asFloat() * ratio; - if ( target["mp"].asFloat() > mpDrain ) mpDrain = target["mp"].asFloat(); - target["mp"] = target["mp"].asFloat() - mpDrain; - payload["message"] = payload["message"].asString() + "\n " + colorString("0000FF") + std::to_string(mpDrain); + if ( skillData["drains"].as() ) { + float ratio = damage / target["max hp"].as(); + int mpDrain = target["max mp"].as() * ratio; + if ( target["mp"].as() > mpDrain ) mpDrain = target["mp"].as(); + target["mp"] = target["mp"].as() - mpDrain; + payload["message"] = payload["message"].as() + "\n " + colorString("0000FF") + std::to_string(mpDrain); showMessage( payload ); @@ -1217,7 +1217,7 @@ void ext::HousamoBattle::initialize() { damage = oldDamage; if ( curHp <= 0 ) { - payload["message"] = payload["message"].asString() + "\n"+colorString("FF0000") + ""+ charaData["name"].asString() +" "+colorString("FFFFFF") + "died!"; + payload["message"] = payload["message"].as() + "\n"+colorString("FF0000") + ""+ charaData["name"].as() +" "+colorString("FFFFFF") + "died!"; target["hp"] = 0; uf::Serializer statusPayload; @@ -1225,30 +1225,30 @@ void ext::HousamoBattle::initialize() { target["statuses"] = Json::arrayValue; target["statuses"].append(statusPayload); } - }; applyDamage(repel ? json["uid"].asString() : target["uid"].asString()); + }; applyDamage(repel ? json["uid"].as() : target["uid"].as()); // counter statuses if ( !repel ) { - for ( auto& status : metadata["battle"]["transients"][target["uid"].asString()]["statuses"] ) { - std::string statusId = status["id"].asString(); + for ( auto& status : metadata["battle"]["transients"][target["uid"].as()]["statuses"] ) { + std::string statusId = status["id"].as(); if ( statusId != "19" ) continue; uf::Serializer statusData = masterDataGet("Status", statusId); for ( auto it = status["modifier"].begin(); it != status["modifier"].end(); ++it ) { - statusData[it.key().asString()] = *it; + statusData[it.key().as()] = *it; } - if ( !statusData["type"].isNull() && elementData["type"] != statusData["type"] ) continue; - if ( !statusData["attributes"].isNull() ) { + if ( !ext::json::isNull( statusData["type"] ) && elementData["type"] != statusData["type"] ) continue; + if ( !ext::json::isNull( statusData["attributes"] ) ) { bool found = false; for ( auto& value : statusData["attributes"] ) { if ( value == elementData["id"] ) found = true; } if ( !found ) continue; } - if ( statusData["proc"].isNumeric() ) { + if ( statusData["proc"].is() ) { float r = (rand() % 100) / 100.0; - if ( r <= statusData["proc"].asFloat() / 100.0f ) { - applyDamage(json["uid"].asString()); - payload["message"] = payload["message"].asString() + "\nCountered!"; + if ( r <= statusData["proc"].as() / 100.0f ) { + applyDamage(json["uid"].as()); + payload["message"] = payload["message"].as() + "\nCountered!"; } } } @@ -1256,33 +1256,33 @@ void ext::HousamoBattle::initialize() { // apply status { for ( auto& status : skillData["statuses"] ) { - std::string target = status["target"].asString(); - std::string statusId = status["id"].asString(); + std::string target = status["target"].as(); + std::string statusId = status["id"].as(); uf::Serializer statusData = masterDataGet("Status", statusId); - if ( skillData["type"].asInt64() == 16 ) continue; + if ( skillData["type"].as() == 16 ) continue; float r = (rand() % 100) / 100.0; if ( repel ) { if ( target == "enemy" ) target = "self"; else target = ""; } - if ( statusData["proc"].isNumeric() ) { + if ( statusData["proc"].is() ) { // failed - if ( r > statusData["proc"].asFloat() / 100.0f ) { + if ( r > statusData["proc"].as() / 100.0f ) { target = ""; } } uf::Serializer targets; if ( target == "self" ) { - targets.append(json["uid"].asString()); + targets.append(json["uid"].as()); // } else if ( target == "enemy" || target == "ally" ) { } else { - targets.append(targetId.asString()); + targets.append(targetId.as()); } for ( auto& target : targets ) { // remove status(es) if ( status["type"] == "remove" ) { - for ( auto& statusC : metadata["battle"]["transients"][target.asString()]["statuses"] ) { + for ( auto& statusC : metadata["battle"]["transients"][target.as()]["statuses"] ) { if ( statusC["id"] == statusId ) { statusC = Json::nullValue; statusC["id"] = 0; @@ -1296,21 +1296,21 @@ void ext::HousamoBattle::initialize() { statusPayload["id"] = statusId; statusPayload["modifier"] = status["modifier"]; - statusPayload["turns"] = status["turns"].isNumeric() ? status["turns"] : statusData["turns"]; - metadata["battle"]["transients"][target.asString()]["statuses"].append(statusPayload); + statusPayload["turns"] = status["turns"].is() ? status["turns"] : statusData["turns"]; + metadata["battle"]["transients"][target.as()]["statuses"].append(statusPayload); for ( auto it = status["modifier"].begin(); it != status["modifier"].end(); ++it ) { - statusData[it.key().asString()] = *it; + statusData[it.key().as()] = *it; } - uf::Serializer cardData = masterDataGet( "Card", metadata["battle"]["transients"][target.asString()]["id"].asString() ); - uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); + uf::Serializer cardData = masterDataGet( "Card", metadata["battle"]["transients"][target.as()]["id"].as() ); + uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].as()); - // payload["message"] = payload["message"].asString() + "\nApplied "+colorString("FF0000") + "" + statusData["name"].asString() + ""+colorString("FFFFFF") + " to " + charaData["name"].asString(); + // payload["message"] = payload["message"].as() + "\nApplied "+colorString("FF0000") + "" + statusData["name"].as() + ""+colorString("FFFFFF") + " to " + charaData["name"].as(); { uf::Serializer payload; payload["uid"] = targetId; - payload["message"] = skillData["name"].asString(); + payload["message"] = skillData["name"].as(); payload["color"] = "9900FF"; showMessage( payload ); } @@ -1322,9 +1322,9 @@ void ext::HousamoBattle::initialize() { float r = (rand() % 100) / 100.0; // if ( r < 0.5 ) { if ( r < 1.0 ) { - playSound(*this, member["id"].asString(), r > 0.25 ? "attack" : "skill"); + playSound(*this, member["id"].as(), r > 0.25 ? "attack" : "skill"); } else { - playSound(*this, target["id"].asString(), r > 0.75 ? "damagedsmall" : "damagedlarge"); + playSound(*this, target["id"].as(), r > 0.75 ? "damagedsmall" : "damagedlarge"); } for ( int i = 0; i < 16; ++i ) { uf::Serializer payload; @@ -1342,10 +1342,10 @@ void ext::HousamoBattle::initialize() { } /* heal self */ - if ( skillData["add hp"].isNumeric() ) { - int heal = skillData["add hp"].asFloat() / 100.0f * member["max hp"].asFloat(); - if ( heal + member["hp"].asFloat() >= member["max hp"].asFloat() ) heal = member["max hp"].asFloat() - member["hp"].asFloat(); - member["hp"] = member["hp"].asFloat() + heal; + if ( skillData["add hp"].is() ) { + int heal = skillData["add hp"].as() / 100.0f * member["max hp"].as(); + if ( heal + member["hp"].as() >= member["max hp"].as() ) heal = member["max hp"].as() - member["hp"].as(); + member["hp"] = member["hp"].as() + heal; uf::Serializer payload; payload["uid"] = member["uid"]; @@ -1360,8 +1360,8 @@ void ext::HousamoBattle::initialize() { } if ( turnEffects.loseTurn > 0 ) { auto& turnState = metadata["battle"]["turn"]; - float decrement = turnState["decrement"].asFloat(); - turnState["counter"] = turnState["counter"].asFloat() - turnEffects.loseTurn; + float decrement = turnState["decrement"].as(); + turnState["counter"] = turnState["counter"].as() - turnEffects.loseTurn; turnState["decrement"] = 0; } @@ -1374,50 +1374,50 @@ void ext::HousamoBattle::initialize() { }); this->addHook( "world:Battle.Get.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - auto& member = metadata["battle"]["transients"][json["uid"].asString()]; + auto& member = metadata["battle"]["transients"][json["uid"].as()]; /* ext::Housamo* transient = transients.at(uid); uf::Serializer& member = transient->getComponent(); */ std::string message; - uf::Serializer cardData = masterDataGet("Card", member["id"].asString()); - uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); + uf::Serializer cardData = masterDataGet("Card", member["id"].as()); + uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].as()); uf::Serializer affinity = cardData["affinity"]; - std::string name = charaData["name"].asString(); + std::string name = charaData["name"].as(); if ( member["type"] == "player" ) message += colorString("00FF00"); else if ( member["type"] == "enemy" ) message += colorString("FF0000"); else message += colorString("AAAAAA"); - message += name + colorString("FFFFFF") + ": " + member["type"].asString(); + message += name + colorString("FFFFFF") + ": " + member["type"].as(); - message += "\n" + colorString("FF0000") + "HP: " + member["hp"].asString(); - message += "\n" + colorString("0000FF") + "MP: " + member["mp"].asString(); + message += "\n" + colorString("FF0000") + "HP: " + member["hp"].as(); + message += "\n" + colorString("0000FF") + "MP: " + member["mp"].as(); message += "\n" + colorString("9900FF") + "Ailments" + colorString("FFFFFF") + ":"; for ( auto& status : member["statuses"] ) { - std::string statusId = status["id"].asString(); + std::string statusId = status["id"].as(); uf::Serializer statusData = masterDataGet("Status", statusId); for ( auto it = status["modifier"].begin(); it != status["modifier"].end(); ++it ) { - statusData[it.key().asString()] = *it; + statusData[it.key().as()] = *it; } if ( statusId == "0" ) continue; // affinity change check for ( auto it = statusData["affinity"].begin(); it != statusData["affinity"].end(); ++it ) { - affinity[it.key().asString()] = *it; + affinity[it.key().as()] = *it; } - message += "\n\t" + statusData["name"].asString() + (status["turns"].isNull() ? "" : " (Turns: " + status["turns"].asString() + ")" ); + message += "\n\t" + statusData["name"].as() + (ext::json::isNull( status["turns"] ) ? "" : " (Turns: " + status["turns"].as() + ")" ); } message += "\n" + colorString("9900FF") + "Affinities" + colorString("FFFFFF") + ":"; for ( auto it = affinity.begin(); it != affinity.end(); ++it ) { - std::string elementId = it.key().asString(); + std::string elementId = it.key().as(); std::string value = it->asString(); uf::Serializer elementData = masterDataGet("Element", elementId); - message += "\n\t" + elementData["name"].asString() + ": " + value; + message += "\n\t" + elementData["name"].as() + ": " + value; } uf::Serializer payload; @@ -1445,13 +1445,13 @@ void ext::HousamoBattle::initialize() { } transients.clear(); - if ( json["won"].asBool() ) { + if ( json["won"].as() ) { // play death sound - // playSound(*this, metadata["battle"]["enemy"]["uid"].asUInt64(), "killed"); + // playSound(*this, metadata["battle"]["enemy"]["uid"].as(), "killed"); // kill { uf::Scene& scene = uf::scene::getCurrentScene(); - std::size_t uid = metadata["battle"]["enemy"]["uid"].asUInt64(); + std::size_t uid = metadata["battle"]["enemy"]["uid"].as(); uf::Entity* = scene.findByUid(uid); if ( ) { uf::Object& parent = ->getParent(); @@ -1471,13 +1471,13 @@ void ext::HousamoBattle::initialize() { payload["end"] = true; return payload; /* - if ( json["action"].asString() == "killed" ) { + if ( json["action"].as() == "killed" ) { // play death sound - playSound(*this, metadata["battle"]["enemy"]["uid"].asUInt64(), "killed"); + playSound(*this, metadata["battle"]["enemy"]["uid"].as(), "killed"); // kill { uf::Scene& scene = uf::scene::getCurrentScene(); - std::size_t uid = metadata["battle"]["enemy"]["uid"].asUInt64(); + std::size_t uid = metadata["battle"]["enemy"]["uid"].as(); uf::Entity* = scene.findByUid(uid); if ( ) { uf::Object& parent = ->getParent(); @@ -1490,7 +1490,7 @@ void ext::HousamoBattle::initialize() { // clear battle data on player { uf::Scene& scene = uf::scene::getCurrentScene(); - std::size_t uid = metadata["battle"]["player"]["uid"].asUInt64(); + std::size_t uid = metadata["battle"]["player"]["uid"].as(); uf::Entity* = scene.findByUid(uid); if ( ) { uf::Serializer& pMetadata = ->getComponent(); diff --git a/ext/scenes/worldscape/housamo/dialogue.cpp b/ext/scenes/worldscape/housamo/dialogue.cpp index 8cb37005..4c7ff828 100644 --- a/ext/scenes/worldscape/housamo/dialogue.cpp +++ b/ext/scenes/worldscape/housamo/dialogue.cpp @@ -43,13 +43,13 @@ namespace { uf::Serializer& masterdata = scene.getComponent(); uf::Serializer cardData = masterDataGet("Card", id); - uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].asString()); - std::string name = charaData["filename"].asString(); + uf::Serializer charaData = masterDataGet("Chara", cardData["character_id"].as()); + std::string name = charaData["filename"].as(); std::string url = "https://cdn..xyz//unity/Android/voice/voice_" + name + "_"+key+".ogg"; std::cout << url << std::endl; - if ( charaData["internal"].asBool() ) { + if ( charaData["internal"].as() ) { url = "./data/smtsamo/voice/voice_" + name + "_" + key + ".ogg"; } @@ -64,7 +64,7 @@ namespace { uf::Entity* = scene.findByUid(uid); if ( ! ) return; uf::Serializer& metadata = ->getComponent(); - std::string id = metadata[""]["id"].asString(); + std::string id = metadata[""]["id"].as(); playSound( entity, id, key ); } void playSound( ext::DialogueManager& entity, const std::string& key ) { @@ -107,7 +107,7 @@ void ext::DialogueManager::initialize() { uf::Serializer& metadata = this->getComponent(); uf::Serializer& masterdata = scene.getComponent(); - std::string filename = json["filename"].asString(); + std::string filename = json["filename"].as(); if ( uf::io::extension(filename) != "ogg" ) return "false"; @@ -115,7 +115,7 @@ void ext::DialogueManager::initialize() { if ( voice.playing() ) voice.stop(); voice = uf::Audio(); voice.load(filename); - voice.setVolume(masterdata["volumes"]["voice"].asFloat()); + voice.setVolume(masterdata["volumes"]["voice"].as()); voice.play(); return "true"; @@ -126,7 +126,7 @@ void ext::DialogueManager::initialize() { uf::Scene& scene = uf::scene::getCurrentScene(); uf::Serializer& masterdata = scene.getComponent(); - std::string filename = json["filename"].asString(); + std::string filename = json["filename"].as(); if ( uf::io::extension(filename) != "ogg" ) return "false"; @@ -134,24 +134,24 @@ void ext::DialogueManager::initialize() { if ( sfx.playing() ) sfx.stop(); sfx = uf::Audio(); sfx.load(filename); - sfx.setVolume(masterdata["volumes"]["sfx"].asFloat()); + sfx.setVolume(masterdata["volumes"]["sfx"].as()); sfx.play(); return "true"; }); this->addHook( "asset:Music.Load.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - if ( json["music"].isString() ) playMusic(*this, json["music"].asString()); + if ( json["music"].is() ) playMusic(*this, json["music"].as()); return "true"; }); this->addHook( "asset:Sfx.Load.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - if ( json["sfx"].isString() ) playSound(*this, json["sfx"].asString()); + if ( json["sfx"].is() ) playSound(*this, json["sfx"].as()); return "true"; }); this->addHook( "asset:Voice.Load.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - if ( json["voice"].isObject() ) playSound(*this, json["voice"]["id"].asString(), json["voice"]["key"].asString()); + if ( ext::json::isObject( json["voice"] ) ) playSound(*this, json["voice"]["id"].as(), json["voice"]["key"].as()); return "true"; }); @@ -196,7 +196,7 @@ void ext::DialogueManager::initialize() { std::string hookName = ""; uf::Serializer payload; - std::string action = json["action"].asString(); + std::string action = json["action"].as(); if ( action == "dialogue-select" ) { payload = json; @@ -217,32 +217,32 @@ void ext::DialogueManager::initialize() { uf::Serializer json = event; uf::Serializer payload; - std::string index = json["index"].asString(); + std::string index = json["index"].as(); uf::Serializer part = metadata["dialogue"][index]; - if ( part["quit"].asBool() ) return this->callHook("menu:Dialogue.End.%UID%")[0]; + if ( part["quit"].as() ) return this->callHook("menu:Dialogue.End.%UID%")[0]; payload["message"] = part["message"]; payload["actions"] = part["actions"]; - if ( part["music"].isString() ) { + if ( part["music"].is() ) { uf::Serializer pload; pload["music"] = part["music"]; this->queueHook( "asset:Music.Load.%UID%", pload ); } - if ( part["sfx"].isString() ) { + if ( part["sfx"].is() ) { uf::Serializer pload; pload["sfx"] = part["sfx"]; this->queueHook( "asset:Sfx.Load.%UID%", pload ); } - if ( part["voice"].isObject() ) { + if ( ext::json::isObject( part["voice"] ) ) { uf::Serializer pload; pload["voice"] = part["voice"]; this->queueHook( "asset:Voice.Load.%UID%", pload ); } - if ( part["hook"].isObject() ) { + if ( ext::json::isObject( part["hook"] ) ) { part["hooks"].append( part["hook"] ); } for ( auto hook : part["hooks"] ) { hook["payload"]["uid"] = metadata["uid"]; - this->queueHook( hook["name"].asString(), uf::Serializer{hook["payload"]}, hook["timeout"].asFloat() ); + this->queueHook( hook["name"].as(), uf::Serializer{hook["payload"]}, hook["timeout"].as() ); } return payload; }); diff --git a/ext/scenes/worldscape/housamo/housamo.cpp b/ext/scenes/worldscape/housamo/housamo.cpp index 67901bfb..1d15ffb2 100644 --- a/ext/scenes/worldscape/housamo/housamo.cpp +++ b/ext/scenes/worldscape/housamo/housamo.cpp @@ -38,58 +38,58 @@ void ext::Housamo::initialize() { * "skin": "skin1" }, */ - std::string id = metadata[""]["id"].asString(); - uint64_t lv = !metadata[""]["level"].isNull() ? parseInt(metadata[""]["level"].asString()) : parseInt(metadata[""]["lv"].asString()); - uint64_t sl = !metadata[""]["skill level"].isNull() ? parseInt(metadata[""]["skill level"].asString()) : parseInt(metadata[""]["sl"].asString()); - uint64_t jingi = parseInt(metadata[""]["jingi"].asString()); - uint64_t limit = parseInt(metadata[""]["limit"].asString()); - uint64_t str = parseInt(metadata[""]["str"].asString()); - uint64_t mag = parseInt(metadata[""]["mag"].asString()); - uint64_t vit = parseInt(metadata[""]["vit"].asString()); - uint64_t agi = parseInt(metadata[""]["agi"].asString()); - int64_t hp = metadata[""]["hp"].isNull() ? -1 : parseInt(metadata[""]["hp"].asString()); - int64_t mp = metadata[""]["mp"].isNull() ? -1 : parseInt(metadata[""]["mp"].asString()); + std::string id = metadata[""]["id"].as(); + uint64_t lv = !ext::json::isNull( metadata[""]["level"] ) ? parseInt(metadata[""]["level"].as()) : parseInt(metadata[""]["lv"].as()); + uint64_t sl = !ext::json::isNull( metadata[""]["skill level"] ) ? parseInt(metadata[""]["skill level"].as()) : parseInt(metadata[""]["sl"].as()); + uint64_t jingi = parseInt(metadata[""]["jingi"].as()); + uint64_t limit = parseInt(metadata[""]["limit"].as()); + uint64_t str = parseInt(metadata[""]["str"].as()); + uint64_t mag = parseInt(metadata[""]["mag"].as()); + uint64_t vit = parseInt(metadata[""]["vit"].as()); + uint64_t agi = parseInt(metadata[""]["agi"].as()); + int64_t hp = ext::json::isNull( metadata[""]["hp"] ) ? -1 : parseInt(metadata[""]["hp"].as()); + int64_t mp = ext::json::isNull( metadata[""]["mp"] ) ? -1 : parseInt(metadata[""]["mp"].as()); std::vector skills; for ( auto i = 0; i < metadata[""]["skills"].size(); ++i ) { - skills.push_back(metadata[""]["skills"][i].asString()); + skills.push_back(metadata[""]["skills"][i].as()); } uf::Serializer cardData = masterDataGet("Card",id); /* { - uint64_t base = parseInt(cardData["base_hp"].asString()); - uint64_t max = parseInt(cardData["max_hp"].asString()); - uint64_t maxlv = parseInt(cardData["max_lv"].asString()); + uint64_t base = parseInt(cardData["base_hp"].as()); + uint64_t max = parseInt(cardData["max_hp"].as()); + uint64_t maxlv = parseInt(cardData["max_lv"].as()); max_hp += ( (max - base) * (lv - 1) / (maxlv - 1) ) + base; max_hp /= 20.0f; } { - uint64_t base = parseInt(cardData["base_mp"].asString()); - uint64_t max = parseInt(cardData["max_mp"].asString()); - uint64_t maxlv = parseInt(cardData["max_lv"].asString()); + uint64_t base = parseInt(cardData["base_mp"].as()); + uint64_t max = parseInt(cardData["max_mp"].as()); + uint64_t maxlv = parseInt(cardData["max_lv"].as()); max_mp += ( (max - base) * (lv - 1) / (maxlv - 1) ) + base; } */ { float scale = 3.0f; if ( str == 0 ) { - uint64_t base = parseInt(cardData["base_atk"].asString()); - uint64_t max = parseInt(cardData["max_atk"].asString()); - uint64_t maxlv = parseInt(cardData["max_lv"].asString()); + uint64_t base = parseInt(cardData["base_atk"].as()); + uint64_t max = parseInt(cardData["max_atk"].as()); + uint64_t maxlv = parseInt(cardData["max_lv"].as()); str = ( (max - base) * (lv - 1) / (maxlv - 1) ) + base; str /= scale * 100.0f; } if ( mag == 0 ) { - uint64_t base = parseInt(cardData["base_atk"].asString()); - uint64_t max = parseInt(cardData["max_atk"].asString()); - uint64_t maxlv = parseInt(cardData["max_lv"].asString()); + uint64_t base = parseInt(cardData["base_atk"].as()); + uint64_t max = parseInt(cardData["max_atk"].as()); + uint64_t maxlv = parseInt(cardData["max_lv"].as()); mag = ( (max - base) * (lv - 1) / (maxlv - 1) ) + base; mag /= scale * 100.0f; } if ( vit == 0 ) { - uint64_t base = parseInt(cardData["base_hp"].asString()); - uint64_t max = parseInt(cardData["max_hp"].asString()); - uint64_t maxlv = parseInt(cardData["max_lv"].asString()); + uint64_t base = parseInt(cardData["base_hp"].as()); + uint64_t max = parseInt(cardData["max_hp"].as()); + uint64_t maxlv = parseInt(cardData["max_lv"].as()); vit = ( (max - base) * (lv - 1) / (maxlv - 1) ) + base; vit /= scale * 100.0f; } @@ -97,14 +97,14 @@ void ext::Housamo::initialize() { uint64_t max_hp = (lv + vit) * 6; uint64_t max_mp = (mag + lv) * 3; - if ( metadata[""]["max hp"].isNumeric() ) max_hp = parseInt(metadata[""]["max hp"].asString()); - if ( metadata[""]["max mp"].isNumeric() ) max_mp = parseInt(metadata[""]["max mp"].asString()); + if ( metadata[""]["max hp"].is() ) max_hp = parseInt(metadata[""]["max hp"].as()); + if ( metadata[""]["max mp"].is() ) max_mp = parseInt(metadata[""]["max mp"].as()); if ( hp == -1 ) hp = max_hp; if ( mp == -1 ) mp = max_mp; if ( limit == 0 ) { uint64_t baseL0 = 0; - switch ( parseInt(cardData["rarity"].asString() ) ) { + switch ( parseInt(cardData["rarity"].as() ) ) { case 1: baseL0 = 20; break; case 2: baseL0 = 25; break; case 3: baseL0 = 30; break; @@ -119,9 +119,9 @@ void ext::Housamo::initialize() { // populate skills based on masterdata if ( skills.empty() ) { for ( auto i = 0; i < cardData["skill_id"].size(); ++i ) { - int learn = cardData["skill_learn_lv"][i].asInt(); + int learn = cardData["skill_learn_lv"][i].as(); if ( lv < learn ) break; - skills.push_back(cardData["skill_id"][i].asString()); + skills.push_back(cardData["skill_id"][i].as()); } } diff --git a/ext/scenes/worldscape/terrain/behavior.cpp b/ext/scenes/worldscape/terrain/behavior.cpp index ed22202d..83f9be2d 100644 --- a/ext/scenes/worldscape/terrain/behavior.cpp +++ b/ext/scenes/worldscape/terrain/behavior.cpp @@ -21,7 +21,7 @@ #include -EXT_BEHAVIOR_ENTITY_CPP_BEGIN(Terrain) +UF_BEHAVIOR_ENTITY_CPP_BEGIN(ext::Terrain) #define this ((ext::Terrain*) &self) void ext::TerrainBehavior::initialize( uf::Object& self ) { // alias Mesh types @@ -29,9 +29,9 @@ void ext::TerrainBehavior::initialize( uf::Object& self ) { std::size_t seed = 0; if ( metadata["terrain"]["seed"].isUInt64() ) { - seed = metadata["terrain"]["seed"].asUInt64(); - } else if ( metadata["terrain"]["seed"].isString() ) { - seed = std::hash{}( metadata["terrain"]["seed"].asString() ); + seed = metadata["terrain"]["seed"].as(); + } else if ( metadata["terrain"]["seed"].is() ) { + seed = std::hash{}( metadata["terrain"]["seed"].as() ); } { std::cout << "Seed: " << seed << std::endl; @@ -48,13 +48,13 @@ void ext::TerrainBehavior::initialize( uf::Object& self ) { metadata["system"]["hash"] = uf::string::sha256( input ); try { - std::string save = "./data/save/" + metadata["system"]["hash"].asString() + "/"; + std::string save = "./data/save/" + metadata["system"]["hash"].as() + "/"; int status = mkdir(save.c_str()); } catch ( ... ) { } try { - std::string save = "./data/save/" + metadata["system"]["hash"].asString() + "/regions/"; + std::string save = "./data/save/" + metadata["system"]["hash"].as() + "/regions/"; int status = mkdir(save.c_str()); } catch ( ... ) { @@ -74,8 +74,8 @@ void ext::TerrainBehavior::initialize( uf::Object& self ) { metadata["system"]["modified"] = true; this->addHook( "system:TickRate.Restore", [&](const std::string& event)->std::string{ - std::cout << "Returning limiter from " << uf::thread::limiter << " to " << metadata["system"]["limiter"].asFloat() << std::endl; - uf::thread::limiter = metadata["system"]["limiter"].asFloat(); + std::cout << "Returning limiter from " << uf::thread::limiter << " to " << metadata["system"]["limiter"].as() << std::endl; + uf::thread::limiter = metadata["system"]["limiter"].as(); return "true"; }); this->addHook( "terrain:GenerateMesh.%UID%", [&](const std::string& event)->std::string{ @@ -93,12 +93,12 @@ void ext::TerrainBehavior::initialize( uf::Object& self ) { return "true"; }); this->addHook( "terrain:Post-Initialize.%UID%", [&](const std::string& event)->std::string{ - if ( metadata["terrain"]["unified"].asBool() ) { + if ( metadata["terrain"]["unified"].as() ) { std::string textureFilename = ""; { uf::Asset assetLoader; for ( uint i = 0; i < metadata["system"]["assets"].size(); ++i ) { if ( textureFilename != "" ) break; - std::string filename = this->grabURI( metadata["system"]["assets"][i].asString(), metadata["system"]["root"].asString() ); + std::string filename = this->grabURI( metadata["system"]["assets"][i].as(), metadata["system"]["root"].as() ); textureFilename = assetLoader.cache( filename ); } } @@ -113,7 +113,7 @@ void ext::TerrainBehavior::initialize( uf::Object& self ) { texture.loadFromFile( textureFilename ); std::string suffix = ""; { - std::string _ = this->getRootParent().getComponent()["shaders"]["region"]["suffix"].asString(); + std::string _ = this->getRootParent().getComponent()["shaders"]["region"]["suffix"].as(); if ( _ != "" ) suffix = _ + "."; } graphic.material.initializeShaders({ @@ -141,18 +141,18 @@ void ext::TerrainBehavior::tick( uf::Object& self ) { auto transitionState = [&]( ext::Terrain& that, const std::string& next, bool unresolved ){ uf::Serializer& metadata = that.getComponent(); // uf::thread::add( mainThread, [&]() -> int { - // std::cout << "Transitioning: " << metadata["system"]["state"].asString() << " -> "; + // std::cout << "Transitioning: " << metadata["system"]["state"].as() << " -> "; metadata["system"]["state"] = unresolved ? next : "open"; metadata["system"]["modified"] = unresolved; - // std::cout << metadata["system"]["state"].asString() << std::endl; + // std::cout << metadata["system"]["state"].as() << std::endl; // return 0;}, true ); }; // lambda to transition into a resolving state auto transitionResolvingState = [&]( ext::Terrain& that ){ uf::Serializer& metadata = that.getComponent(); - // std::cout << "Resolving: " << metadata["system"]["state"].asString() << " -> "; - metadata["system"]["state"] = "resolving:" + metadata["system"]["state"].asString(); - // std::cout << metadata["system"]["state"].asString() << std::endl; + // std::cout << "Resolving: " << metadata["system"]["state"].as() << " -> "; + metadata["system"]["state"] = "resolving:" + metadata["system"]["state"].as(); + // std::cout << metadata["system"]["state"].as() << std::endl; }; // lambda for sorting regions, nearest to farthest, from the controller auto sortRegions = [&]( uf::Object& controller, std::vector& regions ){ @@ -191,16 +191,16 @@ void ext::TerrainBehavior::tick( uf::Object& self ) { for ( uf::Entity* region : this->getChildren() ) { if ( !region || region->getName() != "Region" ) continue; const pod::Transform<>& transform = region->getComponent>(); pod::Vector3i location = { - (int) transform.position.x / metadata["region"]["size"][0].asInt(), - (int) transform.position.y / metadata["region"]["size"][1].asInt(), - (int) transform.position.z / metadata["region"]["size"][2].asInt() + (int) transform.position.x / metadata["region"]["size"][0].as(), + (int) transform.position.y / metadata["region"]["size"][1].as(), + (int) transform.position.z / metadata["region"]["size"][2].as() }; // location too far bool degenerate = !this->inBounds( location ); // keep if an entity requests for it for ( uf::Entity* entity : region->getChildren() ) { if ( !entity ) continue; uf::Serializer& metadata = entity->getComponent(); - if ( metadata["region"].isObject() && metadata["region"]["persist"].asBool() ) { + if ( ext::json::isObject( metadata["region"] ) && metadata["region"]["persist"].as() ) { degenerate = false; break; } @@ -225,20 +225,20 @@ void ext::TerrainBehavior::tick( uf::Object& self ) { // retrieve changed regions for ( uf::Entity* region : this->getChildren() ) { if ( !region ) continue; uf::Serializer& metadata = region->getComponent(); - // if ( metadata["region"]["location"].isObject() ) + // if ( ext::json::isObject( metadata["region"]["location"] ) ) regions.push_back((uf::Object*) region); } // sort by closest to farthest sortRegions(controller, regions); - if ( metadata["terrain"]["unified"].asBool() ) { + if ( metadata["terrain"]["unified"].as() ) { auto& graphic = this->getComponent(); auto& mesh = this->getComponent(); mesh.destroy(); for ( uf::Object* region : regions ) { uf::Serializer& metadata = region->getComponent(); - if ( !metadata["region"]["initialized"].asBool() ) region->initialize(); - if ( !metadata["region"]["generated"].asBool() ) region->callHook("region:Generate.%UID%", ""); - if ( !metadata["region"]["rasterized"].asBool() ) { + if ( !metadata["region"]["initialized"].as() ) region->initialize(); + if ( !metadata["region"]["generated"].as() ) region->callHook("region:Generate.%UID%", ""); + if ( !metadata["region"]["rasterized"].as() ) { region->queueHook("region:Finalize.%UID%", ""); region->queueHook("region:Populate.%UID%", ""); } @@ -251,9 +251,9 @@ void ext::TerrainBehavior::tick( uf::Object& self ) { for ( uf::Object* region : regions ) { // uf::thread::add( uf::thread::fetchWorker(), [&]() -> int { uf::Serializer& metadata = region->getComponent(); - if ( !metadata["region"]["initialized"].asBool() ) region->initialize(); - if ( !metadata["region"]["generated"].asBool() ) region->callHook("region:Generate.%UID%", ""); - if ( !metadata["region"]["rasterized"].asBool() ) region->callHook("region:Rasterize.%UID%", ""); + if ( !metadata["region"]["initialized"].as() ) region->initialize(); + if ( !metadata["region"]["generated"].as() ) region->callHook("region:Generate.%UID%", ""); + if ( !metadata["region"]["rasterized"].as() ) region->callHook("region:Rasterize.%UID%", ""); // return 0;}, true ); } } @@ -269,7 +269,7 @@ void ext::TerrainBehavior::render( uf::Object& self ){ uf::Scene& scene = uf::scene::getCurrentScene(); uf::Serializer& metadata = this->getComponent(); - if ( !metadata["terrain"]["unified"].asBool() ) return; + if ( !metadata["terrain"]["unified"].as() ) return; /* Update uniforms */ if ( this->hasComponent() ) { auto& scene = uf::scene::getCurrentScene(); auto& graphic = this->getComponent(); @@ -286,4 +286,4 @@ void ext::TerrainBehavior::render( uf::Object& self ){ } void ext::TerrainBehavior::destroy( uf::Object& self ){} #undef this -EXT_BEHAVIOR_ENTITY_CPP_END(Terrain) \ No newline at end of file +UF_BEHAVIOR_ENTITY_CPP_END(Terrain) \ No newline at end of file diff --git a/ext/scenes/worldscape/terrain/generator.cpp b/ext/scenes/worldscape/terrain/generator.cpp index 2cd474d6..e6f89577 100644 --- a/ext/scenes/worldscape/terrain/generator.cpp +++ b/ext/scenes/worldscape/terrain/generator.cpp @@ -89,23 +89,23 @@ void ext::TerrainGenerator::generate( uf::Object& region ){ /* COLOR ambientLight = uint16ToColor(AMBIENT_LIGHT); { uf::Serializer& tMetadata = region.getComponent(); - ambientLight.r *= tMetadata["region"]["light"]["ambient"][0].asFloat(); - ambientLight.g *= tMetadata["region"]["light"]["ambient"][1].asFloat(); - ambientLight.b *= tMetadata["region"]["light"]["ambient"][2].asFloat(); + ambientLight.r *= tMetadata["region"]["light"]["ambient"][0].as(); + ambientLight.g *= tMetadata["region"]["light"]["ambient"][1].as(); + ambientLight.b *= tMetadata["region"]["light"]["ambient"][2].as(); } */ - std::string base = region.getParent().getComponent()["system"]["hash"].asString(); + std::string base = region.getParent().getComponent()["system"]["hash"].as(); std::string filename = "./data/save/" + base + "/regions/" + std::to_string(location.x) + "." + std::to_string(location.y) + "." + std::to_string(location.z) + ".json"; // old region, load save if ( uf::io::exists( filename ) ) { uf::Serializer save; save.readFromFile(filename); // ID - if ( save["voxels"]["id"]["base64"].isString() ) { - std::string base64 = save["voxels"]["id"]["base64"].asString(); + if ( save["voxels"]["id"]["base64"].is() ) { + std::string base64 = save["voxels"]["id"]["base64"].as(); auto raw = uf::base64::decode( base64 ); - if ( save["voxels"]["id"]["rle"].asBool() ) { + if ( save["voxels"]["id"]["rle"].as() ) { // [uint8_t]*4 -> [uint16_t, uint16_t] this->m_voxels.id.rle.resize( raw.size() / ( sizeof(pod::RLE::length_t) + sizeof(pod::RLE::value_t) ) ); memcpy( &this->m_voxels.id.rle[0], &raw[0], raw.size() ); @@ -113,15 +113,15 @@ void ext::TerrainGenerator::generate( uf::Object& region ){ } else { } - this->m_voxels.id.swizzle = (TerrainGenerator::Swizzle) save["voxels"]["id"]["swizzle"].asUInt64(); + this->m_voxels.id.swizzle = (TerrainGenerator::Swizzle) save["voxels"]["id"]["swizzle"].as(); this->unwrapVoxel(); } // Lighting - if ( save["voxels"]["lighting"]["base64"].isString() ) { - std::string base64 = save["voxels"]["lighting"]["base64"].asString(); + if ( save["voxels"]["lighting"]["base64"].is() ) { + std::string base64 = save["voxels"]["lighting"]["base64"].as(); auto raw = uf::base64::decode( base64 ); - if ( save["voxels"]["lighting"]["rle"].asBool() ) { + if ( save["voxels"]["lighting"]["rle"].as() ) { // [uint8_t]*4 -> [uint8_t, uint8_t] this->m_voxels.lighting.rle.resize( raw.size() / ( sizeof(pod::RLE::length_t) + sizeof(pod::RLE::value_t) ) ); memcpy( &this->m_voxels.lighting.rle[0], &raw[0], raw.size() ); @@ -129,7 +129,7 @@ void ext::TerrainGenerator::generate( uf::Object& region ){ } else { } - this->m_voxels.lighting.swizzle = (TerrainGenerator::Swizzle) save["voxels"]["lighting"]["swizzle"].asUInt64(); + this->m_voxels.lighting.swizzle = (TerrainGenerator::Swizzle) save["voxels"]["lighting"]["swizzle"].as(); this->unwrapLight(); } // load failed / new region @@ -329,13 +329,13 @@ void ext::TerrainGenerator::writeToFile() { this->wrapLight(); uf::Serializer serializer; - std::string base = this->m_terrain ? this->m_terrain->getComponent()["system"]["hash"].asString() : "UNKNOWN"; + std::string base = this->m_terrain ? this->m_terrain->getComponent()["system"]["hash"].as() : "UNKNOWN"; std::string filename = "./data/save/" + base + "/regions/" + std::to_string(this->m_location.x) + "." + std::to_string(this->m_location.y) + "." + std::to_string(this->m_location.z) + ".json"; { // encode as base64, json safe serializer["voxels"]["id"]["base64"] = uf::base64::encode( this->m_voxels.id.rle ); // hash of raw data for data integrity - serializer["voxels"]["id"]["hash"] = uf::string::sha256( uf::base64::decode(serializer["voxels"]["id"]["rle"]["base64"].asString()) ); + serializer["voxels"]["id"]["hash"] = uf::string::sha256( uf::base64::decode(serializer["voxels"]["id"]["rle"]["base64"].as()) ); serializer["voxels"]["id"]["rle"] = true; serializer["voxels"]["id"]["swizzle"] = this->m_voxels.id.swizzle; } @@ -343,7 +343,7 @@ void ext::TerrainGenerator::writeToFile() { // encode as base64, json safe serializer["voxels"]["lighting"]["base64"] = uf::base64::encode( this->m_voxels.lighting.rle ); // hash of raw data for data integrity - serializer["voxels"]["lighting"]["hash"] = uf::string::sha256( uf::base64::decode(serializer["voxels"]["lighting"]["rle"]["base64"].asString()) ); + serializer["voxels"]["lighting"]["hash"] = uf::string::sha256( uf::base64::decode(serializer["voxels"]["lighting"]["rle"]["base64"].as()) ); serializer["voxels"]["lighting"]["rle"] = true; serializer["voxels"]["lighting"]["swizzle"] = this->m_voxels.lighting.swizzle; } @@ -1321,9 +1321,9 @@ void ext::TerrainGenerator::rasterize( std::vector(); COLOR color = uint16ToColor( ambientLight ); - color.r *= tMetadata["region"]["light"]["ambient"][0].asFloat(); - color.g *= tMetadata["region"]["light"]["ambient"][1].asFloat(); - color.b *= tMetadata["region"]["light"]["ambient"][2].asFloat(); + color.r *= tMetadata["region"]["light"]["ambient"][0].as(); + color.g *= tMetadata["region"]["light"]["ambient"][1].as(); + color.b *= tMetadata["region"]["light"]["ambient"][2].as(); ambientLight = colorToUint16( color ); } pod::Matrix4f modelMatrix = uf::transform::model( transform ); diff --git a/ext/scenes/worldscape/terrain/region.cpp b/ext/scenes/worldscape/terrain/region.cpp index 30e3515b..a98bc183 100644 --- a/ext/scenes/worldscape/terrain/region.cpp +++ b/ext/scenes/worldscape/terrain/region.cpp @@ -12,8 +12,8 @@ #include #include -EXT_BEHAVIOR_REGISTER_CPP(RegionBehavior) -EXT_BEHAVIOR_REGISTER_AS_OBJECT(RegionBehavior, Region) +UF_BEHAVIOR_REGISTER_CPP(ext::RegionBehavior) +UF_BEHAVIOR_REGISTER_AS_OBJECT(ext::RegionBehavior, ext::Region) #define this ((uf::Object*) &self) void ext::RegionBehavior::initialize( uf::Object& self ) { // alias Mesh types @@ -25,13 +25,13 @@ void ext::RegionBehavior::initialize( uf::Object& self ) { uf::Serializer& metadata = this->getComponent(); metadata["region"]["initialized"] = true; - if ( !metadata["terrain"]["unified"].asBool() ) { + if ( !metadata["terrain"]["unified"].as() ) { std::string textureFilename = ""; { uf::Serializer& metadata = this->getParent().getComponent(); uf::Asset assetLoader; for ( uint i = 0; i < metadata["system"]["assets"].size(); ++i ) { if ( textureFilename != "" ) break; - std::string filename = this->grabURI( metadata["system"]["assets"][i].asString(), metadata["system"]["root"].asString() ); + std::string filename = this->grabURI( metadata["system"]["assets"][i].as(), metadata["system"]["root"].as() ); textureFilename = assetLoader.cache( filename ); } } @@ -47,7 +47,7 @@ void ext::RegionBehavior::initialize( uf::Object& self ) { texture.loadFromFile( textureFilename ); std::string suffix = ""; { - std::string _ = this->getRootParent().getComponent()["shaders"]["region"]["suffix"].asString(); + std::string _ = this->getRootParent().getComponent()["shaders"]["region"]["suffix"].as(); if ( _ != "" ) suffix = _ + "."; } /* @@ -64,15 +64,15 @@ void ext::RegionBehavior::initialize( uf::Object& self ) { uf::Serializer json = event; uf::Serializer& metadata = this->getComponent(); - if ( !metadata["region"]["initialized"].asBool() ) return "false"; - if ( metadata["region"]["generated"].asBool() ) return "false"; + if ( !metadata["region"]["initialized"].as() ) return "false"; + if ( metadata["region"]["generated"].as() ) return "false"; pod::Vector3ui size; { - size.x = metadata["region"]["size"][0].asUInt(); - size.y = metadata["region"]["size"][1].asUInt(); - size.z = metadata["region"]["size"][2].asUInt(); + size.x = metadata["region"]["size"][0].as(); + size.y = metadata["region"]["size"][1].as(); + size.z = metadata["region"]["size"][2].as(); } - uint subdivisions = metadata["region"]["subdivisions"].asUInt(); + uint subdivisions = metadata["region"]["subdivisions"].as(); ext::TerrainGenerator& generator = this->getComponent(); generator.initialize(size, subdivisions); generator.generate(*this); @@ -139,16 +139,16 @@ void ext::RegionBehavior::initialize( uf::Object& self ) { this->addHook( "region:Populate.%UID%", [&](const std::string& event)->std::string{ uf::Serializer json = event; - if ( metadata["region"][""]["initialized"].asBool() ) return "false"; + if ( metadata["region"][""]["initialized"].as() ) return "false"; metadata["region"][""]["initialized"] = true; bool first = false; pod::Transform<>& transform = this->getComponent>(); float r = (rand() % 100) / 100.0; pod::Vector3ui size = { - metadata["region"]["size"][0].asUInt64() / 4, - metadata["region"]["size"][1].asUInt64() / 4, - metadata["region"]["size"][2].asUInt64() / 4, + metadata["region"]["size"][0].as() / 4, + metadata["region"]["size"][1].as() / 4, + metadata["region"]["size"][2].as() / 4, }; uint half_x = size.x / 2; uint half_y = size.y / 2; @@ -182,8 +182,8 @@ void ext::RegionBehavior::initialize( uf::Object& self ) { } // add lights { - bool should = metadata["region"]["lights"]["should"].asBool(); - if ( r > metadata["region"]["lights"]["rate"].asFloat() ) should = false; + bool should = metadata["region"]["lights"]["should"].as(); + if ( r > metadata["region"]["lights"]["rate"].as() ) should = false; // std::cout << "Rate: " << r << ": " << transform.position.x << ", " << transform.position.y << ", " << transform.position.z << std::endl; if ( metadata["region"]["location"][0] == 0 && @@ -205,7 +205,7 @@ void ext::RegionBehavior::initialize( uf::Object& self ) { auto& metadata = entity->getComponent(); auto& transform = entity->getComponent>(); transform.position = origin; - // if ( !metadata["light"]["color"].isArray() ) { + // if ( !ext::json::isArray( metadata["light"]["color"] ) ) { metadata["light"]["color"][0] = color.x; metadata["light"]["color"][1] = color.y; metadata["light"]["color"][2] = color.z; @@ -216,7 +216,7 @@ void ext::RegionBehavior::initialize( uf::Object& self ) { uf::Serializer& metadata = light.getComponent(); pod::Transform<>& lTransform = light.getComponent>(); lTransform.position += transform.position; - if ( !metadata["light"]["color"].isArray() ) { + if ( !ext::json::isArray( metadata["light"]["color"] ) ) { metadata["light"]["color"][0] = (rand() % 100) / 100.0; metadata["light"]["color"][1] = (rand() % 100) / 100.0; metadata["light"]["color"][2] = (rand() % 100) / 100.0; @@ -226,8 +226,8 @@ void ext::RegionBehavior::initialize( uf::Object& self ) { } // add mobs { - bool should = metadata["region"][""]["should"].asBool(); - if ( r > metadata["region"][""]["rate"].asFloat() ) should = false; + bool should = metadata["region"][""]["should"].as(); + if ( r > metadata["region"][""]["rate"].as() ) should = false; // std::cout << "Rate: " << r << ": " << transform.position.x << ", " << transform.position.y << ", " << transform.position.z << std::endl; if ( metadata["region"]["location"][0] == 0 && @@ -241,14 +241,14 @@ void ext::RegionBehavior::initialize( uf::Object& self ) { if ( first ) { // shiro - if ( metadata["region"][""]["NPCs"].asBool() ) { + if ( metadata["region"][""]["NPCs"].as() ) { // uf::Object* = (uf::Object*) this->findByUid(this->loadChildUid("./shiro.json", true)); uf::Object& = this->loadChild("./shiro.json", true); pod::Transform<>& pTransform = .getComponent>(); pTransform.position += transform.position + pod::Vector3f{ 2, 0, 0 }; } // pong - if ( metadata["region"][""]["NPCs"].asBool() ) { + if ( metadata["region"][""]["NPCs"].as() ) { // uf::Object* = (uf::Object*) this->findByUid(this->loadChildUid("./pongy.json", true)); uf::Object& = this->loadChild("./pongy.json", true); uf::Serializer& pMetadata = .getComponent(); @@ -259,7 +259,7 @@ void ext::RegionBehavior::initialize( uf::Object& self ) { return "true"; } - for ( uint i = 0; i < metadata["region"][""]["amount"].asUInt64(); ++i ) { + for ( uint i = 0; i < metadata["region"][""]["amount"].as(); ++i ) { // uf::Object* = (uf::Object*) this->findByUid(this->loadChildUid("./.json", false)); uf::Object& = this->loadChild("./.json", false); // set name @@ -275,9 +275,9 @@ void ext::RegionBehavior::initialize( uf::Object& self ) { float rx = first ? 0.3 : (rand() % 100) / 100.0; float rz = first ? 0.7 : (rand() % 100) / 100.0; float spread = 32.0f; - spread = std::min( metadata["region"]["size"][0].asFloat(), spread ); - spread = std::min( metadata["region"]["size"][1].asFloat(), spread ); - spread = std::min( metadata["region"]["size"][2].asFloat(), spread ); + spread = std::min( metadata["region"]["size"][0].as(), spread ); + spread = std::min( metadata["region"]["size"][1].as(), spread ); + spread = std::min( metadata["region"]["size"][2].as(), spread ); pod::Vector3f randomOffset = { rx * spread - spread/2.0f, 0, @@ -299,20 +299,20 @@ void ext::RegionBehavior::tick( uf::Object& self ) { auto& scene = uf::scene::getCurrentScene(); auto& sMetadata = scene.getComponent(); auto& metadata = this->getComponent(); - bool threaded = !sMetadata["system"]["physics"]["single threaded"].asBool(); - bool sort = sMetadata["system"]["physics"]["sort"].asBool(); - bool useStrongest = sMetadata["system"]["physics"]["use"]["strongest"].asBool(); - bool queued = sMetadata["system"]["physics"]["use"]["queue"].asBool(); - bool updatePhysics = !sMetadata["system"]["physics"]["entity-local update"].asBool(); - bool useWorkers = sMetadata["system"]["physics"]["use"]["worker"].asBool(); + bool threaded = !sMetadata["system"]["physics"]["single threaded"].as(); + bool sort = sMetadata["system"]["physics"]["sort"].as(); + bool useStrongest = sMetadata["system"]["physics"]["use"]["strongest"].as(); + bool queued = sMetadata["system"]["physics"]["use"]["queue"].as(); + bool updatePhysics = !sMetadata["system"]["physics"]["entity-local update"].as(); + bool useWorkers = sMetadata["system"]["physics"]["use"]["worker"].as(); pod::Thread& thread = uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true, false ); auto& generator = this->getComponent(); auto& regionPosition = this->getComponent>().position; pod::Vector3f size; { - size.x = metadata["region"]["size"][0].asUInt(); - size.y = metadata["region"]["size"][1].asUInt(); - size.z = metadata["region"]["size"][2].asUInt(); + size.x = metadata["region"]["size"][0].as(); + size.y = metadata["region"]["size"][1].as(); + size.z = metadata["region"]["size"][2].as(); } auto function = [&]() -> int { @@ -325,11 +325,11 @@ void ext::RegionBehavior::tick( uf::Object& self ) { auto& transform = entity->getComponent>(); auto& physics = entity->getComponent(); if ( metadata["system"]["physics"]["gravity"] != Json::nullValue ) { - physics.linear.acceleration.x = metadata["system"]["physics"]["gravity"][0].asFloat(); - physics.linear.acceleration.y = metadata["system"]["physics"]["gravity"][1].asFloat(); - physics.linear.acceleration.z = metadata["system"]["physics"]["gravity"][2].asFloat(); + physics.linear.acceleration.x = metadata["system"]["physics"]["gravity"][0].as(); + physics.linear.acceleration.y = metadata["system"]["physics"]["gravity"][1].as(); + physics.linear.acceleration.z = metadata["system"]["physics"]["gravity"][2].as(); } - if ( !metadata["system"]["physics"]["collision"].asBool() ) { + if ( !metadata["system"]["physics"]["collision"].as() ) { physics.linear.acceleration.x = 0; physics.linear.acceleration.y = 0; physics.linear.acceleration.z = 0; @@ -341,7 +341,7 @@ void ext::RegionBehavior::tick( uf::Object& self ) { { std::function filter = [&]( uf::Entity* entity ) { auto& metadata = entity->getComponent(); - if ( !metadata["system"]["physics"]["collision"].isNull() && !metadata["system"]["physics"]["collision"].asBool() ) return; + if ( !ext::json::isNull( metadata["system"]["physics"]["collision"] ) && !metadata["system"]["physics"]["collision"].as() ) return; if ( entity->hasComponent() ) entities.push_back((uf::Object*) entity); }; @@ -462,24 +462,24 @@ void ext::RegionBehavior::tick( uf::Object& self ) { auto& scene = uf::scene::getCurrentScene(); auto& sMetadata = scene.getComponent(); - if ( !sMetadata["system"]["physics"]["collision"].asBool() ) return; + if ( !sMetadata["system"]["physics"]["collision"].as() ) return; auto& mutex = *(this->getComponent()); mutex.lock(); - bool threaded = !sMetadata["system"]["physics"]["single threaded"].asBool(); - bool sort = sMetadata["system"]["physics"]["sort"].asBool(); - bool useStrongest = sMetadata["system"]["physics"]["use"]["strongest"].asBool(); - bool queued = sMetadata["system"]["physics"]["use"]["queue"].asBool(); - bool ignoreStaticEntities = sMetadata["system"]["physics"]["optimizations"]["ignore static entities"].asBool(); - bool ignoreDuplicateTests = sMetadata["system"]["physics"]["optimizations"]["ignore duplicate tests"].asBool(); - bool updatePhysics = !sMetadata["system"]["physics"]["optimizations"]["entity-local update"].asBool(); - bool useWorkers = sMetadata["system"]["physics"]["use"]["worker"].asBool(); + bool threaded = !sMetadata["system"]["physics"]["single threaded"].as(); + bool sort = sMetadata["system"]["physics"]["sort"].as(); + bool useStrongest = sMetadata["system"]["physics"]["use"]["strongest"].as(); + bool queued = sMetadata["system"]["physics"]["use"]["queue"].as(); + bool ignoreStaticEntities = sMetadata["system"]["physics"]["optimizations"]["ignore static entities"].as(); + bool ignoreDuplicateTests = sMetadata["system"]["physics"]["optimizations"]["ignore duplicate tests"].as(); + bool updatePhysics = !sMetadata["system"]["physics"]["optimizations"]["entity-local update"].as(); + bool useWorkers = sMetadata["system"]["physics"]["use"]["worker"].as(); pod::Thread& thread = uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true, false ); auto function = [&]() -> int { std::vector entities; std::function filter = [&]( uf::Entity* entity ) { auto& metadata = entity->getComponent(); - if ( !metadata["system"]["physics"]["collision"].isNull() && !metadata["system"]["physics"]["collision"].asBool() ) return; + if ( !ext::json::isNull( metadata["system"]["physics"]["collision"] ) && !metadata["system"]["physics"]["collision"].as() ) return; if ( entity->hasComponent() ) entities.push_back((uf::Object*) entity); }; @@ -514,9 +514,9 @@ void ext::RegionBehavior::tick( uf::Object& self ) { auto& generator = this->getComponent(); auto& regionPosition = this->getComponent>().position; pod::Vector3f size; { - size.x = metadata["region"]["size"][0].asUInt(); - size.y = metadata["region"]["size"][1].asUInt(); - size.z = metadata["region"]["size"][2].asUInt(); + size.x = metadata["region"]["size"][0].as(); + size.y = metadata["region"]["size"][1].as(); + size.z = metadata["region"]["size"][2].as(); } for ( auto* _ : entities ) { uf::Object& entity = *_; @@ -643,7 +643,7 @@ void ext::RegionBehavior::render( uf::Object& self ){ uf::Scene& scene = uf::scene::getCurrentScene(); uf::Serializer& metadata = this->getComponent(); - if ( !metadata["region"]["rasterized"].asBool() ) return; + if ( !metadata["region"]["rasterized"].as() ) return; /* Update uniforms */ if ( this->hasComponent() ) { auto& scene = uf::scene::getCurrentScene(); auto& mesh = this->getComponent(); diff --git a/ext/scenes/worldscape/terrain/terrain.cpp b/ext/scenes/worldscape/terrain/terrain.cpp index ca809902..9c5c7827 100644 --- a/ext/scenes/worldscape/terrain/terrain.cpp +++ b/ext/scenes/worldscape/terrain/terrain.cpp @@ -23,18 +23,18 @@ namespace { std::unordered_map region_table; } -EXT_OBJECT_REGISTER_BEGIN(Terrain) - UF_OBJECT_REGISTER_BEHAVIOR(EntityBehavior) - UF_OBJECT_REGISTER_BEHAVIOR(ObjectBehavior) - EXT_OBJECT_REGISTER_BEHAVIOR(TerrainBehavior) -EXT_OBJECT_REGISTER_END() +UF_OBJECT_REGISTER_BEGIN(ext::Terrain) + UF_OBJECT_REGISTER_BEHAVIOR(uf::EntityBehavior) + UF_OBJECT_REGISTER_BEHAVIOR(uf::ObjectBehavior) + UF_OBJECT_REGISTER_BEHAVIOR(ext::TerrainBehavior) +UF_OBJECT_REGISTER_END() void ext::Terrain::relocateChildren() { uf::Scene& scene = uf::scene::getCurrentScene(); std::vector entities; scene.process( [&]( uf::Entity* entity ) { if ( !entity || entity->getUid() == 0 ) return; uf::Serializer& metadata = entity->getComponent(); - if ( metadata["region"].isObject() && metadata["region"]["track"].asBool() ) { + if ( ext::json::isObject( metadata["region"] ) && metadata["region"]["track"].as() ) { if ( std::find( entities.begin(), entities.end(), entity ) == entities.end() ) { entities.push_back(entity); } @@ -43,9 +43,9 @@ void ext::Terrain::relocateChildren() { uf::Serializer& metadata = this->getComponent(); pod::Vector3ui size = { - metadata["region"]["size"][0].asUInt(), - metadata["region"]["size"][1].asUInt(), - metadata["region"]["size"][2].asUInt(), + metadata["region"]["size"][0].as(), + metadata["region"]["size"][1].as(), + metadata["region"]["size"][2].as(), }; for ( uf::Entity* e : entities ) { uf::Entity& entity = *e; @@ -80,9 +80,9 @@ void ext::Terrain::relocateChildren() { bool ext::Terrain::exists( const pod::Vector3i& position ) const { const uf::Serializer& metadata = this->getComponent(); pod::Vector3i size = { - metadata["region"]["size"][0].asInt(), - metadata["region"]["size"][1].asInt(), - metadata["region"]["size"][2].asInt(), + metadata["region"]["size"][0].as(), + metadata["region"]["size"][1].as(), + metadata["region"]["size"][2].as(), }; if ( this->getChildren().empty() ) return false; for ( auto it = this->getChildren().begin(); it != this->getChildren().end(); ++it ) { uf::Entity* kv = *it; @@ -102,14 +102,14 @@ bool ext::Terrain::inBounds( const pod::Vector3i& position ) const { const pod::Transform<>& player = scene.getController().getComponent>(); const uf::Serializer& metadata = this->getComponent(); pod::Vector3ui size = { - metadata["region"]["size"][0].asUInt(), - metadata["region"]["size"][1].asUInt(), - metadata["region"]["size"][2].asUInt(), + metadata["region"]["size"][0].as(), + metadata["region"]["size"][1].as(), + metadata["region"]["size"][2].as(), }; pod::Vector3ui threshold = { - metadata["terrain"]["radius"][0].asUInt(), - metadata["terrain"]["radius"][1].asUInt(), - metadata["terrain"]["radius"][2].asUInt(), + metadata["terrain"]["radius"][0].as(), + metadata["terrain"]["radius"][1].as(), + metadata["terrain"]["radius"][2].as(), }; pod::Vector3i point = { (int) (player.position.x / size.x), @@ -124,14 +124,14 @@ bool ext::Terrain::inBounds( const pod::Vector3i& position ) const { void ext::Terrain::generate( bool single ) { uf::Serializer& metadata = this->getComponent(); pod::Vector3i radius = { - metadata["terrain"]["radius"][0].asInt(), - metadata["terrain"]["radius"][1].asInt(), - metadata["terrain"]["radius"][2].asInt(), + metadata["terrain"]["radius"][0].as(), + metadata["terrain"]["radius"][1].as(), + metadata["terrain"]["radius"][2].as(), }; pod::Vector3i size = { - metadata["region"]["size"][0].asInt(), - metadata["region"]["size"][1].asInt(), - metadata["region"]["size"][2].asInt(), + metadata["region"]["size"][0].as(), + metadata["region"]["size"][1].as(), + metadata["region"]["size"][2].as(), }; uf::Scene& scene = uf::scene::getCurrentScene(); @@ -164,9 +164,9 @@ uf::Object* ext::Terrain::at( const pod::Vector3i& position ) const { const uf::Serializer& metadata = this->getComponent(); pod::Vector3i size = { - metadata["region"]["size"][0].asInt(), - metadata["region"]["size"][1].asInt(), - metadata["region"]["size"][2].asInt(), + metadata["region"]["size"][0].as(), + metadata["region"]["size"][1].as(), + metadata["region"]["size"][2].as(), }; if ( this->getChildren().empty() ) return NULL; for ( auto it = this->getChildren().begin(); it != this->getChildren().end(); ++it ) { uf::Entity* kv = *it; @@ -183,9 +183,9 @@ uf::Object* ext::Terrain::at( const pod::Vector3i& position ) const { void ext::Terrain::generate( const pod::Vector3i& position ) { uf::Serializer& metadata = this->getComponent(); pod::Vector3i size = { - metadata["region"]["size"][0].asInt(), - metadata["region"]["size"][1].asInt(), - metadata["region"]["size"][2].asInt(), + metadata["region"]["size"][0].as(), + metadata["region"]["size"][1].as(), + metadata["region"]["size"][2].as(), }; if ( this->exists(position) ) return; diff --git a/makefiles/win64.gcc.make b/makefiles/win64.gcc.make index c1fd73f5..31af142e 100644 --- a/makefiles/win64.gcc.make +++ b/makefiles/win64.gcc.make @@ -1,4 +1,4 @@ ARCH = win64 PREFIX = gcc CC = /opt/mingw-w64/x86_64-7.2.0-posix-seh-rt_v5-rev1/mingw64/bin/g++ -FLAGS = -fdiagnostics-color=always -Og -g -Wall -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder -Wno-sign-compare -Wno-unused-but-set-variable -Wno-ignored-attributes -Wno-narrowing -Wno-misleading-indentation \ No newline at end of file +FLAGS = -fdiagnostics-color=always -Wall -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder -Wno-sign-compare -Wno-unused-but-set-variable -Wno-ignored-attributes -Wno-narrowing -Wno-misleading-indentation \ No newline at end of file diff --git a/makefiles/win64.gcc10.make b/makefiles/win64.gcc10.make index 0271e0c5..18f6f722 100644 --- a/makefiles/win64.gcc10.make +++ b/makefiles/win64.gcc10.make @@ -1,4 +1,4 @@ ARCH = win64 PREFIX = gcc10 CC = g++ -FLAGS = -fdiagnostics-color=always -O3 -DUF_DISABLE_ALIGNAS -Wall -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder -Wno-sign-compare -Wno-unused-but-set-variable -Wno-ignored-attributes -Wno-narrowing -Wno-misleading-indentation \ No newline at end of file +FLAGS = -fdiagnostics-color=always -Wall -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder -Wno-sign-compare -Wno-unused-but-set-variable -Wno-ignored-attributes -Wno-narrowing -Wno-misleading-indentation \ No newline at end of file diff --git a/program.sh b/program.sh index 5dc89e42..b77526e4 100644 --- a/program.sh +++ b/program.sh @@ -1,5 +1,4 @@ #!/bin/bash tskill program cd bin -./program.bat $@ -tskill program +./program.bat $@ || tskill program \ No newline at end of file