-
-
Save fowlmouth/5516425 to your computer and use it in GitHub Desktop.
## entitty has been moved to the fowltek package |
Unicast macro result: | |
proc die*(entity: var TEntity) {..} = | |
echo "message ID is ", messageID("die") | |
echo "vtable is $# len" % $ len(entity.typeInfo.vtable) | |
if not entity.typeInfo.vtable[messageID("die")].isNil: | |
cast[proc (entity: var TEntity) {.noConv.}](entity.typeInfo.vtable[ | |
messageID("die")])(entity) | |
Unicast macro result: | |
proc takeDamage*(entity: var TEntity; amount: int) {..} = | |
echo "message ID is ", messageID("takeDamage") | |
echo "vtable is $# len" % $ len(entity.typeInfo.vtable) | |
if not entity.typeInfo.vtable[messageID("takeDamage")].isNil: | |
cast[proc (entity: var TEntity; amount: int) {.noConv.}](entity.typeInfo.vtable[ | |
messageID("takeDamage")])(entity, amount) | |
block: | |
let msg_id = MessageID("debugStr") | |
let comp = componentInfo(THealth) | |
if messageTypes[msg_id]: | |
if comp.multicast_messages.hasKey(msg_id): | |
echo "Overriding the implementation of multicast message `debugStr` for ", | |
comp.name | |
comp.multicast_messages[msg_id] = cast[pointer](proc (entity: var TEntity; | |
result: var seq[string]) = | |
result.add "$#: $#".format(ComponentInfo(THealth).name, entity[THealth])) | |
else: | |
if comp.unicast_messages.hasKey(msg_id): | |
echo "Overriding implementation of unicast message debugStr for ", | |
comp.name | |
comp.unicast_messages[msg_id] = (weight: 0, func: cast[pointer](proc ( | |
entity: var TEntity; result: var seq[string]) = | |
result.add "$#: $#".format(ComponentInfo(THealth).name, entity[THealth]))) | |
block: | |
let msg_id = MessageID("debugStr") | |
let comp = componentInfo(TPos) | |
if messageTypes[msg_id]: | |
if comp.multicast_messages.hasKey(msg_id): | |
echo "Overriding the implementation of multicast message `debugStr` for ", | |
comp.name | |
comp.multicast_messages[msg_id] = cast[pointer](proc (entity: var TEntity; | |
result: var seq[string]) = | |
result.add "$#: $#".format(ComponentInfo(TPos).name, entity[TPos])) | |
else: | |
if comp.unicast_messages.hasKey(msg_id): | |
echo "Overriding implementation of unicast message debugStr for ", | |
comp.name | |
comp.unicast_messages[msg_id] = (weight: 0, func: cast[pointer](proc ( | |
entity: var TEntity; result: var seq[string]) = | |
result.add "$#: $#".format(ComponentInfo(TPos).name, entity[TPos]))) | |
block: | |
let msg_id = MessageID("debugStr") | |
let comp = componentInfo(TVel) | |
if messageTypes[msg_id]: | |
if comp.multicast_messages.hasKey(msg_id): | |
echo "Overriding the implementation of multicast message `debugStr` for ", | |
comp.name | |
comp.multicast_messages[msg_id] = cast[pointer](proc (entity: var TEntity; | |
result: var seq[string]) = | |
result.add "$#: $#".format(ComponentInfo(TVel).name, entity[TVel])) | |
else: | |
if comp.unicast_messages.hasKey(msg_id): | |
echo "Overriding implementation of unicast message debugStr for ", | |
comp.name | |
comp.unicast_messages[msg_id] = (weight: 0, func: cast[pointer](proc ( | |
entity: var TEntity; result: var seq[string]) = | |
result.add "$#: $#".format(ComponentInfo(TVel).name, entity[TVel]))) | |
block: | |
let msg_id = MessageID("debugStr") | |
let comp = componentInfo(TSpriteInstance) | |
if messageTypes[msg_id]: | |
if comp.multicast_messages.hasKey(msg_id): | |
echo "Overriding the implementation of multicast message `debugStr` for ", | |
comp.name | |
comp.multicast_messages[msg_id] = cast[pointer](proc (entity: var TEntity; | |
result: var seq[string]) = | |
result.add "$#: $#".format(ComponentInfo(TSpriteInstance).name, | |
entity[TSpriteInstance])) | |
else: | |
if comp.unicast_messages.hasKey(msg_id): | |
echo "Overriding implementation of unicast message debugStr for ", | |
comp.name | |
comp.unicast_messages[msg_id] = (weight: 0, func: cast[pointer](proc ( | |
entity: var TEntity; result: var seq[string]) = | |
result.add "$#: $#".format(ComponentInfo(TSpriteInstance).name, | |
entity[TSpriteInstance]))) | |
block: | |
let msg_id = MessageID("debugStr") | |
let comp = componentInfo(TBoundingBox) | |
if messageTypes[msg_id]: | |
if comp.multicast_messages.hasKey(msg_id): | |
echo "Overriding the implementation of multicast message `debugStr` for ", | |
comp.name | |
comp.multicast_messages[msg_id] = cast[pointer](proc (entity: var TEntity; | |
result: var seq[string]) = | |
result.add "$#: $#".format(ComponentInfo(TBoundingBox).name, | |
entity[TBoundingBox])) | |
else: | |
if comp.unicast_messages.hasKey(msg_id): | |
echo "Overriding implementation of unicast message debugStr for ", | |
comp.name | |
comp.unicast_messages[msg_id] = (weight: 0, func: cast[pointer](proc ( | |
entity: var TEntity; result: var seq[string]) = | |
result.add "$#: $#".format(ComponentInfo(TBoundingBox).name, | |
entity[TBoundingBox]))) | |
block: | |
let msg_id = MessageID("takeDamage") | |
let comp = componentInfo(THealth) | |
if messageTypes[msg_id]: | |
if comp.multicast_messages.hasKey(msg_id): | |
echo "Overriding the implementation of multicast message `takeDamage` for ", | |
comp.name | |
comp.multicast_messages[msg_id] = cast[pointer](proc (entity: var TEntity; | |
amount: int) = | |
entity[THealth].hp -= amount | |
if entity[THealth].hp <= 0: | |
entity.die() | |
echo "Entity took damage, now at ", entity[THealth].hp) | |
else: | |
if comp.unicast_messages.hasKey(msg_id): | |
echo "Overriding implementation of unicast message takeDamage for ", | |
comp.name | |
comp.unicast_messages[msg_id] = (weight: 0, func: cast[pointer](proc ( | |
entity: var TEntity; amount: int) = | |
entity[THealth].hp -= amount | |
if entity[THealth].hp <= 0: | |
entity.die() | |
echo "Entity took damage, now at ", entity[THealth].hp)) | |
block: | |
let msg_id = MessageID("debugDraw") | |
let comp = componentInfo(TPos) | |
if messageTypes[msg_id]: | |
if comp.multicast_messages.hasKey(msg_id): | |
echo "Overriding the implementation of multicast message `debugDraw` for ", | |
comp.name | |
comp.multicast_messages[msg_id] = cast[pointer](proc (entity: var TEntity; | |
R: PRenderer) = | |
let s = $ entity[TPos] | |
let p = entity[TPos] | |
R.stringRGBA(p.x.int16, p.y.int16, s, 255, 0, 0, 255) | |
) | |
else: | |
if comp.unicast_messages.hasKey(msg_id): | |
echo "Overriding implementation of unicast message debugDraw for ", | |
comp.name | |
comp.unicast_messages[msg_id] = (weight: 0, func: cast[pointer](proc ( | |
entity: var TEntity; R: PRenderer) = | |
let s = $ entity[TPos] | |
let p = entity[TPos] | |
R.stringRGBA(p.x.int16, p.y.int16, s, 255, 0, 0, 255) | |
)) |
I've been busy this week at work, but I'll look at the problems you've reported this weekend (or sooner).
I've noticed you are not a big user of getAst
or quote
from the macros module. Why so? They are both nicer to look at IMO and much faster to execute by the compiler (because most of the AST crunching happens only once during the semantic analysis instead of every time in "evals").
The same argument for branching in unicast messages applies for multicast as well.
There is no reason why the dispatched code can't be just
for entry in entity.typeInfo.multicastTable[MulticastMessageID("msgname")]:
cast[proc_type](entity.procptr) (offset_ptr(entity.entityData, entry.offset), args... )
If there is only one implementation, it still will be faster to have a for loop over 1 element array/seq than to have a branching in the dispatcher code to detect that.
I'm a bit inconsistent in my explanations about the vtable and the multicastTable. The reason for this is that in my system there were no such distinction (I was just using C++ unions for the record types). It's easier to explain the system with two tables and it doesn't hurt the performance at all, but please note that if there are two tables, there must be also two MessageID functions: MessageID vs MulticastMessageID
Nice progress, fowl. I have to study a bit more carefully what are you doing inside the macros, but I can see certain things already. You don't need to have this kind of branching inside the message dispatchers:
if not entity.typeInfo.vtable[messageID("die")].isNil:
Instead, it's smarted if you populate the vtable with a "default" implementation that raises an error or silently ignores the message. My system also allowed the user to supply his own default implementation for a given message. The default implementation should take an entity as a parameter (instead of component). To achieve this you need to use a trampoline function. Here is how it works: