Please request registration email again and then check your "Spam" folder


Poking at School Subject details in VEE

Started by TBBle, Jan 04, 2024, 06:30 PM

Previous topic - Next topic

TBBleTopic starter

So I had a genius idea.

Quote from: TBBle on Jan 04, 2024, 04:55 PM(Actually, this gives me an idea for a Teacher 1:1 Event to actually give the player hints about the Evaluation Influence, although I'm not sure how easy that information is to access from VEE.)

Anyway, just showing the Subject Experience Ratio using Get Property by Name worked easily, but I hit an issue trying to examine the Evaluation Influences.

Events\Interactions\School\ (MEGA) if you want to see where I got to. (The issue-occurance is disabled there, reconnect node 41 Out to node 66 In to trigger the issue.)

This fails with

Unable to cast object of type 'System.Collections.Generic.List`1[hhs_.SchoolSubjectInfluence]' to type 'System.Collections.Generic.List`1[System.Object]'.
   at hhs_.SeqVar_ObjectList.SetVarValue(Object value) in hhs+\_Editor\_EventModules\_EventVariables\SeqVar_ObjectList.cs:line 100
   at hhs_.SeqAct_GetPropertyByName.Activated(EventRunner Runner) in hhs+\_Editor\_EventModules\_EventActions\_EventActions_Base\SeqAct_GetPropertyByName.cs:line 108
   at hhs_.EventRunner.<ExecuteAsync>d__126.MoveNext() in hhs+\_Editor\_EventModules\EventRunner.cs:line 1229

I'm guessing from my limited C# knowledge that hhs_.SchoolSubjectInfluence is not System.Object but an interface? (My original guess was "struct", but apparently structs in C# do derive from System.Object. And maybe a real C# programmer would tell me that I'm barking up the wrong tree entirely...)

I don't see a better VEE variable to use as the output here.

Assuming the above is that I've just overlooked something, the next issue will be that Get Property by Name doesn't have properties for hhs_.SchoolSubjectInfluence, it has properties for hhs_.SchoolSubjectInfluence_Stat and hhs_.SchoolSubjectInfluence_Family.

I am guessing these are the two implementations of that Interface, but I don't see any exposed way of knowing which one a given hhs_.SchoolSubjectInfluence represents; VEE exposes nothing for this, AFAICT. I can't just try one then the other, since guessing the wrong property name throws an exception.

I also note that hhs_.SchoolSubjectInfluence_Family and SchoolSubject both have a property of type hhs_.SchoolSubjectFamily, and that doesn't have properties listed in Get Property by Name; is that another interface? Or just a missing exposure in VEE? (These are hard-coded in the engine, right? I don't see anywhere in File Editor one could affect this list.)

Assuming my guesses are correctish, both problems may have the same solution: Expose an appropriate variable and list variable for whatever hhs_.SchoolSubjectInfluence is in the C# code-base, and some VEE nodes to operate on them to get to things like hhs_.SchoolSubjectInfluence_Family.


Use Object > Convert to Object List to convert IEnumerables to VEE Object List.

Also check the right side of Office\RSDFeedback for something along those lines.

TBBleTopic starter

Thank you, that got me past the first point.

I worked out that I can use Convert to String to get the Object kind from the IEnumerable.

Does that work for any Object variable? Or do some actually stringify to their value? Or is this specific to IEnumerable and similar erased types? (It'd be nice if we had String Constant values for these types, even if it was a separate VEE node from the current String Constant, to avoid typos in this use-case.)

Anyway, I got it working, broke out a couple of useful FunctionLibrary events (GetStatByName, FlattenSchoolSubjectInfluence), and will post it in the mods thread in case it's useful to anyone, even to see how it works.

One annoying thing, I can't see a way to get from the Int Enum for hhs_.SchoolSubjectFamily to the Display string, short of a library function paralleling whatever the engine UI is doing internally, which is a shame.

I initially missed that the block you were talking about in RSDFeedback is unconnected and way over to the right, so had worked out how to handle a serialised dictionary myself for GetStatByName. And I'm glad I did, because RSDFeedback flattens it into a string and parses it... I guess it predates the VEE Dictionary handling nodes?

But yeah, clearly a similar idea going on, that one is about guiding subject mix in a similar way, although as noted subject family experience isn't specifically relevant beyond its influences.

TBBleTopic starter

So, seeing, I have a couple of questions that relate to it, that came up while I was working on this code. (I had literally thought "Hmm, if I had lambdas, this would be much less awful to work on".)

I'd prefer to post this as a reply to that blog post, but I don't see a nice way to do that, and the first use-case I have for that is this thread anyway.

My use-case is being able to write a generic "For Each SchoolSubjectInfluence", which takes a couple of lambdas, one for SchoolSubjectInfluence_Family and one for SchoolSubjectInfluence_Stat, which would allow that code to be much more readable than the current setup. I'd also perhaps create a couple of structs, and make those the lambda inputs rather than Object of known type as we generally do now. This is basically a Pattern Match-type setup, compared to the type-name-check I have used already. Implementation-wise, it's still a type-name-check, of course. We just hide that boilerplate from the caller.

And thinking about that, it occurred to me that a generic "For Each Object" would also be useful. Compared to the existing Iterator, I think it's cleaner and easier to read, but a couple of features are lost or at-risk. The "Same" entry point doesn't seem wildly valuable to me (I haven't looked to see if it's ever used in the current code-base) and more-importantly, the ability to break-out of the loop will require either Operation References to be able to return a value, i.e. a "break" value, or for the VEE to be able to take a Variable Reference which would then allow the lambda to change that variable during its execution to indicate a break, and the ForEach event can see that change.

Of the two, returning a value seems more-isolated, given support for lambdas in a different event. And Variable Reference already means something else in VEE. >_<

That said, maybe Variable References are valuable elsewhere too? The Arguments of a Remote Event call are in-effect these already, except by copy-in/copy-out, rather than the remote event modifying them directly. That doesn't work for the ForEach "Break" case because there's no return to the calling Event between loops. So having a *-named variable argument would complement the *-named operation argument. (Maybe Remote Event call and whatever we use to call Lambdas should always take their arguments by reference instead...)

It's not part of this thread, but lambdas would also make it cleaner to implement Item Events that can be used directly from Inventory and be called remotely from things that are managing the UI already, e.g., the discussion around for dumping drugs into the drinks at a party, or the multiple-energy-drink button in

It'd also be nice to be able to wrap up the "Add use-count to the most-used inventory item and rejig the inventory stacks" in something with a lambda that gets back the specific inventory item that was rejigged. There's at least two places in the code that need to do this (Coffee Beans and the Shave button in Your Bathroom) but if it's easy to do, maybe more would be added, e.g., a Sunbathe button on the Beach to save a couple of clicks.