Cunning fox Posted May 25, 2020 Share Posted May 25, 2020 (edited) DISCLAIMER: This guide is for modded items only. Klei prohibited creating custom skins for official items, and this library won't be able to add them. Hey everyone! Since I haven't found up-to-date and easy to use library for creating custom skins for items, I decided to make my own one and share it with you I used @Kzisor / Ysovuka's library as a base for mine.1. Installation First of all, you'll need to download the library from here: Then, you'll need to put it in your mod's folder. I'll be using path scripts/libs/skins_api.lua. After that, you'll need to include this library for your mod. Add this line into your modmain: modimport("scripts/libs/skins_api.lua") All set! The library is installed, and we can actually add our skins.2. Making custom skin prefab Unlike Klei's skins, modded skins use different prefabs for every skin. So, you can different properties for every skin! They even can have different functionality. So, you have 2 options: Make a separate prefabs file for skins (or each skin) Make prefab's skins directly in the base prefab's file. To register your skin you'll need to use CreateModPrefabSkin(name, properties) function, where name is a string with the name of your skin, and properties is a table. For example: CreateModPrefabSkin("dummy_formal", { assets = { Asset("ANIM", "anim/dummy_formal.zip"), }, base_prefab = "dummy", fn = formal, rarity = "Timeless", reskinable = true, build_name_override = "dummy_formal", type = "item", skin_tags = { }, release_group = 0, }) Assets: a table of assets for your skin; base_prefab: Prefab of the items you're making a skin for. fn: Prefab's constructor. Acts like a regular prefab constructor. rarity: Your item's rarity. reskinable: Will your item be reskinable using the Clean Sweeper. build_name_override: The build of the skin. The rest of the properties is only used by Klei, so it's better to just keep them unchanged. If you're confused about the Fn, here's an example: Let's say that you want to make a skin for something similar to a carrot. You have a constructor function: local function fn() local inst = CreateEntity() inst.entity:AddTransform() inst.entity:AddAnimState() inst.entity:AddNetwork() inst.AnimState:SetBank("carrot") inst.AnimState:SetBuild("carrot") inst.AnimState:PlayAnimation("planted") inst.entity:SetPristine() if not TheWorld.ismastersim then return inst end inst:AddComponent("inspectable") inst:AddComponent("pickable") inst.components.pickable:SetUp("carrot", 10) inst.components.pickable.onpickedfn = onpicked return inst end To make a skin you'll need to create a new constructor like this: local function carrot_skin() local inst = fn() inst.AnimState:SetBuild("skinned_carrot_build") return inst end Here we create a default carrot (using fn()), and then apply some changes to it (change the carrot's build). After that, we'll need to return our skin, just like a regular prefab. At the end of the file you need to put: return Prefab("carrot", fn, assets), CreateModPrefabSkin("dummy_formal", { assets = { Asset("ANIM", "anim/skinned_carrot.zip"), }, base_prefab = "carrot", fn = carrot_skin, -- This is our constructor! rarity = "Timeless", reskinable = true, build_name_override = "skinned_carrot", type = "item", skin_tags = { }, release_group = 0, }) 3. Updating the recipe and adding strings After creating your skins' prefab, you'll need to update your recipe too. After you've added your item's recipe with AddRecipe, you'll need to call MadeRecipeSkinnable(recipe_name, atlas_data), where recipe_name is the name of your recipe, and atlas_data is a table, containing info about your skin's inventory image. MadeRecipeSkinnable("dummy", { dummy_formal = { atlas = "images/inventoryimages/dummy.xml", image = "dummy_formal.tex", }, }) The second argument is the table. Here you'll add atlas and image of the skin. Here, dummy_formal is the name of the skin, the atlas is a path to .xml file, and the image is the name of the texture. After that, you'll need to name your skin, using STRINGS.SKIN_NAMES table. Is works just like adding names to regular prefabs, but the name of the prefab has to be lowercased. STRINGS.SKIN_NAMES.dummy_formal = "Formal dummy" All set! Your modded item now should have its own skin.4. Applying skins on placers. If your item is a structure and has a placer, you'll want to apply a skin to its placer too. To do it, you'll need to modify your MakePlacer, to make it look like this: MakePlacer("dummy_placer", "dummy", "dummy", "anim", nil, nil, nil, nil, nil, nil, placer) placer here is a custom function that'll be applying the skin itself. If should look like this: local function placer(inst) inst.ApplySkin = function(inst, skin) if skin == "dummy_formal" then inst.AnimState:SetBuild("dummy_formal") end end end Here placer function adds ApplySkin function. The skin argument is the name of the skin for the item. In this example, we check if the skin is dummy_formal, and apply custom build for a placer if it's true. That's all you need to add a skin for your item! If you have any questions or feature requests, feel free to ask them in the comments! Mods that use this library (You can use them as an example)The Dummy Mod Edited May 25, 2020 by Cunning fox 4 4 Link to comment Share on other sites More sharing options...
Thomas Die Posted May 25, 2020 Share Posted May 25, 2020 Ahh yes, thank you. 1 Link to comment Share on other sites More sharing options...
Stormish Posted May 31, 2020 Share Posted May 31, 2020 My game froze and crashed with the API when someone spawned a clean sweeper. This is the error I got: Spoiler [00:30:47]: error calling PrefabPostInit: reskin_tool in mod workshop-1422448457 (Thomas, The Skeleton Chef): [string "../mods/workshop-1422448457/scripts/tools/i..."]:222: attempt to index field 'spellcaster' (a nil value) LUA ERROR stack traceback: ../mods/workshop-1422448457/scripts/tools/itemskins_api.lua(222,1) =(tail call) ? =[C] in function 'xpcall' scripts/mods.lua(162,1) in function 'mod' scripts/mainfunctions.lua(267,1) [00:30:47]: Disabling workshop-1422448457 (Thomas, The Skeleton Chef) because it had an error. [00:30:47]: [string "../mods/workshop-1422448457/scripts/tools/i..."]:222: attempt to index field 'spellcaster' (a nil value) LUA ERROR stack traceback: ../mods/workshop-1422448457/scripts/tools/itemskins_api.lua(222,1) =(tail call) ? =[C] in function 'xpcall' scripts/mods.lua(162,1) in function 'mod' scripts/mainfunctions.lua(267,1) [00:30:48]: [string "../mods/workshop-1422448457/scripts/tools/i..."]:222: attempt to index field 'spellcaster' (a nil value) LUA ERROR stack traceback: ../mods/workshop-1422448457/scripts/tools/itemskins_api.lua(222,1) =(tail call) ? =[C] in function 'xpcall' scripts/mods.lua(162,1) in function 'mod' scripts/mainfunctions.lua(267,1) [00:30:48]: error calling PrefabPostInit: reskin_tool in mod workshop-1341057026 (Stormish): [string "../mods/workshop-1341057026/scripts/tools/i..."]:222: attempt to index field 'spellcaster' (a nil value) LUA ERROR stack traceback: ../mods/workshop-1341057026/scripts/tools/itemskins_api.lua(222,1) =(tail call) ? =[C] in function 'xpcall' scripts/mods.lua(162,1) in function 'mod' scripts/mainfunctions.lua(267,1) [00:30:48]: Disabling workshop-1341057026 (Stormish) because it had an error. Link to comment Share on other sites More sharing options...
Stormish Posted June 2, 2020 Share Posted June 2, 2020 (edited) I found out the reason why the game crashes when the Clean Sweeper is spawned. The reason why it crashed is because you didn't rmake it check if the spellcaster component existed or not and since it's doing this on client side, it wasn't able to find the spellcaster component so the game crashed for that very reason, hence why it says spellcaster is a "nil" value. This is what the PrefabPostInit function for "reskin_tool" should look like now in the API code: Spoiler env.AddPrefabPostInit("reskin_tool", function(inst) local spellcaster = inst.components.spellcaster if spellcaster ~= nil then local _can_cast_fn = spellcaster.can_cast_fn spellcaster.can_cast_fn = function(doer, target, ...) if HasSkins(target) then return true end return _can_cast_fn(doer, target, ...) end -- Our custom reskinner! local _spell = spellcaster.spell spellcaster.spell = function(inst, target, ...) target = target or inst.components.inventoryitem.owner --if no target, then get the owner of the tool. Self target for beards if not HasSkins(target) then return _spell(inst, target, ...) end SpawnAt("explode_reskin", target) local prefab = target.base_prefab or target.prefab local skin = target.skinname or target.prefab if not inst._cached_reskinname[prefab] then inst._cached_reskinname[prefab] = skin end while inst._cached_reskinname[prefab] == skin do for item_type, _ in pairs(MODDED_SKINS[prefab]) do if item_type ~= skin then inst._cached_reskinname[prefab] = item_type break end end end ReskinModEntity(target, inst._cached_reskinname[prefab]) end end end) Edited June 2, 2020 by Stormish 1 1 Link to comment Share on other sites More sharing options...
Cunning fox Posted June 4, 2020 Author Share Posted June 4, 2020 On 6/2/2020 at 4:42 PM, Stormish said: I found out the reason why the game crashes when the Clean Sweeper is spawned. The reason why it crashed is because you didn't rmake it check if the spellcaster component existed or not and since it's doing this on client side, it wasn't able to find the spellcaster component so the game crashed for that very reason, hence why it says spellcaster is a "nil" value. This is what the PrefabPostInit function for "reskin_tool" should look like now in the API code: Reveal hidden contents env.AddPrefabPostInit("reskin_tool", function(inst) local spellcaster = inst.components.spellcaster if spellcaster ~= nil then local _can_cast_fn = spellcaster.can_cast_fn spellcaster.can_cast_fn = function(doer, target, ...) if HasSkins(target) then return true end return _can_cast_fn(doer, target, ...) end -- Our custom reskinner! local _spell = spellcaster.spell spellcaster.spell = function(inst, target, ...) target = target or inst.components.inventoryitem.owner --if no target, then get the owner of the tool. Self target for beards if not HasSkins(target) then return _spell(inst, target, ...) end SpawnAt("explode_reskin", target) local prefab = target.base_prefab or target.prefab local skin = target.skinname or target.prefab if not inst._cached_reskinname[prefab] then inst._cached_reskinname[prefab] = skin end while inst._cached_reskinname[prefab] == skin do for item_type, _ in pairs(MODDED_SKINS[prefab]) do if item_type ~= skin then inst._cached_reskinname[prefab] = item_type break end end end ReskinModEntity(target, inst._cached_reskinname[prefab]) end end end) Oh, right, sorry. It's just exams season in my university rn, I don't have that much time on mods, but I'll update it asap! 1 Link to comment Share on other sites More sharing options...
Vindorable Posted July 26, 2020 Share Posted July 26, 2020 Hello @Cunning fox! Do you have a small guide on making custom skins for walls? Because, the script is far more complicated than a simple weapon/armor script. Link to comment Share on other sites More sharing options...
Kyno Posted October 7, 2021 Share Posted October 7, 2021 This API works for critter skins too? Link to comment Share on other sites More sharing options...
Revanchist Posted October 8, 2021 Share Posted October 8, 2021 What needs to be changed if it's a helmet skin? I am doing something wrong, the textures on the skin are not displayed correctly. Link to comment Share on other sites More sharing options...
TheSkylarr Posted January 9, 2022 Share Posted January 9, 2022 I have multiple skins on one item in my implementation, but the Clean Sweeper only toggles between my item's default skin and one other skin, despite there being 3 working and craftable skins other than the default, not just one. Anyone seem to know why? Example: Starts with 3 different skins plus default, end up with only default and one other. Link to comment Share on other sites More sharing options...
Triple_MD Posted February 2, 2022 Share Posted February 2, 2022 I'm doing something wrong, the textures on the skin are not displayed Link to comment Share on other sites More sharing options...
Triple_MD Posted February 6, 2022 Share Posted February 6, 2022 On 09.01.2022 at 18:12, TheSkylarr said: У меня есть несколько скинов для одного предмета в моей реализации, но Clean Sweeper переключается только между скином моего предмета по умолчанию и одним другим скином, несмотря на то, что есть 3 рабочих и создаваемых скина, отличных от стандартного, а не только один. Кажется, кто-нибудь знает, почему? Пример: начинается с 3 разных скинов плюс по умолчанию, заканчивается только по умолчанию и еще одним. Could you post the source? Link to comment Share on other sites More sharing options...
TheSkylarr Posted February 7, 2022 Share Posted February 7, 2022 (edited) 17 hours ago, Triple_MD said: Could you post the source? What do you mean by that? Edited February 7, 2022 by TheSkylarr Link to comment Share on other sites More sharing options...
Triple_MD Posted February 7, 2022 Share Posted February 7, 2022 3 hours ago, TheSkylarr said: Что ты имеешь в виду? prefabs file "Kid's Hat" Link to comment Share on other sites More sharing options...
TheSkylarr Posted February 7, 2022 Share Posted February 7, 2022 8 hours ago, Triple_MD said: prefabs file "Kid's Hat" You take a look here, though I'm not sure why you want to https://github.com/Groundlarr/HatKidDSTMod/blob/main/scripts/prefabs/kidhat.lua Link to comment Share on other sites More sharing options...
Triple_MD Posted April 2, 2022 Share Posted April 2, 2022 On 25.05.2020 at 20:39, Cunning fox said: DISCLAIMER: This guide is for modded items only. Klei prohibited creating custom skins for official items, and this library won't be able to add them. Hey everyone! Since I haven't found up-to-date and easy to use library for creating custom skins for items, I decided to make my own one and share it with you I used @Kzisor / Ysovuka's library as a base for mine. 1. Installation First of all, you'll need to download the library from here: Then, you'll need to put it in your mod's folder. I'll be using path scripts/libs/skins_api.lua. After that, you'll need to include this library for your mod. Add this line into your modmain: modimport("scripts/libs/skins_api.lua") All set! The library is installed, and we can actually add our skins. 2. Making custom skin prefab Unlike Klei's skins, modded skins use different prefabs for every skin. So, you can different properties for every skin! They even can have different functionality. So, you have 2 options: Make a separate prefabs file for skins (or each skin) Make prefab's skins directly in the base prefab's file. To register your skin you'll need to use CreateModPrefabSkin(name, properties) function, where name is a string with the name of your skin, and properties is a table. For example: CreateModPrefabSkin("dummy_formal", { assets = { Asset("ANIM", "anim/dummy_formal.zip"), }, base_prefab = "dummy", fn = formal, rarity = "Timeless", reskinable = true, build_name_override = "dummy_formal", type = "item", skin_tags = { }, release_group = 0, }) Assets: a table of assets for your skin; base_prefab: Prefab of the items you're making a skin for. fn: Prefab's constructor. Acts like a regular prefab constructor. rarity: Your item's rarity. reskinable: Will your item be reskinable using the Clean Sweeper. build_name_override: The build of the skin. The rest of the properties is only used by Klei, so it's better to just keep them unchanged. If you're confused about the Fn, here's an example: Let's say that you want to make a skin for something similar to a carrot. You have a constructor function: local function fn() local inst = CreateEntity() inst.entity:AddTransform() inst.entity:AddAnimState() inst.entity:AddNetwork() inst.AnimState:SetBank("carrot") inst.AnimState:SetBuild("carrot") inst.AnimState:PlayAnimation("planted") inst.entity:SetPristine() if not TheWorld.ismastersim then return inst end inst:AddComponent("inspectable") inst:AddComponent("pickable") inst.components.pickable:SetUp("carrot", 10) inst.components.pickable.onpickedfn = onpicked return inst end To make a skin you'll need to create a new constructor like this: local function carrot_skin() local inst = fn() inst.AnimState:SetBuild("skinned_carrot_build") return inst end Here we create a default carrot (using fn()), and then apply some changes to it (change the carrot's build). After that, we'll need to return our skin, just like a regular prefab. At the end of the file you need to put: return Prefab("carrot", fn, assets), CreateModPrefabSkin("dummy_formal", { assets = { Asset("ANIM", "anim/skinned_carrot.zip"), }, base_prefab = "carrot", fn = carrot_skin, -- This is our constructor! rarity = "Timeless", reskinable = true, build_name_override = "skinned_carrot" 3. Обновление рецепта и добавление строк После создания префаба ваших скинов вам также нужно будет обновить свой рецепт. После того, как вы добавили рецепт вашего предмета с помощью AddRecipe , вам нужно будет вызвать MadeRecipeSkinnable(recipe_name, atlas_data) , где recipe_name — это название вашего рецепта, а atlas_data — это таблица, содержащая информацию об изображении инвентаря вашего скина. Второй аргумент — это таблица. Здесь вы добавите атлас и изображение кожи. Здесь dummy_formal — название скина, атлас — путь к XML-файлу, а изображение — имя текстуры. После этого вам нужно будет назвать свой скин, используя таблицу STRINGS.SKIN_NAMES . Это работает так же, как добавление имен к обычным префабам, но имя префаба должно быть в нижнем регистре. Все готово! Ваш модифицированный предмет теперь должен иметь собственный скин. 4. Нанесение шкур на россыпи. Если ваш предмет представляет собой структуру и имеет россыпь, вы также захотите применить скин к его россыпи. Для этого вам нужно изменить MakePlacer, чтобы он выглядел так: россыпь здесь — это пользовательская функция, которая будет применять сам скин. Если должно выглядеть так: Здесь функция россыпи добавляет функцию ApplySkin. Аргумент skin — это имя скина для предмета. В этом примере мы проверяем, является ли скин dummy_formal , и применяем кастомную сборку для россыпи, если это правда. Это все, что вам нужно, чтобы добавить скин для вашего предмета! Если у вас есть какие-либо вопросы или пожелания, не стесняйтесь задавать их в комментариях! Моды, которые используют эту библиотеку (Вы можете использовать их в качестве примера) The Dummy Mod It doesn't work anymore. Link to comment Share on other sites More sharing options...
TheSkylarr Posted April 30, 2022 Share Posted April 30, 2022 (edited) Seems like this is broken with the update to the crafting UI. Dang. From a few minutes of glancing at the code, it may be able to be mostly reused, just will need some changes to replace the new UI rather than the old one. Unfortunately I have no idea how to do this on my own. Edited April 30, 2022 by TheSkylarr Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now