Skip to content

Instantly share code, notes, and snippets.

@fowlmouth
Last active December 16, 2015 23:49
Show Gist options
  • Save fowlmouth/5516425 to your computer and use it in GitHub Desktop.
Save fowlmouth/5516425 to your computer and use it in GitHub Desktop.
nimrod component/entity system
## 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)
))
@zah
Copy link

zah commented May 15, 2013

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment