#making-mods-general

1 messages Β· Page 358 of 1

halcyon nest
#

I’VE MESSED IT UP TOO DW

pine elbow
#

okay guys ill comeback tomorrow i do think i see htis being completed ill stick to smlal for now use c sharp for more ambitious projects

halcyon nest
#

translating OpenFire sure was an. Experience with trying to figure out portraits LOL

pine elbow
#

beacause im wayy too fucking tired to ask qeustions now

halcyon nest
#

please go get some sleep, ur questions can wait till tomorrow

slow basin
#

hmm im trying to figure out how to make someone do a sequence of sprites for an animation during their schedule but i cant figure it out, can anyone aide me if they know the answer or can point me at the correct direction, im loooking at the schedule section but cant seem to find what im looking for from a quick perusal

#

wait i think i found it

#

sorry for the trouble!

#

@_@ i found the answer but dont exactly know how to understand what its telling me

pine elbow
slow basin
#

yes

#

i think

#

basically i want them to move from point a to point b and then do an animation

vernal crest
#

Ah yes I was going to hop on my computer to help you with that

slow basin
#

your so kind 🫢

karmic gust
vernal crest
#

So what you're looking at is a schedule animation, which you'll create by adding a new key to Data/animationDescriptions.

karmic gust
#

Actually I just reread your message. Were you already reading that?

slow basin
#

do i add that to content json or is this a seperate json going in my data folder

vernal crest
#

You asked about looping: the "repeat frames" field is the part where you put the frames that you want to repeat.

slow basin
vernal crest
slow basin
#

hmm alright!

vernal crest
#

Separate json files only exist so we can organise our stuff if we want to rather than having one gigantic content.json file

#

One of my NPCs is made entirely in the content.json, no other json files at all (except manifest.json and default.json because they do different things)

slow basin
#

πŸ™‚β€β†•οΈ

#

i think probably for organizations sake i might make it its own seperate json in my data section then, just so i can make sure to understand what it means better if i make another npc eventually

vernal crest
#

So the format of an entry in Data/animationDescriptions is this:
"{{ModId}}_GeckoNPCAnimation": "entry frames/repeat frames/leaving frames/message key/offset X Y/laying_down"

Which in practice might look like this:
"{{ModId}}_GeckoNPCAnimation": "10 11 12/12 13 14 15/16 17 18/Characters\\Dialogue\\{{ModId}}_GeckoNPC:GeckoNPCDancing"

#

(I invented a name for your NPC for this example: {{ModId}}_GeckoNPC)

slow basin
#

:0 oooh ok isee

vernal crest
#
  • The entry frames are the frames that play once starting from when they arrive at the schedule point.
  • The repeat frames play on a loop until near the end of the time that they're meant to be there.
  • The leaving frames play once right before they leave.
  • The message key is for if you want them to say something specific while they're doing their animation (and you can put a dialogue portrait command in there to make them use the specific portrait you want).
  • Offset is for if you want them to visually appear somewhere slightly different to where they actually are. An example of this is if you wanted them sitting on a fence - you'd have them actually at the tile next to the fence and would use offset to move their sprite so it was aligned on the fence.
  • Laying_down just removes their shadow.
slow basin
#

:0 awesome that would solve both of my questions in one ty! now i just need to format the animationdesc json right

inner harbor
#

question: this would read as "true, true" if the config is set to "true" for theFriendableNPCs, right? "CanSocialize": "PLAYER_HAS_SEEN_EVENT Host 57873022, {{FriendableZuzuNPCs |contains=Kennedy}}"

lucid iron
#

FriendableZuzuNPCs needs to contain the value Kennedy

inner harbor
#

yeh, it will.

vernal crest
lucid iron
#

then its fine i think

inner harbor
#

just trying to sae myself from "When" conditions.

slow basin
#

I guess it should be a question i just realized i dont know hwo toa ccurately do a json im learning as i go a bit

inner harbor
#

I'll give it a burl

vernal crest
inner harbor
#

polishing up stuff for the beta release

slow basin
#

Ye but i dont know how to do the animation one as im mostly copying the bones of how to do dialogue and such from an old npc of mine but ive never done the animation thing before

#

also its probably been a couple of years since that abandoned project

#

im afraid i lost all that information sorry >.<

#

im trying to follow the wikis as close as possible to adfjust

#

*adjust

vernal crest
# slow basin im afraid i lost all that information sorry >.<

No need to apologise! I'm just trying to ascertain what you already know so we can build on that. Do you have any EditData patches in your json anywhere? (A patch is a bit containing an "Action" field within a set of curly brackets, let me know if you need to see an example.)

slow basin
#

Ah i do think I have an edit data one!

#

its for egagement dialogue it looks like

#

i imagine i change that to uh "Action":EditData:,
"Target": DataAnimationDescription"?

vernal crest
#

If you don't mind popping it into the json validator (https://smapi.io/json) and sharing the link, I can check it's what I'm expecting and then guide you through changing it.

vernal crest
#

Okay cool yes that will work.

vernal crest
slow basin
#

gotcha!

#
      "LogName": "Animation",
      "Action": "EditData",
      "Target": "Data/AnimationDescription",
      "Entries": {
    "{{ModId}}_GeckoNPCAnimation": "16 17 18 19/16 17 18 19/16 17 18 19/Characters\\Dialogue\\{{ModId}}_AliciaGummyNPC:GeckoNPCDancing"
      }
    }```


does this look right
vernal crest
#

Oops no sorry your Target is wrong. It needs to be exactly what I put in my message.

#

And then in their dialogue file you will add a dialogue line called "GeckoNPCDancing" (perhaps change that to "AliciaDancing" or something?) and then add what you want them to say.

pine elbow
#

so tomoroow ill have alot of quesitons but tonight guys im eating a holemade triple cheeseburger

slow basin
#

Aah gotcha

round timber
#

@pine elbow please refrain from posting AI gifs here, thank you!

slow basin
vernal crest
slow basin
#

inside the characters dialogue entry patch in the dialogue json

#

like where it says "introduction" etc etc

vernal crest
#

Ah yup dialogue. Yes anywhere in there works

slow basin
#

alrighty!

pine elbow
#

Did you manage to find this...?

#

didnt know it was ai

#

i want a chessburger mod now

slow basin
pine elbow
slow basin
#

Ooh ok!

#

ty

vernal crest
slow basin
#

πŸ™‚β€β†•οΈ

#

tysm for your help !

urban patrol
# pine elbow Did you manage to find this...?
Stardew Modding Wiki

I put together a template for adding your NPC to custom festivals, mostly because I don't feel like coding everything from scratch each time I do an NPC. Just change the positions and add your dialogue and you'll be good to go! If anyone wants to add in code blocks for the festivals I haven't included, go right ahead!
Custom NPC Tiles is a gre...

slow basin
#

oop i must have done something wrong because she moved to the location but didnt do the animaition but theres no smapi errors πŸ€”

lucid iron
#

@twilit quest fyi the farmhouse stuff u were testing is officially out on nexus now

pine elbow
urban patrol
#

do they have dialogue keys for rejecting and accepting?

pine elbow
#

Yes

urban patrol
#

hmmm

pine elbow
#

It's like the FlowerDanceCanDance entry just isn't working?

urban patrol
#

i'd offer to take a closer look, but right now i'm watching the sandman with my family, sorry! i could look later though

karmic gust
torpid sparrow
#

great reminder to check it out tmr

hard fern
#

πŸ€” is it possible that they cant dance unless they're romanceable

urban patrol
#

no, mine are non-romanceable and can dance

hard fern
#

oh

#

hm

#

strange

pine elbow
twin wadi
#

hmm can you send the json file with the disposition stuff?

tender bloom
#

Patchsummary possibly also worth it

vernal crest
# slow basin oop i must have done something wrong because she moved to the location but didnt...

Can you copy patch export Data/animationDescriptions into your SMAPI window, then follow where it says to go to find the file, and then put the whole thing into the json validator and share the link here? We will use that to check if it got added to the game properly. Then do the same with patch export Characters/schedules/GummiGecko.AliciaGummyNPC.

If you ping me when you share the links I'll see it faster :)

twilit quest
hard fern
#

πŸ€” if i have two accept gift dialogue that's for a taste and a context tag, but an item matched the taste and context tag for both dialogue lines, which one would win...

pine elbow
hard fern
ocean sailBOT
#

JSON is a standard format for machine-readable text files that's used by Stardew Valley mods.

If you need help with a JSON file, you can upload it to smapi.io/json to see automatic validation and share the link here.

When making mods, it's recommended to edit your files in a text editor with JSON support, such as VS Code, Notepad++, or Sublime Text. These programs will check for syntax errors.

ocean sailBOT
#

Log Info: SMAPI 4.2.1 with SDV 1.6.15 build 24356 on Microsoft Windows 11 Home, with 3 C# mods and 2 content packs.

latent mauve
uncut viper
#

however, you must remove the outer braces on the key inside the when token

latent mauve
#

Also that, yes

uncut viper
#
"When": {
  "YourToken": "Value"
}
pine elbow
latent mauve
#

Line 17 and 25 in the validator

#

Removed my example because it was not strictly correct and button's is better

#

(I'm on mobile, so it's harder for me to pull the CP docs right now)

twin wadi
pine elbow
latent mauve
#

The FlowerDance field not working?

pine elbow
#

Yeah

lucid mulch
#

how much dialogue does the npc have for the given event?

latent mauve
#

Did you already add the accept and decline dialogue entries?

#

Decline is required I think, but Accept can use the generic, according to the wiki?

#

Unless the wiki is misleading me

hard fern
latent mauve
#

Per the wiki: If the NPC can dance, you should also add the dance sprite frames and FlowerDance_Decline dialogue text. You can optionally set the FlowerDance_Accept dialogue too (though NPCs have a default accept dialogue if not).

pine elbow
#

Accept and decline dialogue
And normal dialogue for both years
It all works perfectly fine if the NPC has the "CanBeRomanced" disposition
But the prompt to ask doesn't show up if it's just the FlowerDanceCanDance disposition

twin wadi
hard fern
#

what i wanted to know specifically was if i had these two lines, and something like spaghetti was a loved food, it would fit into both of these, so i wanted to know which one would take precendence

"AcceptGift_Loved_color_red": "{{i18n:Gift.Placeholder.Red}}",```
lucid mulch
#

