Suggested AbritaryStats Module

xtariq

New Member
Contributor
Following a discussion on AlterationEffects on Slack, we had a long discussion on what do with PhysicalStats. Currently, AE has a larger scope that what PS contains, but has fallen outside of the original scope of containing effects related to the "Alteration" branch of magic.

PhysicalStats covers seven physical stats, but what about other attributes/stats that an entity may have? @manu3d pointed out the example where an entity can be a snake, and have a "venom potency" stat. Having a component dedicated to that may lead to component-bloat, as it may not be used in many places. Plus, a modder would have to implement the component and systems related to it by themselves. So, one solution to this problem would be to implement an AbritaryStats module.

If we have concrete/granular definitions of attributes (like Health or maybe PhysicalStats), they can be separate. After all, having more concrete components like these allows for type safety when dealing with things, as well as custom behaviors/information. But for other more minor ones, we can create a mapping of 0 to n arbitrary stats - where each stat has a value (or can be a MappedContainer) and is associated with a String ID. So, an outside system can access/modify these stats by accessing a mapped table of attributes.

@Cervator mentioned the idea of having a three-layer approach based on how concrete they are and how often they are used.
  1. Health, discrete, used very fundamentally.
  2. PhysicalStats (and potentially MagicalStats), discrete, tied to specific effects (buffs and debuffs), other common magic system stuff etc.
  3. ArbitraryStats with a single Component that anything caring about any arbitrary stat would have to check (less efficient, but more rarely used).
Of course, there's also the issue of multiplayer and the amount of data required.

What do you all think about this matter?
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
Some more logging from Slack (edited out unrelated stuff):

several people are typing said:
cervator [17:48]
@Skaldarnar the trouble with using AS as a proxy for, say, `HealthComponent` is you lose the granularity of just asking for `XComponent` - even if you then do a quick `if` check you're still doing a pointless lookup there :confused:

manu3d [17:51]
I just thought of multiplayer. I'm guessing if there's a big explosion and many players are affected having the health parameter mapped and transmitted as some kind of string:value pair might be a bandwidth hit. The AS really might be good for infrequently changing values.

cervator [17:51]
yep, exactly

[17:52]
thus my thought on the three tiers: common (Health), uncommon (PS), rare (AS)

manu3d [17:55]
Hmmm... I'm guessing when client and server handshake they could exchange a map of more bandwidth-friendly stats id, so that when the server sends the info "everybody gets their health reduced by 19 points following an explosion" it really sends just "1:-19" 1 being understood by the client as the id of the health stat.

cervator [17:56]
possibly, but then that adds complication :slightly_smiling_face:

skaldarnar [17:56]
@Cervator: I know, I was looking for a way keep both worlds. If someone is ok with the stats interfaces as provided by AS, then that's ok, but other systems can still handle the base component X

manu3d [17:57]
The complication would be in the network layer, that's complicated anyway!! :laughing:

manu3d [18:00]
I'm just thinking in that direction because, going back to my silly snake example, there could be an Area of Effect spell that reduces the Venom Toxicity parameter to a bunch of player all at once. If we follow the same reasoning used for Health after an explosion, than we cannot implement Venom Toxicity as an ArbitraryStat unless we do something about network transmission. And perhaps also about server storage. But again, stats could be identifiable on initialization through strings, but in-game they could all be behind a short int id. It should be possible to make it all fairly performance-friendly.

cervator [18:03]
@manu3d one additional complication: individual systems tend to handle their stuff individually (good incapsulation). So lets look at the case of an AoE poison bomb with both an instant damage effect plus a DoT effect being applied from the poison

[18:04]
first frame you trigger a health loss effect by all affected targets - that's one action, throws a CauseDamage event or what not that involves the HealthComponent

[18:05]
you also trigger the creation of a DamageOverTimeComponent containing the poison info, which is then attached to all the affected targets

[18:05]
next frame the DOT "ticks" and in turn throws its own CauseDamage event applying the damage per DOT tick

[18:05]
say you bundled all the together in an AS system including health

[18:06]
excepting the DOT probably, since that's fundamentally different (an over time effect instead of instant then gone)

[18:06]
you now are looking to catch a single arbitrary stats action, then parse out "Hmm, I gotta do damage, so lets throw some CauseDamage events, then I also have to apply the DOT, so lets go do that over there..."

[18:07]
imagine how complex that could get when you have dozens of dozens of involved effects and attributes :slightly_smiling_face:

[18:08]
as it works presently you can blithely ignore the different systems and just have each care entirely about their own thing

[18:08]
i don't know if that entirely covers it or is super accurate (CauseDamage is definitely not the right event name for instance), but i think it gets the big picture?

[18:09]
maybe i'm a little off and really the AS part would be less involved with the action itself, only being looked up *by* the action

skaldarnar [18:11]
my final words on this topic for today: a thought I had some days ago was to be able to select/restrict what is usable of a module in a game play setting. My thinking was towards something like "use blocks A and B, but not C and D", but it might be interesting to think about whether this could be applied to more complex things like the stats we are talking about. So, for a specific gameplay mode, you could select Health and a few of PS stats to be available, and forbid/throw out everything else.
Edit: One additional point from me in favor of the three-tier system is that we could easily completely ignore the need for the third system (ArbitraryStats) until such a time in the future where somebody actually needs it. But by then it would probably be handy to have a quick design thread like this handy :)

Similar systems exist in DynamicCities (market commodities are paired as arbitrary strings) and Spawning (spawners and spawnables)
 

manu3d

Active Member
Contributor
Architecture
There are certainly some performance issues that would need to be verified going the ArbitraryStats way. In particular when thinking about multiplayer and the associated memory and bandwidth usage.

I.e. let's assume a ludicrous number: 1000 players connected to the same server. How would a health parameter implemented as an arbitrary stat compare to the current ad-hoc system? Health values need to be stored on a per-player basis on the server memory and they need to be replicated to all other players using bandwidth (leaving aside potential distance-based optimizations).

That been said, at least the string:value mapping can be optimized on game initialization to become a more performance friendly int:value. I.e. a module introduces the arbitrary stat "Venom Toxicity" while a second module introduces water blocks that reduce venom toxicity when drunk. Internally both modules would rely on the ArbitraryStats module to provide them with an integer id for Venom Toxicity at initializatio time. And that's what would be used for most game mechanics. A second map int:string would be available through the AS module for those circumstances in which the stat name is needed.

Also, in the discussion we had I mentioned that type-safety could be handled via metadata considered again only at initialization time. For example a statistic such as "Health" might have an associated type, i.e. byte and a min/max value, i.e. 0/100. Maybe to keep in mind a secondary goal.

That been said, I'm for elegance... as long as it works. So, I'd (theoretically) do everything via an ArbitraryStats module as long as it doesn't kill performance. If it does the three-tier system suggested by Cervator makes sense.
 
Top