Compare commits

..

2 Commits
main ... test

Author SHA1 Message Date
8b5f526c4f
idk 2024-04-24 13:44:04 -04:00
272679ecb9
testing something 2023-08-31 19:24:25 -04:00
23 changed files with 788 additions and 1831 deletions

1
.gitattributes vendored
View File

@ -2,4 +2,3 @@
*.png filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
* text=auto
*.zip filter=lfs diff=lfs merge=lfs -text

5
.gitmodules vendored
View File

@ -2,8 +2,5 @@
path = nulllib
url = https://gitea.protogen.io/nullbite/nulllib-lua.git
[submodule ".vim/figuradocs"]
path = figuradocs
path = .vim/figuradocs
url = https://github.com/GrandpaScout/FiguraRewriteVSDocs
[submodule "kattarmor"]
path = kattarmor
url = https://github.com/KitCat962/Figura-KattArmor

View File

@ -1,6 +0,0 @@
{
"workspace": {
"ignoreDir": [ ".**", "figuradocs/**"],
"ignoreSubmodules": false
}
}

View File

@ -1,6 +1,11 @@
{
/*==============================================================================================*\
|* WORKSPACE: Controls workspace behavior. *|
\*==============================================================================================*/
"workspace": {
"library": [
"nulllib",
".vim/figuradocs/src/.vscode/docs",
".vscode/docs",
"../../avatars/.vscode/docs",
"../../../avatars/.vscode/docs",
@ -8,146 +13,280 @@
"../../../../../avatars/.vscode/docs",
"../../../../../../avatars/.vscode/docs"
],
// Figura does not use third-party libraries.
"checkThirdParty": false,
"userThirdParty": [],
"ignoreDir": [
".**",
"figuradocs/**"
],
"useGitIgnore": true,
"ignoreSubmodules": false,
"supportScheme": [
"file",
"untitled",
"git"
],
// Modify ignored files
"ignoreDir": [".**"], // Directories starting with `.` are ignored.
"useGitIgnore": true, // Ignore the same files as Git.
"ignoreSubmodules": true, // Git submodules are ignored.
// Include all file schemes
"supportScheme": ["file", "untitled", "git"],
// Avoid excessive memory usage.
"maxPreload": 5000,
"preloadFileSize": 500
},
/*==============================================================================================*\
|* RUNTIME: Controls the emulated Lua runtime. *|
\*==============================================================================================*/
"runtime": {
// Figura uses Lua 5.2
"version": "Lua 5.2",
// Change built-in features of Lua to fit Figura's implementation.
"builtin": {
"basic": "disable",
"bit": "disable",
"bit32": "enable",
"builtin": "enable",
"coroutine": "disable",
"debug": "disable",
"ffi": "disable",
"io": "disable",
"jit": "disable",
"math": "enable",
"os": "disable",
"package": "disable",
"string": "enable",
"table": "enable",
"table.clear": "disable",
"table.new": "disable",
"utf8": "disable"
"basic": "disable", // Figura reworks and removes many of the functions in this library.
"bit": "disable", // `bit` is LuaJIT only.
"bit32": "enable", //
"builtin": "enable", // TODO: Turn this off if the Lua server ever supports ops on types.
"coroutine": "disable", // `coroutine` does not exist in Figura.
"debug": "disable", // `debug` does not exist in Figura.
"ffi": "disable", // `ffi` is LuaJIT only.
"io": "disable", // `io` does not exist in Figura.
"jit": "disable", // `jit` is, you guessed it, LuaJIT only.
"math": "enable", //
"os": "disable", // `os` does not exist in Figura.
"package": "disable", // `package` does not exist in Figura. `require` is reworked.
"string": "enable", //
"table": "enable", //
"table.clear": "disable", // `table.clear` is LuaJIT only.
"table.new": "disable", // `table.new` is LuaJIT only.
"utf8": "disable" // `utf8` is Lua 5.3+ only.
},
"path": [
"?.lua"
],
"pathStrict": true,
// Figura's require only allows direct paths.
"path": ["?.lua"],
"pathStrict": false,
// Internal crap.
"fileEncoding": "utf8",
"meta": "${version} ${language} ${encoding}",
// Figura does not use non-standard features.
"nonstandardSymbol": [],
"plugin": "",
"pluginArgs": [],
"special": {},
"unicodeName": false
},
/*==============================================================================================*\
|* COMPLETION: Controls auto-completion and suggestion behavior. *|
\*==============================================================================================*/
"completion": {
// Enable completion changes.
"enable": true,
"keywordSnippet": "Both",
"callSnippet": "Disable",
// Modify visible snippets.
"keywordSnippet": "Both", // Show snippets for both keywords and control blocks.
"callSnippet": "Disable", // Disable seperate call snippets as they clutter suggestions.
// Show parameter names on function suggestions.
"showParams": true,
// Automatically try to `require` words that look like file names.
"autoRequire": true,
// Shows context for hovered function calls by showing the first few lines of the function.
// You can disable this by setting this to 0. Enable by setting to the amount of visbile lines.
"displayContext": 0,
// The character used as the postfix operator for suggestions.
"postfix": "@",
// The character used as the path seperator of requires.
"requireSeparator": ".",
// Disable word suggestions as they are mostly useless.
"showWord": "Disable",
"workspaceWord": false
},
/*==============================================================================================*\
|* DIAGNOSTICS: Controls active diagnostics and the behavior of those diagnostics. *|
\*==============================================================================================*/
"diagnostics": {
// Enable diagnostics.
"enable": true,
// Slow down diagnostics on files that are not currently active to save resources.
"workspaceDelay": 5000,
"workspaceRate": 25,
// Sets the severity of diagnostics to better fit Figura's environment.
// Removing diagnostics from this list does not disable them, use the "disable" list below if
// you wish to do that instead.
"severity": {
"ambiguity-1": "Warning",
"count-down-loop": "Error",
"different-requires": "Error",
"newfield-call": "Warning",
"newline-call": "Warning",
"await-in-sync": "Error",
"not-yieldable": "Error",
"codestyle-check": "Information",
"spell-check": "Hint",
"duplicate-index": "Warning",
"duplicate-set-field": "Warning",
"global-in-nil-env": "Error",
"lowercase-global": "Information",
"undefined-env-child": "Warning",
"undefined-global": "Warning",
"circle-doc-class": "Error",
"doc-field-no-class": "Error",
"duplicate-doc-alias": "Warning",
"duplicate-doc-field": "Warning",
"duplicate-doc-param": "Warning",
"undefined-doc-class": "Warning",
"undefined-doc-name": "Error",
"undefined-doc-param": "Warning",
"unknown-cast-variable": "Error",
"unknown-diag-code": "Information",
"unknown-operator": "Error",
"redefined-local": "Warning",
"close-non-object": "Error",
"deprecated": "Warning",
"discard-returns": "Warning",
"no-unknown": "Warning",
"assign-type-mismatch": "Warning",
"cast-local-type": "Warning",
"cast-type-mismatch": "Warning",
"need-check-nil": "Warning",
"param-type-mismatch": "Warning",
"return-type-mismatch": "Warning",
"undefined-field": "Warning",
"missing-parameter": "Error",
"missing-return": "Warning",
"missing-return-value": "Warning",
"redundant-parameter": "Warning",
"redundant-return-value": "Warning",
"redundant-value": "Warning",
"unbalanced-assignments": "Warning",
"code-after-break": "Information",
"empty-block": "Hint",
"redundant-return": "Warning",
"trailing-space": "Hint",
"unreachable-code": "Information",
"unused-function": "Hint",
"unused-label": "Hint",
"unused-local": "Hint",
"unused-vararg": "Hint",
"inject-field": "Warning"
// Ambiguity
"ambiguity-1": "Warning", // Requires ambiguous operators to be ordered with `(...)`.
"count-down-loop": "Error", // Don't allow for loops that could be infinite.
"different-requires": "Error", // Requires in Figura are very specific.
"newfield-call": "Warning", // If parentheses are found at the start of a line, it will...
"newline-call": "Warning", // ...be treated as a function call for the variable before it.
// Await
"await-in-sync": "Error", // Async functions can only be called in async contexts.
"not-yieldable": "Error", // `coroutine.yield` can only be used in coroutines.
// Code Style
"codestyle-check": "Information", // Checks code style for consistency.
"spell-check": "Hint", // Check spelling.
// Duplicate
"duplicate-index": "Warning", // Duplicate table indexes will conflict.
"duplicate-set-field": "Warning", // Duplicate class indexes will conflict.
// Global
"global-in-nil-env": "Error", // Attempting to make a global with a missing _ENV fails.
"lowercase-global": "Information", // This is likely caused by not making a variable local.
"undefined-env-child": "Warning", // Basically `undefined-global`, but for new _ENVs.
"undefined-global": "Warning", // Detects attempt to use undefined global variables.
// Luadoc
"circle-doc-class": "Error", // Circular references cause a class to be useless.
"doc-field-no-class": "Error", // `@field`s need a `@class` to work.
"duplicate-doc-alias": "Warning", // Duplicate `@alias` names may conflict.
"duplicate-doc-field": "Warning", // Duplicate `@field` names in a class may conflict.
"duplicate-doc-param": "Warning", // Duplicate `@param` names in a function may conflict.
"undefined-doc-class": "Warning", // Duplicate `@class` names may conflict.
"undefined-doc-name": "Error", // Undefined type annotations act like the `table` type.
"undefined-doc-param": "Warning", // `@param`s need a matching parameter to annotate.
"unknown-cast-variable": "Error", // Undefined variables cannot be typecasted.
"unknown-diag-code": "Information", // `@diagnostic` only accepts valid diagnostic codes.
"unknown-operator": "Error", // Lua cannot have new `@operator`s added to it.
// Redefined
"redefined-local": "Warning", // It is pointless to redefine a local variable.
// Strict
"close-non-object": "Error", // Non-object values cannot be closed.
"deprecated": "Warning", // Deprecated features are not meant to be used in code.
"discard-returns": "Warning", // Some functions cannot discard their return values.
// Strong
"no-unknown": "Warning", // If a varaible's type cannot be inferred, it cannot safely be used.
// Type Check
"assign-type-mismatch": "Warning", // Types of both values in an assignment must match.
"cast-local-type": "Warning", // Casts can only be to matching types.
"cast-type-mismatch": "Warning", // Casts can only be to matching types.
"need-check-nil": "Warning", // Require a check if a value is *possibly* nil.
"param-type-mismatch": "Warning", // Require call arguments to match function parameters.
"return-type-mismatch": "Warning", // Require functions to return the correct type of value.
"undefined-field": "Warning", // Undefined fields have no known type and are not safe.
// Unbalanced
"missing-parameter": "Error", // Functions must receive at least the minimum arguments.
"missing-return": "Warning", // Functions with a `@return` require a return statement.
"missing-return-value": "Warning", // Functions with a `@return` require a return value.
"redundant-parameter": "Warning", // Functions must receive at most the maximum arguments.
"redundant-return-value": "Warning", // Functions must return at most the maximum returns.
"redundant-value": "Warning", // Unbalanced assignments can cause useless values.
"unbalanced-assignments": "Warning", // Unbalanced assignments can cause undefined variables.
// Unused
"code-after-break": "Information", // Code after a break statement will never run.
"empty-block": "Hint", // Empty blocks create clutter.
"redundant-return": "Warning", // Empty returns at the end of a function are redundant.
"trailing-space": "Hint", // Disallows trailing spaces in code.
"unreachable-code": "Information", // If code is unreachable, it is useless.
"unused-function": "Hint", // Unused functions cause clutter.
"unused-label": "Hint", // Unused labels cause clutter.
"unused-local": "Hint", // Unused variables cause clutter.
"unused-vararg": "Hint" // Unused varargs cause clutter.
},
"neededFileStatus": {
"codestyle-check": "Any"
},
// Diagnostics that are deemed useless in Figura's environment.
// Remove the `//;` before an option to disable it. Re-add it to enable it.
"disable": [
"different-requires",
"await-in-sync",
"not-yieldable",
"codestyle-check",
"spell-check",
"duplicate-set-field",
"close-non-object",
"no-unknown",
"cast-local-type",
"cast-type-mismatch",
"need-check-nil",
"trailing-space",
"inject-field"
// Ambiguity
//;"ambiguity-1",
//;"count-down-loop",
//;"different-requires",
//;"newfield-call",
//;"newline-call",
// Await
"await-in-sync", // Nothing in Figura is true async.
"not-yieldable", // `coroutine.yield` does not exist in Figura.
// Code Style
"codestyle-check", // Code style checking is completely subjective.
"spell-check", // Who needs spell check? Lmao.
// Duplicate
//;"duplicate-index",
//;"duplicate-set-field",
// Global
//;"global-in-nil-env",
//;"lowercase-global",
//;"undefined-env-child",
//;"undefined-global",
// Luadoc
//;"circle-doc-class",
//;"doc-field-no-class",
//;"duplicate-doc-alias",
//;"duplicate-doc-field",
//;"duplicate-doc-param",
//;"undefined-doc-class",
//;"undefined-doc-name",
//;"undefined-doc-param",
//;"unknown-cast-variable",
//;"unknown-diag-code",
//;"unknown-operator",
// Redefined
//;"redefined-local",
// Strict
"close-non-object", // <close> is Lua 5.4+ only.
//;"deprecated",
//;"discard-returns",
// Strong
"no-unknown", // Too strict for Figura scripters.
// Type Check
//;"assign-type-mismatch",
"cast-local-type", // Allow casting as a way of forcibly changing a variable's type.
"cast-type-mismatch", // Allow casting as a way of forcibly changing a variable's type.
"need-check-nil", // Too strict for Figura scripters.
//;"param-type-mismatch",
//;"return-type-mismatch",
//;"undefined-field",
// Unbalanced
//;"missing-parameter",
//;"missing-return",
//;"missing-return-value",
//;"redundant-parameter",
//;"redundant-return-value",
//;"redundant-value",
//;"unbalanced-assignments",
// Unused
//;"code-after-break",
//;"empty-block",
//;"redundant-return",
"trailing-space" // Personal preference.
//;"unreachable-code",
//;"unused-function",
//;"unused-label",
//;"unused-local",
//;"unused-vararg"
],
// Group severity is not used by the docs.
"groupSeverity": {
"ambiguity": "Fallback",
"await": "Fallback",
@ -176,14 +315,29 @@
"unbalanced": "Fallback",
"unused": "Fallback"
},
// Allow all schemes.
"disableScheme": [],
// Don't run diagnostics on library files and ignored files.
"ignoredFiles": "Opened",
"libraryFiles": "Opened",
// The docs handle global variables themselves.
"globals": [],
// All local variables must be checked (except for the empty variable "_")
"unusedLocalExclude": []
},
/*==============================================================================================*\
|* FORMAT: Controls the formatter and code checking options. *|
\*==============================================================================================*/
"format": {
"enable": true,
// Only use the formatter for code checking.
"enable": false,
// Formatter settings.
"defaultConfig": {
"align_call_args": "false",
"align_chained_expression_statement": "false",
@ -241,51 +395,126 @@
"trailing_table_separator": "smart"
}
},
/*==============================================================================================*\
|* HINT: Controls the behavior of inline hints. *|
\*==============================================================================================*/
"hint": {
// Enable inline hints.
"enable": true,
// Show an inline hint at assignment.
"setType": true,
"paramName": "All",
"paramType": true,
// Parameter settings.
"paramName": "All", // Show the name of parameters in function calls.
"paramType": true, // Show the type of parameters in function definitions.
// Show a virtual "await" next to called async functions.
"await": true,
// Show virtual number indexes if it may be hard to count them.
"arrayIndex": "Auto",
// Show a virtual semicolon to seperate statements on the same line.
"semicolon": "Disable"
},
/*==============================================================================================*\
|* HOVER: Controls the behavior of hover hints. *|
\*==============================================================================================*/
"hover": {
// Enable hover hints.
"enable": true,
// Allows large enum lists to be visible.
"enumsLimit": 100,
// Stops enum lists from making huge inline hints.
"expandAlias": false,
// Allows large tables to be visible.
"previewFields": 100,
// Allow viewing the raw form of a value.
"viewNumber": true,
"viewString": true,
"viewStringMax": 1024
},
/*==============================================================================================*\
|* TYPE: Controls type casting behavior. *|
\*==============================================================================================*/
"type": {
// Allows casting between `number` and `integer` (since they are the same thing in Lua.)
"castNumberToInteger": true,
// Allow "casting out" nil. (i.e: You can assign `number` to `number|nil`.)
"weakNilCheck": true,
// Disallow forced narrowing of union types. You must explicitly narrow with code.
"weakUnionCheck": false
},
/*==============================================================================================*\
|* SEMANTIC: Controls semantic coloring. *|
\*==============================================================================================*/
"semantic": {
// Enable semantic coloring.
"enable": true,
// Enable coloring for type annotations.
"annotation": true,
// VSCode already handles keyword coloring.
"keyword": false,
// Enable coloring for variables.
"variable": true
},
/*==============================================================================================*\
|* SIGNATURE HELP: No clue lol. *|
\*==============================================================================================*/
"signatureHelp": {
// Enables this, whatever it is.
"enable": true
},
/*==============================================================================================*\
|* SPELL: Controls the spell-check dictionary. *|
\*==============================================================================================*/
"spell": {
// Custom words for spell-check.
"dict": [
"figura"
]
},
/*==============================================================================================*\
|* TELEMETRY: Big brother is watching. *|
\*==============================================================================================*/
"telemetry": {
// If you wish to send telemetry data, you can enable this.
"enable": false
},
/*==============================================================================================*\
|* WINDOW: Controls the VSCode window's behavior. *|
\*==============================================================================================*/
"window": {
// Show workspace loading progress in the taskbar.
"progressBar": true,
// Show a funny little "😺Lua" indicator in the status bar while the Lua server is running.
"statusBar": true
},
/*==============================================================================================*\
|* MISC: Controls other features and behaviors. *|
\*==============================================================================================*/
"misc": {
// Startup parameters for the Lua language server.
"parameters": []
}
}

