mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-02-27 13:29:32 +00:00
ecs: ref types?
This commit is contained in:
parent
310ce87bcc
commit
8b96c746a2
@ -71,21 +71,21 @@ system SimpleKernel
|
||||
sbc {{<ypos}}
|
||||
sta {{$11}}
|
||||
|
||||
ldy {{<bitmap}} ; deref
|
||||
lda Bitmap_bitmapdata_b0,y
|
||||
ldy {{<bitmap}} ; deref
|
||||
lda {{<Bitmap.bitmapdata}},y
|
||||
sec
|
||||
sbc {{$11}}
|
||||
sta {{$0}},x
|
||||
lda Bitmap_bitmapdata_b8,y
|
||||
lda {{>Bitmap.bitmapdata}},y
|
||||
sbc #0
|
||||
sta {{$2}},x
|
||||
|
||||
ldy {{<colormap}}
|
||||
lda Colormap_colormapdata_b0,y
|
||||
lda {{<Colormap.colormapdata}},y
|
||||
sec
|
||||
sbc {{$11}}
|
||||
sta {{$4}},x
|
||||
lda Colormap_colormapdata_b8,y
|
||||
lda {{>Colormap.colormapdata}},y
|
||||
sbc #0
|
||||
sta {{$6}},x
|
||||
|
||||
@ -273,7 +273,7 @@ scope Main
|
||||
init height = 8
|
||||
init xpos = 100
|
||||
init ypos = 60
|
||||
init bitmap = 1
|
||||
init bitmap = #Bitmap2
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -92,7 +92,7 @@ export class ECSCompiler extends Tokenizer {
|
||||
this.compileError(`Unknown data type`); // TODO
|
||||
}
|
||||
|
||||
parseDataValue() : DataValue {
|
||||
parseDataValue(field: DataField) : DataValue {
|
||||
let tok = this.peekToken();
|
||||
if (tok.type == 'integer') {
|
||||
return this.expectInteger();
|
||||
@ -102,9 +102,17 @@ export class ECSCompiler extends Tokenizer {
|
||||
return new Uint8Array(this.parseDataArray());
|
||||
}
|
||||
if (tok.str == '#') {
|
||||
let reftype = field.dtype == 'ref' ? field as RefType : undefined;
|
||||
let e = this.parseEntityRef();
|
||||
// TODO: entity ref types by query?
|
||||
return e.id;
|
||||
let id = e.id;
|
||||
if (reftype) {
|
||||
// TODO: make this a function? elo ehi etc?
|
||||
let atypes = this.em.archetypesMatching(reftype.query);
|
||||
let entities = this.currentScope.entitiesMatching(atypes);
|
||||
if (entities.length == 0) this.compileError(`This entitiy doesn't seem to fit the reference type.`);
|
||||
id -= entities[0].id;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
this.compileError(`Unknown data value`); // TODO
|
||||
}
|
||||
@ -211,7 +219,9 @@ export class ECSCompiler extends Tokenizer {
|
||||
let comps = this.em.componentsWithFieldName([{etype: e.etype, cmatch:e.etype.components}], name);
|
||||
if (comps.length == 0) this.compileError(`I couldn't find a field named "${name}" for this entity.`)
|
||||
if (comps.length > 1) this.compileError(`I found more than one field named "${name}" for this entity.`)
|
||||
let value = this.parseDataValue();
|
||||
let field = comps[0].fields.find(f => f.name == name);
|
||||
if (!field) this.internalError();
|
||||
let value = this.parseDataValue(field);
|
||||
if (cmd == 'const') this.currentScope.setConstValue(e, comps[0], name, value);
|
||||
if (cmd == 'init') this.currentScope.setInitValue(e, comps[0], name, value);
|
||||
} else {
|
||||
@ -235,7 +245,7 @@ export class ECSCompiler extends Tokenizer {
|
||||
return cref;
|
||||
}
|
||||
|
||||
parseEntityRef() : Entity {
|
||||
parseEntityRef(reftype?: RefType) : Entity {
|
||||
this.expectToken('#');
|
||||
let name = this.expectIdent().str;
|
||||
let eref = this.currentScope.entities.find(e => e.name == name);
|
||||
|
@ -28,6 +28,11 @@
|
||||
// - managing memory and scope
|
||||
// - converting assets to native formats?
|
||||
// - removing unused data
|
||||
//
|
||||
// it's more convenient to have loops be zero-indexed
|
||||
// for page cross, temp storage, etc
|
||||
// should references be zero-indexed to a field, or global?
|
||||
// should we limit # of entities passed to systems? min-max
|
||||
|
||||
function mksymbol(c: ComponentType, fieldName: string) {
|
||||
return c.name + '_' + fieldName;
|
||||
@ -174,8 +179,15 @@ Start:
|
||||
indexed_x(ident: string) {
|
||||
return ident + ',x';
|
||||
}
|
||||
fieldsymbol(component: ComponentType, field: DataField, bitofs: number) {
|
||||
return `${component.name}_${field.name}_b${bitofs}`;
|
||||
}
|
||||
datasymbol(component: ComponentType, field: DataField, eid: number) {
|
||||
return `${component.name}_${field.name}_e${eid}`;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: merge with Dialect?
|
||||
export class SourceFileExport {
|
||||
lines: string[] = [];
|
||||
|
||||
@ -364,7 +376,7 @@ export class EntityScope {
|
||||
// TODO: split arrays
|
||||
f.access = [];
|
||||
for (let i = 0; i < bits; i += 8) {
|
||||
let symbol = name + '_b' + i;
|
||||
let symbol = this.dialect.fieldsymbol(f.component, f.field, i);
|
||||
f.access.push({ symbol, bit: 0, width: 8 }); // TODO
|
||||
if (!readonly) {
|
||||
segment.allocateBytes(symbol, rangelen * bytesperelem); // TODO
|
||||
@ -382,9 +394,9 @@ export class EntityScope {
|
||||
let entcount = fieldrange.ehi - fieldrange.elo + 1;
|
||||
// is it a byte array?
|
||||
if (v instanceof Uint8Array) {
|
||||
let datasym = `${c.name}_${f.name}_e${e.id}`;
|
||||
let ptrlosym = `${c.name}_${f.name}_b0`;
|
||||
let ptrhisym = `${c.name}_${f.name}_b8`;
|
||||
let datasym = this.dialect.datasymbol(c, f, e.id);
|
||||
let ptrlosym = this.dialect.fieldsymbol(c, f, 0);
|
||||
let ptrhisym = this.dialect.fieldsymbol(c, f, 8);
|
||||
segment.allocateInitData(datasym, v);
|
||||
let loofs = segment.allocateBytes(ptrlosym, entcount);
|
||||
let hiofs = segment.allocateBytes(ptrhisym, entcount);
|
||||
@ -396,7 +408,7 @@ export class EntityScope {
|
||||
// TODO: what if > 8 bits?
|
||||
// TODO: what if mix of var, const, and init values?
|
||||
if (fieldrange.ehi > fieldrange.elo) {
|
||||
let datasym = `${c.name}_${f.name}_b0`;
|
||||
let datasym = this.dialect.fieldsymbol(c, f, 0);
|
||||
let base = segment.allocateBytes(datasym, entcount);
|
||||
segment.initdata[base + e.id - fieldrange.elo] = v;
|
||||
}
|
||||
@ -438,10 +450,16 @@ export class EntityScope {
|
||||
setConstValue(e: Entity, component: ComponentType, fieldName: string, value: DataValue) {
|
||||
let c = this.em.singleComponentWithFieldName([{etype: e.etype, cmatch:[component]}], fieldName, "setConstValue");
|
||||
e.consts[mksymbol(component, fieldName)] = value;
|
||||
if (this.em.symbols[mksymbol(component, fieldName)] == 'init')
|
||||
throw new Error(`Can't mix const and init values for a component field`);
|
||||
this.em.symbols[mksymbol(component, fieldName)] = 'const';
|
||||
}
|
||||
setInitValue(e: Entity, component: ComponentType, fieldName: string, value: DataValue) {
|
||||
let c = this.em.singleComponentWithFieldName([{etype: e.etype, cmatch:[component]}], fieldName, "setConstValue");
|
||||
let c = this.em.singleComponentWithFieldName([{etype: e.etype, cmatch:[component]}], fieldName, "setInitValue");
|
||||
e.inits[mkscopesymbol(this, component, fieldName)] = value;
|
||||
if (this.em.symbols[mksymbol(component, fieldName)] == 'const')
|
||||
throw new Error(`Can't mix const and init values for a component field`);
|
||||
this.em.symbols[mksymbol(component, fieldName)] = 'init';
|
||||
}
|
||||
generateCodeForEvent(event: string): string {
|
||||
// find systems that respond to event
|
||||
@ -517,7 +535,7 @@ export class EntityScope {
|
||||
return this.generateCodeForField(sys, action, atypes, entities, rest, 0);
|
||||
case '>': // high byte
|
||||
return this.generateCodeForField(sys, action, atypes, entities, rest, 8);
|
||||
case '^': // reference
|
||||
case '^': // subroutine reference
|
||||
return this.includeSubroutine(rest);
|
||||
default:
|
||||
throw new Error(`unrecognized command ${cmd} in ${entire}`);
|
||||
@ -541,8 +559,22 @@ export class EntityScope {
|
||||
generateCodeForField(sys: System, action: Action,
|
||||
atypes: ArchetypeMatch[], entities: Entity[],
|
||||
fieldName: string, bitofs: number): string {
|
||||
|
||||
var component : ComponentType;
|
||||
var qualified = false;
|
||||
// is qualified field?
|
||||
if (fieldName.indexOf('.') > 0) {
|
||||
let [cname,fname] = fieldName.split('.');
|
||||
component = this.em.getComponentByName(cname);
|
||||
fieldName = fname;
|
||||
qualified = true;
|
||||
if (component == null) throw new Error(`no component named "${cname}"`)
|
||||
} else {
|
||||
component = this.em.singleComponentWithFieldName(atypes, fieldName, `${sys.name}:${action.event}`);
|
||||
}
|
||||
// find archetypes
|
||||
let component = this.em.singleComponentWithFieldName(atypes, fieldName, `${sys.name}:${action.event}`);
|
||||
let field = component.fields.find(f => f.name == fieldName);
|
||||
if (field == null) throw new Error(`no field named "${fieldName}" in component`)
|
||||
// see if all entities have the same constant value
|
||||
let constValues = new Set<DataValue>();
|
||||
for (let e of entities) {
|
||||
@ -561,19 +593,29 @@ export class EntityScope {
|
||||
}
|
||||
}
|
||||
// TODO: offset > 0?
|
||||
//let range = this.bss.getFieldRange(component, fieldName);
|
||||
// TODO: don't mix const and init data
|
||||
let range = this.bss.getFieldRange(component, fieldName) || this.rodata.getFieldRange(component, fieldName);
|
||||
let eidofs = range.elo - entities[0].id;
|
||||
// TODO: dialect
|
||||
let ident = `${component.name}_${fieldName}_b${bitofs}`;
|
||||
if (action.select == 'once') {
|
||||
let ident = this.dialect.fieldsymbol(component, field, bitofs);
|
||||
if (qualified) {
|
||||
return this.dialect.absolute(ident);
|
||||
} else if (action.select == 'once') {
|
||||
if (entities.length != 1)
|
||||
throw new Error(`can't choose multiple entities for ${fieldName} with select=once`);
|
||||
return this.dialect.absolute(ident) // TODO? check there's only 1 entity?
|
||||
return this.dialect.absolute(ident);
|
||||
} else {
|
||||
return this.dialect.indexed_x(ident)
|
||||
// TODO: right direction?
|
||||
if (eidofs > 0) {
|
||||
ident += '+' + eidofs;
|
||||
} else if (eidofs < 0) {
|
||||
ident += '' + eidofs;
|
||||
}
|
||||
return this.dialect.indexed_x(ident);
|
||||
}
|
||||
}
|
||||
entitiesMatching(atypes: ArchetypeMatch[]) {
|
||||
let result = [];
|
||||
let result : Entity[] = [];
|
||||
for (let e of this.entities) {
|
||||
for (let a of atypes) {
|
||||
// TODO: what about subclasses?
|
||||
@ -646,6 +688,7 @@ export class EntityManager {
|
||||
components: { [name: string]: ComponentType } = {};
|
||||
systems: { [name: string]: System } = {};
|
||||
scopes: { [name: string]: EntityScope } = {};
|
||||
symbols: { [name: string] : 'init' | 'const' } = {};
|
||||
|
||||
constructor(public readonly dialect: Dialect_CA65) {
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user