Improved typing of creature properties

This commit is contained in:
ThaumRystra
2025-01-12 23:28:43 +02:00
parent 0125367085
commit 1b05b8d3bf
9 changed files with 147 additions and 25 deletions

View File

@@ -7,6 +7,7 @@ import propertySchemasIndex from '/imports/api/properties/computedPropertySchema
import { storedIconsSchema } from '/imports/api/icons/Icons';
import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS';
import { InferType, TypedSimpleSchema } from '/imports/api/utility/TypedSimpleSchema';
import type { ComputedProperty, ComputedPropertyTypeMap } from '/imports/api/properties/Property.type';
const PreComputeCreaturePropertySchema = new TypedSimpleSchema({
_id: {
@@ -153,15 +154,15 @@ for (key in propertySchemasIndex) {
}
}
export type CreaturePropertyByType<T extends keyof typeof propertySchemasIndex> =
InferType<typeof propertySchemasIndex[T]>
export type CreaturePropertyByType<T extends keyof ComputedPropertyTypeMap> =
ComputedProperty<T>
& InferType<typeof CreaturePropertySchema>
& InferType<typeof ColorSchema>
& InferType<typeof ChildSchema>
& InferType<typeof SoftRemovableSchema>
type ConvertToUnion<T> = T[keyof T];
export type CreatureProperty = ConvertToUnion<{ [key in keyof typeof propertySchemasIndex]: CreaturePropertyByType<key> }>;
export type CreatureProperty = ConvertToUnion<{ [key in keyof ComputedPropertyTypeMap]: CreaturePropertyByType<key> }>;
export default CreatureProperties;
export {

View File

@@ -1,5 +1,5 @@
import { PropTask } from '/imports/api/engine/action/tasks/Task';
import TaskResult from 'imports/api/engine/action/tasks/TaskResult';
import TaskResult from '/imports/api/engine/action/tasks/TaskResult';
import getPropertyTitle from '/imports/api/utility/getPropertyTitle';
import { findLast, filter, difference, intersection } from 'lodash';
import { getPropertiesOfType, getPropertyAncestors } from '/imports/api/engine/loadCreatures';
@@ -53,9 +53,10 @@ export default async function applyBuffRemoverProperty(
} else {
// Get all the buffs targeted by tags
const allBuffs = getPropertiesOfType(targetId, 'buff');
const targetedBuffs = filter(allBuffs, buff => {
const targetedBuffs = filter(allBuffs, (buff): boolean => {
if (buff.inactive) return false;
if (buffRemoverMatchTags(prop, buff)) return true;
return false;
});
// Remove the buffs
if (prop.removeAll) {
@@ -65,7 +66,7 @@ export default async function applyBuffRemoverProperty(
});
} else {
// Sort in reverse order
targetedBuffs.sort((a, b) => b.order - a.order);
targetedBuffs.sort((a, b) => b.left - a.left);
// Remove the one with the highest order
const buff = targetedBuffs[0];
if (buff) {

View File

@@ -1,9 +1,10 @@
import { debounce } from 'lodash';
import Creatures from '/imports/api/creature/creatures/Creatures';
import CreatureVariables from '/imports/api/creature/creatures/CreatureVariables';
import CreatureProperties, { CreatureProperty } from '/imports/api/creature/creatureProperties/CreatureProperties';
import CreatureProperties, { CreatureProperty, CreaturePropertyByType } from '/imports/api/creature/creatureProperties/CreatureProperties';
import computeCreature from './computeCreature';
import { getFilter } from '/imports/api/parenting/parentingFunctions';
import { ComputedPropertyTypeMap } from '../properties/Property.type';
const COMPUTE_DEBOUNCE_TIME = 100; // ms
export const loadedCreatures: Map<string, LoadedCreature> = new Map(); // creatureId => {creature, properties, etc.}
@@ -81,13 +82,13 @@ export function getProperties(creatureId: string): CreatureProperty[] {
return props;
}
export function getPropertiesOfType(creatureId, propType) {
export function getPropertiesOfType<T extends keyof ComputedPropertyTypeMap>(creatureId, propType: T): CreaturePropertyByType<T>[] {
const creature = loadedCreatures.get(creatureId);
if (creature) {
const props = Array.from(creature.properties.values())
.filter(prop => !prop.removed && prop.type === propType)
.sort((a, b) => a.left - b.left);
return EJSON.clone(props);
return EJSON.clone(props) as unknown as CreaturePropertyByType<T>[];
}
// console.time(`Cache miss on creature properties: ${creatureId}`)
const props = CreatureProperties.find({
@@ -98,7 +99,7 @@ export function getPropertiesOfType(creatureId, propType) {
sort: { left: 1 },
}).fetch();
// console.timeEnd(`Cache miss on creature properties: ${creatureId}`);
return props;
return props as unknown as CreaturePropertyByType<T>[];
}
/**

View File

@@ -2,7 +2,7 @@ import SimpleSchema from 'simpl-schema';
import VARIABLE_NAME_REGEX from '/imports/constants/VARIABLE_NAME_REGEX';
import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS';
import createPropertySchema from '/imports/api/properties/subSchemas/createPropertySchema';
import type { Expand, InferType } from '/imports/api/utility/TypedSimpleSchema';
import { Expand, InferType, TypedSimpleSchema } from '/imports/api/utility/TypedSimpleSchema';
/*
* Attributes are numbered stats of a character
@@ -40,7 +40,7 @@ const AttributeSchema = createPropertySchema({
// For type hitDice, the size needs to be stored separately
hitDiceSize: {
type: String,
allowedValues: ['d1', 'd2', 'd4', 'd6', 'd8', 'd10', 'd12', 'd20', 'd100'],
allowedValues: ['d1', 'd2', 'd4', 'd6', 'd8', 'd10', 'd12', 'd20', 'd100'] as const,
optional: true,
},
// For type spellSlot, the level needs to be stored separately
@@ -297,7 +297,7 @@ const ComputedOnlyAttributeSchema = createPropertySchema({
},
});
const ComputedAttributeSchema = new SimpleSchema({})
const ComputedAttributeSchema = new TypedSimpleSchema({})
.extend(ComputedOnlyAttributeSchema)
.extend(AttributeSchema);

View File

@@ -1,7 +1,6 @@
import SimpleSchema from 'simpl-schema';
import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS';
import createPropertySchema from '/imports/api/properties/subSchemas/createPropertySchema';
import { Expand, InferType } from '/imports/api/utility/TypedSimpleSchema';
import { Expand, InferType, TypedSimpleSchema } from '/imports/api/utility/TypedSimpleSchema';
const BranchSchema = createPropertySchema({
branchType: {
@@ -53,12 +52,12 @@ const ComputedOnlyBranchSchema = createPropertySchema({
},
});
const ComputedBranchSchema = new SimpleSchema({})
const ComputedBranchSchema = new TypedSimpleSchema({})
.extend(BranchSchema)
.extend(ComputedOnlyBranchSchema);
export type Branch = InferType<typeof BranchSchema>;
export type ComputedOnlyBranch = InferType<typeof ComputedOnlyBranchSchema>;
export type ComputedBranch = Expand<InferType<typeof BranchSchema> & InferType<typeof ComputedOnlyBranchSchema>>;
export type ComputedBranch = Expand<InferType<typeof BranchSchema> & InferType<typeof ComputedBranchSchema>>;
export { BranchSchema, ComputedBranchSchema, ComputedOnlyBranchSchema }

View File

@@ -1,15 +1,16 @@
import SimpleSchema from 'simpl-schema';
import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS';
import createPropertySchema from '/imports/api/properties/subSchemas/createPropertySchema';
import { Expand, InferType, TypedSimpleSchema } from '/imports/api/utility/TypedSimpleSchema';
let BuffSchema = createPropertySchema({
const BuffSchema = createPropertySchema({
name: {
type: String,
optional: true,
max: STORAGE_LIMITS.name,
},
description: {
type: 'inlineCalculationFieldToCompute',
type: 'inlineCalculationFieldToCompute' as const,
optional: true,
},
hideRemoveButton: {
@@ -41,14 +42,14 @@ let BuffSchema = createPropertySchema({
},
});
let ComputedOnlyBuffSchema = createPropertySchema({
const ComputedOnlyBuffSchema = createPropertySchema({
description: {
type: 'computedOnlyInlineCalculationField',
type: 'computedOnlyInlineCalculationField' as const,
optional: true,
max: STORAGE_LIMITS.description,
},
duration: {
type: 'computedOnlyField',
type: 'computedOnlyField' as const,
optional: true,
},
durationSpent: {
@@ -74,8 +75,12 @@ let ComputedOnlyBuffSchema = createPropertySchema({
},
});
const ComputedBuffSchema = new SimpleSchema()
const ComputedBuffSchema = new TypedSimpleSchema({})
.extend(BuffSchema)
.extend(ComputedOnlyBuffSchema);
export type Buff = InferType<typeof BuffSchema>;
export type ComputedOnlyBuff = InferType<typeof ComputedOnlyBuffSchema>;
export type ComputedBuff = Expand<InferType<typeof BuffSchema> & InferType<typeof ComputedOnlyBuffSchema>>;
export { BuffSchema, ComputedOnlyBuffSchema, ComputedBuffSchema };

View File

@@ -0,0 +1,115 @@
import { Attribute, ComputedAttribute, ComputedOnlyAttribute } from './Attributes';
import { Branch, ComputedBranch, ComputedOnlyBranch } from './Branches';
import { Buff, ComputedBuff, ComputedOnlyBuff } from './Buffs';
import { Class, ComputedClass, ComputedOnlyClass } from './Classes';
import { Constant, ComputedConstant, ComputedOnlyConstant } from './Constants';
import { Container, ComputedContainer, ComputedOnlyContainer } from './Containers';
import { CreatureTemplate, ComputedCreatureTemplate, ComputedOnlyCreatureTemplate } from './CreatureTemplates';
import { Damage, ComputedDamage, ComputedOnlyDamage } from './Damages';
import { DamageMultiplier, ComputedDamageMultiplier, ComputedOnlyDamageMultiplier } from './DamageMultipliers';
import { Effect, ComputedEffect, ComputedOnlyEffect } from './Effects';
import { Feature, ComputedFeature, ComputedOnlyFeature } from './Features';
import { Folder, ComputedFolder, ComputedOnlyFolder } from './Folders';
import { Item, ComputedItem, ComputedOnlyItem } from './Items';
import { Note, ComputedNote, ComputedOnlyNote } from './Notes';
import { PointBuy, ComputedPointBuy, ComputedOnlyPointBuy } from './PointBuys';
import { Proficiency, ComputedProficiency, ComputedOnlyProficiency } from './Proficiencies';
import { Reference, ComputedReference, ComputedOnlyReference } from './References';
import { Roll, ComputedRoll, ComputedOnlyRoll } from './Rolls';
import { SavingThrow, ComputedSavingThrow, ComputedOnlySavingThrow } from './SavingThrows';
import { Skill, ComputedSkill, ComputedOnlySkill } from './Skills';
import { Slot, ComputedSlot, ComputedOnlySlot } from './Slots';
import { SpellList, ComputedSpellList, ComputedOnlySpellList } from './SpellLists';
import { Spell, ComputedSpell, ComputedOnlySpell } from './Spells';
import { Toggle, ComputedToggle, ComputedOnlyToggle } from './Toggles';
import { Trigger, ComputedTrigger, ComputedOnlyTrigger } from './Triggers';
export type PropertyTypeMap = {
'attribute': Attribute,
'branch': Branch,
'buff': Buff,
'class': Class,
'constant': Constant,
'container': Container,
'creatureTemplate': CreatureTemplate,
'damage': Damage,
'damageMultiplier': DamageMultiplier,
'effect': Effect,
'feature': Feature,
'folder': Folder,
'item': Item,
'note': Note,
'pointBuy': PointBuy,
'proficiency': Proficiency,
'reference': Reference,
'roll': Roll,
'savingThrow': SavingThrow,
'skill': Skill,
'slot': Slot,
'spellList': SpellList,
'spell': Spell,
'toggle': Toggle,
'trigger': Trigger,
}
export type Property<T extends keyof PropertyTypeMap> = PropertyTypeMap[T]
export type ComputedPropertyTypeMap = {
'attribute': ComputedAttribute,
'branch': ComputedBranch,
'buff': ComputedBuff,
'class': ComputedClass,
'constant': ComputedConstant,
'container': ComputedContainer,
'creatureTemplate': ComputedCreatureTemplate,
'damage': ComputedDamage,
'damageMultiplier': ComputedDamageMultiplier,
'effect': ComputedEffect,
'feature': ComputedFeature,
'folder': ComputedFolder,
'item': ComputedItem,
'note': ComputedNote,
'pointBuy': ComputedPointBuy,
'proficiency': ComputedProficiency,
'reference': ComputedReference,
'roll': ComputedRoll,
'savingThrow': ComputedSavingThrow,
'skill': ComputedSkill,
'slot': ComputedSlot,
'spellList': ComputedSpellList,
'spell': ComputedSpell,
'toggle': ComputedToggle,
'trigger': ComputedTrigger,
}
export type ComputedProperty<T extends keyof ComputedPropertyTypeMap> = ComputedPropertyTypeMap[T]
export type ComputedOnlyPropertyTypeMap = {
'attribute': ComputedOnlyAttribute,
'branch': ComputedOnlyBranch,
'buff': ComputedOnlyBuff,
'class': ComputedOnlyClass,
'constant': ComputedOnlyConstant,
'container': ComputedOnlyContainer,
'creatureTemplate': ComputedOnlyCreatureTemplate,
'damage': ComputedOnlyDamage,
'damageMultiplier': ComputedOnlyDamageMultiplier,
'effect': ComputedOnlyEffect,
'feature': ComputedOnlyFeature,
'folder': ComputedOnlyFolder,
'item': ComputedOnlyItem,
'note': ComputedOnlyNote,
'pointBuy': ComputedOnlyPointBuy,
'proficiency': ComputedOnlyProficiency,
'reference': ComputedOnlyReference,
'roll': ComputedOnlyRoll,
'savingThrow': ComputedOnlySavingThrow,
'skill': ComputedOnlySkill,
'slot': ComputedOnlySlot,
'spellList': ComputedOnlySpellList,
'spell': ComputedOnlySpell,
'toggle': ComputedOnlyToggle,
'trigger': ComputedOnlyTrigger,
}
export type ComputedOnlyProperty<T extends keyof ComputedOnlyPropertyTypeMap> = ComputedOnlyPropertyTypeMap[T]

View File

@@ -1,5 +1,5 @@
import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS';
import { TypedSimpleSchema } from 'imports/api/utility/TypedSimpleSchema';
import { TypedSimpleSchema } from '/imports/api/utility/TypedSimpleSchema';
const ErrorSchema = new TypedSimpleSchema({
message: {

View File

@@ -1,6 +1,6 @@
import SimpleSchema from 'simpl-schema';
import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS';
import { TypedSimpleSchema } from 'imports/api/utility/TypedSimpleSchema';
import { TypedSimpleSchema } from '/imports/api/utility/TypedSimpleSchema';
const TagTargetingSchema = new TypedSimpleSchema({
// True when targeting by tags instead of stats