Hornete Posted June 4, 2022 Author Share Posted June 4, 2022 3 hours ago, Garamonde said: Thank you! I understand, you gotta do what you gotta do for the better! But uh, having said that, I now have an actual problem with loading my mod: [00:00:05]: [string "../mods/K_K/modmain.lua"]:69: attempt to call global 'AddSkinnableCharacter' (a nil value) You're attemping to call the function "AddSkinnableCharacter", this is a remnant from my old tutorial, removing this call from line 69 of your modmain should fix the issue, 1 Link to comment Share on other sites More sharing options...
Garamonde Posted June 4, 2022 Share Posted June 4, 2022 Ahh, thank you! I think the only problem I'm having now is with filenames not matching. I'm getting dedicated server failed to start errors that tell me it "can't find 'kk_ghost' in any of the search paths," for example. And just to see if it'd work, I even manually renamed my .ZIP builds like this, to match your code in the OP: ...With the "ms_" prefacing the alternate skin for my character. Only trouble is in doing that, the autocompiler tries to remake the ANIM builds and have them have "_build" appended to the names, just as the ESC mod tends to do. (The game also crashes upon trying to launch a server once I do this) Here is another log, I didn't see anything obvious in it, but hopefully it helps. Also hopefully that all makes sense, and sorry about the trouble! master_server_log.txt client_log.txt Link to comment Share on other sites More sharing options...
Hornete Posted June 4, 2022 Author Share Posted June 4, 2022 36 minutes ago, Garamonde said: Ahh, thank you! I think the only problem I'm having now is with filenames not matching. I'm getting dedicated server failed to start errors that tell me it "can't find 'kk_ghost' in any of the search paths," for example. May you show me your CreatePrefabSkin call? The part of the code where you're creating your skin. For example: table.insert(prefabs, CreatePrefabSkin("ms_whimsy_victorian", { assets = { Asset("ANIM", "anim/ms_whimsy_victorian.zip"), Asset("ANIM", "anim/ghost_whimsy.zip"), }, skins = { normal_skin = "ms_whimsy_victorian", ghost_skin = "ghost_whimsy", }, base_prefab = "whimsy", build_name_override = "ms_whimsy_victorian", torso_untuck_builds = { "ms_whimsy_victorian", }, type = "base", rarity = "ModLocked", condition = { --no_gift = true }, skin_tags = { "BASE", "WHIMSY", "VICTORIAN"}, })) 1 Link to comment Share on other sites More sharing options...
Garamonde Posted June 4, 2022 Share Posted June 4, 2022 Sure! local prefabs = {} table.insert(prefabs, CreatePrefabSkin("kk_none", { assets = { Asset("ANIM", "anim/kk.zip"), }, skins = { normal_skin = "kk", ghost_skin = "ghost_kk", }, base_prefab = "kk", build_name_override = "kk", type = "base", rarity = "Character", skin_tags = { "BASE", "kk"}, })) table.insert(prefabs, CreatePrefabSkin("ms_kk_hallowed", { assets = { Asset("ANIM", "anim/ms_kk_hallowed.zip"), Asset("ANIM", "anim/ghost_kk_hallowed.zip"), }, skins = { normal_skin = "ms_kk_hallowed", ghost_skin = "ghost_kk_hallowed", }, base_prefab = "kk", build_name_override = "ms_kk_hallowed", torso_untuck_builds = { "ms_kk_hallowed", }, type = "base", rarity = "ModMade", skin_tags = { "BASE", "kk", "HALLOWED"}, })) return unpack(prefabs) This is the entirety of my "_none" script file. Link to comment Share on other sites More sharing options...
Hornete Posted June 4, 2022 Author Share Posted June 4, 2022 (edited) Hmm everything looks like it should be fine on the CreatePrefabSkin's end. 49 minutes ago, Garamonde said: I even manually renamed my .ZIP builds like this Ah! If you want to rename your builds, you shouldn't be renaming the compiled zip but rather the scml file name, that is your build name. E.g. my build name here is "ms_example", if I wanted the build name to be "ms_test", i'd rename the scml document to "ms_test" Make sure to change the folder name it's in too, it should always be matching with the name of the scml document Be sure to let me know if this helped to solve your issue. Edited June 4, 2022 by Hornete 1 Link to comment Share on other sites More sharing options...
Garamonde Posted June 4, 2022 Share Posted June 4, 2022 Ohhh, I forgot about the .SCML files! Alrighty, I renamed those and recompiled everything, but the game still crashes... I'll just send my whole folder, if that's more helpful. K_K.zip And more logs, just in case: master_server_log.txt client_log.txt 1 Link to comment Share on other sites More sharing options...
Hornete Posted June 4, 2022 Author Share Posted June 4, 2022 20 minutes ago, Garamonde said: Ohhh, I forgot about the .SCML files! Alrighty, I renamed those and recompiled everything, but the game still crashes... I'll just send my whole folder, if that's more helpful. K_K.zip 15.51 MB · 1 download And more logs, just in case: master_server_log.txt 29.62 kB · 1 download client_log.txt 22.22 kB · 4 downloads Hm, extremely strange, I'm able to open up a world with your mod and the API just fine and it works perfectly. Your logs also don't seem to be providing any meaningful information as to what could be crashing you. Would you happen to have any other mods enabled? Client or server? I'd also suggest trying to verify the games files. Your client log has this at the end of it, which looks very strange and seemingly isn't related to any mods but rather assets in the vanilla game are running into errors: [00:08:55]: ERROR: HWTexture::DeserializeTexture failed on anim/oasis_tile.zip:oasis_tile--atlas-0.tex. glGetError returned 0x505 [00:08:55]: 2048x2048 format: 0x83f3 mips: 12 [00:08:55]: ERROR: HWTexture::DeserializeTexture failed on anim/oasis_tile.zip:oasis_tile--atlas-1.tex. glGetError returned 0x505 [00:08:55]: 2048x2048 format: 0x83f3 mips: 12 1 Link to comment Share on other sites More sharing options...
Garamonde Posted June 4, 2022 Share Posted June 4, 2022 (edited) Thank you! Yeah, my logs tend to be unhelpful a lot of the time, for some reason. So I tried it again, with no mods other than Modded Skins API and K_K, and I got a "ran out of memory and must shut down" crash... Which doesn't make sense given the fact that I can run servers with 19 mods... That's probably an issue with my PC, though. I think the super-final thing now is that default K_K's ghost doesn't show up on the character select screen (but his alternate skin's ghost does): Edited June 4, 2022 by Garamonde Added an extra image. Link to comment Share on other sites More sharing options...
Hornete Posted June 4, 2022 Author Share Posted June 4, 2022 20 minutes ago, Garamonde said: I think the super-final thing now is that default K_K's ghost doesn't show up on the character select screen (but his alternate skin's ghost does): Oh! Did you load K_K's ghost asset? I noticed it's not in the "kk_none" assets table. table.insert(prefabs, CreatePrefabSkin("kk_none", { assets = { Asset("ANIM", "anim/kk.zip"), }, ... --Should most likely be.. table.insert(prefabs, CreatePrefabSkin("kk_none", { assets = { Asset("ANIM", "anim/kk.zip"), Asset("ANIM", "anim/ghost_kk.zip"), }, 1 Link to comment Share on other sites More sharing options...
Garamonde Posted June 4, 2022 Share Posted June 4, 2022 (edited) D'oh! I guess it would help to load the graphics of the ghost... There he goes! Thank you so much for your help!! I'll be sure to let you know when my mod's done! EDIT: Oh. I just loaded into the world and... He's not showing up and the gold name isn't appearing. Edited June 4, 2022 by Garamonde 1 Link to comment Share on other sites More sharing options...
Hornete Posted June 4, 2022 Author Share Posted June 4, 2022 14 minutes ago, Garamonde said: EDIT: Oh. I just loaded into the world and... Ah! For the "Thingamabob" thing, you'll need to make strings for the "kk_none" just like you did for the skin I believe STRINGS.SKIN_NAMES.kk_none = "K_K" STRINGS.SKIN_DESCRIPTIONS.kk_none = "A descriptor" As for them being missing in the portrait frame, and having no portrait, AND missing their golden name... I'm not completely sure what causes those, but I'll try to look into it. 1 Link to comment Share on other sites More sharing options...
Garamonde Posted June 4, 2022 Share Posted June 4, 2022 Somewhat good news at least, adding the "_none" skin strings fixed 2 of those issues: So now all that's left is the golden name and big portrait. I'm rather baffled at that because it worked prior to me changing stuff to accommodate for the API update... and I didn't change anything regarding either of those (except for the Hallowed Nights portrait filenames). Link to comment Share on other sites More sharing options...
Hornete Posted June 4, 2022 Author Share Posted June 4, 2022 2 minutes ago, Garamonde said: [snip] Ah! I believe I see what's going on, and I believe it's something on Klei's side actually. So in that popup screen, that game checks to see if there's a xml file that's in the "bigportraits/characternamehere.xml" portrait, and if that doesn't exist, it defaults to "unknownmod" for the name. These portraits are something like this: Most modded characters aren't gonna have these however, because, well, they're not used anymore! Only the oval portraits are now used! These rectangular portraits are from a earlier time in DST, and so there isn't and shouldn't be a need for the game to check for these, they should rather be looking for the charactername_none portrait instead. TL:DR, if you wanna fix it, then you just need to make a new portrait just named "kk.xml" and "kk.tex" in the bigportraits folder, even though these don't get used at all the game thinks your characters assets don't exist for the popup avatar without them :P. I'll try to get a bug report in sometime so the developers could perhaps take a look at this outdated mechanic and make it more modder-friendly. 1 Link to comment Share on other sites More sharing options...
Garamonde Posted June 5, 2022 Share Posted June 5, 2022 Yep, you were right; that was the problem! NOW that should be it for issues from me, for now. Thank you again!! 1 Link to comment Share on other sites More sharing options...
Wonderlarr Posted June 9, 2022 Share Posted June 9, 2022 Do I need to rebuild all my old skins if I'm transitioning from the old skins API? I'm worried about the "ms_" prefix requirement you outlined in the main post, I can totally put that in the ID, no problem, but none of my builds have that prefix. It seems to work fine in game, but I'm wondering if this is some Klei rule that I shouldn't violate. 1 Link to comment Share on other sites More sharing options...
Hornete Posted June 9, 2022 Author Share Posted June 9, 2022 8 minutes ago, TheSkylarr said: but I'm wondering if this is some Klei rule that I shouldn't violate. Oh no no, don't worry about it, it's just a 'us' thing, not a 'Klei' thing. We actually do put the ms_ prefix automatically for you if you don't have it, but it's in the main post just to let you know incase you relied on the game automatically finding your skin build from the name of the skin and thus need to either re-name the build or set the "build_name_override" in the skin prefab. Link to comment Share on other sites More sharing options...
Wonderlarr Posted June 9, 2022 Share Posted June 9, 2022 54 minutes ago, Hornete said: Oh no no, don't worry about it, it's just a 'us' thing, not a 'Klei' thing. We actually do put the ms_ prefix automatically for you if you don't have it, but it's in the main post just to let you know incase you relied on the game automatically finding your skin build from the name of the skin and thus need to either re-name the build or set the "build_name_override" in the skin prefab. Awesome to know! Thanks for being so responsive! Link to comment Share on other sites More sharing options...
Wonderlarr Posted June 10, 2022 Share Posted June 10, 2022 Figured I'd share how I saved myself some code. I have a bunch of skins that all use the same config, besides build and ID, so I just wrote a for loop to iterate through a list of my skins and add them with way less code. I still had to do the hatkid_none skin separately, but as far as the actual skins go, I saved myself from doing 9 iterations of the same code. Yay for basic for loops! local hatskins = { "ms_hatkid_cat", "ms_hatkid_detective", "ms_hatkid_dye_bowkid", "ms_hatkid_dye_groovy", "ms_hatkid_dye_lunar", "ms_hatkid_dye_niko", "ms_hatkid_dye_pinkdanger", "ms_hatkid_dye_sans", "ms_hatkid_dye_toonlink", } for k,v in pairs(hatskins) do table.insert(prefabs, CreatePrefabSkin(v, { assets = { Asset("ANIM", "anim/" .. v .. ".zip"), Asset("ANIM", "anim/ghost_hatkid_build.zip"), }, skins = { normal_skin = v, ghost_skin = "ghost_hatkid_build", }, base_prefab = "hatkid", build_name_override = v, type = "base", rarity = "ModMade", skin_tags = { "BASE", "HATKID" }, })) end 1 Link to comment Share on other sites More sharing options...
Cagealicous Posted June 15, 2022 Share Posted June 15, 2022 Another question that has been bothering me is how would I set up the condition(s) for unlocking a locked skin; as for example, let's say I'd like to unlock the skin by digging up enough graves and killing a certain amount of innocent creatures (Glommer, Rabbits, Butterflies, etc.), how would I go about setting that up with using the following: On 5/26/2022 at 12:33 AM, Hornete said: Now as for actually unlocking the skin, we’ll be using a RPC that the API adds for you that’ll allow you to pass the id of your skin to be unlocked. if CLIENT_MOD_RPC[“ModdedSkins”] then --This is necessary to make sure the RPC actually exists as depending on your mod a user may not always have the API enabled. SendModRPCToClient(GetClientModRPC("ModdedSkins", "UnlockModdedSkin"), sender_list, "skinid") --sender_list can either be nil to send the rpc to all clients, or be the string for a single clients user id, OR an array that includes multiple user id’s to send the rpc to all the clients bearing those user id’s. Skinid should be filled out with the id of the skin you’d like to be unlocked. end Link to comment Share on other sites More sharing options...
Hornete Posted June 15, 2022 Author Share Posted June 15, 2022 (edited) 14 hours ago, Cagealicous said: Another question that has been bothering me is how would I set up the condition(s) for unlocking a locked skin; as for example, let's say I'd like to unlock the skin by digging up enough graves and killing a certain amount of innocent creatures (Glommer, Rabbits, Butterflies, etc.), how would I go about setting that up with using the following: To do the former, you could have your character(or any player with a AddPlayerPostInit) in their fn by listening for the 'finishedwork' event and checking for the target if it's a tag, and if it's a grave, then we can tick up a counter that we initialized earlier. inst.gravesdugcounter = 0 --starts at 0 inst:ListenForEvent("finishedwork", function(inst, data) if data and data.target and data.target:HasTag("grave") then --Any entity with the grave tag, hey! it's mod compatibility too if any other mod adds a grave with this tag! inst.gravesdugcounter = inst.gravesdugcounter + 1 --take the last value of gravesdugcounter and add 1 if inst.gravesdugcounter >= 10 then --Over OR equal to ten? then pass the check if CLIENT_MOD_RPC[“ModdedSkins”] then --This is necessary to make sure the RPC actually exists as depending on your mod a user may not always have the API enabled. SendModRPCToClient(GetClientModRPC("ModdedSkins", "UnlockModdedSkin"), inst.userid, "whatevertheskinidofyourcustomskinis") end end end end) You can do pretty much the same thing too for innocent creatures, but instead, listen for the 'killed' event! inst.innocentskilled = 0 --starts at 0 inst:ListenForEvent("killed", function(inst, data) if data and data.victim and NAUGHTY_VALUES[data.victim.prefab] ~= nil then --We check if the victim killed has a naughtiness value inst.innocentskilled = inst.innocentskilled + 1 --take the last value of innocentskilled and add 1 if inst.innocentskilled >= 10 then --Over OR equal to ten? then pass the check if CLIENT_MOD_RPC[“ModdedSkins”] then --This is necessary to make sure the RPC actually exists as depending on your mod a user may not always have the API enabled. SendModRPCToClient(GetClientModRPC("ModdedSkins", "UnlockModdedSkin"), inst.userid, "whatevertheskinidofyourcustomskinis") end end end end) Edited June 15, 2022 by Hornete 1 Link to comment Share on other sites More sharing options...
Cagealicous Posted June 16, 2022 Share Posted June 16, 2022 2 hours ago, Hornete said: To do the former, you could have your character(or any player with a AddPlayerPostInit) in their fn by listening for the 'finishedwork' event and checking for the target if it's a tag, and if it's a grave, then we can tick up a counter that we initialized earlier. inst.gravesdugcounter = 0 --starts at 0 inst:ListenForEvent("finishedwork", function(inst, data) if data and data.target and data.target:HasTag("grave") then --Any entity with the grave tag, hey! it's mod compatibility too if any other mod adds a grave with this tag! inst.gravesdugcounter = inst.gravesdugcounter + 1 --take the last value of gravesdugcounter and add 1 if inst.gravesdugcounter >= 10 then --Over OR equal to ten? then pass the check if CLIENT_MOD_RPC[“ModdedSkins”] then --This is necessary to make sure the RPC actually exists as depending on your mod a user may not always have the API enabled. SendModRPCToClient(GetClientModRPC("ModdedSkins", "UnlockModdedSkin"), inst.userid, "whatevertheskinidofyourcustomskinis") end end end end) You can do pretty much the same thing too for innocent creatures, but instead, listen for the 'killed' event! inst.innocentskilled = 0 --starts at 0 inst:ListenForEvent("killed", function(inst, data) if data and data.victim and NAUGHTY_VALUES[data.victim.prefab] ~= nil then --We check if the victim killed has a naughtiness value inst.innocentskilled = inst.innocentskilled + 1 --take the last value of innocentskilled and add 1 if inst.innocentskilled >= 10 then --Over OR equal to ten? then pass the check if CLIENT_MOD_RPC[“ModdedSkins”] then --This is necessary to make sure the RPC actually exists as depending on your mod a user may not always have the API enabled. SendModRPCToClient(GetClientModRPC("ModdedSkins", "UnlockModdedSkin"), inst.userid, "whatevertheskinidofyourcustomskinis") end end end end) Where would I put this in? My character's prefab file, or somewhere else? And, if it is in the prefab file, which part, like masterpostinit, or somewhere near the top? Link to comment Share on other sites More sharing options...
Hornete Posted June 16, 2022 Author Share Posted June 16, 2022 2 minutes ago, Cagealicous said: Where would I put this in? My character's prefab file, or somewhere else? And, if it is in the prefab file, which part, like masterpostinit, or somewhere near the top? Master postinit of your character file! Link to comment Share on other sites More sharing options...
Pinkamena11FazP Posted June 16, 2022 Share Posted June 16, 2022 If I was to make a custom skin for a DST character that already exists/that I own and draw the custom skin myself without tracing or reusing designs that already exist would that still be counted as bad? I really want to try to tweak Walter's bee suit to be a little more lively and less plain but have no clue how specific the rules are for making custom skins like that. Link to comment Share on other sites More sharing options...
Cagealicous Posted June 16, 2022 Share Posted June 16, 2022 (edited) 7 hours ago, Hornete said: To do the former, you could have your character(or any player with a AddPlayerPostInit) in their fn by listening for the 'finishedwork' event and checking for the target if it's a tag, and if it's a grave, then we can tick up a counter that we initialized earlier. inst.gravesdugcounter = 0 --starts at 0 inst:ListenForEvent("finishedwork", function(inst, data) if data and data.target and data.target:HasTag("grave") then --Any entity with the grave tag, hey! it's mod compatibility too if any other mod adds a grave with this tag! inst.gravesdugcounter = inst.gravesdugcounter + 1 --take the last value of gravesdugcounter and add 1 if inst.gravesdugcounter >= 10 then --Over OR equal to ten? then pass the check if CLIENT_MOD_RPC[“ModdedSkins”] then --This is necessary to make sure the RPC actually exists as depending on your mod a user may not always have the API enabled. SendModRPCToClient(GetClientModRPC("ModdedSkins", "UnlockModdedSkin"), inst.userid, "whatevertheskinidofyourcustomskinis") end end end end) You can do pretty much the same thing too for innocent creatures, but instead, listen for the 'killed' event! inst.innocentskilled = 0 --starts at 0 inst:ListenForEvent("killed", function(inst, data) if data and data.victim and NAUGHTY_VALUES[data.victim.prefab] ~= nil then --We check if the victim killed has a naughtiness value inst.innocentskilled = inst.innocentskilled + 1 --take the last value of innocentskilled and add 1 if inst.innocentskilled >= 10 then --Over OR equal to ten? then pass the check if CLIENT_MOD_RPC[“ModdedSkins”] then --This is necessary to make sure the RPC actually exists as depending on your mod a user may not always have the API enabled. SendModRPCToClient(GetClientModRPC("ModdedSkins", "UnlockModdedSkin"), inst.userid, "whatevertheskinidofyourcustomskinis") end end end end) Hmm... that code didn't seem to unlock the skin. I did add prints after each one in the following to check if it was working: inst.gravesdugcounter = 0 --starts at 0 inst:ListenForEvent("finishedwork", function(inst, data) if data and data.target and data.target:HasTag("grave") then inst.gravesdugcounter = inst.gravesdugcounter + 1 print("dig") end if inst.gravesdugcounter >= 10 then --Over OR equal to ten? then pass the check if CLIENT_MOD_RPC["ModdedSkins"] then SendModRPCToClient(GetClientModRPC("ModdedSkins", "UnlockModdedSkin"), inst.userid, "ms_characternamehere_shadow") print("unlock") end end end) As for my character's ..._skins.lua file I put the following for the character: table.insert(prefabs, CreatePrefabSkin("ms_characternamehere_shadow", { base_prefab = "characternamehere", build_name_override = "ms_characternamehere_shadow", type = "base", rarity = "ModLocked", skin_tags = {"BASE", "CHARACTERNAMEHERE", "SHADOW"}, skins = { normal_skin = "ms_characternamehere_shadow", ghost_skin = "ghost_characternamehere_build", powerup = "ms_characternamehere_shadow_powerup", }, assets = { Asset("ANIM", "anim/ms_characternamehere_shadow.zip"), Asset("ANIM", "anim/ms_characternamehere_shadow_powerup.zip"), Asset("ANIM", "anim/ghost_characternamehere_build.zip"), }, })) It also seems to not show the unlock requirements button too. I put that in modmain.lua along with any other strings. (Also, that isn't the character's name by the way. Just made it filler for whoever.) Edited June 16, 2022 by Cagealicous Link to comment Share on other sites More sharing options...
Hornete Posted June 16, 2022 Author Share Posted June 16, 2022 4 minutes ago, Cagealicous said: As for my character's ..._skins.lua file I put the following for the character: You need to include the 'condition' table, even if you have no conditions set the table needs to exist. table.insert(prefabs, CreatePrefabSkin("ms_characternamehere_shadow", { base_prefab = "characternamehere", build_name_override = "ms_characternamehere_shadow", type = "base", rarity = "ModLocked", condition = { --Here! }, skin_tags = {"BASE", "CHARACTERNAMEHERE", "SHADOW"}, skins = { normal_skin = "ms_characternamehere_shadow", ghost_skin = "ghost_characternamehere_build", powerup = "ms_characternamehere_shadow_powerup", }, assets = { Asset("ANIM", "anim/ms_characternamehere_shadow.zip"), Asset("ANIM", "anim/ms_characternamehere_shadow_powerup.zip"), Asset("ANIM", "anim/ghost_characternamehere_build.zip"), }, })) 1 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