From b7656b5249f1adee0b6da00e277f11b0a9eb5b9f Mon Sep 17 00:00:00 2001 From: reidlab Date: Sun, 9 Feb 2025 21:04:51 -0800 Subject: [PATCH] init --- .editorconfig | 11 + .gitignore | 4 + README.md | 9 + avatar.json | 12 + avatar.png | Bin 0 -> 1051 bytes models/main.bbmodel | 1 + scripts/ear_physics.lua | 19 + scripts/libs/SquAPI.lua | 1178 ++++++++++++++++++++++++++++++++++++ scripts/libs/SquAssets.lua | 428 +++++++++++++ scripts/main.lua | 6 + scripts/nameplate.lua | 22 + scripts/tail_physics.lua | 17 + scripts/vanilla_model.lua | 6 + textures/extras.png | Bin 0 -> 739 bytes textures/main.png | Bin 0 -> 1753 bytes 15 files changed, 1713 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 README.md create mode 100644 avatar.json create mode 100644 avatar.png create mode 100644 models/main.bbmodel create mode 100644 scripts/ear_physics.lua create mode 100644 scripts/libs/SquAPI.lua create mode 100644 scripts/libs/SquAssets.lua create mode 100644 scripts/main.lua create mode 100644 scripts/nameplate.lua create mode 100644 scripts/tail_physics.lua create mode 100644 scripts/vanilla_model.lua create mode 100644 textures/extras.png create mode 100644 textures/main.png diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..263e3ee --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +end_of_line = lf +indent_style = space +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.nix] +indent_size = 2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a3646cb --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +# figura extension files +.vscode +.luarc.json +avatar.code-workspace diff --git a/README.md b/README.md new file mode 100644 index 0000000..18b8b2c --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# figura-skin + +my figura avatar!! this currently targets version **0.14** + +`textures/vanilla.png` contains the skins base, which can be used as your default minecraft skin if you so choose + +## development + +to get proper typings, find the correct branch for your figura version [on this repository](github.com/GrandpaScout/FiguraRewriteVSDocs/). then, copy everything from the `src/` folder into your current working folder here diff --git a/avatar.json b/avatar.json new file mode 100644 index 0000000..119b9ca --- /dev/null +++ b/avatar.json @@ -0,0 +1,12 @@ +{ + "name": "reidlab's avatar", + "description": "meee", + "authors": [ + "reidlab", + "mrsirsquishy: Squishy's API", + "purpledeni + Manuel_: Gradient Scroll Nickname" + ], + "color": "#d87b5a", + "version": "0.1.4", + "autoScripts": [ "scripts/main.lua" ] +} diff --git a/avatar.png b/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..088cec65536036aaee711526b1c673f21c0ec335 GIT binary patch literal 1051 zcmeAS@N?(olHy`uVBq!ia0y~yU=RUe4kiW$2Bz0tQ49U|>mi z^mSxl*x1kgCy|wbfq}EYBeIx*fp0$uGg`0)t1vJyZ}4<+46*Rf4e`y9b``11Pb+)7 z^?F&7`V1A{VAWnvRWGGhC#FnRrmX@K8w5J!ISZd(Qep{l+RM1NfrWhu*F~={4*D{) z*d`XSE|d$n)8^fI0-3gf6JL`xaGjLTb^ohM&f`|{~F?)N-%DuZ;U9a*dNzchZW zNa{`Jrn)otg|=&JX&;z;Ahe)oANQ;tyBX&+^z{1vPpMXB`25u@p<+Q(y`;oN&I_lS93OR_{GPS{{Oi4L>*F5X&;K1PU0qU~_PqFQ<-hLt zR(&N7ou^g9WA1<3Td&XV{U1k6 z@?G{aS~f>vs;15DEdHuhGKa*NOq38C*vXbVkuyS`}3pdv5qZNW<(+-44U5sHHw{dMB81e~SBbrMpx|DDKA3SC_6%`>1Y^xnh$(_dmxU z{}oC$9@UKSxwd1Xr}t%rJrNeaFS2hj?{n9^!d+f+@QyrBXWfD}#W&~gvPG&NXx%^a zYSM{>9-b|S4&8HnQ*UVanR%u6jjvN4|7=@5XVW^qS$HHoH%Km%*pJ^A5aiv-MrNF&dK-imJOP?hzXutc-`mDlXU zhAtcLs=VB=>ccCi#CLZ;JNyke9~imz$4+10%oBN&f-eg1&@S1VaA?6?v6p?5%7UM} ziM_hH^8PftzY))8FAciVRTZ7BPY?I2ShwC<9$i0{>=+SO)a0#RI=FdB` z@3YLlt)g}2on3yitJT#5%ocMhXC``c?8@38Q^E6A= corner1.x and point.x <= corner2.x and + point.y >= corner1.y and point.y <= corner2.y and + point.z >= corner1.z and point.z <= corner2.z +end + +--returns true if the number is within range, false otherwise +function squassets.inRange(lower, num, upper) + return lower <= num and num <= upper +end + +-- Linear graph +-- locally generates a graph between two points, returns the y value at t on that graph +function squassets.lineargraph(x1, y1, x2, y2, t) + local slope = (y2-y1)/(x2-x1) + local inter = y2 - slope*x2 + return slope*t + inter +end + +--Parabolic graph +--locally generates a parabolic graph between three points, returns the y value at t on that graph +function squassets.parabolagraph(x1, y1, x2, y2, x3, y3, t) + local denom = (x1 - x2) * (x1 - x3) * (x2 - x3) + + local a = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / denom + local b = (x3^2 * (y1 - y2) + x2^2 * (y3 - y1) + x1^2 * (y2 - y3)) / denom + local c = (x2 * x3 * (x2 - x3) * y1 + x3 * x1 * (x3 - x1) * y2 + x1 * x2 * (x1 - x2) * y3) / denom + + return a * t^2 + b * t + c +end + +--returns 1 if num is >= 0, returns -1 if less than 0 +function squassets.sign(num) + if num < 0 then + return -1 + end + return 1 +end + +--returns a vector with the signs of each vector(shows the direction of each vector) +function squassets.Vec3Dir(v) + return vec(squassets.sign(v.x), squassets.sign(v.y), squassets.sign(v.z)) +end + +--raises all values in a vector to a power +function squassets.Vec3Pow(v, power) + local power = power or 2 + return vec(math.pow(v.x, power), math.pow(v.y, power), math.pow(v.z, power)) +end + + + + + + + + +--Debug/Display Functions +-------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------------- + +--displays the corners of a bounding box, good for debugging +---@param corner1 vector coordinate of first corner +---@param corner2 vector coordinate of second corner +---@param color vector of the color, or a string of one of the preset colors +function squassets.bbox(corner1, corner2, color) + dx = corner2[1] - corner1[1] + dy = corner2[2] - corner1[2] + dz = corner2[3] - corner1[3] + squassets.pointMarker(corner1, color) + squassets.pointMarker(corner2, color) + squassets.pointMarker(corner1 + vec(dx,0,0), color) + squassets.pointMarker(corner1 + vec(dx,dy,0), color) + squassets.pointMarker(corner1 + vec(dx,0,dz), color) + squassets.pointMarker(corner1 + vec(0,dy,0), color) + squassets.pointMarker(corner1 + vec(0,dy,dz), color) + squassets.pointMarker(corner1 + vec(0,0,dz), color) +end + + +--draws a sphere +function squassets.sphereMarker(pos, radius, color, colorCenter, quality) + local pos = pos or vec(0, 0, 0) + local r = radius or 1 + local quality = (quality or 1)*10 + local colorCenter = colorCenter or color + + + -- Draw the center point + squassets.pointMarker(pos, colorCenter) + + -- Draw surface points + for i = 1, quality do + for j = 1, quality do + local theta = (i / quality) * 2 * math.pi + local phi = (j / quality) * math.pi + + local x = pos.x + r * math.sin(phi) * math.cos(theta) + local y = pos.y + r * math.sin(phi) * math.sin(theta) + local z = pos.z + r * math.cos(phi) + + squassets.pointMarker(vec(x, y, z), color) + end + end +end + +--draws a line between two points with particles, higher density is more particles +function squassets.line(corner1, corner2, color, density) + local l = (corner2 - corner1):length() -- Length of the line + local direction = (corner2 - corner1):normalize() -- Direction vector + local density = density or 10 + + for i = 0, l, 1/density do + local pos = corner1 + direction * i -- Interpolate position + squassets.pointMarker(pos, color) -- Create a particle at the interpolated position + end +end + +--displays a particle at a point, good for debugging +---@param pos vector coordinate where it will render +---@param color vector of the color, or a string of one of the preset colors +function squassets.pointMarker(pos, color) + if type(color) == "string" then + if color == "R" then color = vec(1, 0, 0) + elseif color == "G" then color = vec(0, 1, 0) + elseif color == "B" then color = vec(0, 0, 1) + elseif color == "yellow" then color = vec(1, 1, 0) + elseif color == "purple" then color = vec(1, 0, 1) + elseif color == "cyan" then color = vec(0, 1, 1) + elseif color == "black" then color = vec(0, 0, 0) + else + color = vec(1,1,1) + end + else + color = color or vec(1,1,1) + end + particles:newParticle("minecraft:wax_on", pos):setSize(0.5):setLifetime(0):setColor(color) +end + + + + + + + + + +--Classes +-------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------------- + +squassets.vanillaElement = {} +squassets.vanillaElement.__index = squassets.vanillaElement +function squassets.vanillaElement:new(element, strength, keepPosition) + local self = setmetatable({}, squassets.vanillaElement) + + -- INIT ------------------------------------------------------------------------- + self.keepPosition = keepPosition + if keepPosition == nil then self.keepPosition = true end + self.element = element + self.element:setParentType("NONE") + self.strength = strength or 1 + self.rot = vec(0,0,0) + self.pos = vec(0,0,0) + + -- CONTROL ------------------------------------------------------------------------- + + self.enabled = true + function self:disable() + self.enabled = false + end + function self:enable() + self.enabled = true + end + function self:toggle() + self.enabled = not self.enabled + end + --returns it to normal attributes + function self:zero() + self.element:setOffsetRot(0, 0, 0) + self.element:setPos(0, 0, 0) + end + --get the current rot/pos + function self:getPos() + return self.pos + end + function self:getRot() + return self.rot + end + + -- UPDATES ------------------------------------------------------------------------- + + function self:render(dt, context) + if self.enabled then + local rot, pos = self:getVanilla() + self.element:setOffsetRot(rot*self.strength) + if self.keepPosition then + self.element:setPos(pos) + end + end + end + + return self +end + +squassets.BERP3D = {} +squassets.BERP3D.__index = squassets.BERP3D +function squassets.BERP3D:new(stiff, bounce, lowerLimit, upperLimit, initialPos, initialVel) + local self = setmetatable({}, squassets.BERP3D) + + self.stiff = stiff or 0.1 + self.bounce = bounce or 0.1 + self.pos = initialPos or vec(0, 0, 0) + self.vel = initialVel or vec(0, 0, 0) + self.acc = vec(0, 0, 0) + self.lower = lowerLimit or {nil, nil, nil} + self.upper = upperLimit or {nil, nil, nil} + + --target is the target position + --dt, or delta time, the time between now and the last update(delta from the events.update() function) + --if you want it to have a different stiff or bounce when run input a different stiff bounce + function self:berp(target, dt, stiff, bounce) + local target = target or vec(0,0,0) + local dt = dt or 1 + + for i = 1, 3 do + --certified bouncy math + local dif = (target[i]) - self.pos[i] + self.acc[i] = ((dif * math.min(stiff or self.stiff, 1)) * dt) --based off of spring force F = -kx + self.vel[i] = self.vel[i] + self.acc[i] + + --changes the position, but adds a bouncy bit that both overshoots and decays the movement + self.pos[i] = self.pos[i] + (dif * (1-math.min(bounce or self.bounce, 1)) + self.vel[i]) * dt + + --limits range + + if self.upper[i] and self.pos[i] > self.upper[i] then + self.pos[i] = self.upper[i] + self.vel[i] = 0 + elseif self.lower[i] and self.pos[i] < self.lower[i] then + self.pos[i] = self.lower + self.vel[i] = 0 + end + end + + --returns position so that you can immediately apply the position as it is changed. + return self.pos + end + + return self +end + + + +--stiffness factor, > 0 +--bounce factor, reccomended when in range of 0-1. bigger is bouncier. +--if you want to limit the positioning, use lowerlimit and upperlimit, or leave nil +squassets.BERP = {} +squassets.BERP.__index = squassets.BERP +function squassets.BERP:new(stiff, bounce, lowerLimit, upperLimit, initialPos, initialVel) + local self = setmetatable({}, squassets.BERP) + + self.stiff = stiff or 0.1 + self.bounce = bounce or 0.1 + self.pos = initialPos or 0 + self.vel = initialVel or 0 + self.acc = 0 + self.lower = lowerLimit or nil + self.upper = upperLimit or nil + + --target is the target position + --dt, or delta time, the time between now and the last update(delta from the events.update() function) + --if you want it to have a different stiff or bounce when run input a different stiff bounce + function self:berp(target, dt, stiff, bounce) + local dt = dt or 1 + + --certified bouncy math + local dif = (target or 10) - self.pos + self.acc = ((dif * math.min(stiff or self.stiff, 1)) * dt) --based off of spring force F = -kx + self.vel = self.vel + self.acc + + --changes the position, but adds a bouncy bit that both overshoots and decays the movement + self.pos = self.pos + (dif * (1-math.min(bounce or self.bounce, 1)) + self.vel) * dt + + --limits range + + if self.upper and self.pos > self.upper then + self.pos = self.upper + self.vel = 0 + elseif self.lower and self.pos < self.lower then + self.pos = self.lower + self.vel = 0 + end + + --returns position so that you can immediately apply the position as it is changed. + return self.pos + end + + + + return self +end + + +return squassets diff --git a/scripts/main.lua b/scripts/main.lua new file mode 100644 index 0000000..8d64bcc --- /dev/null +++ b/scripts/main.lua @@ -0,0 +1,6 @@ +events.ENTITY_INIT:register(function () + require("scripts.vanilla_model") + require("scripts.tail_physics") + require("scripts.ear_physics") + require("scripts.nameplate") +end) diff --git a/scripts/nameplate.lua b/scripts/nameplate.lua new file mode 100644 index 0000000..1ed2a1c --- /dev/null +++ b/scripts/nameplate.lua @@ -0,0 +1,22 @@ +local name = "reidlab!" +local colors = { "#d87b5a", "#e0ab91" } +local offset = 0.05 +local speed = 0.05 + +colors[#colors + 1] = colors[1] +offset = offset / speed + +function events.tick() + local newName = "[" + + for i = 1, #name, 1 do + local counter = (((world.getTime() + offset * i) * speed) % (#colors - 1)) + 1 + local counterFloored = math.floor(counter) + local color = math.lerp(vectors.hexToRGB(colors[counterFloored]), vectors.hexToRGB(colors[counterFloored + 1]), counter - counterFloored) + newName = newName .. '{"text":"' .. name:sub(i,i) .. '","color":"#' .. vectors.rgbToHex(color) .. '"},' + avatar:setColor(color) + end + + newName = newName:sub(1, #newName - 1) .. "]" + nameplate.ALL:setText(newName) +end diff --git a/scripts/tail_physics.lua b/scripts/tail_physics.lua new file mode 100644 index 0000000..5f36ff0 --- /dev/null +++ b/scripts/tail_physics.lua @@ -0,0 +1,17 @@ +local squapi = require("scripts.libs.SquAPI") + +local segments = { + models.models.main.Body.Tail, + models.models.main.Body.Tail2, + models.models.main.Body.Tail3 +} + +squapi.tail:new( + segments, + nil, + nil, + nil, + nil, + 1, + 5 +) diff --git a/scripts/vanilla_model.lua b/scripts/vanilla_model.lua new file mode 100644 index 0000000..1e0ffda --- /dev/null +++ b/scripts/vanilla_model.lua @@ -0,0 +1,6 @@ +for _, vanillaModel in ipairs({ + vanilla_model.PLAYER, + vanilla_model.ARMOR +}) do + vanillaModel:setVisible(false) +end diff --git a/textures/extras.png b/textures/extras.png new file mode 100644 index 0000000000000000000000000000000000000000..74cf67a064fe0327fdaa22ef66aca44f04613d02 GIT binary patch literal 739 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 aenCsO8TW1#PGMkRVDNPHb6Mw<&;$V6=|=|u literal 0 HcmV?d00001