I’ve made a little tool! Just for fun, I thought I’d try my hand at building a 3D graphics engine in Python by following a tutorial. And that got me thinking… Zkillboard contains a ton of data about ship losses and ESI can get me those coordinates. By pulling those two together and adding to a scene in my graphics engine, I can build 3D representations of battles in EVE!
To give credit where credit is due, this was originally an idea by an old corpmate and friend, Akee. He created a much better implementation of this in C++ as a private project.
Code: https://github.com/VargurStorm/pyBattleVis
This thing is honestly really cool. It’s slow as hell, sure. If I wanted to do it properly I would have used an existing graphics/game engine. I also wouldn’t use Python. It’s slow!
You can go ahead and run it from the Github link above. My repo includes instructions on how to run it, though I am not sure if it will work well on Windows. Last I checked there was a major bug with light rendering. If you see it and know how to fix it, please let me know or put a PR in.
Dev Log-ish
You might be wondering how, exactly, this tool works or what it actually does. At the time of writing, these are the steps that my tool takes to produce the 3D scene you can fly around in:
- Shows a Tkinter window, allowing you to enter a Zkillboard BR (not a saved BR)
- Also takes a multipler value to scale your wreck cubes up or down
- Takes an option between ‘ship’ and ‘char’ to render ships on cubes or the portraits of the people who were killed.
- Based on the battle report, it goes to Zkillboard’s API to get a list of losses. For each loss, it stores the killID and hash.
- Using those, it contacts the ESI API to get coordinate information for every loss alongside other info such as the character, ship type, and value.
- This is then passed to a data class to save those inputs before sanitising them a little bit.
- Depending on the choice of ship/char, it downloads the appropriate textures.
- It will then generate OpenGL textures from the supplied PNGs and adds them to the Graphics Engine
- The wrecks are scaled based on a dictionary of sizes that I have added into the tool (modules.config.constants.ShipSizes)
- Finally, we then throw all of that into a build_scene function which just adds cubes like this:
Cube(
app, # Graphics Engine
tex_id=tex_id, # Ship or char
vao_name=vao_name, # This is determining blue or red cubes
pos=(wreck.pos_x, wreck.pos_y, wreck.pos_z), # Pos in space
scale=(wreck.ship_scale, wreck.ship_scale, wreck.ship_scale))
)
The code above isn’t exactly as it is in repo with comments. I added those in here to let you see what is being added to the scene. Once all of that is done, it spins up the engine properly and shows you a scene that you can fly around 😀
Working all of this out was fun and one of the questions I’ve had a few times is “How do you get the positions?”. Other than the aforementioned API calls, EVE gives us really big coordinates like 10111235521 or -512300499212.
By taking those x, y, and z coordinates and doing modulo 10000 on int(coordinate), I can take only the last 5 points of precision. This is, effectively the local position on grid rather than the position in the entire system. It also makes the assumption that all of the battles on the battle report happened on the same grid. I do then also have to scale those values down by a factor of 1000 to give us something more representative of the game.
I don’t have much else to say about it at the moment, but this was a fun tool to learn a bit more about 3D graphics and it’s one of the more complex things I’ve written from scratch so far. Hope you have fun with it. Put in a PR if you want and I’ll keep an eye on 🙂
Here’s that link again if you missed it:
Code: https://github.com/VargurStorm/pyBattleVi
Bonus feature discovery!
It turns out that if you give a negative multiplier in the scale function, you’ll get inside out cubes! This is pretty funky and when you think about it, you can kinda see how it works. Try it out, it’s interesting and lets you see who died inside of someone else (like a pod inside a bigger ship).
Leave a Reply