This is a unofficial changelog of Figura's 0.0.7 updates. All of this is compiled from the Official Figura Discord Figura is a mod for Minecraft: Java Edition that adds support for custom models using Block Bench projects and Lua scripts. You can find more information on their Github page
This is a very very lazily compiled list of most API related changes and things in 0.0.7 as of RC 8, Look at the changelogs for more info. Currently I have compiled all changes from 0.0.7 Release, You can check the changelog for that here
- Documentation: https://cdn.discordapp.com/attachments/349077838240022538/900065078110470205/shader_tut.txt → also heres a template model just in case: https://cdn.discordapp.com/attachments/349077838240022538/900065075287711744/shader_template.zip
- You can now provide item ids like the give command, Example: action_wheel.SLOT_1.setItem('player_head{SkullOwner:"Francielly"}')
- changed rendering method from EntityTranslucent to EntityTranslucentCull → this means that textures are now rendered in only ONE side of the face → this allows things like inverted cubes (outlines) → if you have a cube with 0 depth, you can mimic the previous behaviour by copying the face uv from the opposite side and mirroring its X
- added a new button that completely stops figura rendering until you press it again
- default to unbounded, so you need to choose the keybing yourself :p
-
added Camera parent type → makes objects always face the camera → currently better to be used with parts inside NOPARENT groups → using parts transformations (setPos(), setRot(), etc) might lead in fuzzy behaviour
-
you can choose which texture to use per part → model..setTexture(Texture string, ID string) → ID is only required when using the "Resource" type
Textures: → Custom = your custom texture, if any (default) → Skin = your vanilla minecraft skin → Cape = your cape, or Steve if you dont have a cape → Elytra = your elytra texture (NOT the cape-provided elytra!) (vanilla probably dont even use it at all) → Resource = any loaded vanilla texture! or missing texture if nor found (supports resource packs) (does NOT supports .mcmeta!)
Examples: model.left.setTexture("Skin") model.right.setTexture("Resource", "minecraft:textures/item/apple.png") model.right.setTexture("Resource", "minecraft:textures/entity/zombie/zombie.png") model.left.setTexture("Cape") model.right.setTexture("Resource", "minecraft:textures/models/armor/diamond_layer_1.png")
Templates: Cape → https://cdn.discordapp.com/attachments/349077838240022538/891812241433841684/cape_example.png Skin → https://cdn.discordapp.com/attachments/349077838240022538/891812243413536828/skin_example.png → skin info: black/textured = all alpha gonna be tinted black in there textured/pink = used by the vanilla model pink = optional, can be disabled in-game transparent = free space
-
Disabling the extra textures rendering (currently we use only emissive) → model..setExtraTexEnabled(boolean)
-
Setting UV and texture size → get/setTextureSize(vector) → vector of two values, X and Y, for the size of the texture- → getUVData(Face string)/setUVData(Face string, vector) → a face string, and a vector of 4 values, blockbench uv format → get/setUV() still works and will act as normal (not deprecated)
-
added getType() → returns a string, either "CUBE", "GROUP" or "MESH", of the part type
-
added getName() → returns a string, of the part name (the name as in blockbench for this cube/bone)
-
added setRenderLayers(string) → sets the render layer (custom shader) of the part
-
add get/setCullEnabled(boolean) → enables culling on the custom part
- added setScale(vector) :3
- added "CAPE" accessor, which is well, your cape
- added "EAR" accessor, used for deadmau5 ears (only useful with ear mods, or if youre deadmau5)
-
added getModelStatus()
-
added getScriptStatus()
-
added getTextureStatus()
-
added getBackendStatus() → all of them returns a number between 1 to 4 indicating its current state → 1 - white, 2 - red, 3 - yellow, 4 - green → hover the avatar indicators at the model preview screen for more info
-
added getCanHaveCustomRenderLayer() → returns a boolean if the player can use custom render layers (shaders)
- added isUsingItem()
- added getActiveHand() → get the player active hand → outputs are: nil, "MAIN_HAND", "OFF_HAND" → only updates after using an item → if no item was ever used, it returns nil
- added getActiveItem() → returns an item stack table of the active item
- added isTouchingWater() → true if the entity has contact with water or waterlogged blocks
- added isUnderwater() → true if the entity is fully submerged in water
- added isInLava() → true if the entity is touching lava
- added isInRain() → true if the entity has contact with rain, false for snow
- added isOpenSky(vector pos) → true if the pos has sky access
- added getBiomeTemperature(vector pos) → returns a float of the biome temperature
- added getBiomePrecipitation(vector pos) → returns "NONE", "RAIN" or "SNOW", depending on the biome weather type
- added world.raycastBlocks(startPos, endPos, shapeHandling, fluidHandling, predicate) → Casts a ray from startPos to endPos, looking at the blocks on the way → shapeHandling can be "COLLIDER", "OUTLINE", or "VISUAL" depending on how you want the raycaster to check → fluidHandling can be "NONE", "SOURCE_ONLY", or "ANY", depending on what kinds of fluid blocks should stop the raycast → predicate is optional. It's a function which takes a BlockState and a position. It returns true if you want the raycast to count that as a block, or false if you want it to ignore that block and continue raycasting → world.raycastBlocks returns a table containing two things → table.state - the BlockState of the block you ended up hitting → table.pos - the exact (decimal) position where the ray hit in the world → If the ray never hits anything, then the function returns nil _
- added world.raycastEntities(startPos, endPos, predicate) → Casts a ray from startPos to endPos, returning the first entity it sees on the way → Similar to world.raycastBlocks, predicate is a function which takes an entity and returns a boolean based on if that entity should count as a valid target → Returns the entity table of the first entity the ray hits → If it doesn't hit any entities, returns nil
→ similar to the meta api, the client api access your client variables → only accessible with the host script (local player) → using it on non-host will always return nil for everything (except isHost)
-
added getSystemTime() → returns your current in-real-life time, in milliseconds
-
Original functions: getOpenScreen, getFPS, isPaused, getVersion, getVersionType, getServerBrand, getChunksCount, getEntityCount, getParticleCount, getSoundCount, getActiveShader, getJavaVersion, getMemoryInUse, getMaxMemory, getAllocatedMemory, isWindowFocused, isHudEnabled, getWindowSize, getGUIScale, getFov, isHost
-
you can also change your crosshair properties with: get/setCrosshairPos and get/setCrosshairEnabled
- added isOpen() → return a bool if the action wheel is open or not
- added new line support for titles
- Custom textures → get/setTexture(string type, string id) → set the action wheel custom texture, and ID if its from the game assets → get/setTextureScale(vector) → set the texture scale → get/setUV(vector uvOffset, vector uvSize, vector textureSize) → set the custom texture uv
example: action_wheel.SLOT_2.setTexture("Skin") action_wheel.SLOT_2.setUV({8, 8}, {8, 8}, {64, 64}) action_wheel.SLOT_2.setTextureScale({2, 2})
texture types: → "None" → nothing, uses an item instead → "Custom" → uses your custom/model texture → "Skin" → uses the player vanilla skin → "Cape" → uses the player cape → "Elytra" → uses the player elytra → "Resource" → uses an ingame/resource pack texture
- added getInputText() → returns the text from the message input field, or nil if its empty
- added isBlockItem() → return a boolean if the item has a block form
-
added block/item/text rendering → its a way to render game assets → its cleared on each render tick, so you might want to put them on the render function → it counts towards your model complexity, so beware!
-
renderer.renderBlock(BlockState string, ModelPart, emissive bool, pos, rot, scale) → renders a block
-
renderer.renderItem(ItemStack, ModelPart, TransformationMode, emissive bool, pos, rot, scale) → renders an item
-
renderer.renderText(Text string, ModelPart, emissive bool, pos, rot, scale) → renders a text
→ BlockState = blockstate string, just like how you do in vanilla commands like /setblock (no liquids included) → ItemStack = item stack table, from the item stack API → Text = JSON formatted (or legacy) string → ModelPart = parent part that this extra render gonna be attached to → TransformationMode = mode that the ItemStack gonna be rendered (values listed below) → Emissive = a boolean flag if its emissive or not → pos/rot/scale = A vector (or table) of three values
Examples: local part = model.NO_PARENT.bone renderer.renderText("hello world", part, true, {0, -16, -16.01}) renderer.renderText('{"text":"bye world","color":"#ff0000"}', part, true, {0, -12, -16.01}) renderer.renderBlock("minecraft:redstone_lamp[lit=true]", part, false, {16, 0, 0}) renderer.renderBlock("minecraft:light_blue_stained_glass", part) renderer.renderItem(player.getEquipmentItem(2), part, "THIRD_PERSON_LEFT_HAND", true, {16, -24, -4}, nil, {3, 3, 3}) renderer.renderText("hi mum im on a screenshot", model.base.body.Tail.main, true)
TransformationModes: → "NONE" = no transformations → "THIRD_PERSON_LEFT_HAND" = used when in 3rd person, left hand → "THIRD_PERSON_RIGHT_HAND" = used when in 3rd person, right hand → "FIRST_PERSON_LEFT_HAND" = used when in 1st person, left hand → "FIRST_PERSON_RIGHT_HAND" = used when in 1st person, right hand → "HEAD" = used when worn on the head → "GUI" = used on the GUI → "GROUND" = used on dropped items → "FIXED" = used on item frames
-
added renderer.setMountEnabled(boolean) → toggle the render of the entity youre riding
-
added renderer.setMountShadowEnabled(boolean) → toggle the shadow of the entity youre riding
-
added renderer.getTextWidth(Text string) → returns the lengh, in pixels, of a text/json
-
added isCameraBackwards() → return as boolean if the camera is facing the front or back of the player
-
added getCameraPos() → returns a vector of the VIEWER camera pos
-
added setUniform(string layer, string uniform, number/table value) → custom shader stuff
-
added get/setRenderFire(bool) → allows you to hide the fire overlay on your model
-
renderBlock() now can have a BlockState table instead of a string
-
renderBlock() and renderItem() now have an extra optional argument with the name of the custom render layer used to render it
-
renderlayers.registerShader(name, format, vertexSource, fragmentSource, numSamplers, customUniforms) → Registers a new custom shader with the given name → If format is nil, uses the default of "POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL" → Code for the shader is contained in strings, vertexSource and fragmentSource _
-
renderlayers.registerRenderLayer(name, params, startFunction, endFunction) → Registers a new render layer with the given name → params is a table where you can set certain keys → vertexFormat - needs to match with the format of any shader you want to use. Same default as in registerShader() → hasCrumbling - don't know what this does, but it's true by default → translucent - also don't know this one, but true by default → startFunction and endFunction are two lua functions, called when you start rendering and when you stop rendering this layer. Functions which interact with openGL can only be called inside these
-
renderlayers.setUniform(shaderName, uniformName, value) - Sets the value of the specified uniform in the specified shader. If the shader does not exist yet, does nothing
-
renderlayers.setPriority(renderLayerName, value) - Sets the priority of a render layer. Layers with lower priorities are rendered first. By default, all priorities are 0
-
renderlayers.getPriority(renderLayerName) - Gets the priority of the chosen render layer, or nil if it doesn't exist
-
renderlayers.isShaderReady(shaderName) - Returns true or false depending on if the shader exists yet
-
These can only be called inside one of the functions sent to a registered render layer!
-
useShader(shaderName): Uses the designated shader
-
setTexture(index, textureName): Sets the designated texture based on the name → Special values include "MY_TEXTURE", "MAIN_FRAMEBUFFER", and "LAST_FRAMEBUFFER" → MY_TEXTURE uses your figura avatar texture → MAIN_FRAMEBUFFER uses what is currently drawn on the screen → LAST_FRAMEBUFFER uses what was drawn on the screen last frame → Otherwise, the name is treated as an identifier, so you can get game textures like "textures/block/bee_nest_top.png", for example
-
enableLightmap() and disableLightmap(): Enables/disables lightmap testing
-
enableOverlay() and disableOverlay(): Enables/disables overlay
-
enableCull() and disableCull(): Enables/disables culling
-
enableDepthTest() and disableDepthTest(): Enables/disables depth testing
-
enableBlend() and disableBlend(): Enables/disables blending
-
enableColorLogicOp() and disableColorLogicOp(): Enables/disables color logic operations
-
enableStencil() and disableStencil(): Enables/disables stencil testing
-
depthFunc(func): Sets the GL depth function
-
depthMask(boolean): Enables/disables the GL depth mask
-
blendFunc(src, dst): Sets the GL blend function
-
blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha): Sets the GL blend function
-
defaultBlendFunc(): A minecraft→specific function, resets the GL blend function to default
-
blendEquation(equation): Sets the GL blend equation
-
logicOp(operation): Sets the GL color logic operation
-
colorMask(boolean): Enables/disables the GL color mask
-
stencilMask(number): Sets the GL stencil mask
-
stencilFunc(func, ref, mask): Sets the GL stencil function
-
stencilOp(sfail, dpfail, dppass): Sets the GL stencil operations
-
enableScissors(x, y, width, height): Enables GL scissors with those values
-
disableScissors(): Disables GL scissors
-
lineWidth(): Sets the shader line width
- The API has a good number of the GL constants; it should have everything you need for the GL functions above. It has GL_NEVER, GL_FUNC_ADD, GL_ONE_MINUS_SRC_ALPHA, among many others_
- If figura doesn't have the value you need, for whatever reason, find the decimal value at https://javagl.github.io/GLConstantsTranslator/GLConstantsTranslator.html and use that
-
now you can modify vector values
-
added vectors.quaternionRotation(vec init, vec rotation) → rotate a vector, by the rotation, using quaternions
-
added toQuaternion(vector) → convert a XYZ vector into a quaternion
-
added fromQuaternion(vector) → convert a quaternion into a XYZ vector
-
added worldToScreenSpace(Vector pos)
-
added .toRad() and .toDeg() → converts the vector values to radians/degrees
- added get/setName(String name) → sets the name of the file youre going to save → also changes the name of your script :)
-
added a new function, world_render(delta) → this function executes every render tick → even when your avatar is not rendering_ → like when invisible or when holding items in first person → the player must still be inside your render distance to run the function
-
onCommand() and world_render() functions now executes only AFTER player_init
-
added lerp and clamp functions on the builtin math library → math.lerp(a, b, delta) // math.clamp(val, min, max)
- added the unused onDamage function → function function onDamage(amount, source) → amount is a float of how much damage you would took, before any armor/resistance calculation → triggers everytime you take damage → it ignores the resistence effect
→ source is the damage source(?)
-
a new simplified way to send/register pings
-
it still follows the same rules as in the old way only one argument, max 1kb of data per second, etc...
-
to register a ping: ping.myAwesomePing = function(arg) log(arg) end
ping["anotherWay"] = changePose --"changePose" is an function declared elsewhere
function ping.youIsAwesome() log(true) end
-
to send a ping: ping.changeClothes("get pinged!!!")
-
added block state api
-
acts similar to the item stack api, however for block states
-
currently the only way to get a block state table is, either using the world API or creating one like as fellow: block_state.createBlock(block_string, pos) → block string is exactly like /setblock syntax, pos is optional
-
a block state table has the following properties: → all properties that the current world.getBlockState() has → setPos(pos) - to set the position of the block → getBlockTags() - returns a table with all block tags this blockstate have eg: #minecraft:flowers → getMaterial() - returns the material name of the block → getMapColor() → isSolidBlock() → isFullCube() - if the block occupes an entire 16³ cube → hasBlockEntity() - if the block is a block entity → isOpaque() → hasEmissiveLighting() → isTranslucent() → emitsRedstonePower() → getOpacity() → getLuminance() - returns the light level this block produces → getHardness() → getComparatorOutput() - the comparator strenght of this blockstate → getSlipperiness() - eg: ice → getVelocityMultiplier() - eg: soul sand → getJumpVelocityMultiplier() - eg: honey block → getBlastResistance() → isCollidable() - if entities collide with the block → getCollisionShape() - returns a table of vectors, each vector corrisponding to a "box" of the block's collision (format: minX, minY, minZ, maxX, maxY, maxZ) → getOutlineShape() - same as collision shape, but for the visual hitbox of the block (when you try to mine/use it) → getSoundGroup() - returns a table, listing each sound a blockstate may make, also includes base pitch and volume → toStateString() - returns a string of this blockstate with the same syntax as /setblock
- added a new "sounds" folder for avatars -> .ogg files only
- you put all sound files inside this folder
- you also need a sounds.json on the avatar root
- the contents of the json should be the names of your sounds, inside an array, separated by commas eg: ["sound1", "sound2", "sound3"]
- it can be played using: sound.playCustomSound(name, pos, pitchVol)
- also added: → sound.getRegisteredCustomSounds() - returns a table of each custom sound your avatar has → sound.getCustomSounds(arg) - returns a table of all currently playing custom sounds optionally, you may put "true" to get the UUID of the players creating those sounds → sound.registerCustomSound(name, data) - adds a new custom sound to your model, using data from either a table of bytes, OR a base64-encoded string → sound.isCustomSoundRegistered() - check if the sound is already registered → sound.stopCustomSound(name) - stops this specific custom sound
- nameplates, on entities only, can have multiple lines, using \n
- removed deprecated nameplate customizations, now its only avaiable trought JSON
- fixed nameplate "getText()" returning a LuaBoolean
- reworked entity nameplate rendering code
- completely reworked particle api
- now takes how many arguments its needed → 2 for default particles (id, pos+speed) → 3 for dust/block/item particles (id, pos+speed, color+size/block) → 4 for vibration/fade particles (id, pos+speed, color+size/pos/duration, endColor/endPos)
- removed deprecated method from sound api
- now the third arg from the playSound function is optional (vanilla consistency)
- the second arg from create item (nbt data) is now optional! (it was always been) → using nil for empty nbt will throw an error
- nameplates, on entities only, can have multiple lines, using \n
- removed deprecated nameplate customizations, now its only avaiable trought JSON
- fixed nameplate "getText()" returning a LuaBoolean
- reworked entity nameplate rendering code
- completely reworked particle api
- now takes how many arguments its needed → 2 for default particles (id, pos+speed) → 3 for dust/block/item particles (id, pos+speed, color+size/block) → 4 for vibration/fade particles (id, pos+speed, color+size/pos/duration, endColor/endPos)
- removed deprecated method from sound api
- now the third arg from the playSound function is optional (vanilla consistency)
- the second arg from create item (nbt data) is now optional! (it was always been) → using nil for empty nbt will throw an error
- added isUsingItem()
- added getActiveHand() → get the player active hand → outputs are: nil, "MAIN_HAND", "OFF_HAND" → only updates after using an item → if no item was ever used, it returns nil
- added getActiveItem() → returns an item stack table of the active item
- added spyglass blockbench keyword
- just like the shoulder parrot and held item keywords
- this is used to anchor/move/scale the pivot of the spyglass → LEFT_SPYGLASS, RIGHT_SPYGLASS
-
lua errors now >tries< to log the line of code that caused the error
-
added a way to share variables between scripts
-
to store the values: → storeValue("key", )
-
and to retrieve them: → .getStoredValue("key") (you can get players using world.getFiguraPlayers())
-
added client api → similar to the meta api, the client api access your client variables → only accessible with the host script (local player) → using it on non-host will always return nil for everything (except isHost)
-
current functions: getOpenScreen, getFPS, isPaused, getVersion, getVersionType, getServerBrand, getChunksCount, getEntityCount, getParticleCount, getSoundCount, getActiveShader, getJavaVersion, getMemoryInUse, getMaxMemory, getAllocatedMemory, isWindowFocused, isHudEnabled, getWindowSize, getGUIScale, getFov, isHost
-
you can also change your crosshair properties with: get/setCrosshairPos and get/setCrosshairEnabled
- fixed script error message not having the right formatting
- fixed get last damage source vm error
- fixed action wheel vm nil error
- fixed camera vm nil error
- fixed nameplate vm nil error
- fixed version numbers, now it respects semver properly
- cheese
- made the keybinds category from the keybind api more unique (internal-only change)
- Fixed keybind api not registering mouse properly
- Fixed keybinds screen and settings screen not getting mouse input for keybinds
- Fixed keybinds screen and settings screen unable to unbind a keybind
- Fixed config menu not saving configs when leaving the menu without pressing save or cancel
- fixed an exploit with the nameplate badges (thx Grandpa Scout)
- fixed burned star texture
- fixed UI icons textures to match with the vanilla style
- added isOpen() → return a bool if the action wheel is open or not
- added new line support for titles
- added getSystemTime() → returns your current in-real-life time, in milliseconds
- added getInputText() → returns the text from the message input field, or nil if its empty
-
added block/item/text rendering → its a way to render game assets → its cleared on each render tick, so you might want to put them on the render function → it counts towards your model complexity, so beware!
-
renderer.renderBlock(BlockState string, ModelPart, emissive bool, pos, rot, scale) → renders a block
-
renderer.renderItem(ItemStack, ModelPart, TransformationMode, emissive bool, pos, rot, scale) → renders an item
-
renderer.renderText(Text string, ModelPart, emissive bool, pos, rot, scale) → renders a text
→ BlockState = blockstate string, just like how you do in vanilla commands like /setblock (no liquids included) → ItemStack = item stack table, from the item stack API → Text = JSON formatted (or legacy) string → ModelPart = parent part that this extra render gonna be attached to → TransformationMode = mode that the ItemStack gonna be rendered (values listed below) → Emissive = a boolean flag if its emissive or not → pos/rot/scale = A vector (or table) of three values
Examples: local part = model.NO_PARENT.bone renderer.renderText("hello world", part, true, {0, -16, -16.01}) renderer.renderText('{"text":"bye world","color":"#ff0000"}', part, true, {0, -12, -16.01}) renderer.renderBlock("minecraft:redstone_lamp[lit=true]", part, false, {16, 0, 0}) renderer.renderBlock("minecraft:light_blue_stained_glass", part) renderer.renderItem(player.getEquipmentItem(2), part, "THIRD_PERSON_LEFT_HAND", true, {16, -24, -4}, nil, {3, 3, 3}) renderer.renderText("hi mum im on a screenshot", model.base.body.Tail.main, true)
TransformationModes: → "NONE" = no transformations → "THIRD_PERSON_LEFT_HAND" = used when in 3rd person, left hand → "THIRD_PERSON_RIGHT_HAND" = used when in 3rd person, right hand → "FIRST_PERSON_LEFT_HAND" = used when in 1st person, left hand → "FIRST_PERSON_RIGHT_HAND" = used when in 1st person, right hand → "HEAD" = used when worn on the head → "GUI" = used on the GUI → "GROUND" = used on dropped items → "FIXED" = used on item frames
- added renderer.setMountEnabled(boolean) → toggle the render of the entity youre riding
- added renderer.setMountShadowEnabled(boolean) → toggle the shadow of the entity youre riding
- added renderer.getTextWidth(Text string) → returns the lengh, in pixels, of a text/json
- added Camera parent type → makes objects always face the camera → currently better to be used with parts inside NOPARENT groups → using parts transformations (setPos(), setRot(), etc) might lead in fuzzy behaviour
- added setScale(vector) :3
-
this API allows you to save/read persistent key / values pairs in a file, allowing you to keep variables after rejoining worlds or changing avatars
-
it uses the avatar name as file name ("main" for the online avatar)
-
it can save every type of value, except functions
-
only works for local player! so you might want to use pings for sync
-
data.save(string key, any value) → save a value in the file
-
data.load(string key) → returns a LuaValue of the key, or nil if not found
-
data.loadAll() → returns a LuaTable of all the saved variables
-
data.remove(string key) → removes the value from the file
-
data.deleteFile() → completely removes the file from the existence
- you can choose which texture to use per part → model..setTexture(Texture string, ID string) → ID is only required when using the "Resource" type
Textures: → Custom = your custom texture, if any (default) → Skin = your vanilla minecraft skin → Cape = your cape, or Steve if you dont have a cape → Elytra = your elytra texture (NOT the cape-provided elytra!) (vanilla probably dont even use it at all) → Resource = any loaded vanilla texture! or missing texture if nor found (supports resource packs) (does NOT supports .mcmeta!)
Examples: model.left.setTexture("Skin") model.right.setTexture("Resource", "minecraft:textures/item/apple.png") model.right.setTexture("Resource", "minecraft:textures/entity/zombie/zombie.png") model.left.setTexture("Cape") model.right.setTexture("Resource", "minecraft:textures/models/armor/diamond_layer_1.png")
Templates: Cape → https://cdn.discordapp.com/attachments/349077838240022538/891812241433841684/cape_example.png Skin → https://cdn.discordapp.com/attachments/349077838240022538/891812243413536828/skin_example.png → skin info: black/textured = all alpha gonna be tinted black in there textured/pink = used by the vanilla model pink = optional, can be disabled in-game transparent = free space
- you can now disable the extra textures rendering (currently we use only emissive) → model..setExtraTexEnabled(boolean)
-
you can now have script-only avatars → just do not provide a .bbmodel file!
-
you can now use your mc skin as default texture! → just do not provide a texture.png file!
- added a new function, world_render(delta) → this function executes every render tick → even when your avatar is not rendering_ → like when invisible or when holding items in first person → the player must still be inside your render distance to run the function
-
added ping queue on the debug screen
-
added an status indicator for the avatar data, and also the backend connection, find it in the figura model screen
-
added hitbox pivot renderer → shows the custom parts pivots on the world → enabled by using F3+B (show entity debug hitboxes) → blue boxes for groups, pink boxes for cubes → toggable on the settings
- fixed nil error when creating item with the item stack api
- fixed (for real) the nameplate badges exploit, thx again grandpa scout
- fixed scripts with more than 65k characters (note, this make avatars with 65k+ characters incompatible with previous versions (they werent compatible anyway))
- tweaked a bit the custom model part rendering (might improve FPS in some cases)
- fixed no parent parts being rendered again for each arm, first person only
- fixed a crash when trying to load a player when not in a world/server
- tweaked figura's debug screen text
- added a hardcoded limit for the nameplate of 65535 characters (json formatting text also counts towards it) to fix an exploit
- fixed a bug when setting the parent type of special parts
- fixed a java error for invalid setParentType() and setShader()
- fixed custom parts worldToPartDir and worldToPartPos
- disabled loading of lua libraries due to an exploit (they werent supposed to be enabled in first place)
- fixed a crash with FVT mod
- fixed spyglass model api not being accessible on script
- fixed model parts script transformations being saved on the model when uploading
- updated dev list
- disabled the upload button when the avatar is already uploaded
- tweaked gui icons
- fixed a crash when joining worlds with resource packs
- fixed an emissive/shaders issue with iris entity batching (thanks IMS) (this DOES NOT mean that emissives will work with shaders enabled) (only when not having glowing effect)
- model size now reflects better the final/uploaded model size
- fixed a NPE crash with pings
- fixed a NPE when joining worlds
- added isTouchingWater() → true if the entity has contact with water or waterlogged blocks
- added isUnderwater() → true if the entity is fully submerged in water
- added isInLava() → true if the entity is touching lava
- added isInRain() → true if the entity has contact with rain, false for snow
- added isOpenSky(vector pos) → true if the pos has sky access
- added getBiomeTemperature(vector pos) → returns a float of the biome temperature
- added getBiomePrecipitation(vector pos) → returns "NONE", "RAIN" or "SNOW", depending on the biome weather type
-
now you can modify vector values
-
added vectors.quaternionRotation(vec init, vec rotation) → rotate a vector, by the rotation, using quaternions
- onCommand() and world_render() functions now executes only AFTER player_init
- you can now set the UV and texture size → get/setTextureSize(vector) → vector of two values, X and Y, for the size of the texture- → getRebuiltUV(Face string)/rebuildUV(Face string, vector) → a face string, and a vector of 4 values, blockbench uv format → get/setUV() still works and will act as normal (not deprecated)
- added "CAPE" accessor, which is well, your cape
- added "EAR" accessor, used for deadmau5 ears (only useful with ear mods, or if youre deadmau5)
- added getModelStatus()
- added getScriptStatus()
- added getTextureStatus()
- added getBackendStatus() → all of them returns a number between 1 to 4 indicating its current state → 1 - white, 2 - red, 3 - yellow, 4 - green → hover the avatar indicators at the model preview screen for more info
- added support for custom textures → get/setTexture(string type, string id) → set the action wheel custom texture, and ID if its from the game assets → get/setTextureScale(vector) → set the texture scale → get/setUV(vector uvOffset, vector uvSize, vector textureSize) → set the custom texture uv
example: action_wheel.SLOT_2.setTexture("Skin") action_wheel.SLOT_2.setUV({8, 8}, {8, 8}, {64, 64}) action_wheel.SLOT_2.setTextureScale({2, 2})
texture types: → "None" → nothing, uses an item instead → "Custom" → uses your custom/model texture → "Skin" → uses the player vanilla skin → "Cape" → uses the player cape → "Elytra" → uses the player elytra → "Resource" → uses an ingame/resource pack texture
- keyword "SKULL" that replaces your vanilla player head
-
added the unused onDamage function → function onDamage(amount) → amount is a float of how much damage you would took, before any armor/resistance calculation → triggers everytime you take damage → it ignores the resistence effect
-
added lerp and clamp functions on the builtin math library → math.lerp(a, b, delta) // math.clamp(val, min, max)
-
player heads now uses the bb keyword Skull → fallbacks to head parts → respects vanilla_head set_enabled property
-
added a path config for the figura folder → good for things like multimc and such → leave blank to use the current instance folder
-
reworked the mods config → mostly an internal change → changed config names → will automatically parse your old config to the new format
-
added a way to unselect avatars
-
disabled upload/delete buttons when not connected to the backend → reload still enabled, so you can force a reconnect
- fixed a crash with JSON text parser
- fixed java ArrayIndexOutOfBoundsException when creating vector from tables
- fixed a NPE with meta.getCurrentComplexity()
- fixed a ClassCastException with chat nameplate customizations
- fixed a bug with custom/vanilla textures not working when applied in non-root parts
- fixed a bug with disabling extra textures not working when applied in non-root parts
- fixed mimic parts not working inside groups
- fixed backend status indicator
- fixed the goddamm delete avatar texture
- fixed camera parts disappearing when looking straight up/down
- added isFood() → return a boolean if the item is eatable or not
- added getType() → returns a string, either "CUBE", "GROUP" or "MESH", of the part type
- added getName() → returns a string, of the part name (the name as in blockbench for this cube/bone)
- skulls now render on the tab list → disabled with the config playerlist modifications
-
"fixed" a crash when loading avatar data
-
fixed delete and help button overlapping
-
fixed a typo on the reload button
-
fixed the expand preview button overlapping the model list
-
fixed an issue with modmenu moving the figura button on the pause menu
-
players trust settings are now properly saved
-
fixed avatar not loading if model contains a mesh part
-
MESH SUPPORT IS NOT IMPLEMENTED!
- renamed getRebuiltUV() and rebuildUV() to getUVData() and setUVData() → now has the starting uv data from the model parts
- split EARS into LEFT_EAR and RIGHT_EAR
- fixed a crash when typing invalid chars on the model path setting
- fixed part hitboxes rendering on skulls and first person hand
- fixed status indicators rendering when in avatar expanded view
- fixed cape/ears vanilla part model
- fixed being able to click on buttons/list on the preview screen
- fixed parts not updating on world renderer
- fixed trust settings not using the custom figura folder location config
- added isBlockItem() → return a boolean if the item has a block form
- added worldToCameraPos(vec3f offset) → same as worldToPartPos but tied with the camera instead
- added setRenderLayers(string) → sets the render layer (custom shader) of the part
- added isCameraBackwards() → return as boolean if the camera is facing the front or back of the player
- added getCameraPos() → returns a vector of the VIEWER camera pos
- added setUniform(string layer, string uniform, number/table value) → custom shader stuff
- added an optional float parameter to getPos(), getRot() and getBodyYaw(), which lerps the return value
- yep, now you can make your own shaders!
- follow the documentation here: https://cdn.discordapp.com/attachments/349077838240022538/900065078110470205/shader_tut.txt → also heres a template model just in case: https://cdn.discordapp.com/attachments/349077838240022538/900065075287711744/shader_template.zip
- exactly! compatible with all default meshes from blockbench
- by the addition of meshes, .obj loading is now removed and should be converted to meshes through blockbench first!
- a new keybind as added, R, which reloads your avatar, or the avatar of the player youre looking at
- can crash your game if you exploit it :p
- changed default texture, Steve, to EndSky
- because it looks cool
- it is used when your texture is still loading or when something weird happens
- improved (more compact) avatar size
- it makes new avatars (from the backend only) NOT compatible with old versions
- fixed model upload saving script init transforms
- cheese
- changed rendering method from EntityTranslucent to EntityTranslucentCull → this means that textures are now rendered in only ONE side of the face → this allows things like inverted cubes (outlines) → if you have a cube with 0 depth, you can mimic the previous behaviour by copying the face uv from the opposite side and mirroring its X
- added get/setName(String name) → sets the name of the file youre going to save → also changes the name of your script :)
- script keybinds screen now update when script change keybinds
- fixed keybinds breaking other keybinds
- fixed model not loading if it contains blockbench null objects
- fixed some feature renderers customizations not being applied correctly
- fixed a NPE with pings
- fixed piglins invisible and/or using player avatars
- fixed crash when spamming the reload keybind
- fixed a bug when loading certain models
- improved figura directory config description
- fixed extra textures (emissive) not disabling if set it disabled
- fixed script error after loading avatars with custom shaders
- fixed avatar unselect entry not properly unselecting the avatar
- fixed a NPE when rendering avatars
- fixed glowing effect not rendering on custom model parts
- fixed tablist not rendering player skin if player doesnt have custom head or skull
- add get/setCullEnabled(boolean) → enables culling on the custom part
- added badges to figura players
- improved saved nbt of players
- figura players are now sorted on top - thx omo <3
- possibly fixed a crash when rendering the first person hands
- fixed custom models always being culled
- fixed no trust settings for non-figura players
- fixed emissive on player skulls
- changed reload texture to cheese (should only appear if something really weird happened)
- red mark badge now also shows when the script errors
- added an exclusive custom toast
- internal rework of trust settings
- you can now move the local player parent group → local player is shown as aqua and with an indicator → local group and local player are always locked → only local player can be put into the "local" group
- due to internal changes, all previous trust settings are deleted (sorry)
- edited fields (that doesnt inherit from its parent groups) are now aqua
- added expand/collapse icons
- added getCanHaveCustomRenderLayer() → returns a boolean if the player can use custom render layers (shaders)
- added toQuaternion(vector) → convert a XYZ vector into a quaternion
- added fromQuaternion(vector) → convert a quaternion into a XYZ vector
-
player popup!
-
press and hold "R" (configurable) while looking at a player to open it
-
use the mouse scroll to select
-
unpress the button to execute its selected action → if not looking at a player, when in third person, the popup is shown as you instead
-
avatar loading "badge"
- you can now only upload avatar if its finished loading
- fixed trust settings showing avatar size for players without figura
- tried to fix some rendering crashes (concurrent modification exception)
- clamped shadowsize radius to 24 blocks, to avoid crashes and massive fps drops
- fixed avatar breaking when redownloading it too many times too fast
- fixed avatar breaking when selecting it too many times too fast from the avatar list
- changed reload avatar button to player popup button
- fixed badges not showing up for untrusted players
- fixed trust settings saving local players
- fixed rendering not respecting max complexity trust setting
- merged all badges into a single texture
- changed the font file
- added textures for: cheese, toasts, popupmenu, arrows, loading
- moved trust presets to assets/figura/trust
- added accent color
- you can change the color on the settings
- accepts any color (in hex)
- change colors on important things like trust settings and lua logs
- now allows subfolders c:
- list is now loaded async
- appears when you have the tablist open and hold the player popup button
- to avoid exhaustive keypresses, holding the popup button keeps the tablist open
- use mouse scroll to cicle between players, shift + mouse scroll to change the selected action
- just like the player popup, release the popup button to execute the selected action
- added a new "sounds" folder for avatars -> .ogg files only
- you put all sound files inside this folder
- you also need a sounds.json on the avatar root
- the contents of the json should be the names of your sounds, inside an array, separated by commas eg: ["sound1", "sound2", "sound3"]
- it can be played using: sound.playCustomSound(name, pos, pitchVol)
- also added: → sound.getRegisteredCustomSounds() - returns a table of each custom sound your avatar has → sound.getCustomSounds(arg) - returns a table of all currently playing custom sounds optionally, you may put "true" to get the UUID of the players creating those sounds → sound.registerCustomSound(name, data) - adds a new custom sound to your model, using data from either a table of bytes, OR a base64-encoded string → sound.isCustomSoundRegistered() - check if the sound is already registered → sound.stopCustomSound(name) - stops this specific custom sound
- figura will now attempt to get avatars based on playername
- you still need to be authenticated and connected with the backend
- this is supposed to fix the mod not working on servers with uuid scrambles or servers in offline mode
-
a new simplified way to send/register pings
-
it still follows the same rules as in the old way only one argument, max 1kb of data per second, etc...
-
to register a ping: ping.myAwesomePing = function(arg) log(arg) end
ping["anotherWay"] = changePose --"changePose" is an function declared elsewhere
function ping.youIsAwesome() log(true) end
-
to send a ping: ping.changeClothes("get pinged!!!")
-
added block state api
-
acts similar to the item stack api, however for block states
-
currently the only way to get a block state table is, either using the world API or creating one like as fellow: block_state.createBlock(block_string, pos) → block string is exactly like /setblock syntax, pos is optional
-
a block state table has the following properties: → all properties that the current world.getBlockState() has → setPos(pos) - to set the position of the block → getBlockTags() - returns a table with all block tags this blockstate have eg: #minecraft:flowers → getMaterial() - returns the material name of the block → getMapColor() → isSolidBlock() → isFullCube() - if the block occupes an entire 16³ cube → hasBlockEntity() - if the block is a block entity → isOpaque() → hasEmissiveLighting() → isTranslucent() → emitsRedstonePower() → getOpacity() → getLuminance() - returns the light level this block produces → getHardness() → getComparatorOutput() - the comparator strenght of this blockstate → getSlipperiness() - eg: ice → getVelocityMultiplier() - eg: soul sand → getJumpVelocityMultiplier() - eg: honey block → getBlastResistance() → isCollidable() - if entities collide with the block → getCollisionShape() - returns a table of vectors, each vector corrisponding to a "box" of the block's collision (format: minX, minY, minZ, maxX, maxY, maxZ) → getOutlineShape() - same as collision shape, but for the visual hitbox of the block (when you try to mine/use it) → getSoundGroup() - returns a table, listing each sound a blockstate may make, also includes base pitch and volume → toStateString() - returns a string of this blockstate with the same syntax as /setblock
- you can not just type the item/block instead of having to create item_stack tables or a block_state tables eg: action_wheel.SLOT_1.setItem(item_stack.createItem(...)) → .setItem('player_head{SkullOwner:"Francielly"}')
- changed checkboxes to switches
- changed lock icons for more accessibility
- player popup is now done in screen-space
- you can now control player popup using hotbar 1-4
- added worldToScreenSpace(Vector pos)
- added get/setRenderFire(bool) → allows you to hide the fire overlay on your model
- renderBlock() now can have a BlockState table instead of a string
- renderBlock() and renderItem() now have an extra optional argument with the name of the custom render layer used to render it
- [1.18 only] added support for the new particle, block marker
- included damage source
- new syntax is now "function onDamage(amount, source)"
- now has an animated background
- the animation is hardcoded (sorry)
- fixed a crash with player popup related with mouse sensibility
- added vip/dev badges to all discord admins and devs
- fixed symlink custom paths
- fixed model list freezing game when opening
- fixed connecting to backend freezing the game
- fixed all textures mixels
- fixed trust settings sliders
- fixed search box hint
- fixed expanded background texture
- fixed toast cheese
- fixed toast text not correctly centred
- removed unused textures from assets
- fixed tooltips on settings screen hiding the input text
- disabled fire overlay on the model preview screen
- fixed players invisible when joining words
- fixed players being invisible while reloading another player avatar
- removed uneccessary java unknown stacktrace on lua errors on chat
- fixed special parts not counting up to complexity
- fixed math.lerp not working with vectors
- backend status indicator now update on every tick
- fixed pings keeping registered on avatar reload
- fixed some async issues
- added an error when rendering block/item/text on world render, since theyre not properly supported
-
(forgor to add on the last patch notes)
-
world.getFiguraPlayers() now only target players who allows it
-
toggle your targeting with setPlayerTargeting(true/false)
-
default OFF (false)
-
added loadstring(str) for debugging, allowed ONLY for local (non-uploaded) avatars
- added a new button that completely stops figura rendering until you press it again
- default to unbounded, so you need to choose the keybing yourself :p
- added runAction() which executes the current hovered slot function
- added chat.isOpen() which return true if chat is open, otherwise false
- you can now open the selected avatar folder if holding shift when selecting the open models folder button
- now it wont errors out when creating a new vector from table, if the table has non numbers fields
- completely reworked the api
- some keybinds names might be changed
- you can now use keybinds thats been used by the game
- keybind.newKey() now has a third, optional, boolean argument when true, the keybind gonna be detected even when another screen is opened like chat/inventory
- you can also get a list of keybinds using keybind.getKeyList()
- and for registred keybinds, keybind.getRegisteredKeyList()
- fixed custom sounds not loading properly from .ogg
- konami
- fixed keybind API conflicting with game keybinds
- [1.16 only] fixed player popup and vectors.worldToScreenSpace() when having a FOV different than 70
- added world.raycastBlocks(startPos, endPos, shapeHandling, fluidHandling, predicate) → Casts a ray from startPos to endPos, looking at the blocks on the way → shapeHandling can be "COLLIDER", "OUTLINE", or "VISUAL" depending on how you want the raycaster to check → fluidHandling can be "NONE", "SOURCE_ONLY", or "ANY", depending on what kinds of fluid blocks should stop the raycast → predicate is optional. It's a function which takes a BlockState and a position. It returns true if you want the raycast to count that as a block, or false if you want it to ignore that block and continue raycasting → world.raycastBlocks returns a table containing two things → table.state - the BlockState of the block you ended up hitting → table.pos - the exact (decimal) position where the ray hit in the world → If the ray never hits anything, then the function returns nil _
- added world.raycastEntities(startPos, endPos, predicate) → Casts a ray from startPos to endPos, returning the first entity it sees on the way → Similar to world.raycastBlocks, predicate is a function which takes an entity and returns a boolean based on if that entity should count as a valid target → Returns the entity table of the first entity the ray hits → If it doesn't hit any entities, returns nil
- Complete overhaul of custom shaders system using new RenderLayer API
- No more need for any additional files, all custom rendering is controlled through the script
- Should make custom rendering a lot more accessible for everyone
- See the beginner guide linked at the bottom of this pre→release for details
-
renderlayers.registerShader(name, format, vertexSource, fragmentSource, numSamplers, customUniforms) → Registers a new custom shader with the given name → If format is nil, uses the default of "POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL" → Code for the shader is contained in strings, vertexSource and fragmentSource _
-
renderlayers.registerRenderLayer(name, params, startFunction, endFunction) → Registers a new render layer with the given name → params is a table where you can set certain keys → vertexFormat - needs to match with the format of any shader you want to use. Same default as in registerShader() → hasCrumbling - don't know what this does, but it's true by default → translucent - also don't know this one, but true by default → startFunction and endFunction are two lua functions, called when you start rendering and when you stop rendering this layer. Functions which interact with openGL can only be called inside these
-
renderlayers.setUniform(shaderName, uniformName, value) - Sets the value of the specified uniform in the specified shader. If the shader does not exist yet, does nothing
-
renderlayers.setPriority(renderLayerName, value) - Sets the priority of a render layer. Layers with lower priorities are rendered first. By default, all priorities are 0
-
renderlayers.getPriority(renderLayerName) - Gets the priority of the chosen render layer, or nil if it doesn't exist
-
renderlayers.isShaderReady(shaderName) - Returns true or false depending on if the shader exists yet
-
These can only be called inside one of the functions sent to a registered render layer!
-
useShader(shaderName): Uses the designated shader
-
setTexture(index, textureName): Sets the designated texture based on the name → Special values include "MY_TEXTURE", "MAIN_FRAMEBUFFER", and "LAST_FRAMEBUFFER" → MY_TEXTURE uses your figura avatar texture → MAIN_FRAMEBUFFER uses what is currently drawn on the screen → LAST_FRAMEBUFFER uses what was drawn on the screen last frame → Otherwise, the name is treated as an identifier, so you can get game textures like "textures/block/bee_nest_top.png", for example
-
enableLightmap() and disableLightmap(): Enables/disables lightmap testing
-
enableOverlay() and disableOverlay(): Enables/disables overlay
-
enableCull() and disableCull(): Enables/disables culling
-
enableDepthTest() and disableDepthTest(): Enables/disables depth testing
-
enableBlend() and disableBlend(): Enables/disables blending
-
enableColorLogicOp() and disableColorLogicOp(): Enables/disables color logic operations
-
enableStencil() and disableStencil(): Enables/disables stencil testing
-
depthFunc(func): Sets the GL depth function
-
depthMask(boolean): Enables/disables the GL depth mask
-
blendFunc(src, dst): Sets the GL blend function
-
blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha): Sets the GL blend function
-
defaultBlendFunc(): A minecraft→specific function, resets the GL blend function to default
-
blendEquation(equation): Sets the GL blend equation
-
logicOp(operation): Sets the GL color logic operation
-
colorMask(boolean): Enables/disables the GL color mask
-
stencilMask(number): Sets the GL stencil mask
-
stencilFunc(func, ref, mask): Sets the GL stencil function
-
stencilOp(sfail, dpfail, dppass): Sets the GL stencil operations
-
enableScissors(x, y, width, height): Enables GL scissors with those values
-
disableScissors(): Disables GL scissors
-
lineWidth(): Sets the shader line width
- The API has a good number of the GL constants; it should have everything you need for the GL functions above. It has GL_NEVER, GL_FUNC_ADD, GL_ONE_MINUS_SRC_ALPHA, among many others_
- If figura doesn't have the value you need, for whatever reason, find the decimal value at https://javagl.github.io/GLConstantsTranslator/GLConstantsTranslator.html and use that
-
added a version checker → you can choose the update channel (pre-release, full-release or disable) in the settings → you gonna see a warning on the version indicator on the model preview screen if theres an update
-
added a warning on the model preview screen if panic mode is enabled
- added renderlayers.restoreDefaults(), which resets the rendering to default state
- can now access the emissive texture in setTexture() using the key "MY_TEXTURE_EMISSIVE"
- fixed render and world render being counted separately to instruction limit
- fixed error handling inside registered render layer functions
- fixed the predicate argument in world.raycastBlocks(), so it now accepts a blockstate table
- fixed instructions inside render layer functions not counting to instruction limit
- fixed crash from calling renderlayers.setUniform() for a nonexistent uniform
- fixed renderlayers.enableScissors() to be actually usable
- because they can be potentially expensive, both raycast functions now incur a penalty of 2 instructions per block distance raycasted
- hitting the panic button now restores default rendering
- hitting the panic button now stop all custom sounds
- fixed custom sounds not being stopped on reload
- moved figura keybinds to their own category on the vanilla keybinds screen
- fixed config tooltips rendering behind the scrollbar
- fixed a crash when on panic mode, reloading your avatar then selecting an local avatar from the list
- fixed loadstring throwing error instead of returning said error
- fixed chat API being accessed by non-host scripts
- moved raycasting functions from World API to Renderer API
- the stencil buffer is now cleared on every frame
- you can now instantaneously set uniforms, if you call setUniform in the render thread → otherwise it just requests a render call, as it did before this update → this means you can set a uniform in the "before" phase of a render layer without issue
- fixed crash related with current data
- fixed host-only script errors on non-host script
- reworked mesh nbt formatting to a more compact one
- this makes old (uplodaded only) avatars not render their meshes
- added .toRad() and .toDeg()
- converts the vector values to radians/degrees
- fixed model name being trimmed even if theres room for more text
- fixed model size not showing up for script only avatars
- fixed script compression breaking code blocks ([[ and ]])
- fixed script compression not working with bracket level greather than 0 ([=[, [==[ and so on)
- fixed custom sounds not stopping when switching local avatars
-
first person model api
-
"HUD" blockbench keyword → render things attached to your hud c: → spectator compatible → only you can see it
-
added entrypoints for custom apis → any mod can add their own apis if they want → attempting to access its functions without the provider mod present will result in nil errors
- has "MAIN_HAND" and "OFF_HAND"
- allows you to hide/move/scale your arms or holding item in first person
-
removed parts saving the texture size (moved to the main parts tag)
-
tweaked figura info on the debug hud
-
added an new setting, entity batching fix → fixed some rendering issues caused by entity batching present on iris and such mods → can impact your FPS
- added world.hasWorld()
- left segments now starts from right-segments + 1 instead of always 5
- added meta.getCurrentInitCount()
- added getUseAction()
- fixed concurrent modification when rendering world parts
- fixed keybinds being queued while in a screen
- fixed sounds count not decreasing when reloading avatar
- fixed pings giving an error when registred two or more times
- fixed custom sound inverted pitch and volume
- fixed sounds having infinite volume
you are AWESOME