Wonderlarr Posted February 22, 2021 Share Posted February 22, 2021 (edited) Hello! I got a little burnt out making my own character mod, so I decided to solve a little annoying problem with DST, that is the lack of save slot portrait support on modded characters! Now, here's the thing though, I need your guy's help, and it's not help with coding, as I already did all that. At the moment, my mod only supports my own character mod (Hat Kid), I need suggestions on what character mods are used the most, and which creators are fine with me adding support for their character. Here are a couple examples of what my mod does Before After Edit 1: I'm going to go ahead and implement support for Hamlet and Shipwrecked characters, since they're Klei property I shouldn't need to ask anyone. Edited February 22, 2021 by TheSkylarr Link to comment Share on other sites More sharing options...
IronHunter Posted February 22, 2021 Share Posted February 22, 2021 Honestly I think it should be possible to pull data from the modicon at minimum. To show that the character is from that mod. As modicon loads no matter what when viewing all mods. It would be a nice fallback in the event that pulling data from the actual mods is not easy? 1 Link to comment Share on other sites More sharing options...
Wonderlarr Posted February 22, 2021 Author Share Posted February 22, 2021 31 minutes ago, IronHunter said: Honestly I think it should be possible to pull data from the modicon at minimum. To show that the character is from that mod. As modicon loads no matter what when viewing all mods. It would be a nice fallback in the event that pulling data from the actual mods is not easy? At this point I'm not sure how to actually edit the table that deals with the portraits directly, but I'm using a workaround by adding the character asset manually from my own bank of images, the drawback to this is it takes unnecessary ram when actually in game, and also, it seems on single player worlds the "invisible characters" I create to make this work are select able, which shouldn't happen. If anyone could help me find a way to directly manipulate the images there that would be helpful lol Link to comment Share on other sites More sharing options...
Bigfootmech Posted February 23, 2021 Share Posted February 23, 2021 (edited) > At this point I'm not sure how to actually edit the table that deals with the portraits directly For the image you sent, are you editing the default image, or the server listing screens and server creation (read: creation or resume) screens? Try scripts/screens/serverlistingscreen.lua:1045 and/or scripts/screens/redux/serverlistingscreen.lua:1109 Spoiler if not table.contains(DST_CHARACTERLIST, character) then if table.contains(MODCHARACTERLIST, character) then atlas = atlas.."/"..character else character = #character > 0 and "mod_small" or "unknown" end end I could be being dumb, but try making a folder inside data/images/ called "saveslot_portraits", then put the <characterName>.xml and corresponding .tex file there If you already are, or if this doesn't work: You could maybe try to hook in to the screen creation. Possibly AddClassPostConstruct("screens/servercreationscreen", function (theScreenInstance) -- do stuff to the created screen end) Though I'm not 100% on this, as Carl said the PostConstruct only works the first time? , then loop over the widgets, and replace their widget.CHAR_ICON:SetTexture( .xml, .tex) And widget.CHAR.img:SetTexture(atlas, character..".tex") You could probably even screw with the SetTexture function itself. But that sounds like a horrible hack If you want to do it correctly for when you click on the server in the top, you might also need to do something to the servercreationscreen.lua and redux/servercreationscreen.lua too Also, not that useful, but: > takes unnecessary ram when actually in game I did some screwing around with TheNet commands Spoiler print("EASILY SEARCHABLE STRING") print("isDedicated") print(GLOBAL.TheNet:IsDedicated()) -- is server (whether it's fully loaded yet, or not) print("isServer") print(GLOBAL.TheNet:GetIsServer()) -- is server (fully loaded only / ready to accept clients) print("isMasterSimulation") print(GLOBAL.TheNet:GetIsMasterSimulation()) -- same result as "is server"?? print("isClient") print(GLOBAL.TheNet:GetIsClient()) -- is a connected client print("isHosting") print(GLOBAL.TheNet:GetIsHosting()) -- is client host, or is server (has access to log files) print("isServerClientHosted") print(GLOBAL.TheNet:GetServerIsClientHosted()) -- actually does what it says print("isServerDedicated") print(GLOBAL.TheNet:GetServerIsDedicated()) -- seems broken?? print("isAdmin") print(GLOBAL.TheNet:GetIsServerAdmin()) -- assuming this works? print("isOwner") print(GLOBAL.TheNet:GetIsServerOwner()) -- not fully tested print(TheNet:GetIsServerOwner()) If this is true: not GLOBAL.TheNet:GetIsClient() and not GLOBAL.TheNet:IsDedicated() Then you're in the main menu Stuff will get unloaded as soon as you try to load game as well, so you just need to only load your bank when that's true. I attached an openoffice spreadsheet of the states (I can save in some other formats too if you need). Or you can just copy paste the hidden commands and screw around with them Finally (and probably least useful), I did some screwing around with lua.io Spoiler require "io" local file = io.open(path, "r") local file = io.open(filename, "w") file:close() and then I found my package.path was something like default path: "C:\Program Files (x86)\Steam\steamapps\common\Don't Starve Together\data" ../mods/test_mod\scripts\?.lua; ../mods/workshop-1290774114\scripts\?.lua; ../mods/workshop-1295277999\scripts\?.lua; ../mods/workshop-2302837868\scripts\?.lua; ../mods/workshop-351325790\scripts\?.lua; ../mods/workshop-352373173\scripts\?.lua; ../mods/workshop-1918863324\scripts\?.lua; ../mods/workshop-376333686\scripts\?.lua; ../mods/workshop-944320099\scripts\?.lua; ../mods/workshop-2375395675\scripts\?.lua; ../mods/workshop-1529942793\scripts\?.lua; ../mods/workshop-1213299911\scripts\?.lua; ../mods/workshop-496048926\scripts\?.lua; ../mods/workshop-1603516353\scripts\?.lua; ../mods/workshop-343753877\scripts\?.lua; ../mods/workshop-1684100178\scripts\?.lua; ../mods/workshop-1584066691\scripts\?.lua; ../mods/workshop-666155465\scripts\?.lua; ../mods/workshop-727774324\scripts\?.lua; scripts\?.lua; scriptlibs\?.lua; scripts/?.lua dstNetTest.ods Edited February 24, 2021 by Bigfootmech Link to comment Share on other sites More sharing options...
Wonderlarr Posted February 23, 2021 Author Share Posted February 23, 2021 2 hours ago, Bigfootmech said: For the image you sent, are you editing the default image, or the server listing screens and server creation (read: creation or resume) screens? Actually I'm not editing any part of the vanilla game, I'm simply loading "skeleton" versions of the characters by adding characters with almost no data. The game actually tries to look for modded character saveslot portraits when it sees it in the mod list, so I just decided that I add characters, but with a client mod so it runs on the server list screen. The characters are unselectable, but completely unloading them would be ideal, however, if I can directly add to the save portrait table, that would be way more efficient than this hacky way. Quote not GLOBAL.TheNet:GetIsClient() and not GLOBAL.TheNet:IsDedicated() Do I use it in a statement like this? if not GLOBAL.TheNet:GetIsClient() and not GLOBAL.TheNet:IsDedicated() then --Fix character save slot code --Don't have it on hand since im at work lol end Finally, I'm not familiar at all with Lua IO, I have much to learn, though theoretically I know how I could get workshop id's for mods, I don't know how I would detect characters within these mods and add them to the table. Link to comment Share on other sites More sharing options...
Bigfootmech Posted February 24, 2021 Share Posted February 24, 2021 (edited) I think the game tries to look for the saveslot portrait without adding the character? Though I could be wrong? What are you adding when you add these "barebones" characters? (I haven't actually done any character mods) I'd labelled it first, so I knew what was going on . But yeah Spoiler local function IsInMainMenu() return not GLOBAL.TheNet:GetIsClient() and not GLOBAL.TheNet:IsDedicated() -- isn't client + isn't server = main menu; "is dedicated" = even locally hosted server on self. end if IsInMainMenu() then --Fix character save slot code --Don't have it on hand since im at work lol end Not sure if the io is useful tbh. That's why I added it last as a "maybe". You might have more luck digging around modindex or modutil Edited February 24, 2021 by Bigfootmech Link to comment Share on other sites More sharing options...
Wonderlarr Posted February 24, 2021 Author Share Posted February 24, 2021 local function IsInMainMenu() return not GLOBAL.TheNet:GetIsClient() and not GLOBAL.TheNet:IsDedicated() -- isn't client + isn't server = main menu; "is dedicated" = even locally hosted server on self. end if IsInMainMenu() then --Fix character save slot code --Don't have it on hand since im at work lol end Ah okay, this makes a lot of sense. To be honest, even though I've been modding since July last year, I haven't learned a lot of core stuff, like using return haha. 9 hours ago, Bigfootmech said: What are you adding when you add these "barebones" characters? (I haven't actually done any character mods) In character mods, there is a simple line of code to add mod characters to the list of characters, like if I wanted to add Wilbur from Shipwrecked, I would do Assets = { Asset( "IMAGE", "images/saveslot_portraits/wilbur.tex" ), Asset( "ATLAS", "images/saveslot_portraits/wilbur.xml" ) } AddModCharacter("wilbur", "ROBOT") And now the game knows a character called wilbur exists, and since I loaded the his saveslot portrait, it sees a saveslot portrait for Wilbur, and loads it. Link to comment Share on other sites More sharing options...
Bigfootmech Posted February 24, 2021 Share Posted February 24, 2021 I don't think I'm the right person to be teaching you coding principles. Especially since I'm bastardizing them myself. '^_^ But either making "self-documenting" functions, or using comments is a good start on knowing what your code does. Whether it's you who's gonna come back to it months later, or someone new. return is just the return value of a function. It's what it sends back after it's done executing. https://www.tutorialspoint.com/lua/lua_functions.htm This is pretty common in coding/programming Lua is interesting (for me) in that, you can have multiple return values from one function local function MyFunctionName(inputVarOne, inputVarTwo, ...) -- I do something -- I do something else return outputVarOne, outputVarTwo, outputVarThree end local returnedVarOne, returnedVarTwo, returnedVarThree = MyFunctionName() Interesting :o. I don't know how all that is currently handled in DST. Would have to look in to the code Currently, I know: "env" is set up in like modutil I think? one of the mod script files. So you should be able to find what "AddModCharacter" does by text searching through all the files in the /scripts/ folder. Which can be done by your preferred IDE, or Notepad++/Sublime, or even Windows Explorer, if you set to to index the text in that folder. *searches* ok, Spoiler modutil.lua Line 494: env.AddModCharacter = function(name, gender, modes) initprint("AddModCharacter", name, gender, modes) AddModCharacter(name, gender, modes) end and line 66: local function AddModCharacter(name, gender, modes) This tells us that the original definition of AddModCharacter is in modutil. We can then look at what it does Spoiler local function AddModCharacter(name, gender, modes) table.insert(MODCHARACTERLIST, name) if not DoesCharacterExistInGendersTable(name) then if gender == nil then print( "Warning: Mod Character " .. name .. " does not currently specify a gender. Please update the call to AddModCharacter to include a gender. \"FEMALE\", \"MALE\", \"ROBOT\", or \"NEUTRAL\", or \"PLURAL\" " ) gender = "NEUTRAL" end gender = gender:upper() if not CHARACTER_GENDERS[gender] then CHARACTER_GENDERS[gender] = {} end table.insert( CHARACTER_GENDERS[gender], name ) else print( "Warning: Mod Character " .. name .. " already exists in the CHARACTER_GENDERS table. It was either added previously, or added twice. You only need to call AddModCharacter now." ) end MODCHARACTERMODES[name] = modes end This means, it: Adds the "mod character" name to the MODCHARACTERLIST Adds the character's gender in the right place in CHARACTER_GENDERS Sets the character's "modes" whatever that is, in MODCHARACTERMODES We can look back to our scripts/screens/serverlistingscreen.lua:1045 to see if it's relevant if table.contains(MODCHARACTERLIST, character) then Yup, we need it. Possibly not so much the the gender, and "modes" Is it worth cutting the "AddModCharacter" command down any further? possibly not. *searches again* MODCHARACTERLIST seems to be defined in "constants" for whatever reason I'm also not 100% sure where it's used to display characters in the join screen in game, but if you told me that it does, I'd believe you. If you told me it was the one in dlcsupport.lua I'd believe you even more. Either way, we can at least tell it's used in live game logic from the networking.lua So yeah, the easiest thing to do would be to continue using "AddModCharacter" But only in the context of the main menu. ie: what you're doing already One other thing you could maybe do, is try scour other mods for their use of "AddModCharacter". And somehow add this to your client-only main-menu-only loaded mod. But I'm not sure how complicated this would end up being. Link to comment Share on other sites More sharing options...
Wonderlarr Posted February 24, 2021 Author Share Posted February 24, 2021 Wow, thank you for the analysis of everything here, glad to see I'm doing this at least semi-correctly! I already do some commenting, but not all that much. The example I sent you of the Wilbur code was with the comments removed, as they were mostly personal notes to myself and a rant about how AddModCharacter should NOT be the simplest way to add portraits, though it seems like it is... As for looking through my mods to see when characters are added, I actually only have a few character mods installed outside of Shipwrecked and Hamlet characters, which I already added support for. I wonder if there's a way to hook into AddModCharacter, and get the workshop id of the mod the character is from. I think I might be able to put together some hacky form of character detection, but I'll have to look more into how LuaIO works. Link to comment Share on other sites More sharing options...
Bigfootmech Posted February 24, 2021 Share Posted February 24, 2021 Happy to help ^_^ And I didn't do all that much. Just talking through how I did it, to hopefully help you be able to do stuff like that too :) Link to comment Share on other sites More sharing options...
Wonderlarr Posted February 24, 2021 Author Share Posted February 24, 2021 Weird thing, upon testing the suggested improvements to not load the mod, it seems to still load itself when I load a world without caves. I found something to detect this though, I just added and not GLOBAL.TheNet:GetServerIsClientHosted() and that seems to detect it correctly. Link to comment Share on other sites More sharing options...
Bigfootmech Posted February 25, 2021 Share Posted February 25, 2021 Oh, that's weird >.< I didn't test it without caves. And didn't test much with actual dedicated servers 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