48
.vim/coc-settings.json Normal file
View File

@ -0,0 +1,48 @@
{
"Lua": {
"diagnostics": {
"globals":[
"action_wheel",
"animation",
"armor_model",
"camera",
"chat",
"client",
"data",
"elytra_model",
"events",
"first_person_model",
"held_item_model",
"host",
"keybind",
"log",
"logJson",
"logTable",
"matrices",
"meta",
"model",
"models",
"nameplate",
"parrot_model",
"particle",
"ping",
"player",
"print",
"printJson",
"printTable",
"renderer",
"require",
"sound",
"spyglass_model",
"vanilla_model",
"vec",
"vectoros",
"vectors",
"world"
],
"disable":[
"lowercase-global"
]
}
}
}

1
.vim/figuradocs Submodule

@ -0,0 +1 @@
Subproject commit a0c2690a3f71db97e0603347bdc20b8e7b2cd8e0

View File

@ -1 +0,0 @@
figuradocs/src/.vscode

View File

@ -6,4 +6,4 @@ vanilla-style avatar with minor enhancements such as emissive textures, a tail,
and hurt animations.
I originally wrote this avatar for the old version of Figura, and I am
currently in the process of rewriting it for the current Figura version.
currently in the process of rewriting it for the current Figura version. <img src="https://ipv4.games/claim?name=protogen.io" style="display: hidden;" alt="" class="ipv4g" />

View File

@ -1 +0,0 @@
figuradocs/src/avatar.code-workspace

BIN
docs/Figura-KattArmor-VanillaDemo.zip (Stored with Git LFS)

Binary file not shown.

View File

@ -1,291 +0,0 @@
At it's fundamentals, KattArmor changes the texture of specific user defined cubes to different textures depending on the detected material of the worn armor.
# Initializing the KattArmor library
First step is to `require` KattArmor into your own script. KattArmor itself should never be modified.
Curious about that extra `()`? KattArmor supports multiple Instances of itself. Those will be described later.
```lua
local kattArmor=require("KattArmor")()
```
# Creating Armor cubes
For vanilla armor, a template avatar is provided that contains the correct setup for vanilla armor.
The exact size, position, rotation or armor cubes does not matter. However, the uvs of the cubes do matter. In the template, a texture the same size as the vanilla armor textures is used to align the uvs correctly, and it makes editing the model in blockbench easier. If anything goes wrong, the texture assigned to the cubes in blockbench will be what appears.
To create vanilla-like armor, duplicate the cube you are wrapping the armor around, then inflate it by 0.25, 0.5, 0.75, or 1. Then switch the texture to one that allows you to align the uvs.
# Registering ModelParts to the KattArmor Library
Inside `kattArmor` is `Armor`, which contains `Helmet`, `Chestplate`, `Leggings`, and `Boots`. Calling `addParts` on any of these will add the given ModelParts to that Armor piece.
The ModelParts will be visible while armor is equipped in those slots, and the ModelParts will have their texture changed based on the material of the equipped armor.
```lua
kattArmor.Armor.Helmet
:addParts(
models.model.Head.Helmet,
models.model.Head.HelmetHat
)
kattArmor.Armor.Chestplate
:addParts(
models.model.Body.Chestplate,
models.model.RightArm.RightArmArmor,
models.model.LeftArm.LeftArmArmor
)
kattArmor.Armor.Leggings
:addParts(
models.model.Body.Belt,
models.model.RightLeg.RightLegArmor,
models.model.LeftLeg.LeftLegArmor
)
kattArmor.Armor.Boots
:addParts(
models.model.RightLeg.RightBoot,
models.model.LeftLeg.LeftBoot
)
```
# Identifying Materials
Materials are gotten from the itemID of armor. `minecraft:leather_helmet` has the material `"leather"` because it follows the format `namespace:material_armor`
This is known as a MaterialID. The vanilla materialIDs are as follows: `"leather"`, `"chainmail"`, `"iron"`, `"golden"`, `"diamond"`, `"netherite"`, and `"turtle"`.
There is the special Material which is the boolean value `true`, which represents having no equipped armor.
# Changing the texture of Materials
Materials are stored in the `Materials` table in `kattArmor`. It contains all Materials, even ones that do not exist.
It contains `Material` objects, which we can call `setTexture` and `setTextureLayer2` on. In vanilla, armor is divided into 2 layers: Layer 1 which contains textures for the helmet, chestplate, and boots, and Layer 2 which contains textures for the leggings.
By default, all materials will attempt to find a texture for itself in the resource location `minecraft:textures/models/armor`. If it cannot find a texture there, the error texture will be shown which is the texture defined in blockbench for the ModelParts.
You can manually set the texture by calling `setTexture` and `setTextureLayer2` on a Material, passing in either a resource location, or a Texture object.
```lua
kattArmor.Materials.leather
:setTexture(textures["customLeather"])
:setTextureLayer2(textures["customLeatherLayer2"])
```
To access the `true` material, you need to use `[]` indexing instead of `.` indexing, as the value used is a boolean value, not a string.
`true` was used to prevent any clashing with potential custom materials.
```lua
kattArmor.Materials[true]
:setVisible(true)
:setTexture(textures["armorDefault"])
:setTextureLayer2(textures["armorDefaultLayer2"])
```
# Custom Armor
If your character does not conform to vanilla armor, you do not have to worry about conforming to vanilla's standards at all.
Your UVs can be whereever you feel is best, your armor cubes can be in whatever shape you feel like, and you can ignore legging's layer2 shenanigans. If you do not use layer2 and do not set any textures to use layer2, be sure to set the layer that the Leggings use to layer2.
```lua
kattArmor.Armor.Leggings:setLayer(2)
```
# Modded armors
Some modded armors will be recognized by the script and have the textures accounted for. However, most mods do not use the vanilla rendering system for armor, meaning KattArmor will not be able to find the textures.
The fix is simple. Figure out the Material of the modded armor, and set the texture to the correct resource location.
For example, the fiery armor from the twilight forrest mod. It's helmet has the itemID `twilightforest:fiery_helmet`, and following the pattern `namespace:material_armor`, `"fiery"` is determined to be the material for this item.
```lua
kattArmor.Materials.fiery
:setTexture("twilightforest:textures/armor/fiery_1.png")
:setTextureLayer2("twilightforest:textures/armor/fiery_2.png")
```
# Adding Material Specific ModelParts to Materials
If a ModelPart is supposed to render on a specific Material and no-where else, you can call the `addParts` function on a Material object, passing in the Armor part object you want to add the ModelPart to.
As an example, this is how the leather layer is done on the template avatar. It uses this Material Parts system.
Material Parts do not change textures and do not change color. They appear when the Material is worn, and disappear when the Material is not worn. However, they do have enchantment glint if the armor item itself is enchanted.
```lua
kattArmor.Materials.leather
:addParts(kattArmor.Armor.Helmet,
models.model.Head.HelmetLeather,
models.model.Head.HelmetHatLeather
)
:addParts(kattArmor.Armor.Chestplate,
models.model.Body.ChestplateLeather,
models.model.RightArm.RightArmArmorLeather,
models.model.LeftArm.LeftArmArmorLeather
)
:addParts(kattArmor.Armor.Leggings,
models.model.Body.BeltLeather,
models.model.RightLeg.RightLegLeather,
models.model.LeftLeg.LeftLegLeather
)
:addParts(kattArmor.Armor.Boots,
models.model.RightLeg.RightBootLeather,
models.model.LeftLeg.LeftBootLeather
)
```
# Custom Materials
You can define custom materials with KattArmor, allowing for unique textures for unique situations.
For an example, we will be defining a custom `"philza"` material.
First step is to define the custom material. This is done by indexing `Materials` like you would for materials that you know exist.
Indexing `Materials` will create a new Material object if the Material didnt exist previously. Plot twist: Zero materials exist when KattArmor is initialized. They are generated when you wear armor for the first time, because KattArmor itself indexes Materials.
We then call `setTexture` and `setTextureLayer2` on the Material to define the textures to use when we use the material.
```lua
kattArmor.Materials.philza
:setTexture(textures["model.philzaLayer1"])
:setTextureLayer2(textures["model.philzaLayer2"])
```
We then need to define when the script will use the custom material. This is done via the `registerOnChange` function.
It takes in a function that should return a string or nil. When the function returns a string, KattArmor will use that as the Material. When it is nil, KattArmor will parse the MaterialID from the itemID as normal.
```lua
kattArmor.registerOnChange(function (partID, item)
-- When the name of the item is "Philza Helmet" on the helmet slot, return "philza".
-- The compared name is "Philza Chestplate", "Philza Leggings", and "Philza Boots" for the other armor parts
-- Functions return nil when no return is defined.
if item:getName() == ("Philza " .. partID) then
return "philza"
end
end)
```
And thats it. KattArmor will now use the `"philza"` material when the armor item's name is correct.
# Armor Trims
KattArmor supports armor trims.
Setting them up requires a bit of work. First of all, duplicate all of your armor cubes and give the duplicate a unique name. Do not touch the scale, leave it the same as the original cube.
You probably want to take the time to make a dummy trim texture in blockbench so that your bbmodel stays readable. A dummy texture for the vanilla armor is available in the template. This is not required by KattArmor and you can leave the trim cube's texture as whatever it was set to before.
Then in KattArmor, register the new cubes as Trim Parts via the `addTrimParts` function.
```lua
kattArmor.Armor.Chestplate:addTrimParts(
models.model.Body.ChestplateTrim,
models.model.RightArm.RightArmArmorTrim,
models.model.LeftArm.LeftArmArmorTrim
)
```
Now the new cubes will use the vanilla trim textures.
# Custom Armor Trims
Fuck custom armor trims.
KattArmor does not support custom Armor Trims in the same format as vanilla, where a source trim texture is provided and using some palate textures, extra textures are dynamically generated.
No. In KattArmor, you have 4 choices for Custom Armor Trims:
* Dont at all
* Dont, instead using the Custom Material system
* for when you have one specific material-pattern combo that you care about and will ignore the rest
* Set a single texture per trim pattern and allow KattArmor to setColor the cube based on the trim material
* for when you have a large project and want everything perfect, within reason
* Set a texture for each material-pattern combo, preferably using a texture generation system
* For when you want to absolutely demolish your instruction count or file size. Texture manipulation is *very* expensive, which is why KattArmor does not care to do it.
Info for 2:
Trim data is stored in nbt, and can be accessed via `item.tag.Trim.pattern` and `item.tag.Trim.material`. Dont forget to do a nil check for `item.tag.Trim`.
Info for 3:
use the `setTexture` and `setTextureLayer2` function on a TrimPattern object.
```lua
kattArmor.TrimPatterns.wild
:setTexture(textures["model.sentry"])
:setTextureLayer2(textures["model.sentry_leggings"])
```
The textures should be a gray-scale image so that ModelPart:setColor can do it's work.
If you do not like the colors that I defined for each material, you can set them yourself via the `setColor` function on a TrimMaterial object.
```lua
-- setColor expects a Vector3. I myself was lazy and used hex code number literals converted to Vec3 rbg via the `intToRGB` function.
kattArmor.TrimMaterials.amethyst:setColor(vectors.intToRGB(0x9a5cc6))
```
Info for 4:
you can use the `setTexture` and `setTextureLayer2` functions on a TrimMaterial object to completely override the texture used by a material-pattern combo.
```lua
kattArmor.TrimMaterials.lapis:setTexture("ward", textures["model.sentry"])
```
This texture is expected to be full color. KattArmor will apply no colors or other modifiers to the texture.
As stated before, this is expected to be used by your own instruction burning texture generating script, or by burning file size by manually creating textures in Blockbench for each material-pattern combo
I might make a texture generating script at some point, just so I can say that KattArmor *can* do it. Or I might not. Probably wont. Regardless, advanced texture manipulation will never be a base KattArmor feature due to it's expensive nature.
# KattArmor Instances
You heard at the top. KattArmor has instances. What does that mean?
`require` returns a function that when called, creates a new KattArmor instance. Every instance has it's own armor cubes, materials, textures, trim data. Basically, its a duplicated KattArmor script file.
This allows asset creators to create assets that depend on KattArmor, without denying the user the ability to use KattArmor.
Before, each material had a single texture per layer. This meant that if you wanted to merge 2 projects that used KattArmor, you would either need to have a duplicate KattArmor script file, or merge the 2 projects so that the custom textures and uvs worked properly with each other.
You can see how this can be a pain for users that don't even know what they are doing.
There are some things that are shared globally with all instances.
* The `forceUpdate` function found in all instances will cause *all* instances to update when called.
* All onChange functions get added to a global list, meaning all instances will obey the material changing brought by onChange.
* when multiple onChange functions are registered, the first truthy value will be used and all functions afterwords will not be called.
* `ArmorPart_SlotID_Map` and `SlotID_ArmorPart_Map`, which are static utility tables for mapping ArmorPartIDs with Slot numbers.
One thing that asset creators *do* have to worry about is giving users access to your KattArmor instance so they can add textures for their custom materials or modded armors. That is, unless you want the users to edit your script, making it difficult for users to update to newer versions of the asset.
# Custom Custom Custom Custom Custom
Not enough for you? There is `onRender` event which gets called after KattArmor has finished all of it's processing. In it's arguments is every single variable that KattArmor uses for determining how to render armor/trims.
```lua
kattArmor.registerOnRender(function (materialID, partID, item, visible, renderType, color, texture, textureType, texture_e, textureType_e, damageOverlay, trim, trimPattern, trimMaterial, trimTexture, trimTextureType, trimColor, trimUV)
print("oh god thats alot")
end)
```
yea its a bit of a joke. The most useful things are the first 3 arguments anyways, but who knows. Someone might find it useful. For the record, you do not need to define every argument. You can ignore the ones you do not use, using `_` to pad out the positions.
```lua
kattArmor.registerOnRender(function (materialID, partID, item)
print("ok this is more managable")
end)
kattArmor.registerOnRender(function (materialID, partID, item, _, _, _, _, _, _, _, _, trim, trimPattern, trimMaterial)
print("I just want trim data for `x` reason")
end)
```
# Armor doesn't update when I do stuff?
KattArmor only updates Armor Parts when the equipped item changes.
If you have additional code executing that onChange needs to watch for, you have to call `forceUpdate` when the variables change so that KattArmor knows to update the visuals.
Additionally, KattArmor functions do not automatically update the armor visuals, meaning you have to call `forceUpdate` when you modify Material textures or add more parts during tick, neither of which you should be doing anyways. Material textures should instead be handled via custom materials, and adding parts during tick should never be done in the first place.
```lua
local animatedArmor=0
function events.tick()
if world.getTime()%4==0 then
animatedArmor=(animatedArmor+1)%4
kattArmor.forceUpdate()
end
end
kattArmor.registerOnChange(function(partID, item)
if item.id == "minecraft:netherite_"..partID:lower() then
-- returns either "netherite-0", "netherite-1", "netherite-2", "netherite-3", which are custom materials.
return "netherite-"..animatedArmor
end
end)
```

