From 4d5ec74078aecebf4d1c324ef22471b354f35168 Mon Sep 17 00:00:00 2001 From: FatalErr42O <58855799+FatalError42O@users.noreply.github.com> Date: Wed, 26 Jun 2024 21:07:54 -0700 Subject: [PATCH] first commit --- LICENSE | 24 +++++++++++++++++++ init.lua | 3 +++ mod.conf | 4 ++++ new_class.lua | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ proxy_table.lua | 60 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 153 insertions(+) create mode 100644 LICENSE create mode 100644 init.lua create mode 100644 mod.conf create mode 100644 new_class.lua create mode 100644 proxy_table.lua diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..40a7819 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +"/modlib/" directory: Copright (c) respective owners, see License.txt within the "/modlib/" directory. +All files outside of the modlib directory fall under the following license: + +MIT License + +Copyright (c) 2023 FatalError42O, Trevor Pasquali. + +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. diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..5b69e4d --- /dev/null +++ b/init.lua @@ -0,0 +1,3 @@ +local path = minetest.get_modpath("mtul-class") +dofile(path.."/proxy_table.lua") +dofile(path.."/new_class.lua") \ No newline at end of file diff --git a/mod.conf b/mod.conf new file mode 100644 index 0000000..6d2cac1 --- /dev/null +++ b/mod.conf @@ -0,0 +1,4 @@ +name = mtul_class +title = MTUL class lib +description = Simple class system for minetest, with a inbuilt read only table system +author = FatalError42O \ No newline at end of file diff --git a/new_class.lua b/new_class.lua new file mode 100644 index 0000000..7e8aaf1 --- /dev/null +++ b/new_class.lua @@ -0,0 +1,62 @@ +--- An instantiatable class to inherit for defining new instantiatble classes classes +-- the "base" class. To make a new class call `new_class:inherit(your_new_class)` +-- +-- @classmod new_class + +mtul.class.new_class = { + instance = false, + --__no_copy = true +} +--- new_class +-- @table new_class +-- @field instance defines wether the object is an instance, use this in construction to determine what changes to make +-- @field base_class only present for instances: the class from which this instance originates +-- @field parent_class the class from which this class was inherited from + +--- creates a new base class. Calls all constructors in the chain with def.instance=true +-- @param def the table containing a new definition (where the class calling the method is the parent). The content of the definition will override the fields for it's children. +-- @return def a new base class +-- @function Guns4d.Instantiatable_class:inherit() +function mtul.class.new_class:inherit(def) + --construction chain for inheritance + --if not def then def = {} else def = table.shallow_copy(def) end + def.parent_class = self + def.instance = false + --def.__no_copy = true + def._construct_low = def.construct + --this effectively creates a construction chain by overwriting .construct + function def.construct(parameters) + --rawget because in a instance it may only be present in a hierarchy but not the table itself + if self.construct then + self.construct(parameters) + end + if rawget(def, "_construct_low") then + def._construct_low(parameters) + end + end + --iterate through table properties + setmetatable(def, {__index = self}) + def.construct(def) --moved this to call after the setmetatable, it doesnt seem to break anything, and how it should be? I dont know when I changed it... hopefully not totally broken. + return def +end +--- construct +-- every parent constructor is called in order of inheritance, this is used to make changes to the child table. In self you will find base_class defining what class it is from, and the bool instance indicating (shocking) wether it is an instance. +-- @function construct where self is the definition (after all higher parent calls) of the table. This is the working object, no returns necessary to change it's fields/methods. + + +--- creates an instance of the base class. Calls all constructors in the chain with def.instance=true +-- @return def a new instance of the class. +-- @function Guns4d.Instantiatable_class:new(def) +function mtul.class.new_class:new(def) + --if not def then def = {} else def = table.shallow_copy(def) end + def.base_class = self + def.instance = true + --def.__no_copy = true + function def:inherit() + assert(false, "cannot inherit instantiated object") + end + setmetatable(def, {__index = self}) + --call the construct chain for inherited objects, also important this is called after meta changes + self.construct(def) + return def +end \ No newline at end of file diff --git a/proxy_table.lua b/proxy_table.lua new file mode 100644 index 0000000..faec373 --- /dev/null +++ b/proxy_table.lua @@ -0,0 +1,60 @@ +-- +local Proxy_table = mtul.classes.proxy_table +Proxy_table = { + registered_proxies = {}, + proxy_children = {} +} +--this creates proxy tables in a structure of tables +--this is great if you want to prevent the change of a table +--but still want it to be viewable, such as with constants +function Proxy_table:new(og_table, parent) + local new = {} + self.registered_proxies[og_table] = new + if parent then + self.proxy_children[parent][og_table] = true + else + self.proxy_children[og_table] = {} + parent = og_table + end + --set the proxy's metatable + setmetatable(new, { + __index = function(t, key) + if type(og_table[key]) == "table" then + return Proxy_table:get_or_create(og_table[key], parent) + else + return og_table[key] + end + end, + __newindex = function(table, key) + assert(false, "attempt to edit immutable table, cannot edit a proxy table (MTUL-class)") + end, + }) + --[[overwrite og_table meta to destroy the proxy aswell (but I realized it wont be GCed unless it's removed altogether, so this is pointless) + local mtable = getmetatable(og_table) + local old_gc = mtable.__gc + mtable.__gc = function(t) + self.registered_proxies[t] = nil + self.proxy_children[t] = nil + old_gc(t) + end + setmetatable(og_table, mtable)]] + --premake proxy tables + for i, v in pairs(og_table) do + if type(v) == "table" then + Proxy_table:get_or_create(v, parent) + end + end + return new +end +function Proxy_table:get_or_create(og_table, parent) + return self.registered_proxies[og_table] or Proxy_table:new(og_table, parent) +end +function Proxy_table:destroy_proxy(parent) + self.registered_proxies[parent] = nil + if self.proxy_children[parent] then + for i, v in pairs(self.proxy_children[parent]) do + Proxy_table:destroy_proxy(i) + end + end + self.proxy_children[parent] = nil +end \ No newline at end of file