refactor: script in schema

This commit is contained in:
cha0s 2024-10-21 08:58:49 -05:00
parent 01e085499a
commit 21fa00da85
9 changed files with 82 additions and 111 deletions

View File

@ -134,11 +134,22 @@ export default class Component {
$$entity = 0; $$entity = 0;
destroy() {} destroy() {}
initialize(values, defaults) { initialize(values, defaults) {
const {properties} = concrete;
for (const key in values) { for (const key in values) {
this[`$$${key}`] = values[key]; if (properties[key]?.$.set) {
properties[key].$.set(Component, this, `$$${key}`, values[key]);
}
else {
this[`$$${key}`] = values[key];
}
} }
for (const key in defaults) { for (const key in defaults) {
this[`$$${key}`] = defaults[key]; if (properties[key]?.$.set) {
properties[key].$.set(Component, this, `$$${key}`, defaults[key]);
}
else {
this[`$$${key}`] = defaults[key];
}
} }
Component.ecs.markChange(this.entity, {[Component.constructor.componentName]: values}) Component.ecs.markChange(this.entity, {[Component.constructor.componentName]: values})
} }
@ -146,7 +157,12 @@ export default class Component {
const {properties} = concrete; const {properties} = concrete;
const json = {}; const json = {};
for (const key in properties) { for (const key in properties) {
json[key] = this[key]; if (properties[key]?.$.json) {
json[key] = properties[key].$.json(this[key]);
}
else {
json[key] = this[key];
}
} }
return json; return json;
} }
@ -160,9 +176,15 @@ export default class Component {
return this.toFullJSON(); return this.toFullJSON();
} }
update(values) { update(values) {
const {properties} = concrete;
for (const key in values) { for (const key in values) {
if (concrete.properties[key]) { if (properties[key]) {
this[`$$${key}`] = values[key]; if (properties[key]?.$.set) {
properties[key].$.set(Component, this, `$$${key}`, values[key]);
}
else {
this[`$$${key}`] = values[key];
}
} }
else { else {
this[key] = values[key]; this[key] = values[key];
@ -186,7 +208,12 @@ export default class Component {
}, },
set: function set(value) { set: function set(value) {
if (this[`$$${key}`] !== value) { if (this[`$$${key}`] !== value) {
this[`$$${key}`] = value; if (concrete.properties[key]?.$.set) {
concrete.properties[key].$.set(Component, this, `$$${key}`, value);
}
else {
this[`$$${key}`] = value;
}
Component.markChange(this.entity, key, value); Component.markChange(this.entity, key, value);
} }
}, },

View File

@ -19,8 +19,8 @@ export default class Alive extends Component {
this.$$dead = true; this.$$dead = true;
const {Ticking} = ecs.get(this.entity); const {Ticking} = ecs.get(this.entity);
if (Ticking) { if (Ticking) {
this.$$death.locals.entity = ecs.get(this.entity); this.deathScript.locals.entity = ecs.get(this.entity);
const ticker = this.$$death.ticker(); const ticker = this.deathScript.ticker();
ecs.addDestructionDependency(this.entity.id, Ticking.add(ticker)); ecs.addDestructionDependency(this.entity.id, Ticking.add(ticker));
} }
} }
@ -30,21 +30,11 @@ export default class Alive extends Component {
if (0 === instance.maxHealth) { if (0 === instance.maxHealth) {
instance.maxHealth = instance.health; instance.maxHealth = instance.health;
} }
// heavy handed...
if ('undefined' !== typeof window) {
return;
}
instance.$$death = this.ecs.readScript(
instance.deathScript,
{
ecs: this.ecs,
},
);
} }
static properties = { static properties = {
deathScript: { deathScript: {
defaultValue: '/resources/misc/death-default.js', defaultValue: '/resources/misc/death-default.js',
type: 'string', type: 'script',
}, },
health: {type: 'uint32'}, health: {type: 'uint32'},
maxHealth: {type: 'uint32'}, maxHealth: {type: 'uint32'},

View File

@ -16,10 +16,6 @@ export default class Behaving extends Component {
}; };
} }
load(instance) { load(instance) {
// heavy handed...
if ('undefined' !== typeof window) {
return;
}
for (const key in instance.routines) { for (const key in instance.routines) {
instance.$$routineInstances[key] = this.ecs.readScript(instance.routines[key]); instance.$$routineInstances[key] = this.ecs.readScript(instance.routines[key]);
} }

View File

@ -9,8 +9,6 @@ export default class Collider extends Component {
return class ColliderInstance extends super.instanceFromSchema() { return class ColliderInstance extends super.instanceFromSchema() {
$$aabb = {x0: Infinity, x1: -Infinity, y0: Infinity, y1: -Infinity}; $$aabb = {x0: Infinity, x1: -Infinity, y0: Infinity, y1: -Infinity};
$$aabbs = []; $$aabbs = [];
$$collisionStart;
$$collisionEnd;
$$intersections = new Map(); $$intersections = new Map();
get aabb() { get aabb() {
const {Position: {x: px, y: py}} = ecs.get(this.entity); const {Position: {x: px, y: py}} = ecs.get(this.entity);
@ -77,8 +75,8 @@ export default class Collider extends Component {
} }
} }
if (!hasMatchingIntersection) { if (!hasMatchingIntersection) {
if (this.$$collisionStart) { if (this.collisionStartScript) {
const script = this.$$collisionStart.clone(); const script = this.collisionStartScript.clone();
script.locals.entity = thisEntity; script.locals.entity = thisEntity;
script.locals.other = otherEntity; script.locals.other = otherEntity;
script.locals.pair = [body, otherBody]; script.locals.pair = [body, otherBody];
@ -87,8 +85,8 @@ export default class Collider extends Component {
ecs.addDestructionDependency(otherEntity.id, promise); ecs.addDestructionDependency(otherEntity.id, promise);
ecs.addDestructionDependency(thisEntity.id, promise); ecs.addDestructionDependency(thisEntity.id, promise);
} }
if (other.$$collisionStart) { if (other.collisionStartScript) {
const script = other.$$collisionStart.clone(); const script = other.collisionStartScript.clone();
script.locals.entity = otherEntity; script.locals.entity = otherEntity;
script.locals.other = thisEntity; script.locals.other = thisEntity;
script.locals.pair = [otherBody, body]; script.locals.pair = [otherBody, body];
@ -162,8 +160,8 @@ export default class Collider extends Component {
intersection.entity.bodies[intersection.i], intersection.entity.bodies[intersection.i],
intersection.other.bodies[intersection.j], intersection.other.bodies[intersection.j],
]; ];
if (this.$$collisionEnd) { if (this.collisionEndScript) {
const script = this.$$collisionEnd.clone(); const script = this.collisionEndScript.clone();
script.locals.other = otherEntity; script.locals.other = otherEntity;
script.locals.pair = [body, otherBody]; script.locals.pair = [body, otherBody];
const ticker = script.ticker(); const ticker = script.ticker();
@ -171,8 +169,8 @@ export default class Collider extends Component {
ecs.addDestructionDependency(thisEntity.id, promise); ecs.addDestructionDependency(thisEntity.id, promise);
ecs.addDestructionDependency(otherEntity.id, promise); ecs.addDestructionDependency(otherEntity.id, promise);
} }
if (other.$$collisionEnd) { if (other.collisionEndScript) {
const script = other.$$collisionEnd.clone(); const script = other.collisionEndScript.clone();
script.locals.other = thisEntity; script.locals.other = thisEntity;
script.locals.pair = [otherBody, body]; script.locals.pair = [otherBody, body];
const ticker = script.ticker(); const ticker = script.ticker();
@ -268,26 +266,6 @@ export default class Collider extends Component {
}; };
} }
instance.updateAabbs(); instance.updateAabbs();
// heavy handed...
if ('undefined' !== typeof window) {
return;
}
if (instance.collisionEndScript) {
instance.$$collisionEnd = this.ecs.readScript(
instance.collisionEndScript,
{
ecs: this.ecs,
},
);
}
if (instance.collisionStartScript) {
instance.$$collisionStart = this.ecs.readScript(
instance.collisionStartScript,
{
ecs: this.ecs,
},
);
}
} }
static properties = { static properties = {
bodies: { bodies: {
@ -311,8 +289,8 @@ export default class Collider extends Component {
}, },
}, },
}, },
collisionEndScript: {type: 'string'}, collisionEndScript: {type: 'script'},
collisionStartScript: {type: 'string'}, collisionStartScript: {type: 'script'},
isColliding: {defaultValue: 1, type: 'uint8'}, isColliding: {defaultValue: 1, type: 'uint8'},
}; };
} }

View File

@ -6,26 +6,14 @@ export default class Harmful extends Component {
return class HarmfulInstance extends super.instanceFromSchema() { return class HarmfulInstance extends super.instanceFromSchema() {
harm(other) { harm(other) {
const entity = ecs.get(this.entity); const entity = ecs.get(this.entity);
const script = this.$$harm.clone(); const script = this.harmScript.clone();
script.locals.other = other; script.locals.other = other;
script.locals.entity = entity; script.locals.entity = entity;
entity.Ticking.add(script.ticker()); entity.Ticking.add(script.ticker());
} }
} }
} }
load(instance) {
// heavy handed...
if ('undefined' !== typeof window) {
return;
}
instance.$$harm = this.ecs.readScript(
instance.harmScript,
{
ecs: this.ecs,
},
);
}
static properties = { static properties = {
harmScript: {type: 'string'}, harmScript: {type: 'script'},
}; };
} }

