#making-mods-general

1 messages ยท Page 24 of 1

lucid iron
#

til it also drew the price at transparent

brittle pasture
#

oh dang it is smaller

#

no the price just means you cant afford it

uncut viper
#

the price is just bc you cant afford it isnt it

lucid iron
#

ah right forgot its new save kyuuchan_run

sudden scroll
#

hm, no, that's not what I told you to do game

#

ExperienceCurve = new int[10] { 100, 338, 783, 1504, 2570, 4050, 6013, 8528, 11664, 15490 };

brittle pasture
#

update on my poop adventures: made them not fly in the air, but also learned that debris objects are not serialized, so if they aren't collected they'd disappear after exiting the game. oh well, I'll file that under 'intended'

teal bridge
#

If you really wanted to do otherwise, you'd have to hold the debris "precursors" in mod data and generate the actual debris just before warp.

#

(or just after warp, but presumably that's why they were flying)

brittle pasture
#

yeah if you just walk in and exit then you'd lose if after exiting the game (not after saving though, if you sleep and go in the next day they'd still be there)

drowsy pewter
#

tabbing in to see poop adventures and wondering what the hell i've been missing

lucid iron
#

maybe the building has mod data

#

so u can increment until player walks in

#

or autograbber ig

teal bridge
#

I figured you just wanted to make sure they were seen.

hallow prism
brittle pasture
#

the actual main consequence is probably with my 'machine multiple produce' feature integration with Automate, which dumps the excess produce on the ground if the chest is full, so inattentive farmers may lose some of the output if they don't check their sheds regularly

teal bridge
#

Has anyone tried writing a transpiler for a compiler-generated class/method? I know how to search the code instructions to find out what the generated name is, but only know how to do that from a transpiler, which seems too late to be registering an entirely different transpiler.

royal stump
#

(I used to spawn non-object forage as debris, but on top of that issue, mobile had its own DebrisManager that deleted them on warp in 1.4 SDVpufferdizzy)

#

no idea if that'll keep being true, but debris was notably slow and needed reworking at the time

lucid iron
#

hm you need to access method info basically, what kind of compiler generated thing is it?

brittle pasture
#

if SMAPI 1.6 mobile ends up being a thing I think I'd just respond to every mobile compat request/bug reports with a shrug emoji

teal bridge
#

Specifically it's part of an orderby clause. I can find it in ILSpy. But I don't feel like I should trust it to always have the same class/method symbol.

#

The signature itself does not really communicate enough; there are multiple methods with that signature.

#

I guess I have to use GetMethodBody().GetILAsByteArray(), don't I? Maybe Harmony has a public parser for that or something...

next plaza
#

(Mac+Linux variant was from .net framework+Windows / Mono+Mac_Linux days)

teal bridge
#

The type probably won't change, but I'm far less confident about the method name.

calm nebula
#

(PatchProcessor.GetOriginalInstructions)

#

Or something like that

teal bridge
#

Talking about junk like <GetFishFromLocationData>b__495_1 no idea what 495 is.

calm nebula
#

I know it's in patch processor, I know original instructions is part of it

teal bridge
#

Ah, that looks like it.

#

I found the MethodBodyReader and related stuff but they were all internal to Harmony.

#

Oh look, it has a ReadMethodBody too. Wonder why it didn't show up in GitHub's search.

next plaza
#

I'm going to take a wild uneducated guess that 495 is line number

#

I don't think Harmony for SMAPI is up to date, maybe it's not in most recent version?

teal bridge
#

See, that's what it looks like, but the source is definitely not on line 495. Or maybe that's just the decompilation.

#

In the decompilation it's all the way down on line 13739.

next plaza
#

Oh, hmm

teal bridge
#

Whatever it is, the numeric suffixes on those methods seem arbitrary, they are not sequential.

next plaza
#

Let me test something

teal bridge
#

For all I know it's some internal compiler counter that just increments by one every time it generates a new method (for any class).

#

In any case, Atra has come through again so I should be able to use that to spin up a codematcher and find the real class/method name. Or hopefully, if this is coming from Harmony, the operand will be an already resolved method.

next plaza
#

Think I figured it out - it seems to be based on the method index in the type

#

ie. I did this:

#

And got:

teal bridge
#

