diff --git a/script.lua b/script.lua index 85387a4..c8788ba 100644 --- a/script.lua +++ b/script.lua @@ -5,264 +5,11 @@ TEXTURE_WIDTH = 128 TEXTURE_HEIGHT = 128 --- utility functions -- {{{ - ---- Create a string representation of a table ---- @param o table -function dumpTable(o) - if type(o) == 'table' then - local s = '{ ' - local first_loop=true - for k,v in pairs(o) do - if not first_loop then - s = s .. ', ' - end - first_loop=false - if type(k) ~= 'number' then k = '"'..k..'"' end - s = s .. '['..k..'] = ' .. dumpTable(v) - end - return s .. '} ' - else - return tostring(o) - end -end - -do - local function format_any_value(obj, buffer) - local _type = type(obj) - if _type == "table" then - buffer[#buffer + 1] = '{"' - for key, value in next, obj, nil do - buffer[#buffer + 1] = tostring(key) .. '":' - format_any_value(value, buffer) - buffer[#buffer + 1] = ',"' - end - buffer[#buffer] = '}' -- note the overwrite - elseif _type == "string" then - buffer[#buffer + 1] = '"' .. obj .. '"' - elseif _type == "boolean" or _type == "number" then - buffer[#buffer + 1] = tostring(obj) - else - buffer[#buffer + 1] = '"???' .. _type .. '???"' - end - end - --- Dumps object as UNSAFE json, i stole this from stackoverflow so i could use json.tool to format it so it's easier to read - function dumpJSON(obj) - if obj == nil then return "null" else - local buffer = {} - format_any_value(obj, buffer) - return table.concat(buffer) - end - end -end - - ----@param uv table -function UV(uv) - return vectors.of({ - uv[1]/TEXTURE_WIDTH, - uv[2]/TEXTURE_HEIGHT - }) -end - - ----@param inputstr string ----@param sep string -function splitstring (inputstr, sep) - if sep == nil then - sep = "%s" - end - local t={} - for str in string.gmatch(inputstr, "([^"..sep.."]+)") do - table.insert(t, str) - end - return t -end - ----@param input string -function unstring(input) - if input=="nil" then - return nil - elseif input == "true" or input == "false" then - return input=="true" - elseif tonumber(input) ~= nil then - return tonumber(input) - else - return input - end -end - ----@param func function ----@param table table -function map(func, table) - local t={} - for k, v in pairs(table) do - t[k]=func(v) - end - return t -end - ----@param func function ----@param table table -function filter(func, table) - local t={} - for k, v in pairs(table) do - if func(v) then - t[k]=v - end - end - return t -end - ----@param tbl table ----@param val any -function has_value(tbl, val) - for _, v in pairs(tbl) do - if v==val then return true end - end - return false -end - ---- Unordered reduction, only use when working with dictionaries and ---- execution order does not matter ----@param tbl table Table to reduce ----@param func function Function used to reduce table ----@param init any Initial operand for reduce function -function reduce(func, tbl, init) - local result = init - local first_loop = true - for _, v in pairs(tbl) do - if first_loop and init == nil then - result=v - else - result = func(result, v) - end - first_loop=false - end - return result -end - ---- Ordered reduction, does not work with dictionaries ----@param tbl table Table to reduce ----@param func function Function used to reduce table ----@param init any Initial operand for reduce function -function ireduce(func, tbl, init) - local result = init - local first_loop = true - for _, v in ipairs(tbl) do - if first_loop and init == nil then - result=v - else - result = func(result, v) - end - first_loop=false - end - return result -end - ---- Merge two tables. First table value takes precedence when conflict occurs. ----@param tb1 table ----@param tb2 table -function mergeTable(tb1, tb2) - local t={} - for k, v in pairs(tb1) do - t[k]=v - end - for k, v in pairs(tb2) do - if type(k)=="number" then - table.insert(t, v) - else - if t[k]==nil then - t[k]=v - end - end - end - return t -end - -function debugPrint(var) - print(dumpTable(var)) - return var -end - ---- Recursively walk a model tree and return a table containing the group and each of its sub-groups ---- @param group table The group to recurse ---- @return table Resulting table -function recurseModelGroup(group) - local t={} - table.insert(t, group) - if group.getType()=="GROUP" then - for k, v in pairs(group.getChildren()) do - for _, v2 in pairs(recurseModelGroup(v)) do - table.insert(t, v2) - end - end - end - return t -end --- }}} - --- Timer (not mine lol) -- {{{ -do - local timers = {} - function wait(ticks,next) - table.insert(timers, {t=world.getTime()+ticks,n=next}) - end - function tick() - for key,timer in pairs(timers) do - if world.getTime() >= timer.t then - timer.n() - table.remove(timers,key) - end - end - end -end - --- named timers (this one is mine but heavily based on the other) -- --- if timer is armed twice before expiring it will only be called once) -- -do - local timers = {} - function namedWait(ticks, next, name) - -- main difference, this will overwrite an existing timer with - -- the same name - timers[name]={t=world.getTime()+ticks,n=next} - end - function tick() - for key, timer in pairs(timers) do - if world.getTime() >= timer.t then - timer.n() - timers[key]=nil - end - end - end -end - --- named cooldowns -do - local timers={} - function cooldown(ticks, name) - if timers[name] == nil then - timers[name]={t=world.getTime()+ticks} - return true - end - return false - end - function tick() - for key, timer in pairs(timers) do - if world.getTime() >= timer.t then - timers[key]=nil - end - end - end -end - -function rateLimit(ticks, next, name) - if cooldown(ticks+1, name) then - namedWait(ticks, next, name) - end -end - --- }}} +PartsManager = require("nulllib.PartsManager") +nmath = require("nulllib.math") +nmath +lerp=math.lerp +wave=nmath.wave -- syncState {{{ function syncState() @@ -291,15 +38,6 @@ function ping.syncState(tbl) end -- }}} --- Math {{{ ---- Sine function with period and amplitude ---- @param x number Input value ---- @param period number Period of sine wave ---- @param amp number Peak amplitude of sine wave -function wave(x, period, amp) return math.sin((2/period)*math.pi*(x%period))*amp end -function lerp(a, b, t) return a + ((b - a) * t) end --- }}} - -- Master and local state variables -- {{{ -- Local State (these are copied by pings at runtime) -- local_state={} @@ -364,131 +102,6 @@ end -- }}} --- PartsManager -- {{{ -do - PartsManager={} - local pm={} - - --- ensure part is initialized - local function initPart(part) - local part_key=tostring(part) - if pm[part_key] == nil then - pm[part_key]={} - end - pm[part_key].part=part - if pm[part_key].functions == nil then - pm[part_key].functions = {} - end - if pm[part_key].init==nil then - pm[part_key].init="true" - end - end - --- Add function to part in PartsManager. - --- @param part table Any object with a setEnabled() method. - --- @param func function Function to add to model part's function chain. - --- @param init? boolean Default value for chain. Should only be set once, subsequent uses overwrite the entire chain's initial value. - function PartsManager.addPartFunction(part, func, init) - initPart(part) - local part_key=tostring(part) - if init ~= nil then - pm[part_key].init=init - end - table.insert(pm[part_key]["functions"], func) - end - - --- Set initial value for chain. - --- @param part table Any object with a setEnabled() method. - --- @param init? boolean Default value for chain. Should only be set once, subsequent uses overwrite the entire chain's initial value. - function PartsManager.setInitialValue(part, init) - assert(init~=nil) - initPart(part) - local part_key=tostring(part) - pm[part_key].init=init - end - - --- Set initial value for chain on all objects in table. - --- @param group table A table containing objects with a setEnabled() method. - --- @param init? boolean Default value for chain. Should only be set once, subsequent uses overwrite the entire chain's initial value. - function PartsManager.setGroupInitialValue(group, init) - assert(init~=nil) - for _, v in pairs(group) do - PartsManager.setInitialValue(v, init) - end - end - - --- Evaluate a part's chain to determine if it should be visible. - --- @param part table An object managed by PartsManager. - function PartsManager.evaluatePart(part) - local part_key=tostring(part) - assert(pm[part_key] ~= nil) - - local evalFunc=function(x, y) return y(x) end - local init=pm[part_key].init - return ireduce(evalFunc, pm[part_key].functions, true) - end - local evaluatePart=PartsManager.evaluatePart - - --- Refresh (enable or disable) a part based on the result of it's chain. - --- @param part table An object managed by PartsManager. - function PartsManager.refreshPart(part) - local part_enabled=evaluatePart(part) - part.setEnabled(part_enabled) - return part_enabled - end - - --- Refresh all parts managed by PartsManager. - function PartsManager.refreshAll() - for _, v in pairs(pm) do - PartsManager.refreshPart(v.part) - end - end - - --- Add function to list of parts in PartsManager - --- @param group table A table containing objects with a setEnabled() method. - --- @param func function Function to add to each model part's function chain. - --- @param default? boolean Default value for chain. Should only be set once, subsequent uses overwrite the entire chain's initial value. - function PartsManager.addPartGroupFunction(group, func, default) - for _, v in ipairs(group) do - PartsManager.addPartFunction(v, func, default) - end - end -end --- }}} - --- UVManager {{{ -do - local mt={} - UVManager = { - step=vectors.of{u=0, v=0}, - offset=vectors.of{u=0, v=0}, - positions={} - } - mt.__index=UVManager - function UVManager.new(self, step, offset, positions) - local t={} - if step ~= nil then t.step=vectors.of(step) end - if offset ~= nil then t.offset=vectors.of(offset) end - if positions ~= nil then t.positions=positions end - t=setmetatable(t, mt) - return t - end - function UVManager.getUV(self, input) - local vec={} - local stp=self.step - local offset=self.offset - if type(input) == "string" then - if self.positions[input] == nil then return nil end - vec=vectors.of(self.positions[input]) - else - vec=vectors.of(input) - end - local u=offset.u+(vec.u*stp.u) - local v=offset.v+(vec.v*stp.v) - return UV{u, v} - end -end --- }}} - -- Part groups {{{ VANILLA_GROUPS={ ["HEAD"]={vanilla_model.HEAD, vanilla_model.HAT}, @@ -513,66 +126,66 @@ TAIL_BONES={model.Body_Tail, model.Body_Tail.Tail2, model.Body_Tail.Tail2.Tail3, TAIL_ROT={vectors.of{37.5, 0, 0}, vectors.of{-17.5, 0, 0}, vectors.of{-17.5, 0, 0}, vectors.of{-15, 0, 0}} -- }}} --- Enable commands -- {{{ -chat_prefix="$" -chat.setFiguraCommandPrefix(chat_prefix) -function onCommand(input) - local pfx=chat_prefix - input=splitstring(input) - if input[1] == chat_prefix .. "vanilla" then - setVanilla() - print("Vanilla skin is now " .. (skin_state.vanilla_enabled and "enabled" or "disabled")) - end - if input[1] == chat_prefix .. "toggle_custom" then - for key, value in pairs(model) do - value.setEnabled(not value.getEnabled()) - end - end - if input[1] == chat_prefix .. "toggle_outer" then - for k, v in pairs(VANILLA_GROUPS.OUTER) do - v.setEnabled(not v.getEnabled()) - end - end - if input[1] == chat_prefix .. "toggle_inner" then - for k, v in pairs(VANILLA_GROUPS.INNER) do - v.setEnabled(not v.getEnabled()) - end - end - if input[1] == chat_prefix .. "test_expression" then - setExpression(input[2], input[3]) - print(input[2] .. " " .. input[3]) - end - if input[1] == chat_prefix .. "snore" then - if input[2] == "toggle" or #input==1 then - setSnoring() - log("Snoring is now " .. (skin_state.snore_enabled and "enabled" or "disabled")) - end - end - if input[1] == chat_prefix .. "armor" then - setArmor() - log("Armor is now " .. (skin_state.armor_enabled and "enabled" or "disabled")) - end - if input[1] == chat_prefix .. "settings" then - if #input==1 then - printSettings() - elseif #input==2 then - log(tostring(skin_state[input[2]])) - elseif #input==3 then - if skin_state[input[2]] ~= nil then - setState(input[2], unstring(input[3])) - log(tostring(input[2]) .. " is now " .. tostring(skin_state[input[2]])) - syncState() - else - log(tostring(input[2]) .. ": no such setting") - end - end - end - if input[1] == chat_prefix .. "pv" then - setState("vanilla_partial") - syncState() - end -end ---}}} +-- -- Enable commands -- {{{ +-- chat_prefix="$" +-- chat.setFiguraCommandPrefix(chat_prefix) +-- function onCommand(input) +-- local pfx=chat_prefix +-- input=splitstring(input) +-- if input[1] == chat_prefix .. "vanilla" then +-- setVanilla() +-- print("Vanilla skin is now " .. (skin_state.vanilla_enabled and "enabled" or "disabled")) +-- end +-- if input[1] == chat_prefix .. "toggle_custom" then +-- for key, value in pairs(model) do +-- value.setEnabled(not value.getEnabled()) +-- end +-- end +-- if input[1] == chat_prefix .. "toggle_outer" then +-- for k, v in pairs(VANILLA_GROUPS.OUTER) do +-- v.setEnabled(not v.getEnabled()) +-- end +-- end +-- if input[1] == chat_prefix .. "toggle_inner" then +-- for k, v in pairs(VANILLA_GROUPS.INNER) do +-- v.setEnabled(not v.getEnabled()) +-- end +-- end +-- if input[1] == chat_prefix .. "test_expression" then +-- setExpression(input[2], input[3]) +-- print(input[2] .. " " .. input[3]) +-- end +-- if input[1] == chat_prefix .. "snore" then +-- if input[2] == "toggle" or #input==1 then +-- setSnoring() +-- log("Snoring is now " .. (skin_state.snore_enabled and "enabled" or "disabled")) +-- end +-- end +-- if input[1] == chat_prefix .. "armor" then +-- setArmor() +-- log("Armor is now " .. (skin_state.armor_enabled and "enabled" or "disabled")) +-- end +-- if input[1] == chat_prefix .. "settings" then +-- if #input==1 then +-- printSettings() +-- elseif #input==2 then +-- log(tostring(skin_state[input[2]])) +-- elseif #input==3 then +-- if skin_state[input[2]] ~= nil then +-- setState(input[2], unstring(input[3])) +-- log(tostring(input[2]) .. " is now " .. tostring(skin_state[input[2]])) +-- syncState() +-- else +-- log(tostring(input[2]) .. ": no such setting") +-- end +-- end +-- end +-- if input[1] == chat_prefix .. "pv" then +-- setState("vanilla_partial") +-- syncState() +-- end +-- end +-- --}}} -- PartsManager Rules {{{ do @@ -613,13 +226,13 @@ do end -- }}} --- Action Wheel {{{ -do - local slot_1_item = item_stack.createItem("minecraft:netherite_helmet") - action_wheel.SLOT_1.setTitle('Toggle Armor') - action_wheel.SLOT_1.setFunction(function() setArmor() end) - action_wheel.SLOT_1.setItem(slot_1_item) -end +-- -- Action Wheel {{{ +-- do +-- local slot_1_item = item_stack.createItem("minecraft:netherite_helmet") +-- action_wheel.SLOT_1.setTitle('Toggle Armor') +-- action_wheel.SLOT_1.setFunction(function() setArmor() end) +-- action_wheel.SLOT_1.setItem(slot_1_item) +-- end function setArmor()