{"id":22212168,"url":"https://github.com/mcountryman/gloo","last_synced_at":"2025-08-14T05:07:58.264Z","repository":{"id":71261676,"uuid":"141868338","full_name":"mcountryman/gloo","owner":"mcountryman","description":"An OOP helper library for creating binary modules in Garry's Mod","archived":false,"fork":false,"pushed_at":"2019-09-19T12:14:32.000Z","size":39,"stargazers_count":3,"open_issues_count":2,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-12T17:53:22.190Z","etag":null,"topics":["cpp","cpp11","garrysmod","oop"],"latest_commit_sha":null,"homepage":"https://github.com/mcountryman/gloo","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mcountryman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-07-22T05:24:50.000Z","updated_at":"2018-11-12T14:22:33.000Z","dependencies_parsed_at":"2023-07-14T10:01:22.786Z","dependency_job_id":null,"html_url":"https://github.com/mcountryman/gloo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mcountryman/gloo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcountryman%2Fgloo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcountryman%2Fgloo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcountryman%2Fgloo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcountryman%2Fgloo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mcountryman","download_url":"https://codeload.github.com/mcountryman/gloo/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcountryman%2Fgloo/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270364971,"owners_count":24571423,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-14T02:00:10.309Z","response_time":75,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","cpp11","garrysmod","oop"],"created_at":"2024-12-02T20:48:06.235Z","updated_at":"2025-08-14T05:07:58.227Z","avatar_url":"https://github.com/mcountryman.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# gloo\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/71105f2b7c3d431d889044836f5c63bf)](https://www.codacy.com/project/mcountryman/gloo/dashboard?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=mcountryman/gloo\u0026amp;utm_campaign=Badge_Grade_Dashboard)\n\nAn OOP helper library intended to aid the creation of modern C++11 binary modules in Garry's Mod.\n\n## Getting Started\n#### Download\n```shell\ngit submodule add https://github.com/mcountryman/gloo vendor/gloo\ngit submodule update --init --recursive\n```\n#### Premake 5\n```lua\nproject \"...\"\n  include \".../gloo\"\n```\n## Header Overview\n```cpp\n#include \u003cGarrysMod/Lua/LuaValue.h\u003e\n  // class LuaValue\n#include \u003cGarrysMod/Lua/LuaObject.h\u003e\n  // class LuaObject\n#include \u003cGarrysMod/Lua/LuaEvent.h\u003e\n  // class LuaEventEmitter\n  // class ILuaEventEmitter\n  // class LuaEventEmitterManager\n```\n## Examples\nCheck out `test/src/gloo_test.cpp` for an example that goes over 99% of the features of this library.\n### LuaValue\nYou can create a LuaValue two ways both shown below.  The Make method creates an emtpy LuaValue with the supplied type, and the Pop method creates a LuaValue by popping the data from the Lua stack. \n\n```cpp\nusing namespace GarrysMod::Lua;\n\n// Make will default create the object however, default the stored value to \n// something sensible.  For Types::BOOL gloo defaults the value to false.\nLuaValue empty = LuaValue::Make(Types::BOOL);\n\n// Pop method requires a lua state and a position to pop from.\nLuaValue value = LuaValue::Pop(state, 1);\n```\n\nWith this newly created LuaValue object we can use this directly in our C++ library or we can pass it back to the Lua stack.\n```cpp\nusing namespace GarrysMod::Lua;\n\nLuaValue value = ...;\n\n// Push to lua stack\nvalue.Push(state);\n\n// Validate type\nif (value.type() == Type::BOOL)\n{\n  // Automatically cast to boolean\n  bool boolean = value;\n\n  method_with_one_boolean_parameter(value);\n}\n```\n\nIt is important to note that when invoking the cast operator for a LuaValue then [assert](https://en.cppreference.com/w/cpp/error/assert) method is used to ensure the underlying lua type is correctly associated with the requesting cast type.\n\n### LuaObject\nWith the LuaObject base we can create OOP lua objects.\n```cpp\nusing namespace GarrysMod::Lua;\n\nclass Object :\n  // The number in the first parameter of the template for LuaObject is used as\n  // and type identifier for lua.  The second is our defined object.\n  public LuaObject\u003c123, Object\u003e\n{\nprivate:\n  int _field;\npublic:\n  Object() : LuaObject() // The ctor call to LuaObject is used to define the\n                         // default metamethods __gc, __index, __newindex, and\n                         // __tostring.  It is very important that these are \n                         // defined and used.\n  {\n    AddGetter(\"name_of_field\", getter_method); // Add getter method\n    AddSetter(\"name_of_field\", setter_method); // Add setter method\n    AddMethod(\"do_thing\", do_thing);\n  }\npublic:\n  void DoThing() { ... }\nprivate: // Personal preference for myself is to define lua callbacks as static\n         // to not de-organize C++ class members.\n\n  static int getter_method()\n  {\n    // We can pop the instance to our object by using the Pop method show below\n    auto obj = Pop(state, 1);\n\n    // From here we can expose our private field value to lua \n    return LuaValue::Push(state, obj-\u003e_field);\n  }\n\n  static int setter_method()\n  {\n    // Guess what we want to do here?\n    auto obj = Pop(state, 1); // :0\n\n    // Now we use our handy LuaValue magic to grab a value to store from Lua\n    auto value = LuaValue::Pop(state, 2);\n\n    // And ensure it is the correct type\n    if (value.type() != Type::NUMBER)\n      LUA-\u003eArgError(2, \"Expected number!\");\n\n    // Finally assign it to the _field field\n    obj-\u003e_field = value;\n\n    return 0;\n  }\n\n  static int do_thing(lua_State *state)\n  {\n    // Fairly self-explanitory\n    Pop(state, 1)-\u003eDoThing();\n\n    return 0;\n  }\n};\n```\n\n### LuaEventEmitter\nNow that we are all the way down here we can discuss the fun stuff!  The LuaEventEmitter is a base class to be used similarly to the LuaObject class however, it comes with some pretty usefull abilities.\n\nFor one our LuaObject will automatically have the following methods exposed to Lua\n```typescript\nobj:on(event: String, callback: Function)\nobj:once(event: String, callback: Function)\nobj:add_listener(event: String, callback: Function, delete_after_invokation: Boolean)\nobj:remove_listeners()\n```\n\nUsing these methods we call add Lua callbacks to be invoked when the Think hook is called.\n```cpp\nclass Object : public LuaEventEmitter\u003c?, Object\u003e\n{\npublic:\n  void AsyncWork()\n  {\n    Emit(\"event_name\", \"any\", \"valid\", {{ \"lua\", \"value\" }}, 69, LuaValue::Make(Type::NIL));\n  }\n};\n```\n\nThe `Think` hook is added and removed behind the scenes via the `LuaEventEmitterManager` object.  Hooking is done when a listener is created and removal is done when there are zero active `LuaEventEmitter` objects in the `LuaEventEmitter`.  Registration of a `LuaEventEmitter` is again, done when a listener is created.\n\nSeveral potentially obscure things to note; data passed to the `Emit` method will not be dequeued until a valid listener is present during a `Think` event.  The `Think` method in `LuaEventEmitter` is configured by default (via `max_events_per_tick`) to only dequeue 100 events per call.  This can be changed by invoking the `max_events_per_tick` method with an integer value as the first parameter as shown below.\n\n```cpp\nclass Object : public LuaEventEmitter\u003c?, Object\u003e\n{\n  Object() : LuaEventEmitter() // As stated for LuaObject it is important to call\n                            // the parent constructor here if we want access to\n                            // the fields defined by LuaObject and now LuaEventEmitter\n  {\n    // Increase the maximum number of events to be dequeued per tick to 1000.\n    max_events_per_tick(1000);\n  }\n};\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmcountryman%2Fgloo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmcountryman%2Fgloo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmcountryman%2Fgloo/lists"}