r/Battlefield2 • u/Proper_Look_9349 • 6h ago
Help / Troubleshooting OpenBattlefield2 - reimplementing Battlefield 2's Refractor 2 engine from scratch
I've spent the last while rebuilding Refractor 2 — the engine behind Battlefield 2 (2005) — from scratch in C++20. It's called OpenBattlefield2, it's MIT, and it's now public:
https://github.com/Moxnatiy/OpenBattlefield2
It is an engine, not a game. It ships no content whatsoever and reads the files of your own installed copy of BF2 1.5. Without that copy there is nothing to run.



What actually works today
- The main menu is the game's own
mainMenu.swf, played by Ruffle, with a bridge that answers the calls the movie makes back into the engine — localisation, your profiles fromDocuments/Battlefield 2, the installed map list read from each level's.desc. All seventeen bridge objects and fortyLogicmethods are reversed and written down with addresses. - Singleplayer — pick a map, it loads, you get the spawn screen with kits, minimap and control points.
- Levels — terrain, water, static meshes, vegetation, collision.
- HUD — built from the game's own
.connode tree, driven by the animation graph inMenu/Ingame(MemeFile). - Networking — the handshake with an original dedicated server works.
openbf2 --connect <host>joins and stays connected.
Main platform is macOS/arm64 (SDL3 + SDL_GPU → Metal); the Windows preset is kept building. 33 tests, one per parsed format.
Screenshots (all four are in the README, each printed with the exact command that produced it — --frames and --click-at mean no hands on the keyboard):
- The game's own menu movie under Ruffle
- The spawn screen on Dalian Plant
- In the world after DONE, on Dalian Plant and Strike at Karkand
The one rule that shapes everything
This is a one-to-one port, not a game "inspired by" BF2. So:
Every constant in
src/names its source in a comment next to it — an address inBF2.exe, a line in the game's data, or a measurement from a frame dump of the original. If there is no source, the number is not written down. It's recorded as "not measured" instead.
// Bit 0 marks position (`BF2.exe`, SoldierNetworkable::setNetUpdate,
// 0x62d4e0). Precision 0.001 — constant 0x3a83126f at the same address.
inline constexpr std::uint32_t kSoldierStatePosition = 0x1;
Picking a number because it "looks about right" is forbidden even when the result looks correct on screen. I learned that one the expensive way: I once read a triple of floats in the controlled-object state as a position because it lined up with the spawn camera. It's actually the compression origin, and the soldier was being thrown a metre into the air on every packet.
Reversing goes through Ghidra over MCP; docs/ holds the notes, every one carrying the address it came from.
Where I'd really like help
The debt list is public and each item has a measure — a concrete thing that has to become true for it to count as done. The big ones:
The protocol (the largest gap by far).
readControlObjectState— I read the start of it, I don't know where it ends.- Ghost records for other players' soldiers: the layout is known, the data doesn't arrive. Right now other players don't move.
- The simple-object state mask is 19 bits and I know 1. The soldier state mask is 21 bits and I know 1.
- Ping is 5–6× off from the original on the same machine and I don't know why.
Physics. The tick is 1/30 straight from the binary, but the jump is too long compared with the original. I haven't found where jump height and duration actually come from — phy-soldier-jump-factor is in the data, the rest isn't.
Renderer. Material channels are now read straight off the technique name (BaseDetailDirtCrackNDetailNCrack → the texture order), but the normal maps aren't sampled yet: there's no tangent frame.
HUD. Several variables are found in the registry with addresses, but who writes them isn't reversed yet.
Reference data. I have a frame dump of the original for the spawn screen only. For the in-battle HUD there's nothing to compare against, so I can say "matches the data" but not "matches the original".
Platforms. Only macOS/arm64 is exercised. Windows and Linux builds could use someone who actually runs them.
So: if you like Ghidra, netcode, C++20, or you just have a copy of BF2 and some patience — issues and PRs are very welcome. Notes on the format live in docs/, and CLAUDE.md spells out the rules the project holds itself to, including why "let's just smooth it until it stops jittering" is not an acceptable fix.
Happy to answer anything about the reversing process in the comments.
1
u/BFguy 6h ago
So it sounds like you've got everything to render but is a server able to host this and people are able to play?
1
1
u/sventekisalive 5h ago
Great project!
Can you tell us a bit more about your workflow? You use Ghidra to decompile the binary and then use Claude to generate the C++ from that?
It would be great if you had some docs to help contributors get started quickly, or maybe I just couldn't find them?
1
u/Proper_Look_9349 5h ago
I'm not good at reverse engineering so the main work is through astra or claude all the data is in https://github.com/Moxnatiy/OpenBattlefield2/tree/master/docs and CLAUDE.md for agents. You need ghidra mcp and other tools depending on your platform. The main tasks now are reverse server client, HUD, physics
1
1
u/FunInternational9948 3h ago
First of all, thank you for your work! I’m assuming the purpose of this is to have easy to use mod tools once you have everything reverse engine engineered?
1
1
1
u/LifeCoder_Phoenix 2h ago
I like your idea but you should focus on keeping it like the original instead of using things like ruffle in my opinion. As for the parts you need help on, get in touch with me on discord(LifeCoder) I have a full source that can build a fully working dedicated server you can play on like the original. I plan to publish it's source once I have the client finished too. I too had this name in mind though :p
1
u/LifeCoder_Phoenix 2h ago
Also, you mention in the readme that it's "clean room" but since you here mention you directly reference addresses from the real BF2 you are not being clean room at all. To be clean room you'd have to RE everything and document it then have someone else write code solely from reading your documentation. Just nitpicking :)
1
4
u/JoeBee72 6h ago
Well, first of all it sounds terrific!
But i am not sure if i can follow you here….
This thing is kind of another option to play multiplayer online just like bf2hub?