That makes sense (and confirms it's not exactly stable).

next plaza
#

I wonder if you could iterate through the typeof(GameLocation).Methods (or whatever the getter is for all methods) and do it that way

#

Doesn't sound very reliable though

teal bridge
#

Iterate through all methods and do what with them?

next plaza
#

Like, get the index of the method you want to patch in the "all methods" list

#

If they're even in the same order

teal bridge
#

Ah, gotcha. It might work unless C# literally changes the compiler behavior, which is less likely than having new methods inserted. But not really necessary given the ability to read the method body.

#

Once I get the CodeInstructions then I just write a CodeMatcher on it like any other transpiler (except using it to read rather than patch).

calm nebula
#

(My guess is that it has to do with whether or not there are captures)

teal bridge
#

Hm, I thought <c> was the holder, there can be another nesting level?

calm nebula
#

I've seen it both ways

#

Directly on the class or with a holder

calm nebula
teal bridge
#

I think the displayclass is used when any part of any method in the class captures, not necessarily the particular method being generated.

#

This one is an "instance" method but doesn't access any instance data.

calm nebula
#

Yeah, never sure

#

I think captures force a nested holder class but sometimes the compiler just wants one I guess

teal bridge
#

Actually yeah, there are some without the display class. So... who knows.

calm nebula
#

Whatever it is, it is considered like

#

Implementation detail of the compiler

#

And MS may want to change it at any time

teal bridge
#

That is true of course, but my more immediate concern was having things break with minor patch versions of Stardew. Even though Harmony mods are "caveat emptor", I'd still prefer not to have everything blow up with 1.6.9 and then again with 1.6.10.

#

Even if MS doesn't change the implementation, and CA doesn't change that particular method, these signatures might change.

lucid iron
#

can you patch around the method you think?

#

rather than directly do anything to it

teal bridge
#

No. But there's no problem, we've figured it out already.

#

Well, assuming I can wrangle a decent code matcher for the orderby itself, but that's a smaller problem.

teal bridge
#

Took about 15 tries but I think I got it. Yeesh, Linq is nice to write but sure is a pain to IL-weave. Ironic that I was just advising against attempting exactly this type of transpiler the other day.

plucky reef
#

how bad can harmony mess up your stuff? Just crashing the game, or can it actually damage your computer?

lucid iron
#

i doubt you can accidentally damage computer by being bad at harmony

#

it'll die with PAL_SEHException before that

tiny zealot
#

i don't know about damage the computer, but it is possible to bring it completely to its knees and force you to hard shutoff by eating all available memory (speaking from experience. dispose your textures!)

lucid iron
#

you can do that without harmony AnnelieStare

tiny zealot
#

fair play SDVkrobusgiggle

brittle pasture
#

usually Linux just kills the process when I make an recursive infinite loop, thank goodness

lucid iron
#

Oh rly I have to kill it myself

#

Ah yeah I usually just forgor to increment while lol

tiny zealot
#

oh, recursion sure. max stack size and so on

brittle pasture
#

yeah I clarified lol, infinite loops I need to kill, but it doesn't eat memory, just staying there spinning CPU cycles

lucid iron
#

I guess one could write malware in a C# mod think

#

Would hope that nexus virus scan can catch most of that

velvet narwhal
#

i need to throw together a 1.6.9 pack to test that new i18n/default folder SDVpufferwoke

teal bridge
#

But damage your computer? That's just silly Hollywood nonsense, no software can physically damage your computer unless you've already compromised the physical hardware in some way (like ripping out the cooling).

uncut viper
#

you dont actually need to call Advance for CodeMatcher repeat, just need to make sure whatever match action you're repeating isn't gonna re-match on what you just added, presumably

teal bridge
#

Ah. Well it actually happened twice, the first was doing Advance(-1) and actually modifying the instruction at that position, and the second was read-only. So yeah, both cases just looped. "Why isn't my breakpoint being hit? Wait, why isn't the game doing anything at all?"

vast rover
#

for some reason I cant get my custom recipe in the mail I dont know whats wrong with it

#

this is what I wrote in the mail

uncut viper
#

!json please upload your relevant json files and send the links here

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.

uncut viper
#

gonna need to see the content.json that you define the recipe in too, as well as whatever you're using to actually send the mail. is the problem that you can't get the letter at all, or that the letter does not have your recipe in it?

vast rover
#

the letter doesnt have the recipe when received

uncut viper
#

in that case then if your trigger action (i presume) you're sending the mail with is in a different file i dont think you need to upload that one, but it sounds like the ID of your recipe might be wrong in one location or another

vast rover
#

okok Ill try to check again

buoyant apex
#

And for a silly question, I'm wanting to modify some dialogue in questable tractor so it will match my gender swap mods:

would the dialogue file I need to edit be mods>Questabletractor>i18n>default

Then just change the names and gendered words to match what I have?

woeful lintel
#

If I make an asset Seasonal by using Content Patcher, will it trigger a Content.AssetsInvalidated event? the asset is data, so I have to cache some of it in my mod to avoid having to parse it every time I need info, I want to parse it only when it changes.

#

Seasonal would be either by having the path be "my_data_{Season}.json" or "When": {"Season": "Summer"}

lucid iron
#

CP invalidate depending on update rate yes

#

By default once a day

woeful lintel
#

thanks, that should be enough. Modders can change the update rate if they want to update it more often

uncut viper
lucid iron
# woeful lintel thanks, that should be enough. Modders can change the update rate if they want t...

do you have something along these lines

private static void OnAssetRequested(object? sender, AssetRequestedEventArgs e)
{
    // load the custom asset
    if (e.Name.IsEquivalentTo(MyAsset))
    {
        _data = null;
        e.LoadFrom(() => new Dictionary<string, MyModel>(), AssetLoadPriority.Exclusive);
    }
}

private static void OnAssetInvalidated(object? sender, AssetsInvalidatedEventArgs e)
{
    if (e.NamesWithoutLocale.Any(an => an.IsEquivalentTo(MyAsset)))
    {
        _data = RebuildCachedData();
    }
}
teal bridge
#

Seems like the null and Rebuild should be reversed there, no?

lucid iron
#

No cus we have to wait for content packs to apply all their changes

#

First event is equiv of blank json

brittle pasture
#

no? the rebuild call triggers the asset requested event

teal bridge
#

Well, it's more like _data = RebuildCachedData() should actually be part of a lazy loader, but setting to null should happen on invalidate. I don't know why you'd set it to null on asset requested in any case.

lucid iron
#

I think I actually left the loading part to a getter tho

#

Cus I didn't care to parse data beyond putting it in model

brittle pasture
#

yeah come to think of it you don't need setting null there.
if the _data variable is not touched anywhere else but these two events then I think you need to remove the null assignment

woeful lintel
#

I think so, my "cache" objects call GameContent.Load<JObject>(path_to_data) to parse the data and store its values, then it should clear the values and reload the data on invalidation

lucid iron
#

Oh this one is for use with Game1.content

teal bridge
#

Safest strategy would, I believe, be to clear your cache on asset invalidated, and load/cache it on demand, when it is actually accessed. Which is pretty much what SMAPI itself does.

woeful lintel
#

I need to reload it as soon as it's invalidated, because it's the data that defines Furniture

lucid iron
#

Game1.content.Load<Dictionary<string, MyModel>>(MyAsset);

teal bridge
#

I don't think you do; you just need to invalidate it on invalidated so that the next time it is requested, it is retrieved fresh.

lucid iron
#

Rather than directly get from file

teal bridge
#

That's what invalidation means; putting a "don't use this anymore" tag on it but waiting until you actually need it again before reloading it.

lucid iron
#

Since this is not for a mod that's a target of content pack for

#

It doesn't know what files other mods have

#

Rely on them load/edit a target instead

woeful lintel
#

Having it load the data "when it is needed" is kind of a pain in my case, I load it "once" so that I can access it anytime without having to parse it again, then I want to parse this data again if it was edited with CP

teal bridge
#

Why is it a pain exactly?

lucid iron
#

Just make a lazy load property

teal bridge
#

Whatever field you store the data in, make it a property and attach it to a load-and-cache method, that's all.

lucid iron
#

Then it's invisible blobcatgooglyblep

woeful lintel
#

because I have hundreds of lines already written and changing the design would be a waste of time

woeful lintel
round dock
#

Haiiiii question SDVpuffersquee say I wanna pull off a dialogue in an event and wanna do two alternatives: one is that they're married with kids and one where they're married but without kids. Would I only need to set the When condition for that?

woeful lintel
lucid iron
#

I was dum and did it manually (with a field + a property with getter)

#

Fix eventually

teal bridge
#
public Data Data => GetData();

private Data? data;

private Data GetData()
{
  if (data is null)
  {
    data = Game1.Content.Load(...);
  }
  return data;
}
brittle pasture
#

I was thinking of simply using a public getter that checks a private cached field, and reloads it if the cached field is null

teal bridge
#

Or you could use Lazy although that's normally meant for lazy initialization and not for repeated invalidation.

#

In my example above, you can add an InvalidateData() method that just sets data = null.

#

Whatever hundreds of lines of code are written for the loading/parsing/etc. shouldn't need to change.

#

(Chu is going to say that you can have a mutable Lazy field and write a new value to it, which you totally can; it's just not really the intent of Lazy)

lucid iron
#

u can do transformation into Data/Furniture in the getter I think

#

Or hm maybe u do it in AssetRequested too

#

But have the getter for data invalidate data furniture

#

So it cascades

woeful lintel
#

I'm sorry, I can't get to wrap my head around a new concept right now... I have difficulty seeing how to apply this stuff, I can't even make sense of the code snippets you're sending...

teal bridge
#

Loading in AssetRequested is definitely the easiest way to have SMAPI handling the caching and invalidation for you. But there might be reasons for keeping it private.

#

If you're going to be doing caching at all, then this is a pretty important concept to understand. Otherwise, you are basically doing caching wrong.

lucid iron
#

Yeah it's a bit different from the content pack for way

#

Since u r not handling any loading details, just letting CP do it

teal bridge
#

Forcing a reload on invalidate really isn't a nice thing to do; invalidation happens when SMAPI is trying to clean up after itself.

woeful lintel
#

my current situation is that I have the info about all custom Furniture from Furniture Packs in classes (including "included files"), because I have A LOT of transformation to do on the data to make it easier to compute player interactions, collisions and rendering when the game runs. This parsed data is also used when the game loads "Data/Furniture" and "Data/Shops" to populate them with the custom Furniture.

teal bridge
#

And lazy loading/load-on-demand changes none of that.

uncut viper
#

"I load it "once" so that I can access it anytime without having to parse it again"
i think the concept theyre explaining is just to move your rebuild step to the point that you're accessing it, not when you're loading it, if its null when you try to access it (which can be easily done by turning the method you're using to access it into a method that returns the data, instead of accessing the list/array/whatever directly)
assuming im understanding correctly
if you need to access it right away (for example if you want to update furniture in the world thats already placed, i suppose) then it ends up the same, but if you dont need to access it right away, then it saves some work

woeful lintel
#

well, my issue is that there are A TON of demands in the "on-demand" part of "load-on-demand"

teal bridge
#

Currently you have some Data field that you load into and are referencing everywhere; you merely change that to a property as per the snippet above.

#

It doesn't matter. The load only happens once.

uncut viper
#

if you never access the data after the invalidation, then you dont need to rebuild it right away, bc you're not going to access it
if you end up accessing it later, then the method that gets you that access will rebuild if necessary

lucid iron
#

So the api we r suggest is dependent on there being a custom asset in the content pipeline that u create (the Exclusive load in my asset requested example)

teal bridge
#

You can have 1 reader or 1000 readers, the lazy-loading code is the same either way.

vast rover
#

whats the difference between id and an itemid???

lucid iron
#

But I don't think that is a given for the content pack for stuff which just knows what files exist in dependent mods and can use em directly think

uncut viper
#

ItemId is just for items, ID is how to identify a specific entry in a data asset

teal bridge
#

(Technically there are exceptions in case of concurrency, which you generally don't need to worry about in any SDV loops unless you've deliberately written it that way)

lucid iron
#

I originally thought you are move stuff to CP custom asset so that is why I brought this up

brittle pasture
proud wyvern
#

Or there could be a utility class that handles all of that for you

teal bridge
#

I do understand what Leroy is saying, that there's a lot of data derived from the custom asset that isn't in the custom asset. The point I'm making is just, have the lazy loader run that entire pipeline, including both the loading and the derivations.

woeful lintel
teal bridge
#

You must be referencing the data somehow, though; through one field/property, or multiple fields/properties.

woeful lintel
#

If I clear the Furniture Type there's nobody to ask for the data

round dock
#

Thank you, chu/e e_yay

uncut viper
#

if nothing checks that class after setting it to null, though, then there doesnt need to be anyone to ask for the data anyway. but something must be checking that class, right?

lucid iron
#

You only have to invalidate the relevant vanilla data though

#

When game wants furniture data it'll get it

woeful lintel
#

My custom FurnitureType has all these fields (and the one with a custom class for type have some fucked-up parsing to do):

        public readonly string mod_id;
        public readonly string id;
        string display_name;
        string type;
        public readonly int price;
        bool exclude_from_random_sales;
        List<string> context_tags = new();
        int placement_rules;
        int rotations;
        bool can_be_toggled = false;
        bool time_based = false;
        
        DynaTexture texture;
        List<Rectangle> source_rects = new();
        public readonly Rectangle icon_rect = Rectangle.Empty;
        Layers layers;


        int frame_count = 0;
        int frame_length = 0;
        Point anim_offset = Point.Zero;
        bool is_animated = false;


        Collisions collisions;
        Seats seats;
        Slots slots;
        public readonly bool is_table = false;
        Sounds sounds;
        Particles particles;
        LightSources light_sources;

        PlacementType p_type = PlacementType.Normal;


        public readonly string? shop_id = null;
        public readonly List<string> shops = new();


        public readonly SpecialType s_type = SpecialType.None;


        Vector2 screen_position = Vector2.Zero;
        float screen_scale = 4;

        Point bed_spot = new(1);
        public readonly BedType bed_type = BedType.Double;
        Rectangle bed_area;

        Rectangle? fish_area = null;
        public readonly bool disable_fishtank_light = false;

        public readonly string? description;
teal bridge
#

These fields are all part of a class, though, are they not?

woeful lintel
#

yeah

lucid iron
#

This is basically the MyModel class in example

teal bridge
#

You only need to lazy-load/cache the class that contains them. Not every single field individually.

lucid iron
#

Are u loading to JObject and then assigning these by hand think

#

If the field names match u can just load right into the model class

teal bridge
#

I'm guessing stuff like Collisions have to be derived after loading the core data.

woeful lintel
#

and the class handles all the updates: every harmony patch on Furniture will ask the list of FurnitureType if there's a custom Furniture matching the current Furniture ID and the FurnitureType will apply the changes. If the FurnitureType isn't loaded, nobody will know it's missing, I don't understand how to do it other than reload all FurnitureTypes when their data is invalidated

woeful lintel
teal bridge
#

You cache and invalidate the list of furniture types.

#

Set the entire list to null on invalidate and put the entire list behind a lazy loader.

uncut viper
#

instead of having the patch ask the list, have the patch ask a GetList() method to give it the list

#

GetList will load it if it doesnt exist

#

(along with what focustense said of nulling the list itself and not the types)

teal bridge
#

What I'm calling Data could be:

public class FurnitureData
{
  public List<FurnitureType> FurnitureTypes { get; set; } = [];
}

And then you clear the entire FurnitureData.

woeful lintel
#

well, it will load it in the next frame after the invalidation then, what's the point of not loading it right after the invalidation?

teal bridge
#

How do you know it would be the next frame?

uncut viper
#

does your harmony patch run every frame?

woeful lintel
#

yeah, it changes Furniture.draw lmao

#

and collisions

teal bridge
#

Not every map has furniture, though.

#

There's no furniture in the Mines.

woeful lintel
#

fair enough

lucid iron
#

You will have it by the time you draw tho, because you called GetList()

uncut viper
#

the point is not that it will help significantly really, bc you are correct that it will happen basically right away if there is a furniture, if it happens in the draw method

#

but its free cpu cycles to save when it doesnt happen right away

#

and nice practice besides

teal bridge
#

(FWIW, I wouldn't harp on this for any old mod, but since this is a framework mod that many other authors are expected to use, performance, timing and memory usage should be tight.)

woeful lintel
#

ok, I think I get it know, I'll look into it. Since I'm doing a huge revamp update I'll probably do this too

uncut viper
#

(nice practice bc ofc there are a lot of situations where it actually can be significant, even if this specific one isnt always one of them)

woeful lintel
#

I hate my FurniturePack loading system so much, I don't want to touch it again...

uncut viper
#

i think unless you're a true savant i feel like everyones been there, having stuff they wrote initially and hated later

teal bridge
#

You can always ping/ask for additional help. What we're all saying is that switching to a lazy loader isn't actually a big change as long as you have one "loader" right now (vs. a big pile of spaghetti code, which hopefully is not the case).

lucid iron
#

The approach I took for the trinket thing I am make is to make the data class a field on the behavior class

teal bridge
#

If you find that this seems to amount to a major rewrite, then either we've misunderstood the problem or we didn't explain the solution well enough, because it shouldn't be too big a deal.

lucid iron
#

Fancier parsing of data can happen in constructor of the behavior class instead of the data class

#

Tho I'm not doing anything particularly fancy LilyDerp

woeful lintel
woeful lintel
teal bridge
woeful lintel
#

(Stardew breaks all conventions everywhere)

lucid iron
#

It's mostly checking whether a buff id exists

#

Unsure what is best way to abort constructor actually

teal bridge
#

Validation of arguments is fine of course, and expected.

uncut viper
#

just take a page from the collections menu constructor. do literally almost fuckin everything in there.

teal bridge
#

I assumed "fancier parsing" meant like, deserializing a JSON in a constructor or something. That should be done outside the ctor.

lucid iron
#

Nope that's what the data class is for

#

And the net event ig

teal bridge
uncut viper
#

i mean you can at least separate it out to different functions

teal bridge
#

You can; but in terms of where the functions are actually called from, you typically have two choices: the constructor, or draw.

#

And you don't want to do a lot of work in draw...

woeful lintel
#

2000 lines function FTW

uncut viper
#

might also help to not have to call DataLoader for Mail and SecretNotes every single time you construct it too, but c'est la vie

lucid iron
#

Should probably put AssetInvalidated

teal bridge
#

DataLoader is cached though, despite its name.

teal bridge
#

Yes, the clickable menu's "interesting" hover API.

lucid iron
#

Not sure when we would use AssetReady, it only seems to go once around game launch

teal bridge
#

What's missing are basic lifecycle methods like OnShown and OnLayout.

#

But Stardew has no layout system, or really any visibility system, so...

brittle pasture
#

but yeah the wiki example is misleading, since you really only get the ready event firing after you start a Load call

teal bridge
#

Would make sense that "ready" = "loaded".

lucid iron
#

It doesn't seem to trigger on invalidate though think

uncut viper
#

wait i forgot AssetReady was a thing does that mean i dont actually have to manually wait like 4 ticks for content patcher to load content packs in order to load my asset

teal bridge
lucid iron
#

I vaguely remember no, but that was many commits ago and perhaps I was just doing it wrong

brittle pasture
uncut viper
#

oh AssetReady doesnt do what i thought it did
"Raised after an asset is loaded by the content pipeline, after any mod edits specified via AssetRequested have been applied.

This event is only raised if something requested the asset from the content pipeline. Invalidating an asset from the content cache won't necessarily reload it automatically. "

uncut viper
teal bridge
#

I would assume an event like that is for when you have some data or behavior that is dependent on the loaded asset, and it's expensive to compute.

brittle pasture
brittle pasture
teal bridge
#

Technically anything you implement with AssetReady could also be done with a lazy loader, but you might be incurring the cost at an awkward time.

uncut viper
brittle pasture
#

I mean like after CP patches your assets, it should invalidate it, and you should start a fresh load

teal bridge
#

Erf... yeah, loading data on game launch sounds like it could lead to consistency issues.

uncut viper
#

is that not the same as waiting, just with an event instead?

lucid iron
#

I wonder why I was getting 0 things in custom asset back then

#

Will revisit it

uncut viper
#

i know i have to wait for CP to patch my assets, i was sayin i thought AssetReady would be a better way to do it than manually waiting a number of ticks

teal bridge
#

That is exactly what AssetReady is for, AFAICT

uncut viper
#

AssetReady is only when something is requested by the pipeline

#

if its not requested (which it wouldnt be for my custom asset besides from myself) it wont fire

lucid iron
#

maybe just do it on save loaded

uncut viper
#

well, in this case, the asset im loading is my CP harmony patches.... which you might want before a save is loaded

#

hence, the quickness to load them

teal bridge
#

Oh, this is your freaky harmony thing, haha

uncut viper
teal bridge
#

Yeah, there may not be a good answer to that

lucid iron
#

But now you can prank people by having patches that only apply if farm name = selph

brittle pasture
#

yeah, if you're doing work before a save load then I see why you need to wait for CP

lucid iron
teal bridge
#

The problem is that on Entry/GameLaunched, SMAPI/CP may not have actually finished setting up the pipeline.

#

You might be able to fiddle with priorities.

brittle pasture
#

SDVpufferthink I wonder if we can beg ask for a "CP done its thing" event

uncut viper
#
private void OnUpdateTicked(object sender, UpdateTickedEventArgs e)
{
if (e.IsMultipleOf(6) && !DynamicPatcher.IsInitialized)
  {
    DynamicPatcher.Initialize(ModManifest);
    Helper.Events.GameLoop.UpdateTicked -= OnUpdateTicked;
  }
}

this is how im doing it right now. i only chose 6 cause i had vague memories of reading about CP being ready on the 4th tick but i went with 6 just to be safe or something

brittle pasture
#

but then some other C# mods might modify your assets or smth

uncut viper
#

i sincerely hope no other C# mod is modifying my CP harmony patches asset

royal stump
#

Pathos has mentioned it's basically ready at second tick or so ^

lucid iron
#

Maybe this is a case for content pack LilyDerp

#

If you never want 2 mods editing the same patch anyways

teal bridge
#

What happens if some other mod Harmony-patches the DynamicPatcher itself?

uncut viper
#

then to them ill say good luck

#

you can harmony patch DynamicPatcher with DynamicPatcher via CP if you really want, too

teal bridge
#

Yes, but it's probably too late by then.

uncut viper
uncut viper
royal stump
#

I think so, but it's been a while since I checked

uncut viper
#

if you harmony patch the function that unpatches the harmony patch... hm

brittle pasture
#

forget shotguns, this feels like discussing nuclear warheads

uncut viper
#

ill be honest as long as it works for any reasonable use case im just gonna consider any potentially weird fucky cases that cause issues to be "look, just do something else, please, i might get to this eventually but why" in terms of priority

teal bridge
#

I take some perverse pleasure in imagining how people can screw everything up.

uncut viper
lucid iron
#

Are you going to make a white list of things ppl r allowed to touch

uncut viper
#

if you harmony patch AssetInvalidated then you guarantee no one will mess with your CP harmony patches, right

teal bridge
#

In the fishing mod, I've encoded every hardcoded rule as a NoInlining property getter so that just in case some other mod is doing obnoxious things like changing the start/end of the day, I can say "welp, you write the compat patch, just Harmony this here method".

#

(Also, doesn't SMAPI forbid reflection or Harmony patching on itself?)

uncut viper
# lucid iron Are you going to make a white list of things ppl r allowed to touch

truth be told the implementation of the more advanced kinds of patches is taking me long enough that its not gonna be released for a while anywya (if at all, assuming i dont get bored before then) so to start all you'll be able to do is change results (assuming they are simple types like ints or bools) and run trigger action actions anyway, which you cant really do much damage with

#

i mean, you can obviously do a lot of damage if you change the result of a critical function, but again, reasonable use case

next plaza
uncut viper
teal bridge
#

Array.Length is now Array.Length + 1

uncut viper
#

oh, with SMAPIs t hing, that makes sense

teal bridge
#

Should be fine. No problems.

next plaza
#

Iโ€™ve definitely patched and reflected into SMAPI before (using normal reflection for the latter)

teal bridge
#

Yeah, come to think of it, I have too in the radial menu

next plaza
#

The patching SMAPI was for my 3D mod if I remember correctly

#

Reflection Iโ€™ve done for multiple mods

teal bridge
#

I had to yank at the input helper because of the trigger inconsistencies.

#

Though I did it with just normal reflection, not Harmony.

uncut viper
# teal bridge `Array.Length` is now `Array.Length + 1`

this is actually like the main sort of thing thats taking up most of my "hm, how do i wanna implement this" time, is trying to figure out how to easily get the property of an object like that. like, loading up just Game1 is fine, but its not exactly easy to come up with a CP-author-friendly way to access Game1.player.LuckLevel for instance. the drilling down into different properties, turns out, is kinda difficult when you need to turn a string into IL

#

like, not impossible, obviously, but defnitely a "why am i spending effort on this again?" kind of tedious task to figure out

teal bridge
#

Yes, and doubly so once you realize that most content authors are not programmers and won't understand anything that even remotely resembles code.

#

But I meant like, actually patching Array.Length to return the real length + 1, which I imagine would instantly break everything.

uncut viper
#

Lookup Anything can help with some things, since you can see a lot of properties on things when you inspect em

#

oh i thought you were using Array as like a variable name placeholder. yeah what you said is much much worse lmao

teal bridge
#

Or someone transpiles StringBuilder.Append to reload a map asset.

royal stump
#

(ps re CP being ready, all of its APIs also have this, which should confirm the timing)

/// <summary>Whether the conditions API is initialized and ready for use.</summary>
/// <remarks>Due to the Content Patcher lifecycle, the conditions API becomes available roughly two ticks after the <see cref="IGameLoopEvents.GameLaunched"/> event.</remarks>
bool IsConditionsApiReady { get; }```
uncut viper
#

i could limit it to the Stardew Valley namespace if i wanted to, but wheres the fun in that?

brittle pasture
uncut viper
royal stump
#

I'm not entirely sure when the API helper becomes ready either SDVkrobusgiggle

next plaza
#

Games launched

uncut viper
#

when IsConditionsApiReadyApiReady is true, obviously

teal bridge
#

Even if you could patch the ID property of an Item, it wouldn't be consistent with the ID-to-item dictionary (ItemRegistry and related assets) so... I hope you didn't actually do that.

royal stump
#

SDVpufferthumbsup makes sense but it's been ages since I added a new one

brittle pasture
#

thankfully I didn't, I went with a vastly simpler (and safer) method - just add a button to toggle the item between various forms

#

so I can use the 4 butters and 3 olive oils interchangably

teal bridge
#

We can always use moar buttons.

uncut viper
#

me when i try to cook

teal bridge
#

Olive oil's a dressing, I wouldn't be caught dead cooking with it. /ot

brittle pasture
#

smoke point's a myth, I sear all my steak with extra virgin olive oil

uncut viper
#

this just brings back to my mind my firm belief that SDV really needs a Cooking Mama style culinary mod

teal bridge
#

Haha. Not that there aren't like, ten million recipes on the internet saying "throw a bunch of olive oil on/around this thing and then bake it at 400ยฐ".

"HOW ABOUT NO" - Dr. Evil

teal bridge
uncut viper
#

i think Better Cooking would align more with SDV mod names personally

brave fable
#

way too much art SDVsandwich

teal bridge
#

Immersive in the sense that you must actually wait 45 minutes for that cheesy broccoli, and check in on it every 15 minutes.

uncut viper
#

and a feature that if you're waiting on something to boil, in game time moves slower

teal bridge
#

I was sure there was already a "better cooking" but apparently I was wrong.

uncut viper
#

theres Love of Cooking and one other one i cant remember the name of i think

brittle pasture
#

well Better Crafting includes Cooking...

brave fable
next plaza
#

Blueberryโ€™s back!

#

Hiiiiii (canโ€™t recall if my name change was before or after you disappeared)

brave fable
#

i wouldn't go so far as that lol

#

but i am here

brittle pasture
teal bridge
#

If it were realistic, you'd catch 2 fish in 12 hours. Realistic, just not fun.

brittle pasture
#

the same magic that makes crops grow super fast in the valley probably also makes fish swarm its rivers and oceans

teal bridge
#

All can be explained with Junimo Magic.

#

I should start using that as an explanation for every questionable mod feature. "It's not cheating, it's Junimo Magic."

dusty scarab
#

Junimo Magic got rid of my crows! thanks, Junimo Magic!

teal bridge
#

Diamonds grow on trees. Fish gift you pizzas. Why not?

dusty scarab
#

I mean, that would be hilarious as a fish pond output item. however, because the Fish have a sick sense of humor, every pizza is topped with Anchovies.

inland cedar
#

just tested with your example pack and it still good as it should be

half stone
#

guys please help. i want to install smapi for steamdeck and this happening ๐Ÿ˜ญ

round dock
woeful lintel
dusty scarab
#

does anyone know where I can find the artwork for trees in the game files?

hallow prism
#

wild or fruit?

dusty scarab
#

wild

hallow prism
#

content/terrainfeatures

#

the one you plant from seeds. The ones on map are on their map tilesheet

dusty scarab
#

awesome, thank you so much!

uncut viper
woeful lintel
spice inlet
#

Not too happy with how the bundle name is presented quite yet.

#

It could use a name plaque of some sorts

vernal crest
#

Yeah it is a bit hard to make out properly. The rest of it looks really good though.

silver pelican
#

guythu, how do i add a condition where the mail is received by the player once it reaches a certain friendship level with an npc?? Im trying to do it with cp.
"phfood.Adobo": "[letterbg 0]{{i18n:nova.adoborecipeLewis.text}} %item cookingRecipe {{ModId}}Adobo %%[#]{{i18n:nova.adoborecipeLewis.name}}",

vernal crest
hallow prism
#

(there's also a way to set the recipe to have a friendship level as requirement, which will then send it BUT it'll use the default mail for this character)

silver pelican
#

thank you! @vernal crest @hallow prism

silver pelican
#

btw does it matter which one i load first?
i went for : loading sprite, recipe data/object, adding recipe in data/CookingRecipe, data/shops, data/trigger actions, data/mail?

drowsy pewter
#

do any of the C# people know-- would there be any significant downgrade in performance if I used Content Patcher to apply 200 different patches to a data model at the same time as opposed to grouping them into a few patches? For example, adding 200 objects separately each with its own When conditions (typically a combo of config+HasMod) vs sorting all the object entries into ~5-8 patches only, with each patch adding the objects grouped under it in entries.

lone ice
#

Morning everybody, I'm hoping someone will have an answer to a problem I'm having! I added a map patch for this area but something is programmed in to make it so you can't walk on these tiles and the NPC can't move on the water, even though they're all Back layer. I thought maybe it was Passable as a tile property that was the problem but I'm not sure how to turn that off if that's what's causing it. Is it something I would program into the tile properties on the sheet itself in Tiled? or in content patcher?

hallow prism
#

passable on back makes it non passable

#

not sure i would want to have my npc walk on water however, sounds like it could cause issue

lone ice
#

I need some way to do it or a mermaid doesn't work ๐Ÿ˜ฆ

#

But in this case you can't even walk onto the shore

#

which is why I think they used Passable

#

I'm asking if there's a way to turn that off

hallow prism
#

using tiles without the passable property

lone ice
#

would I be able to see that property here if it's the problem:

hallow prism
#

i believe so

lone ice
#

then that's not the issue

hallow prism
#

ok!

spice inlet
#

Better SDVpufferthinkblob

hallow prism
#

looking nice!

#

is it a custom pack you're making or a framework update?

spice inlet
#

framework update

#

this is one of the demo bundles I created for testing

hallow prism
#

cool! if you feel like giving details i'm curious. I am also able to wait (or so i heard) if you prefer ๐Ÿ˜„

spice inlet
#

The idea is to have bundle books that are collections of bundle pages

#

only when all pages are completed will the book be completed

#

that way you can have more demanding (and fun) bundles without having to worry about rewards for every single page

#

it'd also be a neat way to organise a lot of smaller bundles

hallow prism
#

i see! would page have their own reward still (optionally)?

spice inlet
#

yes

#

with gift box and all ๐Ÿ˜„

hallow prism
#

hmm, maybe i'll consider "merging" VMV bundles

spice inlet
#

that'd work

silver pelican
#

okay, so, im not sure what's going on but the i dont receive the mails even when the condition has been met.

        //mail trigger
        {
            "Action": "EditData",
            "Target": "Data/Mail",
            "Entries": {
                "phfood.Adobo_Lewis": "[letterbg 0]{{i18n:nova.Adobo_Lewis.text}} %item cookingRecipe {{ModId}}.Adobo %%[#]{{i18n:nova.Adobo_Lewis.name}}"
            }
        },

        {
            "Action": "EditData",
            "Target": "Data/TriggerActions",
            "Entries": {
                "{{ModId}}.AdoboMail": {
                    "Id": "{{ModId}}.AdoboMail",
                    "Trigger": "DayStarted",
                    "Action": "AddMail Current phfood.Adobo_Lewis now",
                    "Condition": "PLAYER_HEARTS Current Lewis 5"
                }
            }
        },
``` no errors in the console as well. tried to debug action remove mail and the recipe as well (even when it's not been registered in my kitchen) but mail still didnt trigger.
hallow prism
#

you already triggered the trigger action maybe

#

try marking it unapplied too

silver pelican
# hallow prism try marking it unapplied too

to make it unapplied, i did debug action MarkActionApplied Current Novaphene.PHFoodies.AdoboMail false then it said

[game] Trigger action 'Novaphene.PHFoodies.AdoboMail' has action string 'AddMail' which couldn't be applied: required index 1 not found (list has a single value at index 0).

other than that, i tried to AddMail for it to appear only to have the mail icon appear but it doesnt trigger any actual mail/letter.

hallow prism
#

(i prefer no ping on reply)

#

you need to find what the error is and fix it then

silver pelican
terse plank
#

I'm trying to convert my mod into the new format, and probably found out how to add the new items as gift tastes: Example

        "Operation": "Append",
         "Target": ["Fields", "Elliott", 1 ],
        "Value": "Quirinea.JADistillery_Long_Drink",
        "Delimiter": " "
     },```
(putting an example of my attempts here so maybe they help someone else; maybe it should rather be ``` {{ModId}}_Long_Drink``` , but that seems to work neither). I tried to put tastes as a long list (with whitespace as delimitor, and that did not work, only the **last** one was picked.  
But now I'd like to have some unique responses for certain gifts (originally changed Kent's loved gift response "My mom used to give me this when I was little" or the like, very unsuitable for booze!) but this doesn't work. Neither the format I used in the piece above:
   ```{
       "Action": "EditData",
       "Target": "Characters/Dialogue/Kent",
       "Entries": { 
           "AcceptGift_{{ModId}}_Aged_Snow_Gin" :
             "{{i18n: Quirinea.KentLove}}"
       }
   },```
This works, so it is not an obscure syntax error
  ``` {
       "Action": "EditData",
       "Target": "Characters/Dialogue/Kent",
       "Entries": { 
              "AcceptGift_category_fish" :
             "{{i18n: Quirinea.KentLove}}"
       }
   },```
What is wrong?
drowsy pewter
#

hey try flanking your code with ``` on either end to prevent the italics and missing characters

#

in the discord message i mean

#

i cant help with unique gift responses since i havent done it but if you show me what you were trying to do for the long list of gift tastes i can correct it, since that should have worked

terse plank
#

Should they be all on the same virtual line? I saw someone else's mod with added gift tastes and they had used separate entries; I thought it should work with combined ones and got no error messages, but only the last entry taken. I had them each in a line. Actually if they cannot be like that, I rather make separate entries! having umpteen entries on a single line messy list is horrible to check and edit. I had them like this:

        "Operation": "Append",
         "Target": ["Fields", "Elliott", 5 ],
        "Value": "Quirinea.JADistillery_Aged_Bourbon_Whiskey
                  Quirinea.JADistillery_Bourbon_Whiskey
                  Quirinea.JADistillery_Rice_Vodka",
        "Delimiter": " "
     },```
This gets quickly unreadable:
```{
        "Operation": "Append",
         "Target": ["Fields", "Elliott", 5 ],
        "Value": "Quirinea.JADistillery_Aged_Bourbon_Whiskey Quirinea.JADistillery_Bourbon_Whiskey Quirinea.JADistillery_Rice_Vodka",
        "Delimiter": " "
     },```
I tried putting "Values" instead of "Value" and that wasn't correct.
drowsy pewter
#

it may be because you're separating them on separate lines instead of only separating with a space

#

and please do use the ``` symbols around your code

#

As for some other thing you commented on earlier, it doesnt matter if you write Quirinea.JADistillery or {{ModId}} since it will be the same outcome eithe way

woeful lintel
#

!embedcode

ocean sailBOT
#

You can embed code in Discord using a series of three ` :
```
Your code can go here
Even if not a haiku
Just an example
```

For syntax highlighting, add the language code on the same line as the first
``` (with no space, like ```json).
The usual codes are cs (C#) and json.

terse plank
#

Sorry for technical mess. It is three backquotes, isn't it? Seemed to work after I copied them from your message, @drowsy pewter

royal nimbus
#

i need help locating a file. im looking for the traveling merchant's portrait but i cant seem to find it. i looked for it several times in the portraits folder but havent found it. is it else where?

drowsy pewter
#

its not vanilla

#

you're either thinking of SVE, VMV, or they deserve it too

royal nimbus
#

oohhh okay.

#

if i want to make a portrait for a character that doesnt have one, how would i go about that?

#

i just hope its not too complex to do

lucid iron
royal nimbus
#

ty. i will check this out

#

oh these are so cute ;o;

#

now i want to make some for them all too lol

lucid iron
#

I think this mod does have C# component

royal nimbus
#

my heart. i cant.. these are too precious. the mouses

#

yeah i just need to see the json stuff

#

ugh its prob gonna need some complex coding. rip

ivory umbra
#

In c# is there a way to change the color of the placement indicator from red to green (like when holding tree fertilizer)?

lucid iron
#

I think that's a sprite in cursors

royal nimbus
#

oh im seeing some easy looking json code stuff ;ooo

#

ty again for the share

lucid iron
#

You would need to make your mod dependent on this mod I believe

drowsy pewter
#

most of it is achievable with cp

#

depends on the npc

half stone
# woeful lintel `sudo` before the command to install?

A fresh #SteamDeck modding intro for #StardewValley. Since my original guide was outdated with unnecessary tweaks.

Buy from Humble Store with my partner link to support the channel: https://www.humblebundle.com/store?partner=gamingonlinux

Follow me in these places:
Mastodon: https://mastodon.social/@gamingonlinux
Twitter: https://www.twitter.c...

โ–ถ Play video
#

iam using this method bro and this happening permission denied

drowsy pewter
#

this is for making mods

half stone
teal bridge
# drowsy pewter do any of the C# people know-- would there be any significant downgrade in perfo...

Content patcher uses several different dictionaries and SortedSets to preserve its performance even under non-ideal conditions like patches being frequently added/removed, so I'd be inclined to say performance won't be much different as long as the two patches are actually doing the same total amount of work (adding same entries to same lists, etc.). It does this caching both at the asset level and at the token level from what I can tell. By "total work" I mean "difference between original game data and data after all patches are applied" regardless of the exact distribution of the work.

There's going to be some added cost because even hash lookups are not free and you're doing more of them, but this is likely not significant enough to worry about; what matters more is (a) update frequency and (b) which assets are patched in each update.

silk wedge
#

Quick question, are there any popular known mods that use this little area (the cliffs next to the playground) for any warps? Thinking of editing it so I can put my npc home here

teal bridge
#

Aren't there vanilla NPCs who path through there, like Jas/Vincent/Penny? Are you going to edit their schedules?

hallow prism
#

i would also suggest, if you do it, prepare backup plans in your mind

#

lot of modders try to find way to be in the valley and there's definitively situations of two modders wanting warp in same area

#

i decided to not be in the valley at all, to avoid most conflict, but for people doing it, i think it's good to keep in mind that you may never hear of a project before it's released RIGHT where you'd like to be

silk wedge
silk wedge
hallow prism
#

it has pro and con, so it's about seeing which ones matter the most

ornate trellis
silk wedge
#

I might just stick with going the bus route then, seems a little easier LOL

calm nebula
#

What's worse

#

Real estate in the valley

#

Or real estate in California

ornate trellis
#

tbh originally i went with a lil pseudo way in the cliff like this but i will probs just add the sign and make it so you warp when you touch it or w/e cuz thats way easier lmao

#

with just a sign that would make it even easier to slap anywhere on a cliff or something lol

#

but i think i saw someone else wanting that spot too idk who it was tho

silk wedge
#

if that's the case i can probably just stick it somewhere in the forest or something ...

ornate trellis
#

yeee, tbh i tried this sliff thing since i wanted to have the illusion people walk past there but ehhhh

#

but itll be a good while till i work on the nun more anyway since I am doing my big Fishmonger update first

#

That said, ealier I had though about version numbers again and ive been wondering....I basically turn my npc mod into a lil expansion with 4 more npcs, new locations etc...so would it make sense to go from 1.3.8 to 1.4.0 or actually 2.0? I know at the end of the day i can decide that for myself but, hm

#

aka would this update count as mayor or still just minor thonking

silk wedge
#

that def sounds major omg..... so much stuff

hallow prism
#

2.0.0

#

technically the update convention thing has a whole reasonning about the numbers

#

for frameworks it matters more

#

for content packs you basically do whatever feels right, and marketingly speaking, a big change like that is definitively worth being labeled as 2.0.0

ornate trellis
#

yeah, makes sense. I always like to ask first cuz i usually eyeball with my stuff xD

gaunt heath
#

(spotted this while searching messages for something else, those tilesheets are in fact just .pngs. Do with them what you will, they're uploaded like that because someone else wanted them. It was supposed to be a temporary solution, but you know how that goes. Eventually I will replace them with a proper tilesheets mod with a manifest, but I'm extremely busy and barely active)

#

I know you were looking about five million years ago, but that's the timeline I'm on these days ๐Ÿ˜…

forest moat
gaunt heath
#

They're up there to be freely used! I'm glad you got some use out of them! I work full time and study, so my activity here and nexus is sporadic at best. I mostly just hang out in a smaller stardew server and get nothing done lol

#

They've been up for a long time now, I think you're the first person I've seen get use out of them!

#

I'm off to go check out your farm map SDVpuffersquee

sudden scroll
#

๐Ÿค” why is only one of my professions selectable?

#

I don't see any meaningful difference between my code and that of Archaeology or Cooking skills

teal bridge
#

That's probably going to be hard for anyone to answer unless you post the code.

sudden scroll
#

I mean

#

I don't know what part of the code to post lol

final arch
#

is it a spacecore skill?

sudden scroll
#

I'm using SpaceCore, I don't know what could be affecting this

final arch
#

is only one highlighted?

sudden scroll
#

yep

final arch
#

or does clicking to nothing either?

sudden scroll
#

Rain Dish is selectable

#

I'm adding all the professions correctly afai can tell ```cs
private void AddProfessions() {
Professions.Add(ProfCache.prof5a);
Professions.Add(ProfCache.prof10aa);
Professions.Add(ProfCache.prof10ab);

Professions.Add(ProfCache.prof5b);
Professions.Add(ProfCache.prof10ba);
Professions.Add(ProfCache.prof10bb);

ProfessionsForLevels.Add(new(5, ProfCache.prof5a, ProfCache.prof5b));
ProfessionsForLevels.Add(new(10, ProfCache.prof10aa, ProfCache.prof10ab, ProfCache.prof5a));
ProfessionsForLevels.Add(new(10, ProfCache.prof10ba, ProfCache.prof10bb, ProfCache.prof5b));

}```

plucky reef
sudden scroll
#

ProfCache, fwiw: ```cs
public static class ChildIDs {
public static readonly string name = $"{ID}-name";
public static readonly string short_name = $"{ID}-name-short";
public static readonly string per_level = $"{ID}-per-level";
public static readonly string prof5a = $"{ID}-5a";
public static readonly string prof5b = $"{ID}-5b";
public static readonly string prof10aa = $"{ID}-10aa";
public static readonly string prof10ab = $"{ID}-10ab";
public static readonly string prof10ba = $"{ID}-10ba";
public static readonly string prof10bb = $"{ID}-10bb";
}

public static class ProfCache {
public static bool initialized = false;

public static BaseProfession prof5a;
public static BaseProfession prof10aa;
public static BaseProfession prof10ab;

public static BaseProfession prof5b;
public static BaseProfession prof10ba;
public static BaseProfession prof10bb;

public static void InitProfessions(Skills.Skill skill) {
    prof5a = new BaseProfession(skill, ChildIDs.prof5a, "5a"); // Rain Dish
    prof10aa = new BaseProfession(skill, ChildIDs.prof10aa, "10aa"); // Free Rain
    prof10ab = new BaseProfession(skill, ChildIDs.prof10ab, "10ab"); // Rain Meal

    prof5b = new BaseProfession(skill, ChildIDs.prof5b, "5b"); // Tailwind
    prof10ba = new BaseProfession(skill, ChildIDs.prof10ba, "10ba"); // Tail Hurricane
    prof10bb = new BaseProfession(skill, ChildIDs.prof10bb, "10bb"); // Wind Turbine

    initialized = true;
}

}```

teal bridge
# calm nebula Or real estate in California

Definitely California. Real estate in the valley may be scarce, but it is cheap. Like, 100,000g to put in a cellar might sound like a lot, but that's only the cost of 1000 apples or 2 cookbooks. Imagine being able to buy a house for that in San Francisco.

#

What class is BaseProfession above? I don't see that in SpaceCore.

sudden scroll
#

just a smol wrapper ```cs
public class BaseProfession : Skills.Skill.Profession {
public BaseProfession(Skills.Skill skill, string id, string name) : base(skill, id) {
Icon = helper.ModContent.Load<Texture2D>($"assets/skills/{name}.png");
}

public override string GetName() {
    return helper.Translation.Get($"{Id}-name").Default($"{Id}-name").ToString();
}

public override string GetDescription() {
    return helper.Translation.Get($"{Id}-desc").Default($"{Id}-desc").ToString();
}

public Action OnAdded = () => {};
public Action OnRemoved = () => {};

public override void DoImmediateProfessionPerk() {
    OnAdded();
}

public override void UndoImmediateProfessionPerk() {
    OnRemoved();
}

}```

#

basically just standardizing the i18n and icon names

#

the OnAdded/OnRemoved isn't even used ๐Ÿ˜›

#

Here's the actual constructor fwiw ```cs

public WeatherWitchSkill() : base(ID) {
if (!ProfCache.initialized) ProfCache.InitProfessions(this);
AddProfessions();

Icon = helper.ModContent.Load<Texture2D>($"assets/skills/icon.png");
SkillsPageIcon = helper.ModContent.Load<Texture2D>($"assets/skills/icon-page.png");
ExperienceCurve = new int[10] { 100, 338, 783, 1504, 2570, 4050, 6013, 8528, 11664, 15490 };
ExperienceBarColor = new Color(159, 151, 179); // Experience Bars mod support

}```

#

The ExperienceCurve is unfortunately ignored by the game afai can tell, but that's a separate issue

final arch
#

mhhh no idea. I'd try to debug the menu and see why it works in other skills and not yours

teal bridge
#

SpaceCore's version of this is kind of greek to me and MoonSlime's skill mods all have a lot of indirection in their wrappers making them a bit hard to follow, but... I didn't see any reference to RegisterSkill in what you've posted, are you calling that?

sudden scroll
#

That's in Entry, yes

teal bridge
#

So it shows up but isn't selectable. What does not selectable mean in this instance? Is anything showing up in the SMAPI log?

#

Maybe your DoImmediateProfessionPerk or something in that path is throwing.

sudden scroll
#

clicking it does nothing, hovering over it doesn't highlight green
clicking Rain Dish selects it and hovering over it highlights it green

sudden scroll
#

Nothing in the log

#

10aa and 10ab are both selectable just fine

teal bridge
#

Me, I'd pull the SpaceCore repo and put a breakpoint in there to see exactly what's going on.

sudden scroll
#

๐Ÿ˜– gonna try doing that later I suppose
I don't want to dive right into pulling other mods for debugging lol
Also I haven't even managed to breakpoint into my own method so far, so that's fun :D /sarcasm

teal bridge
#

That's the reason to put the breakpoint in SpaceCore, it's the code that runs before your own breakpoint would get hit.

sudden scroll
#

Oh I meant in a completely unrelated method

teal bridge
#

I understand not wanting to debug SpaceCore though. Could try pinging Casey or just waiting.

sudden scroll
#

short story shorter, my double-buff-length-in-rain profession was not working so I tried breakpointing, which didn't work, so I tried pulling the code out into a method and breakpointing that, which also didn't work: ```cs
[HarmonyPatch(typeof(Buff), nameof(Buff.OnAdded))]
class DoProf10ab {
static void Prefix(Buff __instance) {
TryDoubleBuff(__instance);
}
}

private static void TryDoubleBuff(Buff buff) {
if (Game1.player.HasCustomProfession(ProfCache.prof10ab) && Game1.isRaining && buff.millisecondsDuration != Buff.ENDLESS) {
buff.totalMillisecondsDuration = buff.millisecondsDuration *= 2;
}
}```

#

Also I forgot to check whether the buff is from food but besides the point lol

#

(I'm well aware most of my code is probably horribly unconventional/jank)

teal bridge
#

Just adding HarmonyPatch doesn't apply the patch, if that's what you were expecting; you have to register them in your Mod. (It's also not recommended to patch this way, you should use Harmony.Patch directly.)

sudden scroll
#

wha

#

huh

teal bridge
#

[HarmonyPatch] attribute is just metadata for harmony.PatchAll (which, again, you shouldn't use). It doesn't have any magic by itself.

sudden scroll
#

Why shouldn't I use it?

sudden scroll
#

Ah

#

I don't know if I mind my mod breaking enough to bother tbh

teal bridge
#

I guess. It's near zero extra effort to do direct patching though. Either way you still need to create the Harmony instance and call some variant of Patch.

lucid iron
#

I heard it used to be worse bc different platforms had different assembly names

#

Atm it's mainly risk of patch versions breaking your stuff

teal bridge
#

(You also really shouldn't do prefixes if you can avoid it; I don't think this needs a prefix, you can easily do it as a postfix)

sudden scroll
#

I also fail to understand why postfixes are in any way more compatbile or safer than prefixes? Just some C#/Harmony jank?

teal bridge
#

Prefixes can fight each other and some might not run. Postfixes always run.

lucid iron
#

You have a void prefix tho, according harmony docs that always runs

teal bridge
#

Not sure if I trust that doc, but could be the case. Even so, it's still safer to run postfix because prefixes run before transpilers as well.

#

This particular Harmony patch is trying to manipulate the final outcome, which really should run very late in the process.

lucid iron
#

Yeah I personally like postfix more just as a style thing Bolb

sudden scroll
#

Ah yes, gotta love bool Prefix { return false; } lol

#

gotcha

teal bridge
#

Like, what if some other mod or even vanilla logic slightly modifies the buff duration? It might overwrite your double-buff completely.

lucid iron
#

With postfix if I happen to want to know how the func I am patching changed state b4 and after, I can easily add a prefix to track that

#

So it's convenient to start with postfix by default

teal bridge
#

Random unrelated question popped into my head, is Game1.random instanced (e.g. in splitscreen)? Does anyone know?

next plaza
#

Yeah

#

All statics are instanced in classes that have [InstanceStatics], except ones marked with [NonInstancedStatic]

#

(I believe, unless it was changed more after I finished with it)

teal bridge
#

Good thing I asked, this could have led to super-broken split-screen fishing.

sudden scroll
#

(smol wrappers involved, nothing major) ```cs
internal static class Hooks {
private static Harmony h = new(ModEntry.ID);

private static void qpre(Type orig_type, string orig_name, Type pre_type, string pre_name) {
    h.Patch(
        original: Method(orig_type, orig_name),
        prefix: new(pre_type, pre_name)
    );
}

private static void qpost(Type orig_type, string orig_name, Type post_type, string post_name) {
    h.Patch(
        original: Method(orig_type, orig_name),
        postfix: new(post_type, post_name)
    );
}

private static void qtrans(Type orig_type, string orig_name, Type trans_type, string trans_name) {
    h.Patch(
        original: Method(orig_type, orig_name),
        transpiler: new(trans_type, trans_name)
    );
}

public static void hook() {
    Type skill = typeof(WeatherWitchSkill);

    qtrans(typeof(FarmAnimal), nameof(FarmAnimal.updateWhenNotCurrentLocation), skill, nameof(WeatherWitchSkill.DoProf10aa));
    qpost(typeof(Buff), nameof(Buff.OnAdded), skill, nameof(WeatherWitchSkill.DoProf10ab));
}

}```

teal bridge
#

It's the transpiler itself that's crashing, which this code doesn't tell us anything about.

#

Whatever the problem is is in WeatherWitchSkill.DoProf10aa

sudden scroll
#
// Transpiler FarmAnimal::updateWhenNotCurrentLocation
public static IEnumerable<CodeInstruction> Prof10aaTranspiler(IEnumerable<CodeInstruction> insts) {
    MethodInfo is_raining_here = typeof(GameLocation).GetMethod("IsRainingHere");
    if (is_raining_here is null) {
        throw new Exception("GameLocation::IsRainingHere could not be found.");
    }

    bool found = false;

    // look for environment.IsRainingHere() call
    foreach (var inst in insts) {
        if (inst.Calls(is_raining_here)) {
            yield return new CodeInstruction(OpCodes.Callvirt, DoProf10aa);
            found = true;
        }

        yield return inst;
    }

    if (!found)
        monitor.Log($"Failed in {nameof(Prof10aaTranspiler)}\nWhoops", LogLevel.Error);
}

public static bool DoProf10aa(GameLocation env) {
    return !env.IsLightningHere() && (
                Game1.getAllFarmers().Any(farmer => farmer.HasCustomProfession(ProfCache.prof10aa))
                || !env.IsRainingHere()
            );
}```
#

I just added the is_raining_here null check just in case lol

#

it's not getting hit

teal bridge
#

I don't understand, you've set your transpiler to DoProf10aa, but that's not the transpiler method.

sudden scroll
#

Oh

#

I am very smort

#

lol

#

Sorry and thank u

teal bridge
#

Also, the transpiler seems to completely overwrite the entire method, so I'm guessing it won't work anyway...

sudden scroll
#

does it??

teal bridge
#

No, never mind, I was skimming and missed yield return inst.

sudden scroll
#

Ah

teal bridge
#

Just a weird way of writing transpilers, we generally use CodeMatcher

sudden scroll
#

I was going off of Harmony's tutorial lol

#

In this case it's readable to me so w/e, I'll look into CodeMatcher if I ever need to make another

teal bridge
#

Yeah it's a whole side discussion but I think a lot of people would agree that Harmony's documentation/tutorials are actually the worst docs/tuts available for Harmony.

sudden scroll
#

lol

calm nebula
#

Which is probably why it is invalid IL

#

Anyways

teal bridge
#

Callvirt is also wrong, etc... but one step at a time haha

sudden scroll
#

It was Call at first

calm nebula
#

I'm also going to say the method naming is giving me a minor headache

#

Call is correct for static methods

#

And I must be off. Cherrio!

sudden scroll
#

Both result in InvalidOperationException: Unexpected unemittable operand type lol

sudden scroll
teal bridge
#

Yeah, the naming definitely makes things confusing too, but I don't get paid to pick nits.

#

...actually I do, just not here.

sudden scroll
#

Mh, smol mod, learning how to make custom skills, haven't exactly figured out any conventions for myself yet

teal bridge
#

Anyway, "unemittable operand type" is because the operand needs to be a MethodInfo, and it looks like you're just passing the method group itself (surprised it even compiles).

sudden scroll
#

it compiles because the arg is just object

#

I see though

#

Easy enough fix

teal bridge
#

Ah, method groups are implicitly convertible to object (something I've never attempted once in... many years) and VS gives a warning: "Converting method group '...' to non-delegate type 'object'. Did you intend to invoke the method?"
So yes, watch those warnings.

#

The green underline might be wrong. But usually it's right.

sudden scroll
#

I saw the warning but the suggestion ("Did you intend to invoke") was wrong so ignored it lol

lone ice
#

For anyone trying to figure out how to make a mod to use the rocky beach in the forest, there's clear tiles on the buildings layer that keep you from being able to walk on it, not any tile properties. You can delete those if you're patching a map area based on the vanilla map or modifying the vanilla map directly ๐Ÿ˜…

rancid temple
#

Yeah, there's quite a lot of maps with invisible Buildings tiles

hallow prism
#

oh, well, i guess this was too obvious for me to suggest, something in the wording made me think you did already

#

glad it's solved then

teal bridge
#

Check it out - still a few bells and whistles to go, but it is actually working.

lone ice
teal shell
#

yoo!!!

#

that's so cool

lone ice
#

swapping all the storylines and characters and adding a bunch of OP related assets

#

there's boar and turkey you can hunt so Luffy doesn't get sad ๐Ÿคฃ

teal shell
#

BOOOAR

teal shell
#

that's so cool what

lone ice
#

It's been fun but it's going to take ages because we're adding so much content

#

I have a couple people helping me

lone ice
#

Boar using FTM

#

they're technically shadow brutes

spice inlet
#

Huh, the game really struggles drawing finer detail images in splitscreen.
Can't say I've ever noticed that before though

silver snow
patent lanceBOT
#

@velvet narwhal: fix the event wiki addins (48h ago)

teal bridge
#

Oh, the overlay's just a translucent item sprite. This is a different thing vs. the distribution prediction you were discussing in #programmers-off-topic, it's the real fish.

#

...at least, some of the time. It's misbehaving in MineShaft for as-yet unknown reasons.

final arch
finite ginkgo
#

Looks like the magic book sprite from unlockable bundles

brittle pasture
teal bridge
#

I'm patching GetFishFromLocationData as well as MineShaft.getFish, but I found one call that's leaking through, via ItemQueryResolver (but I don't know why, because ItemQueryContext.Random is set to the replayable instance and works fine on outdoor maps).

#

(This probably isn't going to make any sense to anyone who hasn't seen the code - and even many who have, lol)

spice inlet
teal bridge
#

And I'm finding that if I emit a stack trace from the code, it seems to have the original lines and not the decompilation, which makes sense but is unfortunate for me.

next plaza
#

At least you can see the original lines in C#+IL view in ILspy

teal bridge
#

I can?

teal shell
brittle pasture
#

the getfish in mineshaft seems to just use Game1.random directly?

teal bridge
#

Oh, there's a "show line numbers" buried in the options.

teal bridge
brittle pasture
#

got it, since you mentioned ItemQueryContext.random

teal bridge
#

Yes, that would normally be invoked from GetFishFromLocationData

#

Which normally creates an ItemQueryContext using Game1.random and has also been transpiled not to. So it's curious.

#

Is it possible for the random instance on an ItemQueryContext to get overwritten?

#

Ohh, I see it... it only creates the new ItemQueryContext if it doesn't receive one in the method args.

#

Although I can never find any instance of it being called with any value other than null, so... hm.

teal shell
#

idk if this is the right place to ask this, but does anyone know somewhere (website, youtube video, etc) that has information on how to make your own mod?

#

i'm so inspired by everyone here i just wanna try and see if i can make my own!

ocean sailBOT
#

Making mods can be broadly divided into two categories:

Usually itโ€™s easier to start with making content packs, since you don't need to learn programming.

brittle pasture
#

and welcome! what kind of mods are you looking to make?

#

as mentioned in the link, you either only need to use write JSON files with content patcher, or diving a little deeper with C# coding

teal shell
brittle pasture
teal bridge
#

I don't think these ILSpy line numbers are accurate per the stack trace lines.

brittle pasture
#

that's my experience as well, though I generally assumed it was a Linux thing. you definitely need to read the IL and do the mapping yourself

teal bridge
#

Oh, I can map IL to the decompiled C# well enough, but the line in the stack trace is something else altogether (it's the real actual line number in the real source code).

#

Even shows the original file path to D:\Gitlabrunner\...\ConcernedApe\stardewvalley

teal bridge
#

This would be a real nice time to be able to step through the decompilation. @ivory plume, can I get access to that private repo? It's supposed to be debuggable, right?

velvet narwhal
ocean sailBOT
#
Creating a Custom NPC

Keep in mind that making NPCs is a complex process that requires learning many different aspects of Stardew modding.
Here are a few links that can help get you started on all that you need to know:

  1. Tiakall has a great tutorial on making a custom NPC for 1.6:
    https://stardewmodding.wiki.gg/wiki/Tutorial:_Making_a_Custom_NPC

  2. Custom NPCs received many improvements with 1.6. For changes made, see the migration guide:
    https://stardewvalleywiki.com/Modding:Migrate_to_Stardew_Valley_1.6#Custom_NPCs

  3. Some information on the NPC wiki page is still relevant:
    https://stardewvalleywiki.com/Modding:NPC_data
    Just make sure you're checking the migration page and tutorial first as this page still has outdated information on it as well.

  4. Aviroen has put together a template that will allow you to easily create a romanceable NPC:
    https://stardewmodding.wiki.gg/wiki/Npc_template

blissful panther
#

The decompile repo does build and run, yeah. If I recall, line numbers won't be identical between your own build and the build on Steam, but that shouldn't matter too much if you just need it for debugging.

teal bridge
#

If I can step through it then I won't need the line numbers.

blissful panther
#

Yup!

teal bridge
#

The leak is baffling to me. I can clearly see where Game1.random is coming from, and I can also clearly see via [HarmonyDebug] that the method's been patched correctly not to use it. The only explanation is that something is calling GetFishFromLocationData with an existing ItemQueryContext, except that it doesn't, because I'd be able to see that in the stack trace too!

teal shell
worthy rose
#

Hey guys, I want to make my own first mod, I want to be able to assign inventory slots to d pad on controller or any button player wants, does something like this already exist? I dont want to j ust recreate something thats already out there.

#

so like row 2 slot 10 to right on dpad, etc

#

im a python architect and a c# lead so i think i can hang , just wondering if

A. THis already exists (couldnt find it if it does)
B. If this is even possible

teal bridge
#

I think I may have found the culprit.

public static ItemQueryResult[] TryResolve(
  case ItemQuerySearchMode.RandomOfTypeItem:
  {
    ItemQueryResult result2 = Game1.random.ChooseFrom(results.Where((ItemQueryResult p) => p.Item is Item).ToArray());
    results = ((result2 == null) ? LegacyShims.EmptyArray<ItemQueryResult>() : new ItemQueryResult[1] { result2 });
    break;
  }    
}

This implementation does not check ItemQueryContext.Random, it just goes straight to Game1.random. Is this a bug in ItemQueryResolver? (Any of the 1.6 devs happen to be online?)

worthy rose
#

is that c#?

#

hot damn i had no idea this game was in c#

teal bridge
#

The other overload of TryResolve does check the context which is why I think this is a bug: Random random = context?.Random ?? Game1.random;

worthy rose
#

thats amazing

brittle pasture
teal bridge
#

Yeah... I already pinged him once for the repo access 5 minutes ago, hate to spam pings.

#

For now I'm going to patch in my "bug fix"

quaint moss
#

It appears there's an issue with #$action trigger actions where using it at the start of dialogue causes text to act weird. I'm not too sure about the specifics of this issue (I do know that it ends dialogue instantly if there's a #$b# textbox right after) as I'm reporting it on behalf of a friend, but does anyone know if it's a known issue Pathos is hopefully aware of?

velvet narwhal
quaint moss
#

Good to hear, thank you.

brittle pasture
worthy rose
#

thanks

brittle pasture
#

if you're on steam it might be easier to just use Steam Input's remapping

worthy rose
#

im ok with it being like... button combos too, ima have to think about it

#

well i want it to go to specfic inventory index

#

glad to see that the index doesnt change based on selected row

brittle pasture
#

and remap the dpad to be any macros you want

#

so you can bind the dpad to be keyboard buttons and bind those instead

worthy rose
#

ah yeah

#

it might be doable tho, i will find out shortly

silk wedge
#

Hi, quick question! For the life of me I can't get my schedule to work for my npc, once she spawns she stays at her spawn point. I'm probably being stupid and my syntax is wrong or something, but can anyone help me with this?

{
    "Changes":
    [
        {
            "Logname": "Nemona Schedule",
            "Action": "EditData",
            "Target": "Characters/schedules/NemonaWolf",
            "Entries": {
    "Mon": "610 Custom_Nemona_Attic 3 3 3/0900 Custom_Nemona_Room 9 8 2/1800 Custom_Nemona_Room 5 7 2",
    "Tue": "610 Custom_Nemona_Attic 3 3 3/0900 Custom_Nemona_Room 9 8 2/1800 Custom_Nemona_Room 5 7 2",
    "Wed": "610 Custom_Nemona_Attic 3 3 3/0900 Custom_Nemona_Room 9 8 2/1800 Custom_Nemona_Room 5 7 2",
    "Thu": "610 Custom_Nemona_Attic 3 3 3/0900 Custom_Nemona_Room 9 8 2/1800 Custom_Nemona_Room 5 7 2",
    "Fri": "610 Custom_Nemona_Attic 3 3 3/0900 Custom_Nemona_Room 9 8 2/1800 Custom_Nemona_Room 5 7 2",
    "Sat": "610 Custom_Nemona_Attic 3 3 3/0900 Custom_Nemona_Room 9 8 2/1800 Custom_Nemona_Room 5 7 2",
    "Sun": "610 Custom_Nemona_Attic 3 3 3/0900 Custom_Nemona_Room 9 8 2/1800 Custom_Nemona_Room 5 7 2"
            }

        }
    ]
}```

And part of my content.json, just in case

```    {
      "LogName": "Nemona Schedule",
    "Action": "Include",
    "FromFile": "assets/data/schedule.json"
  },```
#

I don't think it's a pathing problem, as I'm pretty sure she should be able to access all the coords I've put down? But I'll check again if it isnt a syntax issue

velvet narwhal
#

schedules req a blank load, iirc
a blank.json loaded ihnto characters/schedules/name -> then editdata

hallow prism
#

(once its done, sleep a day or two. You don't need all week schedules but you kinda need a spring one. You can use goto for schedules that are duplicate of another)

silk wedge
rancid temple
#

Used to crash if you didn't have a spring

silk wedge
#

ohhhh interesting...

rancid temple
#

Spring is like the default if all else fails, so you need it, but also it's what the game uses to send NPC's home at the end of the day

hallow prism
#

spring is used by default by some game things

rancid temple
#

for festivals and such

hallow prism
#

and GI

#

yeah

worthy rose
#

.net core 8.0 is only choice i have, do i have to download the 6.0 SDK?

rancid temple
#

Yep

#

You can throw a <LangVersion> in your PropertyGroup for the project settings, if you need something from a later version than 6 provides

#

But your project needs to target 6 as the TargetFramework

worthy rose
#

im ok with 6 just trying to get it to showup in the available versions when making proj

#

nice ye3ah just needed SDK

supple jackal
#

how is it that I first unpacked the content files like 2 years and I ONLY JUST realized that the order of the objects in springobjects.png and the object IDs are related....... so much time searching.... SDVpufferwaaah

velvet narwhal
#

(me too, just last week)

supple jackal
#

had to get up from my desk and walk that one off lol

#

when the feeling of "bruh" is so strong you need to take a lap

velvet narwhal
#

what made it click? for me it was counting the sprite index for the mermaid pendant

supple jackal
#

I was grabbing sprites so I stop procrastinating on making Nexus images for when I finally upload the thing I'm working on and I went "oh that's neat, items 414 and 416 are right next... to... each other..........."

#

and then I was like ".....those are the 414th and 416th sprites on this sheet aren't they."

rancid temple
#

Just have to avoid working with anything from 1.6 to keep that true

velvet narwhal
#

aren't 1.6 items strings?

rancid temple
#

Well they're all strings, but yes I know what you mean

velvet narwhal
#

words my bad

brave fable
#

it was more clear up until 1.6: the object ids are/were named Parent Sheet Index, which is very self-explanatory lol

rancid temple
#

Well, as long as you have context for what that is lol

next plaza
#

SpaceCore extended tilesheets flashbacks

calm nebula
#

It's a blueberry!

#

Hi blueberry

#

How have you been?

velvet narwhal
#

(i swear we say anything pre 1.6 and casey gets war flashbacks)

worthy rose
#

what the heck, i cant find the pathoschild nuget package

calm nebula
#

Flattened pufferchick. Oh dear

worthy rose
#

ahh im trying torublehsooting now

rancid temple
#

Casey really did jump into the thick of it with this game

velvet narwhal
#

does casey have the highest count of frameworks?

brave fable
#

the thickest of it was pre-1.3 from the sounds of it haha

next plaza
#

Probably aedenthorn

#

The MP mod was fun to make back in 1.07

#

That was before we had Harmony

worthy rose
#

nice adding the source did it

brave fable
#

earlier than i thought ..

next plaza
#

I've been modding since the year of release!

#

It's how I know so much about the code ๐Ÿ˜›

brave fable
#

i knew so much about the code, and then they changed what the code was. and it'll happen to you, too

calm nebula
#

Nah

#

Blueberry, see my name change ๐Ÿ˜›

next plaza
#

Does that mean your hobby was the PS Vita before

velvet narwhal
#

max is gonna get into the knitting scene

calm nebula
#

What the hell is a ps vita

next plaza
#

PlayStation portable device

rancid temple
#

Ok, discord, that's what I wanted

brave fable
#

is ItemRegistry.AddTypeDefinition something we can use to have custom subclass items created without patching everywhere?

calm nebula
#

Yes

next plaza
#

But custom subclasses still have to be registered with SpaceCore for the serializer

brave fable
#

like if i make some RGBItemDataDefinition for raised garden beds

#

well that's just job security

next plaza
#

I used it for necklaces in the initial 1.6 Moon Misadventures port

#

(That is now dead because MMR is gonna be a thing that works pretty differently)

uncut viper
#

me, too forgeful for my own good: "why the hell is this patch im applying to the dailyluck getter seemingly not doing anything. why is my luck stuck when im not doing anything with the patch at all??"

next plaza
#

Cool modders use debug commands and console code instead of CJB Cheats SDVpuffercool (I'm joking)

velvet narwhal
#

i'm too lazy to do debug speed 10 10000 every morning

uncut viper
#

easier for me to give myself inventory rows and maximum speed with the cheats menu

calm nebula
next plaza
#

(Though I legitimately don't use CJB mods)

calm nebula
#

(You are a cool modder though!)

uncut viper
brave fable
#

do we extend baseitemdatadefinition or implement iitemdatadefinition?

calm nebula
#

Either

#

I think extending base was easier

brave fable
#

thanks, i'm pretty clueless about most of the new stuff still

calm nebula
#

No worries

calm nebula
#

I did 80% of my mod updates and then was like "fuck this shit I'm gonna go design knitwear now"

#

So I still remember

next plaza
#

(That code was during the alpha, so a few things might have changed since then)

brave fable
#

i was hoping i could make all the interconnecting object stuff from garden beds into something more generic/inheritable so i could have swimming pools in the same mod, but i couldnt figure out how to have OutdoorPot : SDV.IndoorPot & InterconnectingThing as well as SwimmingPool : SDV.Object & InterconnectingThing

#

i did 1 mod update and didnt post it

next plaza
#

Could interconnectingthing be an interface with default methods?

brave fable
#

i tried interfacing it, but it was too coupled. it was awful

next plaza
#

Ah

#

Sounds like you need mixins ๐Ÿ˜›

#

(I have a source generator for that)

uncut viper
#

SDVpufferthink even after unchecking the max daily luck thing this patch still doesnt wanna actually add to the luck it seems... but it can set it just fine. im so over all this IL stuff

brave fable
#

i think giving up is more accessible & future proof than mixins

calm nebula
#

Have you considered learning Rust instead

uncut viper
#

im waiting for Oxidization personally

calm nebula
#

I don't know

brave fable
#

i read a whole lot about people learning rust and not a lot about people using rust

calm nebula
#

The Carbon fan might show up

brittle pasture
#

rust mentioned, activating proselytization mode

calm nebula
#

Anyways

velvet narwhal
#

oh no

calm nebula
#

See y'all!

brave fable
#

ciao, nice seeing you

brittle pasture
brave fable
#

oh. no more mod dump repo SDVpufferfush

#

my beloved

teal bridge
#

Nyah nyah I beat the MineShaft. And can now see with heightened senses just how horrifically punishing the mine fishing luck really is.

brave fable
#

searching making-mods just doesnt give the same emotions

teal bridge
#

But it works. I'm not sure if I want to massage the random distribution a bit (there is literally no difference which tile you fish, 9 times out of 10) or just let this be a targeted-bait-saver.

#

I'm thinking of giving the RNG a little nudge away from trash in some scenarios like targeted bait or repeated prior trashes. Ironically, level 100 of the mines is way more forgiving; not sure why, but the bizarre way the RNG is set up between MineShaft and GameLocation means that between the Lava Eels and Cave Jellies, you can get both very consistently and get 10+ of each in a day.

#

(I know that L100 has intentionally more forgiving logic for jellies, but that doesn't explain why Lava Eels are more common than Ice Pips other than "freaky math stuff")

brittle pasture
#

Lore reason: Ice Pips has to fight the Ghostfish for resources, while the Lava Eels reigh supreme in their realm

teal bridge
#

Re this carbon thing, the joke may have gone over my head, but I'm pretty sure Carbon is for Rust, the game, and not Rust, the language?

next plaza
#

Carbon is a language I think, related to C++

teal bridge
brittle pasture
#

It is made to be the TypeScript to C++'s Javascript basically

teal bridge
#

Same with this Oxide thing, it seems to refer to a Rust that is definitely not the Rust language.

brittle pasture
#

Rust the game

drowsy pewter
#

over in the rust server, they're having a discussion over something that was made for stardew valley the game, not stardew valley the programming language

brave fable
#

cs note: sdv is short for std::vector SDVdemetriums

velvet narwhal
#

please no, my brain was so addled with >> << when i re-attempted my goose meme mod that i had to take a walk

teal bridge
#

I have no clue how I got that original screenshot. Somehow it worked, but it must have been a fluke, because it seems that the tile position/distance from land actually makes no difference whatsoever to what fish will be hooked except for legendary catches and a couple of one-off scenarios like the submarine.

#

So I accidentally created a real repeatable tile distribution, and now that I've fixed all the bugs, have no idea how to recreate it.

old edge
#

How do I make a c# mod read the data set in a content patcher config schema?

lucid iron
#

Depends on the data

old edge
#

Do I need to look into API?

lucid iron
#

For instance if it's an object you just get ParsedItemData with ItemRegistry

teal bridge
old edge
#

The config schema It's enabling/disabling a trigger action from working but I wanted my C# mod to detect it

lucid iron
#

Hm it might be better to make the config menu in C#

old edge
#

Yeah ok

lucid iron
#

And expose tokens with CP api

old edge
#

I'll do it that way

royal stump
#

checking for the trigger action ID (or whatever else is affected by the toggle) might be the easiest route

teal bridge
#

So this isn't the end of the world, but I'm finding these overlays draw over the fishing minigame, as in this example.

Is there some way to get them to draw underneath in the RenderedWorld event or is that simply too late? I've tried playing around with layer depths but doesn't seem to matter how low or high I set that.

old edge
#

Hmm well I have these rings I added. they work with trigger actions when unequipped using context tags but I also want them to work When equipped.

#

I was only able to add my custom buffs with C# due to the custom companions mod incompatibility with the feature

#

So far it works I have a config that the player can set if they want the rings to work when equipped or unequipped but when it's set to unequipped id still like the buffs to work when the unequipped config value is enabled

#

Cus when I set it only one works at a time ๐Ÿค”๐Ÿ˜”

#

Starting to SDVpufferdizzy

teal bridge
#

Yep, that's what I ended up doing; World_Background step seems to work well. SMAPI says no, but my eyes (the goggles do nothing) say yes.

old edge
#

Been C# for days

#

Miss the pixel art portion of making mods now

cinder goblet
#

Iโ€™m trying to figure out how make a content pack to edit Krobusโ€™ sprites and Dialogue. Does anyone have any guides on how?

old edge
#

Just need content patcher

rancid temple
#

!startmodding

ocean sailBOT
#

Making mods can be broadly divided into two categories:

Usually itโ€™s easier to start with making content packs, since you don't need to learn programming.

vernal crest
#

Downloading an existing mod that edits Krobus is a good way to start as well

cinder goblet
#

I got this error on XNBhacker thing.

Unhandled exception: System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types.
Could not load type 'StardewModdingAPI.IManifestPrivateAssembly' from assembly 'SMAPI.Toolkit.CoreInterfaces, Version=4.0.8.0, Culture=neutral, PublicKeyToken=null'.
at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
at System.Reflection.Assembly.GetTypes()
at StardewValley.LocalMultiplayer.GetStaticFieldsAndDefaults() in D:\GitlabRunner\builds\Gq5qA5P4\0\ConcernedApe\stardewvalley\Farmer\Farmer\LocalMultiplayer.cs:line 121
at StardewValley.LocalMultiplayer.Initialize() in D:\GitlabRunner\builds\Gq5qA5P4\0\ConcernedApe\stardewvalley\Farmer\Farmer\LocalMultiplayer.cs:line 92
at StardewValley.GameRunner..ctor() in D:\GitlabRunner\builds\Gq5qA5P4\0\ConcernedApe\stardewvalley\Farmer\Farmer\LocalMultiplayer.cs:line 440
at StardewXnbHack.Program.CreateTemporaryGameInstance(PlatformContext platform, String contentPath) in /home/pathoschild/git/StardewXnbHack/StardewXnbHack/Program.cs:line 327
at StardewXnbHack.Program.Run(String[] args, GameRunner game, String gamePath, Func`3 getLogger, Boolean showPressAnyKeyToExit) in /home/pathoschild/git/StardewXnbHack/StardewXnbHack/Program.cs:line 149
System.TypeLoadException: Could not load type 'StardewModdingAPI.IManifestPrivateAssembly' from assembly 'SMAPI.Toolkit.CoreInterfaces, Version=4.0.8.0, Culture=neutral, PublicKeyToken=null'.

rancid temple
#

Which version of XnbHack did you download?

cinder goblet
#

1.1.1 for windows

rancid temple
#

You want 1.1.0

ivory plume
worthy rose
#

so my mod works, does anyone mind helping me with the icon that shows in my popup dialogue

#

also i hjave one other issue, when i try to check for key COMBOS it doesnt seem to pick it up

#

like if i set it to trigger for F1 , no problem

#

if i set it to trigger for F1+F2, problem

#

but thats ok with me becausae F1 is definitely deliberate enough, just when it comes to console i wanted to make it like idk, R1+Back or smth

brittle pasture
worthy rose
#

yeah i tried IsDown

#

part im having trouble understanding is this

private void OnButtonsChanged(object sender, ButtonsChangedEventArgs e)
{
if (this.Config.ToggleKey.JustPressed())
{
// perform desired action
}
}

why is thtere no if (e.Button) or whatever

brittle pasture
#

JustPressed checks if the buttons are pressed in the current tick, presumably the same tick OnButtonsChanged was raised

tiny zealot
#

yeah, there is the equivalent of if (e.Button), but not in this example. JustPressed is most likely what you want to use, which is why it's given here

worthy rose
#

yeah im just not familiar with using this sort of thing, but am familiar with stuff like e.Button with WinForms projects

#

vuz i was trying the JustPressed way and wasnt working

brittle pasture
#

Maybe you can post your code so ppl can take a look?

worthy rose
#

yea ima do that

#
 {
     if (!Context.IsWorldReady || Game1.activeClickableMenu != null)
         return;

     // Debugging: Output which button was pressed
     Monitor.Log($"Button Pressed: {e.Button.ToString()}", LogLevel.Debug);

     // Identify the current player (works for split-screen)
     Farmer currentPlayer = GetCurrentPlayer();
     if (currentPlayer == null) return;

     // Handle the key binding if we're in binding mode
     if (isBindingMode)
     {
         BindSlotToButton(e.Button);
         return;
     }

     // Ensure the current player has key bindings
     if (!playerSlotBindings.ContainsKey(currentPlayer.UniqueMultiplayerID))
     {
         playerSlotBindings[currentPlayer.UniqueMultiplayerID] = new Dictionary<SButton, int>();
     }

     var bindings = playerSlotBindings[currentPlayer.UniqueMultiplayerID];
     bool suppressed = this.Helper.Input.IsSuppressed(SButton.LeftShift);
     if (suppressed) {
         Monitor.Log("Shift is pressed", LogLevel.Debug);
         if (this.Helper.Input.IsSuppressed(SButton.S))
         {
             Monitor.Log("Shift + S is pressed.", LogLevel.Debug);
         }
     }
     if (this.Helper.Input.IsSuppressed(SButton.S))
     {
         Monitor.Log("Just S is pressed", LogLevel.Debug);
     }
     // Check if F1 or ControllerBack is pressed to enter binding mode
     if (e.Button == SButton.F1 || e.Button == SButton.ControllerBack)
     {
         EnterBindingMode(currentPlayer);
         return;
     }

     // Handle the inventory slot selection for the player if not in binding mode
     if (bindings.ContainsKey(e.Button))
     {
         int slot = bindings[e.Button];
         SelectInventorySlot(currentPlayer, slot);
     }
 }```
#

me hthat looks crappy hold on ill use my sharex backend

#

ook so , itos working on the Monitor.Log($"Button Pressed: {e.Button.ToString()}", LogLevel.Debug); linoe

#

and the F1 to go into changing the setting works too

#

but the IsSuppressed bollean does not

#

do i maybe need a special event listener somewheres?

#

this is what i have up above

#

iheres what i think is happening

#

i think its getting sent into that code every button press

#

so its not sending in both presses

lucid iron
#

you should use ButtonsChanged

worthy rose
#

is this correct?

brave fable
#

note: you want to use Helper.Input.IsDown ("Get whether a button is pressed"), not Helper.Input.IsSuppressed ("Get whether a button is suppressed, so the game won't see it")

worthy rose
#

oh

#

oof

#

i did have IsDown before

#

i think the issue, however, with IsDown not working too, is that its a key combo im trying to get

#

it works on single key

brittle pasture
#

did you try KeybindList.JustPressed as suggested before?

worthy rose
#

KeybindList oh i missed that part im sorry

#

Oh i see the KeybBidndList.Parse

#

Ahh so i can do KeybindList.JustPressed

brave fable
#

consider using SButtonState, e.g.:
bool isComboHeld = this.Helper.Input.GetState(SButton.F1) is SButtonState.Held && this.Helper.Input.GetState(SButton.Enter) is SButtonState.Held;

brave fable
#

not a hero yet haha, i haven't tested it at all and i don't know where you'd put it, but i've seen button state around

#

if you ctrl-click on any SButtonState in visual studio you'll go to the definition, which has the following info on each state:


/// <summary>The input state for a button during an update frame.</summary>
public enum SButtonState
{
    /// <summary>The button was neither pressed, held, nor released.</summary>
    None,
    /// <summary>The button was pressed in this frame.</summary>
    Pressed,
    /// <summary>The button has been held since the last frame.</summary>
    Held,
    /// <summary>The button was released in this frame.</summary>
    Released
}

you might have to check for pressed OR held on both keys if you check from OnButtonPressed, otherwise should be fine to check held on both keys from OnButtonsChanged

worthy rose
#

but now it is working good point

worthy rose
brave fable
#

i think so

worthy rose
#

ahhh but now i cant get the e.Button

#

why not tho i dont know

brave fable
#

do you need it? you can check any buttons you like

worthy rose
#

e.Pressed used to be e.BUtton

#

yeah to bind that to the slot

#

when they come thru in that context

brave fable
#

OnButtonPressed is reacting to a specific button changing to SButtonState.Pressed, while OnButtonsChanged will give you a place to check any buttons when any of them change state

#

if you're only interested in whether your combo is active or inactive, just check those buttons

worthy rose
#

yeah but i dot know which button to check

#

so i need both

#

i need both on button pressed

#

and on button changed

#

on buttons changed*

brave fable
#

what's your overall task?

worthy rose
#

i think i do need both]

#

ok so , user has slot 7 highlighted, they press L1 + R1, it says ok now binding slot 7, choose button

#

and then they press like, dpad right

#

and then wheneever they press dpad right from then on, itll take them to that exact slot

#

no matter what row youre on

#

it works already too which, since i spend a lot of time in the mines for my gf, and i hate getting flustered over where my damn sword is, im so stoked

lucid iron
teal bridge
worthy rose
#

thats os nice tho haha

#

and pretttyyyy much what i was setting out to do, but at least ion mine i can set any slot to anything, so im ok with it

lucid iron
#

what is bopt

worthy rose
#

i want quick sword button, kinda like how in fortnite i have Q set to shotgun

#

excuse my sloppy typing

#

the StardewValleyAPI is soooOoO good ,

ivory plume
teal bridge
#

Ah, I'll bet it's the debug mode more than the other thing. But thanks, that clears it up.

worthy rose
#

Pathoschild youre literally a legend to me. Thanks for your dedication bro.

teal bridge
#

(As far as this controller convo - the D-pad is already used for actual character movement? But hey, two cakes and all that, maybe it'll be what some players want.)

brittle pasture
#

there's the analog stick

worthy rose
#

i dont mind, so like, even if it moves me up AND pulls out my sowrd, if it only moves me up an inch, idc

brittle pasture
#

if you mean like not making it move the player, then yeah there's no good answer for it

worthy rose
#

but i think next step, which would actually be WAY cooler, would be to allow user to set button combos

teal bridge
#

Right, and I use the stick, though hijacking the d-pad still seems a little more opinionated than hijacking the triggers.

brittle pasture
#

(other than Steam Input)

worthy rose
#

so like imagine, i have it so they hold back button and hit face button

#

hold back hit x, assigned slot 1

teal bridge
#

No, if you really want to disable player movement using the d-pad then that's totally possible to do.

worthy rose
#

really?

#

how

#

id love to do that just so i can use it for my quick slots

#

or maybe for my mod id have it only disable if they set something to it

#

thatd be clever

brave fable
#

does anyone happen to know where this behaviour is handled in the game code? specifically, left-clicking a placed bigcraftable with any other held object causing it to pop-out and be picked-up

teal bridge
#

Just a matter of intercepting the game's responses to it. Might be able to do with SMAPI's input suppression, if not then you have to reflect on the internal XNA input state.

brave fable
#

it doesn't seem to be in checkForAction, placementAction, performUseAction, performDropDownAction, performRemoveAction, performToolAction, or performObjectDropInAction on object/item

brittle pasture
#

that doesn't look like base game behavior?

lucid iron
#

ive never seen this happen

#

except with happy home designer's bc features ig

teal bridge
#

Only place I've seen that in base game is placing a big chest over a chest (or vice versa) and that's probably hardcoded on the chest.

worthy rose
#

idk what oyu guys are talking about but ima just say "shots fired"

brave fable
#

huh

lucid iron
#

do a harmony summary maybe

worthy rose
#

what in tarnation

#

is harmony summary

#

e-harmony date recap

worthy rose
#

ahh so yeah yall goin deep as f with these mods

#

gotcha

#

kubernetes for stardew mods lmao

brave fable
#

maybe it's my own code from years ago in here somewhere

worthy rose
#

^^^^

lucid iron
#

no this is just extra fancy reflection

worthy rose
#

was going to say it, but didnt want to

brave fable
#

it's ok, i didn't want to either

worthy rose
#

its always old code

ivory plume
#

Input suppression should work for disabling player movement using DPad, no need for Harmony.

worthy rose
#

input suppression

#

i wouldnt suppose a wiki page for that?>

worthy rose
#

hmmmmmmmmmmm so i would i catch my event then supress?

ivory plume
#

Yep.

worthy rose
#

so sick

brave fable
#

Button sure has been real quiet since we started talking about suppressing buttons

uncut viper
#

(i just spent far too long trying to debug why my dynamic harmony postfix was concatening the result string twice before realizing i was testing it on GameLocation.DisplayName... which gets the displayname from the parent location first if its null. which obviously gets its own postfix concatenation before being concatenated again in the actual location SDVpufferdead)

#

ive been in IL hell

teal bridge
#

I thought I distracted you from your IL hell. Couldn't stay away, huh?

uncut viper
#

which is a kind of suppression i think

worthy rose
#

so i CAN make it situational. All i have to do is if (DPadDirectionsList.Contains(e.Button)) { supress thing }

uncut viper
#

i can be distracted away from the more advanced patches but i wanted to finish at least letting you change the result in a postfix since i thought that would be easy
and technically it was easy, i figured it out hours ago but thought i didnt bc of that aforementioned hell

worthy rose
#

whats IL

#

do i want to know

lucid iron
#

IL (intermediate language) is C# bytecode

uncut viper
#

its like one layer above assembly code

worthy rose
#

ohj god no

#

pls no

lucid iron
#

u can read about it on microsoft's docs prob

worthy rose
#

intermediate language, i forgot those words

uncut viper
#

(maybe a couple layers idk)

worthy rose
#

for good reason

#

man didnt invent languages for us to still talk binary

teal bridge
#

Uh, ok... IL is not "binary" any more than everything on a computer is "binary".

worthy rose
#

im being overly simplistic

#

im saying its hard and i dont like it

#

easier better

uncut viper
#

IL is sometimes the only (good, respectable) way to make a mod do something you want it to do