diff --git a/docs/tasks/editor.todo b/docs/tasks/editor.todo index 781bbf1..29cfaa0 100644 --- a/docs/tasks/editor.todo +++ b/docs/tasks/editor.todo @@ -1,5 +1,8 @@ Editor: + ☐ Generate boiler-plate code when a new script is created + ☐ Include setting the entity ID + ☐ Add pure virtual ShowProperties method to EditorAsset ✔ Script Editor Asset @done(22-11-14 18:19) ✔ Editor Assets need to switch to using UUIDs @critical @done(22-11-02 18:51) diff --git a/scripts/build.bat b/scripts/build.bat index b1cec30..1a6a7cf 100644 --- a/scripts/build.bat +++ b/scripts/build.bat @@ -36,7 +36,7 @@ IF NOT "!BUILD_ERRORLEVEL!"=="0" ( xcopy /y test_data\engine_state.json build\Release\ -xcopy /y test_data\world_interface.wren build\Release\ +xcopy /y src\scripting\internal_scripts\*.wren build\Release\ xcopy /y src\renderer\shaders\* build\Release\* @@ -51,7 +51,7 @@ IF NOT "!BUILD_ERRORLEVEL!"=="0" ( xcopy /y test_data\engine_state.json build\RelWithDebInfo\ -xcopy /y test_data\world_interface.wren build\RelWithDebInfo\ +xcopy /y src\scripting\internal_scripts\*.wren build\RelWithDebInfo\ xcopy /y src\renderer\shaders\* build\RelWithDebInfo\* ) ELSE ( @@ -65,7 +65,7 @@ IF NOT "!BUILD_ERRORLEVEL!"=="0" ( xcopy /y test_data\engine_state.json build\Debug\ -xcopy /y test_data\world_interface.wren build\Debug\ +xcopy /y src\scripting\internal_scripts\*.wren build\Debug\ xcopy /y src\renderer\shaders\* build\Debug\* ) diff --git a/src/platform/key_codes.h b/src/platform/key_codes.h index 01d0a2d..cb52535 100644 --- a/src/platform/key_codes.h +++ b/src/platform/key_codes.h @@ -12,6 +12,7 @@ #include "window.h" #include +#include namespace lunarium { @@ -221,6 +222,95 @@ namespace lunarium KeyCode::MOUSE_X1_BUTTON, KeyCode::MOUSE_X2_BUTTON }; + + static std::map KeyCodeMap = + { + std::pair {"A", KeyCode::A}, + std::pair {"B", KeyCode::B}, + std::pair {"C", KeyCode::C}, + std::pair {"D", KeyCode::D}, + std::pair {"E", KeyCode::E}, + std::pair {"F", KeyCode::F}, + std::pair {"G", KeyCode::G}, + std::pair {"H", KeyCode::H}, + std::pair {"I", KeyCode::I}, + std::pair {"J", KeyCode::J}, + std::pair {"K", KeyCode::K}, + std::pair {"L", KeyCode::L}, + std::pair {"M", KeyCode::M}, + std::pair {"N", KeyCode::N}, + std::pair {"O", KeyCode::O}, + std::pair {"P", KeyCode::P}, + std::pair {"Q", KeyCode::Q}, + std::pair {"R", KeyCode::R}, + std::pair {"S", KeyCode::S}, + std::pair {"T", KeyCode::T}, + std::pair {"U", KeyCode::U}, + std::pair {"V", KeyCode::V}, + std::pair {"W", KeyCode::W}, + std::pair {"X", KeyCode::X}, + std::pair {"Y", KeyCode::Y}, + std::pair {"Z", KeyCode::Z}, + + std::pair {"NUM_0", KeyCode::NUM_0}, + std::pair {"NUM_1", KeyCode::NUM_1}, + std::pair {"NUM_2", KeyCode::NUM_2}, + std::pair {"NUM_3", KeyCode::NUM_3}, + std::pair {"NUM_4", KeyCode::NUM_4}, + std::pair {"NUM_5", KeyCode::NUM_5}, + std::pair {"NUM_6", KeyCode::NUM_6}, + std::pair {"NUM_7", KeyCode::NUM_7}, + std::pair {"NUM_8", KeyCode::NUM_8}, + std::pair {"NUM_9", KeyCode::NUM_9}, + + std::pair {"F1", KeyCode::F1}, + std::pair {"F2", KeyCode::F2}, + std::pair {"F3", KeyCode::F3}, + std::pair {"F4", KeyCode::F4}, + std::pair {"F5", KeyCode::F5}, + std::pair {"F6", KeyCode::F6}, + std::pair {"F7", KeyCode::F7}, + std::pair {"F8", KeyCode::F8}, + std::pair {"F9", KeyCode::F9}, + std::pair {"F10", KeyCode::F10}, + std::pair {"F11", KeyCode::F11}, + std::pair {"F12", KeyCode::F12}, + + std::pair {"LSHIFT", KeyCode::LSHIFT}, + std::pair {"RSHIFT", KeyCode::RSHIFT}, + std::pair {"LCONTROL", KeyCode::LCONTROL}, + std::pair {"RCONTROL", KeyCode::RCONTROL}, + std::pair {"LALT", KeyCode::LALT}, + std::pair {"RALT", KeyCode::RALT}, + std::pair {"SPACE", KeyCode::SPACE}, + std::pair {"LEFT", KeyCode::LEFT}, + std::pair {"UP", KeyCode::UP}, + std::pair {"RIGHT", KeyCode::RIGHT}, + std::pair {"DOWN", KeyCode::DOWN}, + std::pair {"DEL", KeyCode::DEL}, + std::pair {"RETURN", KeyCode::RETURN}, + std::pair {"BACKSPACE", KeyCode::BACKSPACE}, + std::pair {"TAB", KeyCode::TAB}, + std::pair {"ESCAPE", KeyCode::ESCAPE}, + std::pair {"PAGE_UP", KeyCode::PAGE_UP}, + std::pair {"PAGE_DOWN", KeyCode::PAGE_DOWN}, + std::pair {"SEMICOLON", KeyCode::SEMICOLON}, + std::pair {"EQUALS", KeyCode::EQUALS}, + std::pair {"COMMA", KeyCode::COMMA}, + std::pair {"DASH", KeyCode::DASH}, + std::pair {"DOT", KeyCode::DOT}, + std::pair {"FORWARD_SLASH", KeyCode::FORWARD_SLASH}, + std::pair {"TILDE", KeyCode::TILDE}, + std::pair {"OPEN_BRACKET", KeyCode::OPEN_BRACKET}, + std::pair {"BACKSLASH", KeyCode::BACKSLASH}, + std::pair {"CLOSE_BRACKET", KeyCode::CLOSE_BRACKET}, + std::pair {"QUOTE", KeyCode::QUOTE}, + std::pair {"MOUSE_LEFT_BUTTON", KeyCode::MOUSE_LEFT_BUTTON}, + std::pair {"MOUSE_RIGHT_BUTTON", KeyCode::MOUSE_RIGHT_BUTTON}, + std::pair {"MOUSE_MIDDLE_BUTTON", KeyCode::MOUSE_MIDDLE_BUTTON}, + std::pair {"MOUSE_X1_BUTTON", KeyCode::MOUSE_X1_BUTTON}, + std::pair {"MOUSE_X2_BUTTON", KeyCode::MOUSE_X2_BUTTON} + }; } diff --git a/src/scripting/coreAPI.cpp b/src/scripting/coreAPI.cpp index d67b49e..79f2232 100644 --- a/src/scripting/coreAPI.cpp +++ b/src/scripting/coreAPI.cpp @@ -11,12 +11,15 @@ #include "coreAPI.h" #include "wren_state.h" #include +#include #include +#include namespace lunarium { - CoreAPI* CoreAPI::mpInstance = nullptr; + WrenScript CoreAPI::mScript; + std::vector CoreAPI::mForeignMethods; CoreAPI& CoreAPI::GetInstance() { if (mpInstance == nullptr) @@ -37,14 +40,62 @@ namespace lunarium { mCat = sman.GetLogCat(); + // Register callbacks + sman.RegisterForeignMethodBinder((FMBinder*)&CoreAPI::ForeignMethodBinder); + + // Generate Code + std::string keys_script = GenerateWrenKeyCodes(); + sman.RunSnippet("KeyCodes", keys_script); + + // DEBUG - SAVE GENERATED SCRIPT TO FILE FOR REVIEW + File::WriteTextFile("key_codes.wren", keys_script); + + + // Load Main Script + mScript.SetModuleName("CoreAPI"); + std::string code = File::ReadTextFile("core_api.wren"); // This will eventually move to internal data + mScript.SetScriptCode(code); + // Register methods - // sman.mState["SetWindowSize"] = &CoreAPI::SetWindowSize; - // sman.mState["Log"] = &CoreAPI::Log; // return OpRes::Fail("CoreAPI::Initialize not implemented yet!"); return OpRes::OK(); } + WrenForeignMethodFn CoreAPI::ForeignMethodBinder(WrenVM* vm, const char* module, const char* class_name, bool isStatic, const char* signature) + { + ForeignMethodID FMID = { module, class_name, isStatic, signature }; + + for (auto iter = mForeignMethods.begin(); iter != mForeignMethods.end(); iter++) + { + if (FMID == (*iter)) + { + iter->FM; + } + } + + return nullptr; + } + + + std::string CoreAPI::GenerateWrenKeyCodes() + { + std::string key_codes = "class KeyCodes {\n"; + + for (auto iter = KeyCodeMap.begin(); iter != KeyCodeMap.end(); iter++) + { + key_codes += "\tstatic "; + key_codes += iter->first; + key_codes += "() { "; + key_codes += std::to_string((u32)iter->second); + key_codes += " }\n"; + } + + key_codes += "}"; + + return key_codes; + } + //////////////////////////////////////////////////////////// // API //////////////////////////////////////////////////////////// @@ -66,4 +117,9 @@ namespace lunarium default: { Logger::Trace(mpInstance->mCat, msg); break; } } } + + bool CoreAPI::IsKeyDown(WrenVM* vm) + { + return false; + } } \ No newline at end of file diff --git a/src/scripting/coreAPI.h b/src/scripting/coreAPI.h index 5c13aef..76ce06c 100644 --- a/src/scripting/coreAPI.h +++ b/src/scripting/coreAPI.h @@ -12,8 +12,12 @@ #define CORE_API_H_ #include +#include "wren_script.h" #include +#include +#include +struct WrenVM; namespace lunarium { @@ -27,15 +31,42 @@ namespace lunarium OpRes Initialize(WrenState& state); + private: static CoreAPI* mpInstance; + static WrenScript mScript; u32 mCat; + typedef void (*ForeignMethod)(WrenVM*); + struct ForeignMethodID + { + std::string Module; + std::string Class; + bool IsStatic; + std::string Signature; + ForeignMethod FM; + + bool operator==(const ForeignMethodID& rhs) + { + return (Module == rhs.Module && Class == rhs.Class && IsStatic == rhs.IsStatic && Signature == rhs.Signature); + } + }; + + static std::vector mForeignMethods; + + private: // Helper methods + std::string GenerateWrenKeyCodes(); + + private: // Callbacks + static ForeignMethod ForeignMethodBinder(WrenVM* vm, const char* module, const char* className, bool isStatic, const char* signature); + public: // API static void SetWindowSize(int w, int h); static void Log(int level, const char* msg); + static bool IsKeyDown(WrenVM* vm); + }; } diff --git a/src/scripting/internal_scripts/components.wren b/src/scripting/internal_scripts/components.wren new file mode 100644 index 0000000..044abda --- /dev/null +++ b/src/scripting/internal_scripts/components.wren @@ -0,0 +1,27 @@ +/****************************************************************************** +* File - components.wren +* Author - Joey Pollack +* Date - 2022/11/17 (y/m/d) +* Mod Date - 2022/11/17 (y/m/d) +* Description - The foreign classes for components +******************************************************************************/ + +class Component { + EntityID { _EntityID } + EntityID=(value) { + _EntityID = value + } +} + +foreign class VelocityComponent is Component { + + // The parameter will be used on the C++ side to set the correct C++ component + construct new(entity_id) { + super.EntityID = entity_id + } + + // maybe wrap these in non-foreign methods + // to abstract pulling data out of slots? + foreign GetVelocity() + foreign SetVelocity(x, y) +} \ No newline at end of file diff --git a/src/scripting/internal_scripts/core_api.wren b/src/scripting/internal_scripts/core_api.wren new file mode 100644 index 0000000..9c6051e --- /dev/null +++ b/src/scripting/internal_scripts/core_api.wren @@ -0,0 +1,11 @@ +/****************************************************************************** +* File - core_api.wren +* Author - Joey Pollack +* Date - 2022/11/21 (y/m/d) +* Mod Date - 2022/11/21 (y/m/d) +* Description - The Core API exposes core Lunarium features to scripts +******************************************************************************/ + +class Core { + //foreign static IsKeyDown(key) +} \ No newline at end of file diff --git a/test_data/world_interface.wren b/src/scripting/internal_scripts/world_interface.wren similarity index 64% rename from test_data/world_interface.wren rename to src/scripting/internal_scripts/world_interface.wren index 08dece6..cb2433d 100644 --- a/test_data/world_interface.wren +++ b/src/scripting/internal_scripts/world_interface.wren @@ -6,6 +6,15 @@ * Description - The main interface for scripts to interact with the game world ******************************************************************************/ +class Component { + Tag { 1 } + Transform { 2 } + Velocity { 3 } + Camera { 4 } + BlockOut { 5 } + Script { 6 } +} + // Manages all of the EntityBehaviors class WorldInterface { @@ -14,6 +23,10 @@ class WorldInterface { System.print("WorldInterface initialized") } + ///////////////////////////////////////////////////////////////////// + // EVENTS + ///////////////////////////////////////////////////////////////////// + static RegisterBehavior(behavior) { __Behaviors.add(behavior) // behavior.OnLoad() @@ -37,11 +50,25 @@ class WorldInterface { behavior.Update(dt) } } + + ///////////////////////////////////////////////////////////////////// + // API + ///////////////////////////////////////////////////////////////////// + + static GetComponent(entity_id, component_id) { + + } } class EntityBehavior { + + EntityID { _EntityID } + EntityID=(value) { + _EntityID = value + } + OnLoad() { } diff --git a/src/scripting/wren_state.cpp b/src/scripting/wren_state.cpp index 9c7c404..74c4dc0 100644 --- a/src/scripting/wren_state.cpp +++ b/src/scripting/wren_state.cpp @@ -9,11 +9,13 @@ #include "wren_state.h" #include "wren_script.h" +#include "coreAPI.h" #include #include namespace lunarium { + std::vector WrenState::mFMBinders; WrenState::~WrenState() { @@ -36,6 +38,8 @@ namespace lunarium mpVM = wrenNewVM(&config); + CoreAPI::GetInstance().Initialize(*this); + return OpRes::OK(); } @@ -44,6 +48,15 @@ namespace lunarium return mLogCat; } + void WrenState::RegisterForeignMethodBinder(FMBinder* binder_method) + { + mFMBinders.push_back(binder_method); + } + + ///////////////////////////////////////////////////////////////////// + // HANDLES + ///////////////////////////////////////////////////////////////////// + WrenHandle* WrenState::GetWrenClassHandle(std::string from_module, std::string class_name) { // Load the class into slot 0. @@ -90,6 +103,9 @@ namespace lunarium wrenReleaseHandle(mpVM, handle); } + ///////////////////////////////////////////////////////////////////// + // CODE PROCESSING + ///////////////////////////////////////////////////////////////////// void WrenState::RunScript(WrenScript* script) { @@ -127,6 +143,9 @@ namespace lunarium } } + ///////////////////////////////////////////////////////////////////// + // VM CALLBACK METHODS + ///////////////////////////////////////////////////////////////////// void WrenState::WriteFN(WrenVM* vm, const char* text) { @@ -155,4 +174,23 @@ namespace lunarium break; } } + + + WrenForeignMethodFn WrenState::BindForeignMethodFN(WrenVM* vm, const char* module, const char* className, bool isStatic, const char* signature) + { + // Bind methods + + // If method not recognized, call any registered FMBinder methods + for (auto iter = mFMBinders.begin(); iter != mFMBinders.end(); iter++) + { + auto FN = ((FMBinder)(*iter))(vm, module, className, isStatic, signature); + if (FN) + { + return FN; + } + } + + Logger::Error(mLogCat, "Failed to bind foreign method: %s::%s", className, signature); + return nullptr; + } } \ No newline at end of file diff --git a/src/scripting/wren_state.h b/src/scripting/wren_state.h index db61379..ccda63b 100644 --- a/src/scripting/wren_state.h +++ b/src/scripting/wren_state.h @@ -42,6 +42,8 @@ namespace lunarium class WrenScript; + typedef WrenForeignMethodFn (*FMBinder) (WrenVM*, const char*, const char*, bool, const char*); + class WrenState { public: @@ -50,6 +52,8 @@ namespace lunarium void Shutdown(); u32 GetLogCat() const; + void RegisterForeignMethodBinder(FMBinder* binder_method); + void RunScript(WrenScript* script); void RunSnippet(std::string name, std::string code); @@ -61,12 +65,14 @@ namespace lunarium // CALL BACKS static void WriteFN(WrenVM* vm, const char* text); static void ErrorFN(WrenVM* vm, WrenErrorType type, const char* module, int line, const char* message); + static WrenForeignMethodFn BindForeignMethodFN(WrenVM* vm, const char* module, const char* className, bool isStatic, const char* signature); private: static u32 mLogCat; WrenVM* mpVM; + static std::vector mFMBinders; }; } diff --git a/src/utils/helpers.cpp b/src/utils/helpers.cpp index b337cdd..97fb84e 100644 --- a/src/utils/helpers.cpp +++ b/src/utils/helpers.cpp @@ -338,26 +338,22 @@ namespace lunarium } - std::string File::ReadScriptFile(std::string filename) + void File::WriteTextFile(std::string filename, std::string text, bool truncate) { - std::ifstream ifs(filename); - if (!ifs.is_open()) - { - Logger::Error(LogCategory::UTILITIES, "Could not open file: %s", filename.c_str()); - return ""; - } + std::ofstream ofs; + if (truncate) + ofs.open(filename, std::ios_base::trunc); + else + ofs.open(filename, std::ios_base::app); - std::string contents; - while (ifs) + if (!ofs.is_open()) { - contents += ifs.get(); + Logger::Error(LogCategory::UTILITIES, "Could not open file: %s", filename.c_str()); } - contents.erase(contents.end() - 1); + ofs.write(text.c_str(), text.size()); - ifs.close(); - ifs.clear(); - - return contents; + ofs.close(); + ofs.clear(); } } \ No newline at end of file diff --git a/src/utils/helpers.h b/src/utils/helpers.h index 3cf2e42..6863bef 100644 --- a/src/utils/helpers.h +++ b/src/utils/helpers.h @@ -96,7 +96,7 @@ namespace lunarium { public: static std::string ReadTextFile(std::string filename); - static std::string ReadScriptFile(std::string filename); + static void WriteTextFile(std::string filename, std::string text, bool truncate = true); }; } diff --git a/src/world/world.cpp b/src/world/world.cpp index e26c78d..9e04804 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -77,22 +77,18 @@ namespace lunarium #if !BUILD_NO_EDITOR editor::Script* pScript = (editor::Script*) editor::ContentManager::GetInstance().GetAsset(script_comp.ScriptID); - WrenScript script(pScript->GetScriptFile().filename().string().c_str(), pScript->GetScript()); - mScriptState.RunScript(&script); #endif } // Call OnLoad for each registered EntityBehavior class object - //mScriptState.RunSnippet("WorldInterface", "WorldInterface.DoOnLoad()"); mScriptState.CallWrenMethod(mWIDoOnLoadMethod, mWIHandle, {}, "WorldInterface.DoOnLoad()"); } void World::OnUnload() { // TODO: Call OnUnLoad for each registered EntityBehavior class object - //mScriptState.RunSnippet("WorldInterface", "WorldInterface.DoOnUnload()"); mScriptState.CallWrenMethod(mWIDoOnUnloadMethod, mWIHandle, {}, "WorldInterface.DoOnUnload()"); mScriptState.Shutdown(); } @@ -110,13 +106,8 @@ namespace lunarium void World::Update(float dt) { // Update all scripts - // Call OnUpdate for each registered EntityBehavior class object - // std::string code = "WorldInterface.Update("; - // code.append(std::to_string(dt)); - // code.append(")"); - // mScriptState.RunSnippet("WorldInterface", code); + // Call Update for each registered EntityBehavior class object mScriptState.CallWrenMethod(mWIUpdateMethod, mWIHandle, { {WrenParamType::WPT_DOUBLE, (double)dt} }, "WorldInterface.Update(dt)"); - // Update Transforms for any enity with a velocity