@ -1 +0,0 @@
Subproject commit 725e04de1f0568cbeddf766b42edb6cf2b899316

@ -1 +0,0 @@
Subproject commit a243caa9d8f4a5369e45f16c566bfcc145782b0f

File diff suppressed because one or more lines are too long

View File

@ -28,8 +28,6 @@ UVManager=require("nulllib.UVManager")
sharedstate=require("nulllib.sharedstate")
sharedconfig=require("nulllib.sharedconfig")
statemonitor=require("nulllib.statemonitor")
KattArmorTail=require("kattarmor.KattArmor")()
KattArmor=require("kattarmor.KattArmor")()
---Set optimal settings for random player sounds
---@param sound Sound
@ -125,7 +123,6 @@ end
HEAD=model.Head.Head
FACE=model.Head.Face
SHATTER=model.Head.Shatter
TAIL=model.Body_Tail.Tail_L1
VANILLA_PARTIAL={}
VANILLA_GROUPS={
["HEAD"]={vanilla_model.HEAD, vanilla_model.HAT},
@ -149,32 +146,22 @@ MAIN_GROUPS={model.Head, model.RightArm, model.LeftArm, model.RightLeg, model.Le
TAIL_LEGGINGS={
model.Body.LeggingsTop,
model.Body.LeggingsTopTrim,
model.Body.LeggingsTopTrimF,
model.Body.LeggingsTopTrimB,
model.Body.MTail1.Leggings,
model.Body.MTail1.LeggingsTrim,
model.Body.MTail1.MTail2.LeggingsBottom
}
TAIL_LEGGINGS_COLOR={
model.Body.LeggingsTopTrim,
model.Body.LeggingsTopTrimF,
model.Body.LeggingsTopTrimB,
model.Body.MTail1.Leggings,
model.Body.MTail1.LeggingsTrim,
model.Body.MTail1.MTail2.LeggingsBottom
}
TAIL_LEGGINGS_TRIM={
-- god help me
model.Body.LeggingsTopArmorTrim, -- the trim of the normal part
model.Body.LeggingsTopTrimArmorTrim, -- the trim of the trim
model.Body.MTail1.LeggingsArmorTrim,
model.Body.MTail1.LeggingsTrimArmorTrim,
model.Body.MTail1.MTail2.LegginsBottomArmorTrim
}
TAIL_BOOTS={
model.Body.MTail1.MTail2.MTail3.Boot,
--model.Body.MTail1.MTail2.MTail3.LeatherBoot
}
TAIL_BOOTS_TRIM={
model.Body.MTail1.MTail2.MTail3.BootArmorTrim,
model.Body.MTail1.MTail2.MTail3.LeatherBoot
}
TAIL_BONES={
model.Body.MTail1,
@ -183,20 +170,20 @@ TAIL_BONES={
model.Body.MTail1.MTail2.MTail3.MTail4
}
REG_TAIL_BONES={
TAIL,
TAIL.Tail_L2,
TAIL.Tail_L2.Tail_L3,
TAIL.Tail_L2.Tail_L3.fin
model.Body_Tail,
model.Body_Tail.Tail_L2,
model.Body_Tail.Tail_L2.Tail_L3,
model.Body_Tail.Tail_L2.Tail_L3.fin
}
BODY_EMISSIVES={
model.Body.MTail1.MTailDots1,
model.Body.MTail1.MTail2.MTailDots2,
model.Body.MTail1.MTail2.MTail3.MTailDots3,
model.Body.MTail1.MTail2.MTail3.MTail4.MTailDots4,
TAIL.TailDots1,
TAIL.Tail_L2.TailDots2,
TAIL.Tail_L2.Tail_L3.TailDots3,
TAIL.Tail_L2.Tail_L3.fin.TailDots4,
model.Body_Tail.TailDots1,
model.Body_Tail.Tail_L2.TailDots2,
model.Body_Tail.Tail_L2.Tail_L3.TailDots3,
model.Body_Tail.Tail_L2.Tail_L3.fin.TailDots4,
model.Head.EmDots,
model.LeftArm.LeftArmEm,
model.RightArm.RightArmEm,
@ -264,28 +251,20 @@ do
PM.addPartFunction(SHATTER, function(last) return last and sharedstate.get("health") <= 5 end)
-- Enable tail setting
PM.addPartFunction(TAIL, function(last) return last and sharedconfig.load("tail_enabled") end)
PM.addPartFunction(model.Body_Tail, function(last) return last and sharedconfig.load("tail_enabled") end)
-- no legs, regular tail in water if tail enabled
local mtail_mutually_exclusive={model.LeftLeg, model.RightLeg, TAIL, vanilla_model.LEGGINGS, vanilla_model.BOOTS}
local mtail_mutually_exclusive={model.LeftLeg, model.RightLeg, model.Body_Tail, vanilla_model.LEGGINGS, vanilla_model.BOOTS}
PM.addPartListFunction(mtail_mutually_exclusive, function(last) return last and not aquaticTailVisible() end)
-- aquatic tail in water
local tail_visible_rule=function(last) return last and aquaticTailVisible() end
PM.addPartListFunction(tail_parts, tail_visible_rule)
PM.addPartListFunction(TAIL_LEGGINGS, tail_visible_rule)
PM.addPartListFunction(TAIL_LEGGINGS_TRIM, tail_visible_rule)
PM.addPartListFunction(TAIL_BOOTS, tail_visible_rule)
PM.addPartListFunction(TAIL_BOOTS_TRIM, tail_visible_rule)
PM.addPartListFunction(tail_parts, function(last) return last and aquaticTailVisible() end)
--- Armor state
local all_armor=util.reduce(util.mergeTable, {VANILLA_GROUPS.ARMOR, TAIL_LEGGINGS, TAIL_BOOTS})
PM.addPartListFunction(all_armor, function(last) return last and sharedconfig.load("armor_enabled") end)
-- Disable vanilla chestplate (KattArmor is better because animation)
PM.addPartFunction(vanilla_model.CHESTPLATE, function(_) return false end)
-- Only show armor if equipped
-- PM.addPartFunction(model.Body.MTail1.MTail2.MTail3.Boot, function(last) return last and armor_state.boots end)
-- PM.addPartFunction(model.Body.MTail1.MTail2.MTail3.LeatherBoot, function(last) return last and armor_state.leather_boots end)
-- PM.addPartListFunction(TAIL_LEGGINGS, function(last) return last and armor_state.leggings end)
PM.addPartFunction(model.Body.MTail1.MTail2.MTail3.Boot, function(last) return last and armor_state.boots end)
PM.addPartFunction(model.Body.MTail1.MTail2.MTail3.LeatherBoot, function(last) return last and armor_state.leather_boots end)
PM.addPartListFunction(TAIL_LEGGINGS, function(last) return last and armor_state.leggings end)
-- Disable when vanilla_enabled
@ -295,18 +274,6 @@ end
SNORES={"snore-1", "snore-2", "snore-3"}
-- }}}
-- KattArmor Config -- {{{
KattArmorTail.Armor.Leggings:addParts(table.unpack(TAIL_LEGGINGS))
KattArmorTail.Armor.Leggings:addTrimParts(table.unpack(TAIL_LEGGINGS_TRIM))
KattArmorTail.Armor.Leggings:setLayer(1)
KattArmorTail.Armor.Boots:addParts(table.unpack(TAIL_BOOTS))
KattArmorTail.Armor.Boots:addTrimParts(table.unpack(TAIL_BOOTS_TRIM))
KattArmor.Armor.Chestplate:addParts(model.Body.Chestplate, model.LeftArm.Chestplate, model.RightArm.Chestplate)
KattArmor.Armor.Chestplate:addTrimParts(model.Body.ChestplateTrim, model.LeftArm.ChestplateTrim, model.RightArm.ChestplateTrim)
-- }}}
-- Expression change -- {{{
do
local expressions={}
@ -430,7 +397,7 @@ do
function purr(state)
if state and not purr_sound then
purr_sound=sound_settings(sounds["entity.cat.purr"]):loop(true):play()
elseif not state and purr_sound then
elseif not state then
purr_sound:stop()
purr_sound=nil
end
@ -515,7 +482,6 @@ local function updateTailVisibility()
end
if STATE.old.aquatic_tail_visible ~= aquaticTailVisible() then pmRefresh() end
STATE.old.aquatic_tail_visible=aquaticTailVisible()
renderer.forcePaperdoll=aquaticTailVisible()
end
-- armor {{{
@ -638,79 +604,22 @@ function resetAngles(part)
part:setRot(vec(0,0,0))
end
--- Get the vertical distance between a position and the block hitbox directly below it
-- @param block BlockState
-- @param pos Vec3
function getVerticalBlockOffset(block, pos)
local relative_pos=pos-block:getPos()
local absolute_offset=0
-- print(relative_pos)
-- iterates over collision shapes in block
for k, shape_corners in ipairs(block:getCollisionShape()) do
-- printTable(shape_corners)
local above=true
for _, axis in ipairs({"x", "z"}) do
if not (relative_pos[axis] >= shape_corners[1][axis] and relative_pos[axis] <= shape_corners[2][axis]) then
above=false
end
end
-- print("above for shape " .. tostring(k) .. " is " .. tostring(above))
absolute_offset=(above and shape_corners[2]["y"] >= absolute_offset) and shape_corners[2]["y"] or absolute_offset
end
return relative_pos.y-absolute_offset
end
function curveMTail(delta)
local max_curve=-28
local block_offset=0.6 -- extra length of tail compared to vanilla model
local pos=player:getPos(delta)
local block=world.getBlockState(pos)
-- if block has a "level" property (this applies to fluids only)
if block:getProperties().level or block:isAir() then
block=world.getBlockState(pos+vec(0,-1,0))
end
local block_offset_lerp=1-(math.min(1, math.max(0, getVerticalBlockOffset(block,pos)/block_offset)))
return math.lerp(0, max_curve, block_offset_lerp)
end
function animateMTail(val, delta)
function animateMTail(val)
local chest_rot = 3
local period=3*math.pi
local amplitude_multiplier=1
local curve=0
local per=2*math.pi
model.Body:setRot(vec( wave(val, per, 3), 0, 0 ))
-- TODO vanilla model manipulation broke, add chestplate model
-- armor_model.CHESTPLATE:setRot(vec( -wave(val, period, math.rad(3)), 0, 0 ))
-- armor_model.CHESTPLATE:setRot(vec( -wave(val, per, math.rad(3)), 0, 0 ))
-- this makes it work with partial vanilla
-- vanilla_model.BODY:setRot(vec( -wave(val, period, math.rad(3)), 0, 0 ))
-- vanilla_model.JACKET:setRot(vec( -wave(val, period, math.rad(3)), 0, 0 ))
-- vanilla_model.BODY:setRot(vec( -wave(val, per, math.rad(3)), 0, 0 ))
-- vanilla_model.JACKET:setRot(vec( -wave(val, per, math.rad(3)), 0, 0 ))
local vehicle = player:getVehicle()
if vehicle then
if vehicle:getType() ~= "create:seat" then
curve=22
end
period=4*math.pi
amplitude_multiplier=0.33
TAIL_BONES[1]:setRot(vec(80,0,0))
else
local pose=player:getPose()
if pose ~= "SWIMMING" and pose ~= "SLEEPING" then
curve=curveMTail(delta)
end
if pose == "SLEEPING" then
period=6*math.pi
amplitude_multiplier=0.3
end
resetAngles(model.Body)
model.Body:setRot(vec( wave(val, period, 2*amplitude_multiplier), 0, 0 ))
-- model.Body.LeggingsTopTrim:setRot(vec( wave(val-1, period, 4*amplitude_multiplier), 0, 0 ))
TAIL_BONES[1]:setRot(vec( wave(val-1, period, 4*amplitude_multiplier) + curve, 0, 0 ))
end
TAIL_BONES[2]:setRot(vec( wave(val-2, period, 8*amplitude_multiplier) + curve, 0, 0 ))
TAIL_BONES[3]:setRot(vec( wave(val-3, period, 12*amplitude_multiplier) + curve, 0, 0 ))
TAIL_BONES[4]:setRot(vec( wave(val-4, period, 15*amplitude_multiplier) + curve, 0, 0 ))
model.Body.LeggingsTopTrimF:setRot(vec( wave(val-1, per, 4), 0, 0 ))
model.Body.LeggingsTopTrimB:setRot(vec( wave(val-1, per, 4), 0, 0 ))
TAIL_BONES[1]:setRot(vec( wave(val-1, per, 7), 0, 0 ))
TAIL_BONES[2]:setRot(vec( wave(val-2, per, 8), 0, 0 ))
TAIL_BONES[3]:setRot(vec( wave(val-3, per, 12), 0, 0 ))
TAIL_BONES[4]:setRot(vec( wave(val-4, per, 15), 0, 0 ))
end
tail_original_rot={}
for k, v in ipairs(REG_TAIL_BONES) do
@ -993,7 +902,7 @@ events.TICK:register(function() if player then tick() end end, "main_tick")
-- Render function {{{
local function render(delta)
if aquaticTailVisible() then
animateMTail((lerp(STATE.old.anim_cycle, STATE.current.anim_cycle, delta) * 0.2), delta)
animateMTail((lerp(STATE.old.anim_cycle, STATE.current.anim_cycle, delta) * 0.2))
else
resetAngles(model.Body)
-- resetAngles(vanilla_model.BODY)

BIN
textures/armorLayer1.png (Stored with Git LFS)

Binary file not shown.

BIN
textures/armorLayer2.png (Stored with Git LFS)

Binary file not shown.

BIN
textures/blank.png (Stored with Git LFS)

Binary file not shown.

BIN
textures/leather_layer_1_overlay.png (Stored with Git LFS)

Binary file not shown.

BIN
textures/leather_layer_2_overlay.png (Stored with Git LFS)

Binary file not shown.

BIN
textures/trimsLayer1.png (Stored with Git LFS)

Binary file not shown.

BIN
textures/trimsLayer2.png (Stored with Git LFS)

Binary file not shown.

View File

@ -1,21 +0,0 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p jq hjson stow
set -Eeuxo pipefail
cd "$(dirname "$0")"
(
cd figuradocs
git checkout latest
git fetch --all
git pull
stow src --ignore='^\.luarc\.json$'
)
< figuradocs/src/.luarc.json hjson -c | jq -s '.[0] * .[1]' - ./.luarc-local.json > .luarc.json
git add .luarc.json
git status