hmm, looks like a bug in the code flow, looks like it needs to be datable to actually make it far enough to even get to the FlowerDanceCanDance check

latent mauve
#

Would a workaround be making them datable only during the festival?

#

Until it gets fixed in the code

brittle pasture
#

oh yeah that's a known issue, tia worked around it for Jort and Jeans by temporarily making them dateable during the festival (while rejecting the bouquet via gift rejection iirc)

latent mauve
#

Ah ha, yes, that's what I was remembering

lucid mulch
#

if (
    (
        (
            tile.X != tileLocation.X ||
            (
                tile.Y != tileLocation.Y &&
                tile.Y != tileLocation.Y + 1
            )
        ) &&
        !n.GetBoundingBox().Intersects(tileRect)
    ) || (
        n.CurrentDialogue.Count < 1 &&
        (
            n.CurrentDialogue.Count <= 0 ||
            n.CurrentDialogue.Peek().isOnFinalDialogue()
        ) &&
        !n.Equals(this.festivalHost) &&
        (
            !n.datable.Value ||
            !this.isSpecificFestival("spring24")
        ) && (
            this.secretSantaRecipient == null ||
            !n.Name.Equals(this.secretSantaRecipient.Name)
        )
    )
)
{
    continue;
}

need to get past this block to stand a chance.
First section will hit the continue if not actually near the npc, second block checks:

  1. If there isn't dialogue, hitting continue
  2. the festival host (lewis) is exempt
  3. if its not datable or its not spring24, hit continue
  4. if its not the secret santa recipient
twin wadi
hard fern
#

i guess i'll just have to test it in-game and see

twin wadi
#

yeah, a theory would be that it's take the one on top, but im not sure if that's how it works. maybe it'll use either one randomly, but i think that's up for testing

pine elbow
lucid mulch
#

its a stardew bug, nothing to do with content patcher

latent mauve
#

The game, not CP

pine elbow
#

Ah okay

#

How do I make my npc temporarily datable for the festival then?

vernal crest
hard fern
#

yeah i worded it kinda strange

#

πŸ˜…

vernal crest
vernal crest
hard fern
#

yeah....

regal bane
ocean sailBOT
#

Log Info: SMAPI 4.2.1 with SDV 1.6.15 build 24356 on Microsoft Windows 11 Pro, with 14 C# mods and 20 content packs.
Suggested fixes: One or more mods are out of date, consider updating them

twin wadi
ocean sailBOT
#

For help with modding issues, please ask in #1272025932932055121! When asking for assistance there, sharing an error log will help others identify your issue (see https://smapi.io/log for instructions).

twin wadi
#

bye bye ppl gotta sleep, my brain is turning off SDVkrobusgiggle

hard fern
#

SDVpufferwaaah i havent eaten anything so i should probably take a break

vernal crest
#

Yes, modding on no food is bad for brain

brave fable
#

at a guess i'd imagine it simply iterates over the gift tastes and compares them with the context tags on the item, so it'd depend on the order the tastes/tags are added

#

but it could easily go either way

vernal crest
#

My guess was going to be that it chooses the first applicable context tag line based on the context tag order on the item, but since I don't actually know if those are ordered I did not say it because it's a guess based on a guess haha

uncut viper
#

its likely entirely dependent on dictionary insertion order, which is usually the order things are added in/the order you see them in the export but is technically not guaranteed to be that way

regal bane
uncut viper
regal bane
#

ah, sorry.

vernal crest
half tangle
marble verge
#

Good morning. In CP - if I use Fields to add a Context Tag, does this overwrite the existing Context Tags or does it add my new Context Tag to the bottom of the list?

brave fable
#

in short, you want to use TargetField instead of Fields, with the appropriate syntax

vernal crest
brave fable
#

you'll find some useful examples if you follow the target field link in the above paragraph

marble verge
half tangle
vernal crest
#

No worries!

urban patrol
gentle rose
marble verge
#

Is there a dedicated place to suggest features for Content Patcher - or check if they've already been suggested?

gentle rose
#

what feature are you looking for?

marble verge
#

I'd love to see conditional configuration (i.e. be able to use "When:" in config to stop options from showing up if a mod isn't installed), and the ability to define Dynamic Tokens outside of content.json.

gentle rose
#

like, in an include?

marble verge
#

Yeah.

#

Ideally, just a dedicated file outside of content.json.

gentle rose
#

What's the use case? because I think I'm missing something

marble verge
#

Because mine is getting ridiculously large, and thus difficult to read.

gentle rose
#

why not move everything else into includes though?

marble verge
#

I already did - and my content.json is still massive πŸ˜…

uncut viper
#

iirc dynamic tokens outside of content.json has been talked about before, mostly as a "maybe one day but low priority thing" iirc

gentle rose
#

with just dynamic tokens etc?

uncut viper
#

but like, very low priority

marble verge
marble verge
vernal crest
#

You could use regions to split your content.json up

#

That way you can at least collapse bits you don't need in the moment

marble verge
#

Regions?

#

I think Visual Studio Code already does that, to some extent

#

But I'm not sure how I can create more inside of a block

vernal crest
#
#region Region!
Bla bla bla
#endregion
marble verge
#

Ah!

hard fern
#

i never knew you could do that....

#

omg

vernal crest
#

I use it to split my events testing json into categories since I have one patch per event, making patches not a useful way for me to collapse things

lucid mulch
vernal crest
#

I liked using it for my .cs files in Visual Studio so I went hunting for whether there was a way to use it in json files

marble verge
vernal crest
marble verge
#

At any rate, Dynamic Tokens outside of content.json is a "nice to have", but conditional configuration would be a big one for me.

vernal crest
#

Oh in VSC you need to comment the #region line (and #endregion)

hard fern
#

omg this is so helpful

#

i usually break up my i18ns into various "sections" via comments but to be able to actually hide them at will

vernal crest
#

I don't think it needs an extension SDVpufferthinkblob

hard fern
#

it doesnt need one

marble verge
#

Commenting them works a treat.

vernal crest
#

Sorry to not mention commenting them in the first place, I'd forgotten that part until I actually went to look at my file

marble verge
#

NP.

#

Well, that's one less headache - that just leaves the suggestion for conditional configuration. Honestly, just being able to check if a specific mod is installed would be a big win.

round timber
#

ooh ive learned a new thing

vernal crest
#

I think a lot of people would celebrate if conditional config became a thing

marble verge
#

I'll bet. Here's hoping it'll become a thing 🀞

delicate smelt
#

im making a mod includes Chinese translating correcting function,for example,"juice" should be translate to "θ”¬θœζ±" in chinese,but its "果汁" in the game,i want to correct it,but i dont know how to do,i use CSharp,how to write the code?

final arch
#

you can/should do that with Content Patcher

delicate smelt
#

i dont know how to write its content patcher code too...

royal stump
#

as an example, you can write something like this in the content.json file to replace "Juice" item names:

{
    "Format": "2.7.0",
    "Changes": [
        {
            "Action": "EditData",
            "Target": "Strings/Objects",
            "Entries": {
                "Juice_Name": "θ”¬θœζ±",
                "Juice_Flavored_Name": "{0}θ”¬θœζ±"
            },
            "When": {
                "Language": "zh"
            }
        }
    ]
}```
sharp marsh
#

ty for the help

#

though i dont really understand why i need to put hairstyles in the entries rather than hairtestthing, but it works so

royal stump
#

The game doesn't actually know about mod files like hairtestthing.png; only Content Patcher looks at those.
The "Load" part tells CP to load your image into the game's "asset" pile with a name like Characters/Farmer/hairstyles. The game creates extra hairstyles from Data/HairData, and it looks for an asset named Characters/Farmer/ + whatever you write there, so it'll find your loaded image. SDVpuffernerd

sharp marsh
#

ah... makes sense ty

slow basin
vernal crest
slow basin
#

Oof i must have totally missed that!

#

i put it there as aplaceholder lol

vernal crest
#

It's an easy thing to miss meow_noddies Your brain goes "yep, done that bit! I distinctly remember putting something there so I definitely don't need to read it again" lol

opaque field
#

question, if I want to have both custom sprites and portraits but both need to be named Shane.png how do I do that

vernal crest
#

Why would they both need to be named Shane.png?

opaque field
#

cuz that's what they're both under in the unpacked data - am I going about it totally wrong?

vernal crest
#

Your files don't have to be named anything like what the unpacked files are called. All of my files are called "aba_hiria_portraits_default.png" and so on.

#

The only time the name of the files matters is if you want to use the {{Target}} or {{TargetWithoutPath}} tokens, because then CP is going to look for files that are named the same as the Target.

opaque field
#

Oh okay. So if I did one called Shane-portrait.png and Shane-sprites.png that would work?

blissful panther
#

They could be called stinkbug-for-prime-minister.png for all the game's concerned. SDVkrobusgiggle

vernal crest
#

Yup, call them anything you want.

opaque field
#

Okie. Do I need an include too or just a load?

vernal crest
#

You never need includes.

#

They're just for file organisation (and LocalTokens if you want to use them, but you never need LocalTokens either).

#

And you can't Include a .png file anyway.

#

So just a Load. I assume your mod is intended to be incompatible with other mods that change Shane's portrait and sprite? If not, Load won't work (you could make it a low priority Load but then any other mod with a default Load would stop yours from working anyway).

opaque field
#

oh, okay. It keeps saying it can't apply because the from file doesn't exist but the file is right there when I go look at it

vernal crest
#

Then you have written something incorrect. Feel free to share your json if you want some help checking ^_^

opaque field
#

okies one second πŸ™‚

#
            "Action": "Load",
            "Target": "Portraits/Shane",
            "FromFile": "Assets/Shane-portaits.png"
        },
        {
          "Action": "Load",
          "Target": "Characters/Shane",
          "FromFile": "Assets/Shane-sprites.png"
        },```
