createEmbeddedDocuments issue

I'm going to throw my code in a thread so I don't clutter this channel up with a wall of text
W
wyrmisis•943d ago
const startMonsterProcess = async (folders) => {
const monsters = await fetch('modules/chromatic-dungeons-compendia/rawdata/monsters.json')
.then(res => res.json())
.then(...) // All of my data prep for creating monsters
.then(createMonsters)
.then(actors => actors.map(createMonsterWeapons))
.then(actors => actors.map(createMonsterArmor));
}

const createMonsters = async (items) =>
await Actor.create(items);

const createMonsterWeapons = async (actor) => {
const attackKeys = Object.keys(actor.data.data.attackObjects);

const attackItems = attackKeys.map(
(key) => {
... // Prepare data for the returned object
return ({
name,
type: 'weapon',
data: {
damage,
equipped: true
}
});
}
).filter(item => !!item);



if (attackItems.length)
await actor.createEmbeddedDocuments('Item', attackItems, {parent: actor});

return await actor;
}

const createMonsterArmor = async (actor) => {
actor = await actor;

if (actor.data.data.naturalArmor) {
const naturalArmor = {
name: 'Natural Armor',
type: 'armor',
data: {
ac: actor.data.data.naturalArmor,
equipped: true
}
}
await actor.createEmbeddedDocuments('Item', [naturalArmor], {parent: actor})
}

return actor;
}
const startMonsterProcess = async (folders) => {
const monsters = await fetch('modules/chromatic-dungeons-compendia/rawdata/monsters.json')
.then(res => res.json())
.then(...) // All of my data prep for creating monsters
.then(createMonsters)
.then(actors => actors.map(createMonsterWeapons))
.then(actors => actors.map(createMonsterArmor));
}

const createMonsters = async (items) =>
await Actor.create(items);

const createMonsterWeapons = async (actor) => {
const attackKeys = Object.keys(actor.data.data.attackObjects);

const attackItems = attackKeys.map(
(key) => {
... // Prepare data for the returned object
return ({
name,
type: 'weapon',
data: {
damage,
equipped: true
}
});
}
).filter(item => !!item);



if (attackItems.length)
await actor.createEmbeddedDocuments('Item', attackItems, {parent: actor});

return await actor;
}