View File

@ -4,9 +4,8 @@ export default class Interactive extends Component {
instanceFromSchema() { instanceFromSchema() {
const {ecs} = this; const {ecs} = this;
return class ControlledInstance extends super.instanceFromSchema() { return class ControlledInstance extends super.instanceFromSchema() {
$$interact;
interact(initiator) { interact(initiator) {
const script = this.$$interact.clone(); const script = this.interactScript.clone();
script.locals.initiator = initiator; script.locals.initiator = initiator;
script.locals.subject = ecs.get(this.entity); script.locals.subject = ecs.get(this.entity);
const {Ticking} = script.locals.subject; const {Ticking} = script.locals.subject;
@ -20,20 +19,8 @@ export default class Interactive extends Component {
} }
} }
} }
load(instance) {
// heavy handed...
if ('undefined' !== typeof window) {
return;
}
instance.$$interact = this.ecs.readScript(
instance.interactScript,
{
ecs: this.ecs,
},
);
}
static properties = { static properties = {
interacting: {type: 'uint8'}, interacting: {type: 'uint8'},
interactScript: {type: 'string'}, interactScript: {type: 'script'},
}; };
} }

View File

@ -5,44 +5,26 @@ export default class Plant extends Component {
const {ecs} = this; const {ecs} = this;
const Instance = super.instanceFromSchema(); const Instance = super.instanceFromSchema();
return class PlantInstance extends Instance { return class PlantInstance extends Instance {
$$grow;
$$mayGrow;
grow() { grow() {
const {Ticking} = ecs.get(this.entity); const {Ticking} = ecs.get(this.entity);
Ticking.add(this.$$grow.ticker()); Ticking.add(this.growScript.ticker());
} }
mayGrow() { mayGrow() {
return this.$$mayGrow.evaluate(); return this.mayGrowScript.evaluate();
} }
}; };
} }
load(instance) { load(instance) {
// heavy handed... instance.growScript.locals.plant = instance;
if ('undefined' !== typeof window) { instance.mayGrowScript.locals.plant = instance;
return;
}
instance.$$grow = this.ecs.readScript(
instance.growScript,
{
ecs: this.ecs,
plant: instance,
},
);
instance.$$mayGrow = this.ecs.readScript(
instance.mayGrowScript,
{
ecs: this.ecs,
plant: instance,
},
);
} }
// heavy handed... // heavy handed...
markChange() {} markChange() {}
static properties = { static properties = {
growScript: {type: 'string'}, growScript: {type: 'script'},
growth: {type: 'uint16'}, growth: {type: 'uint16'},
growthFactor: {defaultValue: 127, type: 'uint8'}, growthFactor: {defaultValue: 127, type: 'uint8'},
mayGrowScript: {type: 'string'}, mayGrowScript: {type: 'script'},
stage: {type: 'uint8'}, stage: {type: 'uint8'},
stages: { stages: {
type: 'array', type: 'array',

View File

@ -0,0 +1,22 @@
import string from './string.js';
export default function () {
const spec = string();
return {
...spec,
json: (value) => {
return value ? value.path : '';
},
set: (Component, receiver, key, value) => {
if (!value) {
return;
}
receiver[key] = Component.ecs.readScript(
value,
{
ecs: Component.ecs,
},
);
},
};
}

View File

@ -4,18 +4,19 @@ export default class Script {
static registered = {}; static registered = {};
constructor(fn, locals) { constructor(path, fn, locals) {
if (!fn) { if (!fn) {
throw new TypeError('Script needs a function'); throw new TypeError('Script needs a function');
} }
this.fn = fn; this.fn = fn;
this.iterator = null; this.iterator = null;
this.locals = locals; this.locals = locals;
this.path = path;
this.$$ticker = null; this.$$ticker = null;
} }
clone() { clone() {
return new this.constructor(this.fn, this.locals); return new this.constructor(this.path, this.fn, this.locals);
} }
evaluate() { evaluate() {
@ -27,7 +28,7 @@ export default class Script {
if (!fn) { if (!fn) {
throw new Error(`no such script: ${path}`); throw new Error(`no such script: ${path}`);
} }
const script = new this(fn, locals); const script = new this(path, fn, locals);
if (import.meta.hot) { if (import.meta.hot) {
const hotRef = new WeakRef(script); const hotRef = new WeakRef(script);
import.meta.hot.accept('./scripts.js', ({default: scripts}) => { import.meta.hot.accept('./scripts.js', ({default: scripts}) => {