vernal crest
#

And can you show a screenshot of your Assets folder with the folder path visible, please?

opaque field
vernal crest
#

It does look okay SDVpufferthinkblob Can you share your log so I can see the error message directly?

slow basin
#

woohoo it worked! now to add more frames so she isnt moving like sonic the hedgehog

#

ty again aba

opaque field
ocean sailBOT
#

Log Info: SMAPI 4.2.1 with SDV 1.6.15 build 24356 on Unix 6.8.0.60, with 17 C# mods and 6 content packs.
Suggested fixes: One or more mods are out of date, consider updating them

vernal crest
#

Oh wow that took me a while. You've accidentally spelled it "portaits" without the second r.

#

In your json

opaque field
#

oml

#

yup, yup that'll do it. Ty!

#

Also, I can get to a map by warp on the forest map but I can't get my event to work there when i use changetoTemporaryMap

vernal crest
#

Is it a custom map of yours?

opaque field
#

yis

#

It's more important that it work for the event than it is to be able to get there via forest warp

vernal crest
#

I can't remember if changeToTemporaryMap requires a Data/Events file, but have you got one?

opaque field
#

like a blank json?

#

no, I hadn't thought of that! but I did have to make one for my JojaMart event so that actually makes sense

vernal crest
#

I don't know why it would affect it because unlike changeLocation it's not actually moving location, but it's the first thing I'd try if I couldn't spot any obvious issues like a typo in the location name or something.

opaque field
#

ok I tried a blank json and it gave me a bunch of angry red text

#

said could not find file

vernal crest
#

I would need to see a log to know what it might be upset about

opaque field
#

comin right up

ocean sailBOT
#

Log Info: SMAPI 4.2.1 with SDV 1.6.15 build 24356 on Unix 6.8.0.60, with 17 C# mods and 6 content packs.
Suggested fixes: One or more mods are out of date, consider updating them

vernal crest
opaque field
#
          
      "Action": "Load",
      "Target": "Data/Events/FloralGlade",
      "FromFile": "Data/Events/blank.json",
          
        },
        {
  
        "Action": "Load",
        "Target": "Maps/{{ModId}}_FloralGlade",
        "FromFile": "Assets/Maps/FloralGlade.tmx",
        "Priority": "Low"
        },
        {
            "Action": "EditData",
            "Target": "Data/Locations",
            "Entries": {
                "{{ModId}}_FloralGlade": {
                    "CreateOnLoad": {
                        "MapPath": "Maps/{{ModId}}_FloralGlade",
                        "DefaultArrivalTile": {
                          "X": 16,
                          "Y": 18
                        }
                    },
                    
                }
            }
        },
        {
            "Action": "EditMap",
            "Target": "Maps/Forest",
            "AddWarps": [
                "111 83 {{ModId}}_FloralGlade 16 19" 
            ]
        }
      ]
    }
vernal crest
slow basin
#

i cant seem to make the dialgoue i want for the animation i got working to pop up when i interact with the character doing the animation, ive tried "{{ModId}}_AliciaGummyNPC
and
AliciaDancing"
and
{{ModId}}_AliciaGummyNPC:AliciaDancing"

is it possible to send the json to see where i misstepped?

vernal crest
slow basin
#

alright thank you :3

opaque field
twilit quest
#

@lucid iron I'm finally getting a chance to test the new farmhouse upgrade trigger action. So far it works great, except that it looks like it takes three nights (like the regular farmhouse upgrade) instead of happening overnight as detailed in the documentation.

slow basin
vernal crest
#

Ah, so the dialogue line in your dialogue file should just be "AliciaDancing".

#

And this part in your Data/animationDescriptions patch needs to be your actual NPC's internal name, not the dummy one I made for her lol.
Characters\\Dialogue\\{{ModId}}_AliciaGummyNPC:AliciaDancing.

"AliciaDancing" is the dialogue key.

Characters\\Dialogue\\{{ModId}}_AliciaGummyNPC is the Target for your NPC's dialogue. It needs to match the Target of your EditData patch for her dialogue.

slow basin
#

oo ok let me change it then

finite willow
#

what do I do if SMAPI refuses to work

torpid sparrow
ocean sailBOT
#

For help with modding issues, please ask in #1272025932932055121! When asking for assistance there, sharing an error log will help others identify your issue (see https://smapi.io/log for instructions).

turbid pawn
#

Where are sleeve textures stored?

thorny tiger
#

on your arms

turbid pawn
#

*Your

rough lintel
#

theres no textures per se, but the sleeve variants are on there

opaque field
#

hello! If I do a custom tiledata action "message" on a custom map where/how do I store the actual message data?

turbid pawn
#

So depending on the shirt colour, it recolours part of the farmer base arms?

twilit quest
vernal crest
opaque field
opaque field
#

perfect ty

vernal crest
turbid pawn
#

Where are the sleeve textures in the farmer base sheet? Are they part of the arms?

lucid iron
#

I think it's just arm recolor depending on shirt

turbid pawn
#

I've run both these lines to edit the shirt data when it's loaded, on what logs reveal to be the correct shirt, and the sleeves have neither disappeared nor changed colour

shirt.HasSleeves = false;
shirt.DefaultColor = $"{Game1.player.hairstyleColor.R} {Game1.player.hairstyleColor.G} {Game1.player.hairstyleColor.B} ";
#

What am I doing wrong?

lucid iron
#

Is default color a string NotteThink

lucid iron
#

Would look at transpile FarmerRenderer.ApplySleeveColor

#

Also need to set _shirtDirty and call executeRecolorActions

frigid zenith
#

Hi! I was wondering if anyone knows how to make a hat have an attachment slot like how fishing rods have? I wanted to make so certain items could be attached to a hat to give the player some buffs

lucid iron
#

C#

frigid zenith
lucid iron
#

Are you generally aware of how to make a C# mod? Asking so I know where to start explaining

lucid iron
#

Ok so the game only implement fishing rod type attachment slots for Tool and Hat does not descend from Tool

#

Discard all thought of reusing that and create custom system for tracking what is attached to hat, modData useful for this

#

Hat is extra annoying in that it doesn't descend from Object either so no heldObj to use

#

So recommendation is toss things into a globalinventory, store the guid to the inventory in modData

#

Next thing is adding draw to show attachment on tooltip, probably some kinda transpiler bc draw codeβ„’

#

Also need to implement the place into/remove from attachment behavior, not sure off hand where that is. Will have to think about gamepad compat too

#

Lastly do the stuff to check hat got attachment and perform effects

#

tl;dr gotta do it from scratch

frigid zenith
#

got it, a lot of work lol. thank you so much for the help!

lucid iron
#

If the attaching part aint important there are framework mods that detect if a specific hat is equipped/unequipped

#

Majority of this work is just doing the attachment tracking

frigid zenith
lucid iron
#

ui is never simple in sdv monS

#

However if icon not that important, it is possible to alter the description text and skip a transpiler

frigid zenith
lucid iron
#

I don't know of a framework that alters the description per instance like that off hand

#

I also didn't know item extensions had features related to attaching items blobcatgooglyblep

frigid zenith
old edge
#

What is this? ```json

StardewValley.Tools.WateringCan.DoFunction_PatchedBy<Rafseazz.RidgesideVillage>(WateringCan this, GameLocation location, Int32 x, Int32 y, Int32 power, Farmer who)
at StardewValley.Farmer.useTool(Farmer who)
at StardewValley.FarmerSprite.currentAnimationTick()
at StardewValley.FarmerSprite.animateOnce(GameTime time)
at StardewValley.Farmer.Update(GameTime time, GameLocation location)
at StardewValley.Game1.UpdateCharacters(GameTime time)
at StardewValley.Game1._update(GameTime gameTime)
at StardewValley.Game1.Update(GameTime gameTime)
at StardewModdingAPI.Framework.SCore.OnPlayerInstanceUpdating(SGame instance, GameTime gameTime, Action runUpdate)

100s of these... multiples per second.

gentle rose
#

(you also accidentally cut out the actual error part of the trace log)

final arch
#

a stacktrace

#

so unhelpful you all SDVpufferpensive SDVkrobusgiggle

gentle rose
#

it took me reading this five times to put that together in my head for some reason SDVpuffersquee

half tangle
#

mostly out of idle curiosity since things are working... For a transpiler on the following IL:

    // if (this.EnemyCount == 0)
    IL_011c: ldarg.0
    IL_011d: call instance int32 StardewValley.Locations.MineShaft::get_EnemyCount()
    IL_0122: brtrue.s IL_0132

    // num6 += 0.04;
    IL_0124: ldloc.s 6
    IL_0126: ldc.r8 0.04
    IL_012f: add
    IL_0130: stloc.s 6

I'm matching on that second chunk of four lines. This is in MineShaft.checkStoneForItems, btw. Right after that code is another if statement
// if (who != null && who.hasBuff("dwarfStatue_1"))
and I want to insert code after the above block and before the null check (between the ifs). So my transpiler includes:

             matcher.MatchEndForward(
                new CodeMatch(OpCodes.Ldloc_S),
                new CodeMatch(OpCodes.Ldc_R8),
                new CodeMatch(OpCodes.Add),
                new CodeMatch(OpCodes.Stloc_S)
                )
                .Advance(2)
                .Insert(

So my question is, why is it that when I do Advance(1) the insertion only gets called if the enemy count is 0? i.e. it's still within the if statement. I have to advance 2 (as shown) to get my insertion to be called. Is this as simple as: my insertion when I advance 2 is actually happening after who is loaded onto the stack? Can I not actually insert "between the if statements" since that's not part of the IL?

pine elbow
#

Wow learning even how to make basic mods is hard, but I'm getting there I understand the basics of JSON.

old edge
half tangle
#

That is part of a line of a log

gentle rose
#

you need to move that label to the code you’re inserting after you insert it

uncut viper
gentle rose
#

(moving the label to your IL is thankfully not too difficult iirc)

uncut viper
#

you could add 1,000 lines of IL between that second block and what ILSpy calls IL_0132 and the jump would still work the same

gentle rose
#

(in fact, when you write your own labels, they don’t have to be IL_xxxx at all, they can be whatever you want)

uncut viper
#

(correct. the IL_xxxx convention is just made up by ILSpy)

#

(more or less)

gentle rose
#

the heavy lifting that the phrase β€œmore or less” does in anything relating to code is truly impressive

half tangle
#

Oh, I forgot to include the important detail that this is a matcher.MatchEndForward( so in theory it's setting the position at the end of that

gentle rose
#

right, that’s unrelated to anything that has been said so far afaik though

uncut viper
#

its setting the position at the index of the final instruction

#

if you insert at that index, the final instruction will end up after your instruction

gentle rose
#

isn’t that matchstartforward, button?

uncut viper
#

i dont believe it works differently no matter which direction you come from?

gentle rose
#

direction is the forward part, start and end refer to where it puts you relative to the match iirc

#

but I could very much be incorrect

#

and probably am

uncut viper
#

right but no matter which one it is, it still ends up on an index of an instruction in the match

#

not one before or one after the match

#

matchend means you'll stop on top of the Stloc_S

gentle rose
#

but anyway this changes nothing because the label is still tied to the first instruction of the next block (the start of the β€œif”)

half tangle
#

So once it runs through the CodeMatches the position is at the stloc. Then advance 1 would move it after that, correct? The confusion I have is that advance 1 is keeping it dependent on the enemy count being 0

uncut viper
#

because you havent moved it past the jump

half tangle
#

isn't advance 1 moving it past the jump?

uncut viper
#

imagine a long road with two houses on either end of it. the house at the start of the road is sending a package to the house on the other end of the road using house 2's address
you can add as many new houses as you want between them. house 1 is still addressing its package to the original house 2

gentle rose
#

not unless it’s putting it past the first instruction of the β€œif” statement, no

uncut viper
#

your instructions you're adding are the new houses being added in this analogy

#

and house 1 is the Stloc

opaque field
#
                "LogName": "Add Furniture",
                "Action":"EditData",
                "Target":"Data/Furniture",
                "Entries":{
                    "{{ModId}}_BlueChickenPlushie/decor/-1/-1/2/350/2/Blue Chicken Plushie/0/Mods\\CacklingCaracal.TheWolf\\Furniture"

                }
            }```
#

Double checking that this is the correct way to add furniture?

uncut viper
#

(actually i guess House 1 is the brtrue, and the Stloc is one of 4 houses also on the road, but hopefully you get the idea)

gentle rose
uncut viper
#

point is, a jump does not say "go 1 instruction ahead"

#

it says "go to This specific instruction, no matter where it is"

gentle rose
#

idk furniture syntax off the top of my head but there should be a key or value inside that β€œentries” entry

#

what are you using as reference, caracal?

opaque field
#

I've just been staring at the wiki page for the most part

uncut viper
#

the only reason the instruction has a label in ILSpy that looks like its just a couple instructions ahead is bc thats what ILSpy decided to show it as. the lable is meaningless

gentle rose
opaque field
uncut viper
#

it could just as easily say "br.true_s MyCoolLabel"

gentle rose
#

(I’m just trying to figure out where we stand haha)

opaque field
#

oh uh sorry remind me what syntax means haha cuz I borrowed some of it from how I've been adding my other objects and food items which has been modding item data

gentle rose
opaque field
#

but mostly it's just been patching together what I kind of know already and what I find on the wiki

gentle rose
#

but hold on, let me find some good resources

half tangle
#

Oh, ok, I had definitely been stuck in the "ilspy's lines are one instruction" way of thinking of this. The fact that stloc.s 6 is two labels and the line count is meaningless was what was confusing me, if I'm following correctly

uncut viper
#

definitely try not to rely on line numbers or ILSpy labels at all if you can help it, unlearning that will help a lot

#

adding your instructions will change the count of instructions but the labels are basically memory addresses and you must change them yourself

half tangle
#

Yeah, definitely get that. The actual IL is what's relevant... very obviously

uncut viper
#

as iro said luckily the ILGenerator can do this for you easily

#

or maybe its a harmony extension on CodeInstruction. i dont remember

gentle rose
# opaque field but mostly it's just been patching together what I kind of know already and what...
Stardew Modding Wiki

This tutorial explains how to add custom furniture using the new 1.6 game update features and Content Patcher. The tutorial assumes you already have the game unpacked and that you have some basic familiarity with the Content Patcher format. The mods referenced as examples in this tutorial are Bonsai…

uncut viper
#

somewhere there's a MoveLabelFrom/MoveLabelTo or you can always just create your own new label with the ILGenerator, attach it to the first part of what you wanna add to the if statement, and then change brtrue's operand to your new label instead

gentle rose
half tangle
#

I missed that comment from iro that you're referencing

opaque field
uncut viper
#

(tbh i also usually just do it manually with the last way i just described)

gentle rose
#

these youngins and their fancy generators have no ideaβ€”

half tangle
#

yeah, now that I understand this better, making my own label and replacing brtrue's operand makes more sense - I'm glad I asked

uncut viper
#

ofc you can also just avoid messing with labels altogether by just adding your if stuff entirely after the original if IL

#

and then jumping out of the if-block yourself with your own brtrue

#

which ig doesnt avoid them "altogether" but it means you wouldnt have to mess with the first one on the existing brtrue

gentle rose
#

(which of course would just mean you have to mess with other labels SDVpuffersquee)

uncut viper
#

it does mean you only ever have to advance forward, though

#

which is nice

half tangle
#

I previously had written one transpiler like a year ago, but I'm a much better coder now so it's nice to revisit this now that I have a better understanding to grasp all this with

uncut viper
#

i think all harmony mods should be rewritten as transpilers instead

#

i love transpilers

half tangle
#

it's addictive

gentle rose
#

once you learn them it becomes a β€œwhen all you have is a hammer” situation immediately SDVpuffersquee

half tangle
#

or at least compelling to draw you into its grasps

tawny ore
#

Why stop with Harmony mods. All mods can just be written as transpilers. Including purely content mods.

proud wyvern
#

all mods should be rewritten as Mono.Cecil prepatchers

uncut viper
#

I can be trusted with Mono.Cecil access.

proud wyvern
#

can you imagine the load times if all Harmony mods were Cecil instead

half tangle
proud wyvern
#

just patch the game assembly once

#

and then cache it between runs

uncut viper
#

would it be better or worse

#

i dont know much about cecil

proud wyvern
#

much better

uncut viper
#

sounds great lets bug pathos to make it happen

half tangle
#

anyway, thanks for the insights - glad I asked so I could understand this a little bit better

lucid iron
#

Does it make a difference if no one is doing patches after gamelaunch

uncut viper
#

bit bold to assume no one is doing that

lucid iron
#

No i mean, is cecil and harmony perf the same at runtime

proud wyvern
#

i was kidding, but if we were to really do it, i'm saying to only do Cecil patching once

#

that's not something you can do with Harmony

#

but even if you were to patch again each session, i think Cecil would still be vastly faster than Harmony

lucid iron
proud wyvern
#

it was a while since i profiled my mod loader for Cobalt Core, but i believe about 50% of load times were due to mods doing Harmony patches

#

i assume it's similar in Stardew modding

lucid iron
#

Can u do this but sensibly with cecil

proud wyvern
#

i mean, uh, maybe

lucid iron
proud wyvern
#

unfortunately i've lost my free dotTrace license

#

so i can't check

#

and i don't even have a big modded setup right now

tawny ore
#

Have you looked in the couch cushions? I'm always losing things in there.

lucid iron
#

I am curious about the stuff cecil can do that harmony can't tho

uncut viper
#

cant cecil like add fields and stuff or something

#

to existing classes

lucid iron
#

Yeah that's my vague understanding too

proud wyvern
#

Yeah, you can add new members

#

You can also patch methods which normally get inlined

#

Or generic methods

#

Add interface conformances

uncut viper
#

what was the technical reason that a mod cant do this already by taking Cecil from smapi-internal, does it just have to be done like, super duper early and by the time your mod is loaded its too late

proud wyvern
#

Whatever you could do normally with C#, while building said assembly, really

lucid iron
#

Can i add more enum

proud wyvern
#

Technically? But you can do it anyway, by just using different values from all of the defined ones

proud wyvern
#

By the time mods get to load, Stardew’s .dll is loaded

lucid iron
#

Well do it in a way that satisfy enum try parse from string

uncut viper
#

could i patch SMAPI to do this to another mod if i knew that other mod was going to be loaded after mine

proud wyvern
#

Probably (to patching another mod)

uncut viper
#

I can be trusted with Mono.Cecil access.

patent lanceBOT
calm nebula
#

Not sure about that.

proud wyvern
#

Actually

uncut viper
#

(not that i have any idea how id guarantee that load order without owning the other mod anyway, though, in which case... why)

calm nebula
#

Pathos will turn around and you'll have Cecil via content pack

proud wyvern
#

SMAPI loads all assemblies one after another, before creating mod instances, right?

lucid iron
#

I don't trust myself with anything

proud wyvern
#

I remember it being weird

uncut viper
#

i dont know how SMAPI does it

calm nebula
#

Static constructors lol

uncut viper
#

still though, if my instance is created first, surely i could just patch SMAPI to reload the assembly right

proud wyvern
#

Static ctors don’t get called until their types are referenced

tawny ore
uncut viper
#

dangerously? i think thats like 90% of the reason for most of atras quotes the last month

lucid iron
#

Breaking being making smapi think they r not compat

calm nebula
#

Hi

#

I show up, I hit the quote button, I leave

uncut viper
#

Hi

calm nebula
#

I contribute nothing useful to the conversation

lucid iron
#

Atra go quote 4 things and 6480 real quick

calm nebula
#

No you

torpid sparrow
#

hello, does anyone have experience with conversationtopics? I can't get the dialogue to show up after adding it into an event

uncut viper
#

did you add a corresponding dialogue key to your NPCs dialogue?

torpid sparrow
#

Yes I did

#

im pretty sure i did it right let me upload my json

#

!json

ocean sailBOT
#

JSON is a standard format for machine-readable text files that's used by Stardew Valley mods.

If you need help with a JSON file, you can upload it to smapi.io/json to see automatic validation and share the link here.

When making mods, it's recommended to edit your files in a text editor with JSON support, such as VS Code, Notepad++, or Sublime Text. These programs will check for syntax errors.

torpid sparrow
#

I actually caught myself pathing wrong yesterday, I was doing Data/Characters/Dialogue/Character.json but when i changed it the dialogue still didnt show up

uncut viper
#

your targets all have file extensions

torpid sparrow
#

oh i see

#

i totally forgot

uncut viper
#

remove them

torpid sparrow
#

yes!

#

thank you

#

i got mixed up with loading custom npc dialogue and editing dialogue SMCPufferChickSweatSip

cold marsh
#

I'm supposed to use streamedvorbis: true for both custom sound effects and music that will only play once in a single event, right?

lucid iron
#

Yeah usually

#

There's jank related to using that on short sounds but if it works u good

torpid sparrow
#

Anyone know where the dialogue is stored for when you reject adopting a pet?

brittle pasture
torpid sparrow
brittle pasture
#

well you can change it to something else...

torpid sparrow
#

hm yeah but i would need marnie to not be there at all

#

its ok it'll just be a funny little goof if players choose not to adopt

#

marnie will appear out of nowhere

brittle pasture
#

yeah that's hardcoded unfortunately

#

maybe a request for 1.6.16?

torpid sparrow
#

maybe although i dont know if there are many mods that change adoption altogether

lucid iron
#

if u just null out the event i think ppl just get a little black screen and then nothing

torpid sparrow
#

thats not the problem cause i do want the question to be asked, it just wont make sense bc the event is different xd

lucid iron
#

oh u can just edit that string then

torpid sparrow
#

its fine though if ur downloading a pet and choosing not to adopt idk why you downloaded and chose the pet

lucid iron
#

target Strings/StringsFromCSFiles editdata entries Event.cs.1798

torpid sparrow
#

the string doesn't mention its from marnie

brittle pasture
torpid sparrow
#

wouldn't she still say it

#

yeah

brittle pasture
#
  this.eventCommands[1] = "end";
  this.eventCommands[0] = "speak Marnie \"" + Game1.content.LoadString("Strings\\StringsFromCSFiles:Event.cs.1798") + "\"";

dire times

torpid sparrow
lucid iron
#

what is the behavior you want if ppl download the pet mod and get toothless as pet 2

#

or 3 or 4 etc

uncut viper
#

well if you BETAS harmony patch the array index accessor...

brittle pasture
#

fear

torpid sparrow
#

I briefly considered having the wizard sell the pet license although I don’t like the idea of selling a license for him

lucid iron
#

its hardcoded to marnie rn

torpid sparrow
#

Then SDVpufferwaaah

lucid iron
#

or more accurately hardcoded to the PetAdoption shop

#

which u could open from a tile action, but wouldnt filter to just toothless

uncut viper
#

isn't the pet license an item query

lucid iron
#

yea but idk what peritemcondition would work

#

its not like PET_ADOPTION Cat

mint stirrup
#

all ive done up to now is extremely simple stuff
i need to play a cutscene first thing in the morning, when the player leaves the house "OnNewDay"
of just a random character talking to the player
i dont know if i can link/send a picture here

uncut viper
#

you can yes

mint stirrup
#

i essentially dont know how to do it, and the api docs are somewhat confusing for me

uncut viper
#

you can add an event to Data/Events/Farm and set the preconditions to what you want

lucid iron
#

are you in C# or content patcher?

slow basin
#

im tryiong to get specific dialogue and portrait to show when talking to my npc but it keeps throwing errors but idk how to understand if its looking for a seperate json im supposed to make or if i messed up the pathing

this is the smapi log: https://smapi.io/log/134642f14d4b4a48ab3e05cff51ed882

I can supply whichever json it needs but im not sure which one that would be and i dont want to spam like 4 json parser links

ocean sailBOT
#

Log Info: SMAPI 4.2.1 with SDV 1.6.15 build 24356 on Microsoft Windows 11 Pro, with 3 C# mods and 1 content packs.

mint stirrup
lucid iron
#

yea

mint stirrup
#

doing it all on c#

lucid iron
#

are you invested in doing that?

mint stirrup
#

100%

#

alr made a mod

#

this is needed for an update

uncut viper
#

i think chu asks bc what you want is very simple to do with Content Patcher

lucid iron
uncut viper
#

but it works similarly in C# anyway

lucid iron
#

i only ask so i know what page to link really

mint stirrup
uncut viper
lucid iron
#

content patcher does this (and other stuff) for you based on json files

mint stirrup
lucid iron
#

a lot of docs online about how to format event is targeted at using content patcher, but the concept is same really

mint stirrup
slow basin
#

I think I did yes!

mint stirrup
#

is cp really all that good? ive only ever considered modding in c#

lucid iron
#

you are going to edit a Dictionary<string, string> asset by subscribing to the AssetRequested event, and handling stuff accordingly

uncut viper
lucid iron
#

i mean its qol if u need to do a lot of content edits?

slow basin
#

ofc

lucid iron
#

which is the case for things like npcs

uncut viper
halcyon nest
#

it’s easy and powerful to use too!!!

uncut viper
#

something like 66% of all mods

lucid iron
#

but if your main mod is going to need C# then yea its fine to do the asset editing yourself

mint stirrup
slow basin
#

this is my content json it should be the first section that loads in the blank json i have πŸ™‚β€β†•οΈ

uncut viper
#

all CP does is read json files that you write

#

and assets to go with them ofc like pngs and wavs

lucid iron
#

doodle it'll prob help us if you give a high level summary of the mod

uncut viper
#

but thats like its whole purpose

halcyon nest
#

make a .json, profit

#

cp in a nutshell

lucid iron
#

you can combine content pack and C# too if you want PecoWant

mint stirrup
#

its super simple really. OnNewDay, waits for a player to leave the house, and a cutscene plays of a random NPC (will be changed later) says something (that is read from a .json full of messages and their likelihood of being chosen).

uncut viper
#

is your NPCs internal ID the former or the latter?

lucid iron
#

as long as the random npc is a fixed list

uncut viper
#

not only that but itd be even simpler with Content Patcher

mint stirrup
#

i need to be able to replicate this in cp if that is the case:

`string path = Path.Combine(this.Helper.DirectoryPath, "messages.json");
List<GreetingMessage>? messages;
try
{
using (StreamReader reader = new StreamReader(path))
{
string messagejson = reader.ReadToEnd();
messages = JsonSerializer.Deserialize<List<GreetingMessage>>(messagejson);
}
}
catch (Exception ex)
{
this.Monitor.Log($"Error reading messages.json: {ex.Message}", LogLevel.Error);
messages = new List<GreetingMessage>();
}

int totalWeight = messages.Sum(m => m.likelihood);
int choice = new Random().Next(0, totalWeight);
int cumulative = 0;
GreetingMessage? selected = null;
foreach (var msg in messages)
{
cumulative += msg.likelihood;
if (choice < cumulative)
{
selected = msg;
break;
}
}
if (selected != null)
{
Game1.addHUDMessage(new HUDMessage($"Hey {Game1.player.displayName}! {selected.text}", 1));
Game1.playSound("ding");
}`

#

oh it doesnt format

#

crap

lucid iron
#

the hud message not quite, would need spacecore

uncut viper
#

(and the sound)

lucid iron
#

who is providing messages.json?

mint stirrup
#

it wont make a hudmessage, that part is to be replaced by the cutscene

#

messages.json is already in the mod folder, its made for customizability, so that anyone that gets the mod can change what messages get displayed

slow basin
lucid iron
#

mod itself then Dokkan

languid matrix
#

How do I make it so that an extra json file is only included when a certain mod is installed?

slow basin
#

or is that different i tried setting it as her name because i wasnt sure

uncut viper
#

whatever key you used when editing Data/Characters

#

thats their internal name

uncut viper
#

im assuming its the former since thats where you've loaded all your portraits and stuff to as well

lucid iron
#

yea so in CP land you'd define a token that has the list of NPCs that can appear and use the {{Random: {{NPCList}} }} token to pick one

mint stirrup
#

well aslong as i can replicate the same in cp ill try it

#

itll take some time to learn cp

#

can you link cp docs?

lucid iron
mint stirrup
#

tyty

lucid iron
#

you can also use Random to pick a line to say

spice inlet
#

which of these themes seems most interesting for a bundle?

  • Witchy / Wizardry
  • Flowers, Vines & Roses
  • Pirate Treasure
haughty charm
#

Flowers, Vines, & Roses

slow basin
#

ooh

haughty charm
#

Though Pirate Treasure sounds pretty awesome, too

uncut viper
#

(also even your C# was on hard mode you dont need a streamreader to read a json in your mod, theres something in your ModHelper for reading jsons for you)

spice inlet
#

all three of them could be real pretty SDVpuffersquee

lucid iron
#

oh lix unrelated suggestion

slow basin
#

ok so i should change the part back to AliciaGummyNPC

lucid iron
#

what if pif doors can be only door on part of the furniture

#

someone made big castle PIF door and rn the entire big castle furniture is a door

uncut viper
slow basin
#

πŸ™‚β€β†•οΈ

spice inlet
slow basin
#

ok i changed everything back to {{modId}}_AliciaGummyNPC:AliciaMagic

lucid iron
#

so a really easy way is to register a tile action and tell ppl to use spacecore to add that tile action on the tile that should be a door

spice inlet
#

I mean adding a tileaction would be quite simple to do

lucid iron
#

but i dunno how you'd want to associate it to the furniture in that case blobcatgooglyblep

spice inlet
#

you'd need to provide the furntiture id as an argument

lucid iron
#

ah i was imagine something different actually

spice inlet
#

you mean how placing the furniture would set the tileaction?

lucid iron
#

basically in mmap i have added some warp type tile actions that automatically grabs the building on the current tile, and warp the player inside

#

This is added because the indoor map is instanced and some long guid location name, so you can't use a normal warp

#

this is intended for usage with building ActionTiles

#

pif can work similarly, so as long as you somehow give the property via Furniture.DoesTileHaveProperty

#

spacecore does it ofc but nothing wrong with rolling your own 3sSmolMiku

#

from there you'd have the relative x y as well as the Furniture

spice inlet
#

the location names are generated and I think you could do the same checks PIF does

languid matrix
ocean sailBOT
#

Log Info: SMAPI 4.2.1 with SDV 1.6.15 build 24356 on Microsoft Windows 11 Home, with 8 C# mods and 11 content packs.
Suggested fixes: One or more mods are out of date, consider updating them

spice inlet
#

or I could add an api

lucid iron
#

I feel like it makes the most sense as part of the pif door custom asset model though

#

If u don't mind i can draft a PR for it (eventually)

spice inlet
#

sure

languid matrix
#

Hello? Anyone?

lucid iron
#

That said the easier workaround is just separate the door from the big castle Dokkan

spice inlet
#

I think you're way too mentally invested in this than my sleepy head can follow on the phone now anyway SDVpuffersquee

lucid iron
#

Yes i am very deep in the map sauce

urban patrol
languid matrix
#

How do I add that and how does it work?

urban patrol
#

i would recommend either doing that and/or adding a false dependency in your manifest

urban patrol
urban patrol
#

and if that isn't enough, then adding a false dependency on SVE will ensure that your mod loads after it (if that's what your issue is)

wise forge
#

If this is a silly question I apologize, but... has anyone else ever run into an issue with SMAPI not reading a content.json file even though there is one in the mod's folder?

half tangle
#

well, Content Patcher reads it if your mod is a content pack for Content Patcher. SMAPI isn't what reads it, in case that's relevant to the issue you're having.

wise forge
#

Well that's just a lack of general understanding on my part, but my question remains the same... Why would this happen and how do I fix it

uncut viper
#

do you have content patcher installed?

wise forge
#

I do

#

As well as Json Assets

uncut viper
#

and its actually a .json file and not a content.json.txt in disguise? i.e. do you have file extensions turned on

#

JA is irrelevant

wise forge
#

I double checked that, it's for sure a .json file

ornate locust
#

That doesn't matter

#

Json Assets is an outdated mod

#

you don't need it to work with .json files

wise forge
#

Gotcha

uncut viper
#

pretty sure they were just replying to me asking if it was a json

ornate locust
#

someone correct me if I'm wrong there

half tangle
#

does your manifest have

    "ContentPackFor": {
        "UniqueID": "Pathoschild.ContentPatcher"
    }
uncut viper
#

as said JA is completely irrelevant

#

if you check for what Cam just posted and its there, then send a log

uncut viper
#

!log

ocean sailBOT
#

Important note: Your computer username may appear in the log. If your username is your full name, please be aware of this before uploading it.