const createMonsterArmor = async (actor) => {
actor = await actor;

if (actor.data.data.naturalArmor) {
const naturalArmor = {
name: 'Natural Armor',
type: 'armor',
data: {
ac: actor.data.data.naturalArmor,
equipped: true
}
}
await actor.createEmbeddedDocuments('Item', [naturalArmor], {parent: actor})
}

return actor;
}
E
Ethaks•943d ago
That looks like a ton of individual requests sent to the server, which Foundry does not like all that much. When using createEmbeddedDocuments, you shouldn't need a parent option btw. Question upfront: Given only the raw actor data from the JSON, can you already derive which weapons etc. are to be created?
W
wyrmisis•943d ago
I was originally trying to do this without the parent object, that was a "throw everything at this and see if anything sticks" change Yep! The steps to generate these items are done after Actor creation, so the data's on the Actor already I prune it off at the end of this process Last I counted, there are 260 Actors being processed through this flow. Each actor has between 0-6 items being created in this way.
E
Ethaks•943d ago
In that case, batching the whole creation might be the best approach, since creating those actors one by one and awaiting each creation will take a while I'll elaborate in a sec
W
wyrmisis•943d ago
You're saying, create the actors, then put together all items that are going in at the same time, then create the items? Or is there a way to create embedded items at the same time that you create a batch of actors?
E
Ethaks•943d ago
So, something neat you can do: You can create a local instance of an actor by const actor = new Actor(actorData), and similarly, you can create in-memory instances of Items by using const item = new Item(itemData). To add an item like that to an actor that has not yet been created on the server (which makes createEmbeddedDocuments useless, since it only works with actors that already have an ID), you can then actor.data.update({items: [item.toObject()]}). This adds the raw item data to the actor's source data, which you can eventually send to the server via Actor.create(actor.toObject())
W
wyrmisis•943d ago
Oh neat, so I'd be able to lump those local actors into an array and push them up to the server all at once, yeah? With their items already attached?
E
Ethaks•943d ago
Yep, if you have an array of Actor instances, you can send a single request to the server with Actor.createDocuments(actors.map(a => a.toObject())) If that is possible in your case (data preparation can be a bit weird with in-memory actors), that could allow you to only send a single document creation request to the server, containing all actors with their item data already in their source data
W
wyrmisis•943d ago
I feel like that should def be doable (then again, I've been wrong about "I should be able to do this" before 😂 ) I'll give it a try and get back to you, thanks for pointing me in (what is hopefully) the right direction!
C
ccjmk•943d ago
@Ethaks , i think there might be an issue with that, depending on his scenario - oor i did something pretty bad in my module 😛 I reckon he's creating multiple actors at the same time though, i create just one but when I added items directly into the actor, it didn't transfer properly item's active effects though now that i think of it, i didn't create an in-memory actor First, updated with items, and then created the actor as you mention, I sort of created the actor with stuff in one fell sweep, so that might be part of the problem but at the very least, I'd recommend @wyrmisis to try using items with active effects for a quick test, if its relevant to them
E
Ethaks•943d ago
Did you create the actor with actor data that already contained items which already contained active effects?
C
ccjmk•943d ago
.... yes hahahha
E
Ethaks•943d ago
Yeah, that might bypass the regular AE creation workflow, since that one's probably triggered by stuff getting added, not by it magically existing
C
ccjmk•943d ago
but if your idea works, that would actually be a good improvement I think.. let me show real quick
// newActorData comes here with alll the stuff, name, token data, all items, attributes, etc
const itemsFromActor = newActorData.items; // moving items to a different object to process active effects
newActorData.items = [];
const cls = getDocumentClass('Actor');
const actor = new cls(newActorData);
const newActor = await Actor.create(actor.toObject());
await newActor.createEmbeddedDocuments('Item', itemsFromActor as any);
// newActorData comes here with alll the stuff, name, token data, all items, attributes, etc
const itemsFromActor = newActorData.items; // moving items to a different object to process active effects
newActorData.items = [];
const cls = getDocumentClass('Actor');
const actor = new cls(newActorData);
const newActor = await Actor.create(actor.toObject());
await newActor.createEmbeddedDocuments('Item', itemsFromActor as any);
i removed some error checkings and console.logging in the middle, but that's the core of it, and i end up making two calls to the server, one to create the actor without the items, one with the items from what i gathered, this could be..
const itemsFromActor = newActorData.items; // moving items to a different object to process active effects
newActorData.items = [];
const cls = getDocumentClass('Actor');
const actor = new cls(newActorData);
actor.data.update({items: itemsFromActor.map(i => i.toObject()});
const newActor = await Actor.create(actor.toObject());
//await newActor.createEmbeddedDocuments('Item', itemsFromActor as any);
const itemsFromActor = newActorData.items; // moving items to a different object to process active effects
newActorData.items = [];
const cls = getDocumentClass('Actor');
const actor = new cls(newActorData);
actor.data.update({items: itemsFromActor.map(i => i.toObject()});
const newActor = await Actor.create(actor.toObject());
//await newActor.createEmbeddedDocuments('Item', itemsFromActor as any);
E
Ethaks•943d ago
What is items there? The toObject part is specific to Item/ItemData instances And even then AE might be problematic, but you'd have to tinker around with it. The main issue with them is that Items can have embedded documents (AEs), but only when they're not embedded themselves – they're supposed to give their children to the actor in that case. I'd have to look at Foundry's code to see where that transfer happens though.
C
ccjmk•943d ago
you mean the one I originally take from newActorData.items on the first line? its an array of items taken from compendiums
E
Ethaks•943d ago
Hm, not sure how much of a difference this'd make then tbh. The actor.data.update pretty much only adds the raw item data into the source data items array.
W
wyrmisis•943d ago
FWIW, @Ethaks 's approach worked for me, so thanks. 😄 There's a certain flavor of irony to spending more time on this importer script that I'll run like once than any other feature players will actually touch.
LTL
Leo The League Lion•943d ago
@wyrmisis gave vote LeaguePoints™ to @Ethaks (#6 • 253)
Want results from more Discord servers?
Add your server
More Posts
Base Item@otigon it occurs to me that the new `baseItem` property on weapons and such is probably of interestCompendium loadinghmm ghost, I added some console.time tags here and there to measure the difference between loading oSkill and Ability bonusesA massive enhancement of Skills and Ability Checks/Saves allows them to be individually affected by 150 Sheet Changes@sdenec @lordzeel Sheet Changes required: - New Cog-menu for Ability Scores and Skills to support neDocumentData shennaneginsTIL: It is possible to `update` an Actor or Item's `data.data` with arbitrary information that isn'tflag shenanneginsTIL you can set the `flags` key on a document to whatever you want to (e.g. a string). This is a surraaeAfter some discussion yesterday in #active-effects , I decided to try to create a system-agnostic modevMode json changed warningI checked the module repo and I honestly can't figure out where I would plug in my code. I'd be guesS3 File Picker SettingsCan someone with an S3 configuration give me a test of the FilePicker settings api and tell me if a item preCreate@sol.folango @mrprimate (pinging you two in particular because you do import stuff involving existinItem Macro Compendium WorkflowOkay, here's a long one that's a bit of a doozy. I'm looking at setting up some sort of tooling/workItem Specific Crit DetailsOh that critical hit thing is gonna hit MRE too isn't it... hrm...1.5.x 72%@dnd5e No action required (but suggested 🙂 ) The 1.5.0 milestone is ~72% complete. It has a due daV9 Tabs IssueIf you never figured this out, here's why this happened: A small change in `Tabs` during v9 causes sDeck Creation MacroI created a macro to fill out a 52-card deck, you set the ID of the deck and the base URL of the foldevmode-issues@arcanist figured out, the flex layout elements have `pointer-events: none`, so anything injected wifunction vs methodAnyone know of a good guide that explains the difference between a function and a method? I don't reActive Effect HelpAnd it should be the actual ActiveEffect document for the effect, not just the id. I don't have theTOL JEs@badgerwerks I haven't had a chance to poke around in TOB/BoL yet, but I wanted to ask how you did tCI 2 minute windowAlright, I've got a Gitlab CI pipeline I'm reasonably pleased with as a result of yesterday's effort