Well, I dreamed of a game so immersive you could fight like movie characters fight, with lots of units, with complex character building, and so on. One aspect I need is a high-performance simulation of the game world.
Making a high-performance game engine IS really difficult. I want to cry.
Now, imagine I want to have some units fighting.
struct Unit
health::Float64
attack::Float64
#Bla bla bla...
end
function attack!(x::Unit,y::Unit)
y.health -= x.attack
#Bla bla bla... maybe calculate death and so on.
end
Now, if I have a mod that adds armor.
function attack!(x::Unit,y::Unit)
attack = x.attack
#Calculate armor.
attack -= attack*max(y.armor-x.armor_penetration,0)
y.health -= attack
#Bla bla bla... maybe calculate death and so on.
end
But now, a new field has been added! How do I infer what field do units use?
And if I have TWO mods. Let’s say the second mod adds a morale system.
function attack!(x::Unit,y::Unit)
y.health -= x.attack
#Bla bla bla... maybe calculate death and so on.
end
Now, if I have a mod that adds armor.
function attack!(x::Unit,y::Unit)
attack = x.attack
#Calculate armor.
attack -= attack*max(y.armor-x.armor_penetration,0)
y.health -= attack
#Bla bla bla... maybe calculate death and so on.
end
Wrong.
function attack!(x::Unit,y::Unit)
attack = x.attack
attack *= morale(x)/max_morale(x)
y.health -= attack
#Bla bla bla... maybe calculate death and so on.
end
Right.
function attack!(x::Unit,y::Unit)
attack = x.attack
attack *= morale(x)/max_morale(x)
attack -= attack*max(y.armor-x.armor_penetration,0)
y.health -= attack
#Bla bla bla... maybe calculate death and so on.
end
So, when I add mods, I can’t just replace the code! I need to put them together!
And now, these suddenly add armor, armor penetration, morale system, etc… which means the attributes would have to change! But what attributes? Using a dictionary to store attributes wouldn’t be efficient. Ideally, you would have the compiler infer what attributes the “units” use. This could be implemented in multiple ways, for example, to have each mod explicitly specify what attributes there are, or to trace from usage seen in functions, which I find a bit better since you might have one mod that adds multiple systems for other mods and you might not use all of them.
But the pipeline is not over! Now, imagine I want to add an efficient element system, or maybe a union of unit types or something. Let’s implement these as binary traits.
struct Unit
elements::UInt64
#bla bla bla.
end
For example, if your attack does double damage to enemies with certain elements, half damage to enemies with certain elements, and so on…
you could do…
if has_fire_element(unit)
damage *= 2
end
But… get a lot of these and it gets slow.
You could actually do this.
damage *= damage_multiplier[begin+((unit.element&mask)*magic)>>shift]
How do you actually find the magic number and magic table? Well, perfect hashing brute force search precomputed.
But now, imagine this optimization where the elements and effects came from different mods.
And to push the limit of computation, you need this!
So, I need a compiler system that can compose mods by loading them together, infer the attributes needed, and then figure out the memory layout of those attributes and how to efficiently compute effects based on those attributes!
And that was just the attribute system!
And this was just the attribute system! I have yet to touch the pathfinding, rendering, other GPU programming, AI, light system, sound system, physics system, etc!
I want to cry.