Extend ActiveEffect.changes
How do I extend the ActiveEffect changes array. I want to include additional details for my systems AE changes. I updated the UI to allow editing, but they don't save into database, likely because of a schema issue. My defineSchema knowledge is pretty much non-existent, so some pointers there may be helpful.
Where I'm going with this: I currently have several AE to increase BODY (for example) that expires after 12 seconds. A second increase before the 12 seconds could be a separate AE. But there are crazy people who will increase their BODY every second, making for lots of AEs, which eventually make the token hard to see. I'm trying to consolidate all the increases into a single AE, then expire each change as appropriate. This means I need to store some extra info in the change array.
58 Replies
You cannot store any data within core Foundry's changes since the schema is enforced not only client-side, but also on the server. You would have to either track the added data in a separate
system
/flags
object, or replace core's changes completely and e.g. replace the core data with your own system's (whose schema you are in control of) during preparation.OK, nice to know what road NOT to travel. I tried adding an array to flags to augment changes, merge them in the UI. In the UI I "flags.changes.0.seconds"
the foundry changes is treated like an array, which is great when making updates/changes.
The flags.changes is treated like a json object with numeric keys. Is there a way to make flags.changes treated like an array?
If not I can kluge something together.
Small note: that flag path is missing the namespace, i.e. it should be something like
flags.my-system.changes
Or, since you're the system author, it could use system.changes
or something like that if you want to use that instead of flags.Nice catch on the namespace.
Re: array, you'd have to adjust the format yourself for flags, or use a schema when using
system
.I didn't think system existed on an active effect.
Likely depends on the Foundry version in use since some documents gained their type data over time.
it does exist in v12, surprising.
should I use system instead of flags? Will it be v13 compatible?
For flags, assuming you're extending the AE config, you could override e.g.
_getSubmitData
to transform the object into an array.that was my plan, nice confirmation I was on the track there.
Depends on your specifics. Implementing a
TypeDataModel
for AE's base
type and handling such things in can be quite a nice approach.
Anything that has a system
field will continue to have it, and the schema application should remain just as well.I'm going to explore the TypeDataModel + system approach and see if I can get that to work.
Thanks for your words of wisdom.
@Aaron gave :vote: LeaguePoints™ to @Ethaks (#7 • 395)
Going that route would likely also remove the need for form handling, since the schema should press the data into the provided shape.
When going the merging route of maintaining a parallel set of values belonging to changes, you'll also have to handle core changes being removed.
Which I was going to handle in _getSubmitData... So the system route doesn't really "fix" the need for that.
Hmm, not sure getSubmitData helps with that tbh.
Oh, and whatever you do in your AE sheet: it'll break with v13.
Ya, I basically copied active-effect-config.html and made my own .hbs file. So if v13 changes the UI (app2?) I'll have to rework my hbs file.
Yeah, v13 already has the AppV2 AE config
My coding parter has poked around v13, I've pretty much ignored it so far.
Ordinarily I'd recommend overriding
onDeleteChange
, but since that's private you'll probably have to change the action
callback to your own implementation that also deletes the matching value from your extra change data.
So v13 uses this, which you cannot touch in any way whatsoever
But you could change
That is COMPLETELY different than in v12, where they delete the html.
And then copy paste above method while also cloning your extra data, removing the index value there as well, and add that to the update call
Welcome to AppV2, where everything's new and shiny. Or at least different.
Ugg, so now I'm thinking about punting on this effort, delaying until v13.
That's a very valid consideration 😅
I don't mind a few tweaks for v13, but not looking to overhaul something I just built.
Yep, anything related to core Foundry apps belongs into that category.
I have a custom combat tracker that may be a challenge in v13. Is that one of the appv2 expected in v13?
Shame they use private methods I can't override.
IIRC Foundry aims to replace every app with v2 in v13
OK, I thought I read they intended to, but may not get to them all before v13 releases.
A tracking issue can be found at https://github.com/foundryvtt/foundryvtt/issues/11184
GitHub
All core Application instances migrated to ApplicationV2 and ThemeV...
Requirements Create a tracking spreadsheet for every application in our codebase where we can survey its migration status. These become individual issues which we can track as a sub-project or proj...
Combat tracker is in that list, looks like it's mostly done already.
I'm going to toy around with system and schema, if nothing else to "learn" how the schema stuff works.
I will say that I'm generally a fan of
DataModel
s, and I overall like AppV2 and consider quite a few of its parts a step up.For data models, the wiki has a page: https://foundryvtt.wiki/en/development/api/DataModel
And one for AppV2: https://foundryvtt.wiki/en/development/api/applicationv2
Foundry VTT Community Wiki
Data Model
The abstract base class which defines the data schema contained within a Document.
Foundry VTT Community Wiki
ApplicationV2
The Application class is responsible for rendering an HTMLElement into the Foundry Virtual Tabletop user interface.
Made schema, where AE has a system.changes array. The _updateObject formData returns an array for changes, but a json object for system.changes. How do I make foundry treat system.changes as an array so the native update routies work properly?
Ah, _getSubmitData cheats a bit by coercing changes into an array. I need to do the same with system.changes.
Your system there is not an instance of a data model, so there's no schema applied
Did I miss an instancing step?
What exactly is shown in the first screenshot? Raw data or document?
debugger stuff. The one with red circles is the formData.
I did get it working:
Foundry cheated by coercing data.changes into an array. I just did the same for data.system.changes. Looks like a dataModel isn't really neceessary in this specific case.
The DataModel should make that very form handling obsolete by transforming update data
So check the AE's
system
. If it's an instance of your data model, the schema is applied.
Which should cast its contents into the array shape even if the form data does not contain it like that.Appears to be an instance
Then run an update where your
changes
are in the object form instead of an arraytaking out my "custom" fix and see if it coerces like you said is should.
The schema should cast them into the desired array
Hey it works, mostly. If I have 4 changes and delete one in the middle I get
the coercion into an array bypasses this issue.
If I delete the last change and the array indexes 1-X are sequential, it coerces into an array just fine.
BTW: I'm learning alot in this thread. Thanks for your time!
Like I said I have it working. I'm willing to try more suggestions to make it work better or more inline with foundry/dev recommendations.
You're now at the point where you have to adjust your schema. Your
changes
element SchemaField
is required
by default, meaning the array cannot be sparse.
So you could either make the element not required, allowing an array of [ empty, { … } ]
Or you could give the whole thing empty initial values so that the data is there, just, well, emptyYuck, when I make the ArrayField not required the merge of changes and system.changes no longer is 1-1 and it makes a mess of things.
I supposed I can perform a filter during the merge...
How are you merging the sparse array?
(I would probably recommend the empty data route btw, it feels better than a sparse array)
It could also be interesting to merge the system changes into the changes array at data preparation
That'd depend on how core uses them though
I sorta need a 1-1 match so I can do some backend calculations & change.value fading (custom system rules). Given there is no unique key, I'm left with an index to do the matching.
There are a couple of data prep functions, which one should I look at?
Is my use of getData to merge not ideal?
Not sure I understand your "empty" ArrayField comment. I found the {required: false}, which allows for spare arrays. Is there some sort of {empty: ?} option for ArrayFields that removes the spares property?
I'd have to try this out in v12 since the add/delete handling differs there. Just spitballing though: giving the elements and empty object as initial could work to avoid a sparse array, meaning every value in your changes is an object with your properties.
For the data prep, base should be good enough. Would have to check a) what Foundry does for its own prep, and b) whether the derived data is used for effect application etc. as well.