introduction
a guide to show how to setup a basic plugin
Creating your own module is quite simple really !. here we will make an empty module
tip
When debugging plugins you can enable the debug
mode in C3D to have libC3D/c3d.log contain ton of details about plugin loading !
check how to enable debug mode
First you want to define your init function into which the plugin registration will go
function c3d.init() end
after getting that you need to create the actual plugin object. the plugin load function provides you with a plug/plugin
variable you can use to create a plugin with a given name
function c3d.init() c3d.plugin.load(function() local very_awesome_plugin = plug.new("9551Dev:awesome-plugin") end) end
while this will create your plugin C3D wont actually know it exists since it has not been registered. you can easily do that using the register method
function c3d.init() c3d.plugin.load(function() local very_awesome_plugin = plug.new("9551Dev:awesome-plugin") very_awesome_plugin:register() end) end
now our plugin will be registered but wont show many signs of life. To give it atleast some we can have it output into log when it actually gets registered! to archive this we can use the plugin.on_init_finish callback which gets ran once all plugins have been registered. to find more check plugin callbacks
function c3d.init() c3d.plugin.load(function() local very_awesome_plugin = plug.new("9551Dev:awesome-plugin") function very_awesome_plugin.on_init_finish() c3d.log.add("Hello from awesome plugin !") c3d.log.dump() end very_awesome_plugin:register() end) end
everything after this will be more complex and less commented. you can find more info in the other tabs of the plugin tab
adding a module
now i will add my own module to be used by this plugin. this is done by grabbing the module registry and making new entry in within the register_modules plugin callback
function c3d.init() c3d.plugin.load(function() local very_awesome_plugin = plug.new("9551Dev:awesome-plugin") function very_awesome_plugin.register_modules() local module_registry = c3d.registry.get_module_registry() local awesome_module = module_registry:new_entry("awesome") -- makes the module be called "awesome" end function very_awesome_plugin.on_init_finish() c3d.log.add("Hello from awesome plugin !") c3d.log.dump() end very_awesome_plugin:register() end) end
All thats left for a module is to add some values into it. like functions and such. so why not add a function that just kills C3D by erroring ! :P
function c3d.init() c3d.plugin.load(function() local very_awesome_plugin = plug.new("9551Dev:awesome-plugin") function very_awesome_plugin.register_modules() local module_registry = c3d.registry.get_module_registry() local awesome_module = module_registry:new_entry("awesome") -- makes the module be called "awesome" awesome_module:set_entry(c3d.registry.entry("die"),function() error("oops.") end) end function very_awesome_plugin.on_init_finish() c3d.log.add("Hello from awesome plugin !") c3d.log.dump() end very_awesome_plugin:register() end) end
Now as mentioned you can also use plugins to modify existing entries. As an example of this lets have the c3d.vector.new function just error this will be done by grabbing the registry ID from a environment variable and then using the :get function of the registry
function c3d.init() c3d.plugin.load(function() local very_awesome_plugin = plug.new("9551Dev:awesome-plugin") function very_awesome_plugin.register_modules() local module_registry = c3d.registry.get_module_registry() local vector_module = module_registry:get(MODULE.vector) -- grabs the vector module from the registry vector_module:set_entry(c3d.registry.entry("new"),function() error("oops. no way you making a vector") end) end function very_awesome_plugin.on_init_finish() c3d.log.add("Hello from awesome plugin !") c3d.log.dump() end very_awesome_plugin:register() end) end
Now lets go back a bit and lets see about threads.
Threads can be used to run some update code along with C3D in the background. for example we can have a plugin that will log the FPS every 5 seconds Lets make an example of that here !. this will be very similiar to modules. but actually simpler ! we again use a callback for thread registration and we make a new entry in a registry.
function c3d.init() c3d.plugin.load(function() local very_awesome_plugin = plug.new("9551Dev:awesome-plugin") function very_awesome_plugin.register_threads() local thread_registry = c3d.registry.get_thread_registry() thread_registry:set_entry(c3d.registry_entry("fps-logger-thread"),function() while true do c3d.log.add(c3d.timer.getFPS()) c3d.log.dump() sleep(5) end end) end function very_awesome_plugin.on_init_finish() c3d.log.add("Hello from awesome plugin !") c3d.log.dump() end very_awesome_plugin:register() end) end
objects
now we shall step back again before we did modules. and we should try making our own objects and modifying existing ones. objects are probably the most complex part of C3D plugin making. as you can even do things like add support for new file formats into existing objects.
lets start of by clarifying what an object is. an object is some kind of structure with methods and other values attached to it. along with tools to work with those values.
Any C3D object needs to have a constructor defined. and thats really it. With registies it is the same as with modules. So lets make an object which is just well.. a table. with nothing special.
function c3d.init() c3d.plugin.load(function() local very_awesome_plugin = plug.new("9551Dev:awesome-plugin") function very_awesome_plugin.register_objects() local object_registry = c3d.registry.get_object_registry() local awesome_table = object_registry:new_entry("awesome_table") -- makes the module be called "awesome" awesome_table:constructor(function() return {} end) end function very_awesome_plugin.on_init_finish() c3d.log.add("Hello from awesome plugin !") c3d.log.dump() end very_awesome_plugin:register() end) end
the final goal of this is going to make an object which can be made from a file and will automatically parse json and CC tables from files. also provide get and and set functions cause why not. This will include making a module for creating new objects. As otherwise the object cant be interacted with by the user
So lets start that off by adding a module for creating new objects of this type.
function c3d.init() c3d.plugin.load(function() local very_awesome_plugin = plug.new("9551Dev:awesome-plugin") function very_awesome_plugin.register_objects() local object_registry = c3d.registry.get_object_registry() local awesome_table = object_registry:new_entry("awesome_table") -- makes the module be called "awesome" awesome_table:constructor(function() return {} end) end function very_awesome_plugin.register_modules() local module_registry = c3d.registry.get_module_registry() local awesome_table_module = module_registry:new_entry("awesome_table") local data_bus = very_awesome_plugin.get_c3d_bus() awesome_table_module:set_entry(c3d.registry.entry("new"),function(...) data_bus.object.awesome_table.new(...) end) end function very_awesome_plugin.on_init_finish() c3d.log.add("Hello from awesome plugin !") c3d.log.dump() end very_awesome_plugin:register() end) end
now that we got our module we can finally get to how file handling works. you can define a decoder for an object using :define_decoder and then use :read_file on the object with a given path, which will automatically pick a decoder using the extension in the path given. run the function with the path modifying to fit the projects path and then return what the decoder returns.
note that the data given to :define_decoder needs to be a table with a read
function in it.
the goal here will be to provide either a path to .tbl or .json but have the object always be a Lua table when made using the module with a given path.
function c3d.init() local function json_decode(path) local file = fs.open(path,"w") local data = file.readAll() file.close() return textutils.unserializeJSON(data) end local function tbl_decode(path) local file = fs.open(path,"w") local data = file.readAll() file.close() return textutils.unserialize(data) end c3d.plugin.load(function() local very_awesome_plugin = plug.new("9551Dev:awesome-plugin") function very_awesome_plugin.register_objects() local object_registry = c3d.registry.get_object_registry() local awesome_table = object_registry:new_entry("awesome_table") -- makes the module be called "awesome"ยจ awesome_table:define_decoder(".json",json_decode) awesome_table:define_decoder(".tbl", tbl_decode) awesome_table:constructor(function(path) return awesome_table:read_file(path) end) end function very_awesome_plugin.register_modules() local module_registry = c3d.registry.get_module_registry() local awesome_table_module = module_registry:new_entry("awesome_table") local data_bus = very_awesome_plugin.get_c3d_bus() awesome_table_module:set_entry(c3d.registry.entry("new"),function(...) data_bus.object.awesome_table.new(...) end) end function very_awesome_plugin.on_init_finish() c3d.log.add("Hello from awesome plugin !") c3d.log.dump() end very_awesome_plugin:register() end) end
Thats almost it! the last thing worthy of noting is how to modify existing objects. here we got an awesome_table object which we made in the registry. But lets say we want to add a new method to the vector object. Like add a function which logs the vector. We can do that as easily as with modules!
function c3d.init() c3d.plugin.load(function() local very_awesome_plugin = plug.new("9551Dev:awesome-plugin") function very_awesome_plugin.register_objects() local object_registry = c3d.registry.get_object_registry() local vector_object = object_registry:get(OBJECT.vector) -- grabs the vector object from the registry vector_object:set_entry(c3d.registry.entry("log"),function(this) c3d.log.add("Vector: "..this) c3d.log.dump() end) end function very_awesome_plugin.on_init_finish() c3d.log.add("Hello from awesome plugin !") c3d.log.dump() end very_awesome_plugin:register() end) end
Now you may not realize how powerful this is. but this gives you access to the whole vector object. you can modify the constructor or even define new decoders !
congrats you made it to the end ! hopefully you should now have a good idea of what C3D plugins are capable off :P
quick note: this api took really long to pull off lmao