Please share your SMAPI log file. To do so:

  1. Open this page: smapi.io/log.
  2. Follow the instructions at the top of the page to upload the log file. (Don't copy & paste from the console window!)
  3. After uploading, it will show a green box with a URL to share. Post that URL here.

Please do it even if you don't see any errors. This has useful info like what mods and versions you have, what the mods are doing, etc. If the issue didn’t occur in your last session, please load the game to the point where the issue occurs, then upload the log.

ornate locust
#

Just making sure, because once upon a "trying to figure out mods" time I did momentarily think I needed Json Assets to work with jsons

wise forge
ocean sailBOT
#

Log Info: SMAPI 4.2.1 with SDV 1.6.15 build 24356 on macOS Unix 15.5.0, with 1 C# mods and 1 content packs.

uncut viper
#

can you send a screenshot of your mod folder within Stardew Valley/Mods?

wise forge
#

Just the two of 'em in there

uncut viper
#

sorry, my fault, i meant a screenshot inside your mod folder

#

i shoulda been clear

wise forge
#

Oh, no worries

lucid iron
#

can you turn on file extensions

uncut viper
#

do you have any images in your assets folder? do you see them say .png at the end of them?

lucid iron
#

idk how that works for mac(?)

wise forge
#

Not sure how to turn on file extensions (they may already be on?) but this is how the info panel on my computer identifies the file

uncut viper
#

are you using Stardrop?

#

or any other mod manager

wise forge
#

Nope

#

I also made sure the .json was all valid and parsed correctly

#

So I

#

Oops

#

I'm kind of at a loss πŸ˜…

uncut viper
#

can you double check that its not actually named content.json (with a space at the front)? since i noticed your mod folder name in the log has an extra space at the end, so i wonder if that mightve happened with the file name too

lucid iron
#

It's not that you needed it, but more that the log shows it was there

#

Which makes me think this isn't the actual mod folder

wise forge
#

I just removed it

#

It was in the folder when the log I shared was created

#

Double checked for spaces in the file name, still no dice

#

Same error

uncut viper
#

the only thing i can think of then is that this is either not the mods folder that SMAPI is using or maybe something is preventing read permissions on your file

wise forge
#

Hmm, I'll check the permissions

#

That's been an issue with loading other mods. But it was typically a different error in the log in those cases

#

I replaced a few of the mods that I use (I had removed them so that I could load everything up faster while testing this mod) and everything else is loading up just fine

#

Also no luck in changing the permissions (typically changing all of the permission to read & write fixes that issue for me)

uncut viper
#

then i am unfortunately out of ideas

lucid iron
#

Do u wanna zip up r mod and send it here

wise forge
#

Sure, I can give that a shot

twin wadi
#

isn't the uniqueid case sensitive?

#

the p in pathoschild should be capitalized iirc, not sure though

wise forge
#

That sounds accurate, tbh

uncut viper
#

thats not an issue

twin wadi
#

k just checking jsut in case

uncut viper
#

the log indicates that Content Patcher already found the mod folder

#

it just cannot find the content.json

#

which means its also not an issue with the manifest in general

wise forge
#

It literally just can't identify the content.json for some reason

#

Everything else is in order as far as I can tell

twin wadi
#

could a space at the end of the file name be an issue?

#

folder i mean

wise forge
#

I did just correct that but haven't reloaded since

uncut viper
#

no

wise forge
#

Makes sense, it already found the folder like you said

twin wadi
#

this shouldn't be a problem, right?

half tangle
#

I just tried to open the game with it and CP couldn't preload it. I then moved the internal folder out of it and deleted the rest since it had a __MACOSX folder in it with more content. Then ran the game and it worked

#

(this is at you SMae)

uncut viper
lucid iron
#

What does __MACOSX do...

uncut viper
#

my game was able to load it just fine

lucid iron
#

I always get these files and i just toss em

uncut viper
#

im confused what you even did

half tangle
#

me? I extracted the zip. It extracted to a folder starting with [CP]. Inside it was a folder named the same and the __MACOSX folder. I moved the first of those two internal folders to my Mods folder and deleted everything else.

#

I've seen a few people who make CP mods on a Mac have that folder but I have no idea what its purpose is or why it was affecting this case

#

Logo, for example

uncut viper
#

but SMae did not have the MACOSX folder inside their mods folder, right? it wasnt in their screenshot

#

and even if they did, SMAPI and content patcher did find their mod

#

it read the manifest.json perfectly fine

wise forge
#

Remind me what the "WARNING: Mismatched UI Mode Push/Pop counts. Correcting." error means?

uncut viper
#

that can happen for a lot of reasons

wise forge
#

I remember it being a simple fix but not what the fix was lmao

half tangle
#

it's probably a hidden folder on a Mac

lucid iron
uncut viper
#

but SMAPI clearly read the correct folder fine

#

and read the correct manifest inside the correct folder

uncut viper
#

im just confused where things went wrong, bc i wanna see where in the code it happened

half tangle
#

yeah, idk why it fixed things which is still concerning

lucid iron
#

But in general someone had uncaught exception

#

Unlikely to be a content mod

uncut viper
#

and i dont really understand what SMae did to fix it if they cant see the MACOSX folder

wise forge
# lucid iron This could be anything

It's a menu glitch. Now that the mod is loading correctly the menu isn't displaying it. It's an issue I had before, I just don't remember how I fixed it

half tangle
wise forge
#

Also: I tried just re-extracting it as normal and making certain that folder wasn't actually there

#

It then worked

lucid iron
wise forge
#

I am truly just as ⁉️ as y'all

lucid iron
#

All that warning really means is that something did a bad and could have exploded UI but thankfully smapi/game caught it

wise forge
#

Huh. I see

lucid iron
#

We'd need context basically

wise forge
ocean sailBOT
#

Log Info: SMAPI 4.2.1 with SDV 1.6.15 build 24356 on macOS Unix 15.5.0, with 6 C# mods and 6 content packs.
Suggested fixes: One or more mods are out of date, consider updating them

wise forge
#

It could just be the fact that a bunch of my mods are wonky and pieced out because I've been testing. I'm just gonna put everything back where it belongs and give that a go lmao

lucid iron
#

Try new save first

#

Warping to ScienceHouse

#

You went to Robin's and opened the carpenter menu?

wise forge
#

I did

uncut viper
#

did you used to have Alternative Textures in this mod list?

wise forge
#

I did, yes

uncut viper
#

do you still have the broken tools

#

or the AT tools

#

or maybe really any errored items in your inventory

wise forge
#

I think I did have an error item in my inventory

uncut viper
#

trash it then and try again

wise forge
#

No such luck still.. do I maybe need to reload to clear out the error item?

uncut viper
#

i dunno then. but its finding null object data, so. make a new save for testing.

slow basin
#

I believe I changed the correct things back to the internal id of my character but the special animation dialogue still wont pop up >.< , if it helps she says her regular intro dialogue and spring dialogue but then even though theres another chat indicator when i mouse over her she wont tallk further and errors will spring up in smapi log

ocean sailBOT
#

Log Info: SMAPI 4.2.1 with SDV 1.6.15 build 24356 on Microsoft Windows 11 Pro, with 3 C# mods and 1 content packs.

slow basin
#

let me also grab my dialogue json because im wondering if thats what i have wrong

urban patrol
#

show me your animation descriptions?

#

animation dialogue uses strings usually

slow basin
#

ooh ok

urban patrol
#

okay i actually think the way you do it would work but once again you have mismatched targets

#

with how frequently it’s confusing you, i would honestly recommend simplifying your NPC name. {{ModId}}_Gummy (or something like that)

#

you also don’t have to type out your Mod Id inside of content patcher, which i suspect is also causing confusion

slow basin
#

aa ok ill change all instances to modid and a simpler name

urban patrol
#

i hope that works! and if it doesn’t then i’ll show you how i set up mine with strings the way vanilla does it

slow basin
#

alright thank you!

#

oof i messed something up i think, now she wont do an animation XD time to go back and fix that first

languid matrix
#

How do I fix unnamed items?

river shale
#

hi, can someone help with a mod issue?

tiny zealot
river shale
#

hi, i'm working on a translation of a mod called Ailisia and everything was going ok till i got an end of day error
19:20:59 ERROR game Failed loading special order 'Ailisia'.
System.Collections.Generic.KeyNotFoundException: The given key 'ResetEvents' was not present in the dictionary.
at StardewValley.SpecialOrders.Rewards.ResetEventReward.Load(SpecialOrder order, Dictionary2 data) in D:\GitlabRunner\builds\Gq5qA5P4\0\ConcernedApe\stardewvalley\Farmer\Farmer\SpecialOrders\Rewards\ResetEventReward.cs:line 21
at StardewValley.SpecialOrders.SpecialOrder.GetSpecialOrder(String key, Nullable1 generation_seed) in D:\GitlabRunner\builds\Gq5qA5P4\0\ConcernedApe\stardewvalley\Farmer\Farmer\SpecialOrders\SpecialOrder.cs:line 731

this is only day 8 of a new file so i'm unsure how a spcial order is causeing an error, unless it's trying to load up one of her 2 quests but i'm unsure. need help knowing which part of the code i messed up as you posts in the og mod dosen't seem to have this problem and removeing the mod lets the game go on as normal

twin wadi
#

can you post a log instead of copying and pasting from the console?

#

that way it's easier to see SDVpufferheart

latent mauve
#

Woo, first event coded from scratch rather than modifying an existing event!

#

Master Sword is from JazzMinK's mod, sword pedestal and Deku Tree are from mine. We are having a fun time collaborating. πŸ™‚

#

I know %revealtaste is a thing, but is there a way to randomly pick a random NPC and item to reveal the taste of?

#

(thinking about letting the Deku Tree give insight on likes/loves/hates)

tiny zealot
#

you could probably do something about it if you abuse dynamic tokens enough

lucid iron
#

can u just let people talk to the big tree

river shale
#

error fixed, sorry to bug you guys 😦

latent mauve
#

I mean, I am already gonna be abusing random a bit

#

I figure there's a 75% chance the tree won't even talk to you because he's sleeping, LOL

#

The big tree is a map tile NPC

#

(it'd be cool to implement a hint feature for archipelago with him but I am not that code savvy to even begin to make a specific integration with archipelago)

hard fern
#

SDVpufferflat my greenhouse is cursed. actually cursed.

uncut viper
#

is it meant to be cursed?

hard fern
#

two people have reported the issue that when they go to sleep, they can't plant anything in the greenhouse the next day

#

but i could not replicate it

#

and of course nobody attaches a log

half tangle
#

no log no bug

turbid pawn
#

Is there some documentation I can read on how content packs for a specific mod are provided to that mod through the SMAPI?

half tangle
turbid pawn
#

Thanks

#

I'm making a mod that dynamically chooses between any number of assets that I'd like to be provided through content packs

lucid iron
#

the rec is to have custom asset ppl can editdata

turbid pawn
#

You got any documentation that's less instructional and more theoretical? I want to know what the file and data structures look like for a content pack

uncut viper
#

its json. if youre using content packs for your mod then you decide the structure

lucid iron
#

thats up to mod and anything newtonsoft.json accepts is fine

#

Dictionary<string, CustomDataModel> fairly common pattern

turbid pawn
#

So a content pack can't add arbitrary assets to My mod's assets folder?

uncut viper
#

i think you are misunderstanding what a content pack is

turbid pawn
#

*You

uncut viper
#

?

half tangle
#

you can put your assets into the game's Content and then mods can add to that. Then you can use that modified asset as you please

#

(following the example in the link I provided)

lucid iron
#

a content pack is for people making non c# mods to put in data as desired by mod handing the actual custom behavior

lucid iron
#

no ones putting any assets into my mod directly they provide it to the game's content pipeline and then i look at it

turbid pawn
#

And can assets be provided to the content pipeline by content packs without replacing or editing some other asset provided by the base game or another mod?

fading walrus
#

a content pack for content patcher is just a manifest.json to load in the mod, and then the content json and whatever other shenanigans that might need to be included
assets that add a unique thing to the game are possible and very common

lucid iron
#

yea the special asset i expect mods to edit is called mushymato.MMAP/QuestionDialogue

fading walrus
#

don't have to replace or edit existing game assets if that's not the goal

lucid iron
#

this one's a data asset, but ofc theres also texture assets and map assets

#

those can also have whatever name the content pack author desires, as long as my mod is told to use em via a data asset it's all good

fading walrus
#

(anyway, seems like there's a more complicated convo going on here than my sleep-deprived self is willing to partake in, so back to my stupid exam I go. Or maybe I should take a stretch break first...)

turbid pawn
#

Hmm. I think based on what you're all saying, the ideal solution would be to read a json included in each content pack, create extra asset folders and assets based on the content of those jsons, and allow the content packs to edit those assets I dynamically created.

lucid iron
#

no

uncut viper
#

that sounds like a very convoluted solution and im not even sure thatd work out with the timing

fading walrus
#

I'm not sure I'm following the solution here, to be honest

lucid iron
lucid iron
#

perhaps the Texture is actually several and perhaps theres option for sleeve i dunno

#

Condition is here to control when apply

#

perhaps the apply is actually via trigger action tho, might not even need a custom asset if trigger action args sufficient

turbid pawn
vernal crest
lucid iron
#

also goes to content pipeline

#

honestly go look at how Data/FarmAnimals work it should illustrate most of what i speak of

#

a custom asset is not really different from vanilla asset besides the fact that a mod added it blobcatgooglyblep

turbid pawn
#

Okay, so suppose someone writes a content pack that replaces the image at Characters/Farmer/Shirts/140/shirts.png
This file does not exist in the base game, nor will My mod create it. If a content pack replaces the file, will the file be created, such that I can then use it?

lucid iron
#

the file is created by using content patcher Load

#

like this

#

{{ModId}}/critters/rabbit (which resolves to mushymato.MMAP.Example/critters/rabbit) is arbitrary asset name i use

#

and then later i give this to my C# as a string

turbid pawn
#

Oh awesome. So if someone puts My mod ID in there, they could create an asset that the content pipeline believes is in My mod's assets folder?

lucid iron
#

no its just a string

#

and they should use their own mod id

turbid pawn
#

Can they use the game's content folder?

lucid iron
#

asset names aren't folders despite the convention to use /

#

merely string

#

coulda called this asset mushymato.MMAP.Example-critters-rabbit and it'd work same way

#

every mod has access to content, hence need to uniquely prefix so 2 mods arent both loading to rabbit

turbid pawn
#
"Changes": [
    {
      "Action": "Load",
      "Target": "Characters/Farmer/Shirts/140/Shirts",
      "FromFile": "assets/shirts/140/shirts.png"
    }]

So if a content pack does this, can I then call

this.Helper.ModContent.Load<Texture2D>("Characters/Farmer/Shirts/140/Shirts");

And will that load the texture provided by the content pack?

lucid iron
#

Yeah

#

But again pls use uniqueid somewhere

turbid pawn
#

Thanks

uncut viper
#

(you'd use GameContent, not ModContent)

#

the royal you
but remember if its a Content Patcher mod then you cannot get access to the content pack's files directly ever, if that still matters

#

(not without reflectiony means)

#

so you cant get the .png directly

turbid pawn
#

I just need a way to load textures from content packs, and a way to count and search the textures by type and number

lucid iron
#

Pls dun make contentpackfor without good reasons such as "i wish to replace content patcher"

lucid iron
#

And it allows some reuse

uncut viper
#

one solution would be to create a custom asset called MyUniqueID/Textures which is a string -> string dictionary, with content patcher mods adding entries to that asset where the key is their texture name and the value is an asset name (e.g. Characters/Farmer/Shirts/140/Shirts)
then you can load the entire dictionary at once and then load every texture

turbid pawn
lucid iron
#

I think if the earliest point the asset needs accessing is GameLaunched + 3 ticks then custom asset will do just fine PecoWant

#

Farmer aint getting drawn b4 then I hope

uncut viper
lucid iron
#

i dont trust anyone with cecil button

turbid pawn
#

My mod doesn't currently load any assets until a save is loaded. I'd like to find a way to load assets on the save selection menu, but that's a low priority I'd rather work on after I get to 1.0

uncut viper
#

i did not have cecil plans

lucid iron
#

Save selection menu is many ticks after game launch

turbid pawn
#

Yes

lucid iron
#

So it's fine no?

turbid pawn
#

Yes

#

Is there an ls for content pipeline assets?

lucid iron
#

Personally I do get that asset reuse is fairly unlikely for farmer body yggy

#

No

uncut viper
#

its not a file system once the game launches

lucid iron
#

That is why i suggest a list custom asset too

turbid pawn
# lucid iron Personally I do get that asset reuse is fairly unlikely for farmer body <:yggy:4...

No, it's very likely. I'm planning on supporting up to hundreds of farmer bodies. Currently I know of four farmer body content packs, and I'm planning on implementing two of them within this system. But I'm hoping My mod will encourage the creation of many more. I want to be able to support any number, that's why I was concerned about content packs replacing assets. Thanks for explaining the Load action in Content Patcher, it makes this a lot easier.

lucid iron
#

Yea np, though by asset reuse i mean more like Cursors

#

Where ton of stuff for unrelated things all belong to 1 asset

#

Farmer body, a very complicated bit of asset, is not usually gonna show up on a random tas kyuuchan_run

turbid pawn
#
"Changes": [
  {
    "Action": "EditData",
    "Target": "Data/Vi-'sModExtraTextures",
    "TargetField": [
      "Shirts"
    ],
    "Entries": {
      "140_{{ModId}}": {
        "Mod": "{{ModId}}",
        "Asset": "{{ModID}}/Shirts/140/Shirts"
      }
    }
  }
]
#

Like this?

lucid iron
#

If using TargetFields the Shirts key must exist (can be provided by the default asset ofc)

#

Cp tokens are {{this syntax}}

#

But the value resolved by the time it hits content pipeline

turbid pawn
#

So if the data file looked like

{
  "Bodies": [],
  "Shirts": [],
  "Pants": []
}

It would be all groovy, and I could have a central repository of all the shirt numbers added by content packs?

lucid iron
#

Yeah

turbid pawn
#

Thanks!

lucid iron
#

Could consider separate vimod/shirts vimod/pants vimod/bodies assets too

#

Becomes 3 different loads but removes need for target fields

turbid pawn
#

Is removing the need for target fields important?

lucid iron
#

Qol

#

If these 3 keys r always there anyways then why not is my feel

turbid pawn
#
"Changes": [
  {
    "Action": "EditData",
    "Target": "Data/Vi-'sModExtraShirts",
    "Entries": {
      "140_{{ModId}}": {
        "Mod": "{{ModId}}",
        "Asset": "{{ModID}}/Shirts/140/Shirts"
      }
    }
  }
]

Like this?

lucid iron
#

Yeah sure

#

It is anything goes so as long as the c# supports it and ppl have docs to read

turbid pawn
#

I want to do as much as possible with the C# code to reduce the amount of knowledge artists need to have in order to add textures. That's why I wanted to be able to search the content pack's files. So artists can spend less time editing JSONs and more time drawing

lucid iron
#

I think needing to Load a texture and then put the Target to some assets is well-known pattern

#

Since vanilla does this for many things

#

It does trip new people up sometimes ofc

turbid pawn
#

Yeah I've never made a content pack so I don't know what artists are used to doing. You're saying they expect to do something like this?

lucid iron
#

Yeah try doing a content pack that add a new object perhaps?

#

With new texture and all

#

Should make sense with hands on experience

turbid pawn
#

I'll be making content packs for My mod right away once I finish setting it up to read from content packs

fading walrus
#

content pack creator here (items) - we usually do the jsons ourselves, too, it's not new to do all of that. gotta do the work needed to get the shinies in the game!

the more prolific ones among our numbers have templates, even krobus_giggle

lucid iron
#

Some people who only do retextures don't necessarily know how ofc

turbid pawn
#

Awesome

lucid iron
#

Since EditImage is all that is needed

fading walrus
#

yeah some people do only editimage but adapting isn't too hard

#

just gotta read the docs

turbid pawn
#

I have a simple philosophy when it comes to UX design: People are dumb. Make it easy to do the right thing.

lucid iron
#

I think that's true of users but i got only the highest expectations for fellow modders kyuuchan_run

fading walrus
#

yeah, that's not really fair to expect so little of content modders πŸ˜…
we're not dumb, just working with a different set of tools, and most people work very hard on their stuff

lucid iron
#

Philosophy is provide more knobs so ppl don't have to ask me to expose more knobs later

fading walrus
#

there are a few lazy eggs out there but by and large people have sufficient Figure It Out in the community

lucid iron
#

But make the knobs optional

fading walrus
urban patrol
#

not a week goes by without me asking if some random thing is hardcoded haha

lucid iron
#

Game state queries are very versatile knob for example

uncut viper
#

i gave people the ultimate shiny with BETAS Harmony but chu still tries to offload ideas onto me for other things

fading walrus
#

(I do not expect much from the average mod user, mind. nexus comments are a depressing landscape these days and it is fair to assume low FIO from them)

turbid pawn
lucid iron
#

Yeah

uncut viper
#

to be clear, there is 0 way to actually require the modid

#

you can only strongly, strongly suggest it

lucid iron
#

This is intentional bc 2nd mod might wish to edit 1st mod

turbid pawn
#

Well I can make it so the asset doesn't load if they don't include a ModID, but let's suppose I don't do that.

lucid iron
#

They can just lie

uncut viper
#

you can, however there is no way to guarantee its their modid

lucid iron
#

I wouldn't worry that much cus {{ModId}} token exists

#

If the example packs all have this ppl tend to just copy and accept

turbid pawn
uncut viper
#

the second mod pack can just manually write the other mod id to overwrite it

lucid iron
#

I think the user should not install 2 mods that add shirt 140 monS

turbid pawn
#

Okay so I'm thinking I don't want the ModID to be part of the number key, and if two different mods add 140 shirts, that's a user problem and not something My code should be sorting out and choosing between.

lucid iron
#

It's more specifically a content modder problem

#

A vanilla example is like

#

I shouldn't add a NPC with internal Claire bc I'd be incompatible with older mods that also add Claire

#

Instead i add internal name chu.ClaireNPC_Claire

fading walrus
#

it's essentially the butter problem

turbid pawn
#

One content pack might want to add a 140 shirt for female characters, and another content pack could want to add a 140 shirt for male characters. In that case, I'm thinking it's the user's responsibility to choose between the two mods and uninstall or disable the one for the sex they're not using

lucid iron
#

I would hope the content packs use more descriptive names

uncut viper
#

no that is the content modders responsibility

lucid iron
#

Like chu.ShirtMod_MaleShirt1 or quill.VictorianShirts_FemaleTop

turbid pawn
fading walrus
#

bold of you to assume I have the skills to draw victorian shirts KEK
I'm flattered SDVpuffersquee

lucid iron
#

Just have an int field in the data model

#

I thought shirts have string ids tho do they not?

turbid pawn