Extra lines in dynamic infocards (Reverse-engineering jflp.dll/plugins)
-
So we’ve been trying to add some extra information to dynamic infocards (specifically the shield stats) based on what’s been done in jflp.c for engines and powerplants but have been running into some strange issues and would really appreciate some guidance.
We’ve copied the structure used by the other items that have new stat lines in jflp and added a case for them:
https://cdn.discordapp.com/attachments/679045481300492428/682253489128079395/2.png
The new shield stat-lines show up in game, but the value is not pulled from the [ShieldGenerator] entries in st_equip.ini as it should be:
https://cdn.discordapp.com/attachments/679045481300492428/682253504496140308/2g.png
For some reason it grabs the parent_impulse and child_impulse values and puts them in the regen power drain and constant energy drain places. It’s definitely pulling from the correct entries as if I edit them in the ini they are reflected in the game. Changing the order of the lines in struct ShieldGenerator or adding more seems to stop child_impulse and parent_impulse from being grabbed at all, and the stat lines show up as zero.
For reference, I’ve attached the version of jflp.c I’m working with.
Could anyone shed some light on this? We don’t fully understand how jflp grabs the stats to display in the first place, so we’re probably missing something pretty fundamental here.Many thanks in advance
-
ShieldGenerator is AttachedEquipment, so there’s other data before the shield data, and the order was wrong (Archetype::ShieldGenerator::read in common.dll shows that).
struct ShieldGenerator { BYTE equip[0x70]; BYTE attached_equip[0x1C]; UINT shield_type; float regeneration_rate; float max_capacity; float constant_power_draw; float rebuild_power_draw; float offline_threshold; float offline_rebuild_time; // std::vector <iobjinspect*>hp_shield_type; };</iobjinspect*>
-
This worked absolutely wonderfully, thank you so much!
May I ask what you’re using to peek inside common.dll in such a manner? I have investigated it with a hex editor, but it’s a bit overwhelming and very difficult to find anything coherent.
-
Opened up common.dll in IDA and I can sort of see what you mean! I’ve found the order of things you referenced, and I can see entries relating to AttachedEquipment ahead of ShieldGenerator at [c]Archetype:: ShieldGenerator::read[/c]. This is all way over my head though. I think I have quite a lot of reading to do before I can get my head around playing with this more. Thankyou again for all your help
One odd thing: The newly compiled jflp.dll doesn’t run in Windows 7. Freelancer fails to call it. I can only assume this is related to the change
*len += vswprintf( buf + *len, 4096 - *len, value_fmt, args );
on line 319 you suggested to get it compiling in VS 2019. There’s no spew output other than dacom failing to load the dll and ignoring it. It’s not a big problem though, Win7 users (The few we have) can happily go back to the standard 1.23 dll without any issues.
-
I tried removing /MD (VC2019 defaults to /MT) and got a 110kb(!) DLL. It runs fine in 10, but seems to have the same issue on Windows 7 machines as before. Do you know if there’s a way to see where it’s failing/get some spew output about why it couldn’t be loaded?
-
Both dlls attached! The one that works on 7 is just the unmodified jflp.dll from your website.
-
It’s fine! It’s not the biggest of issues anyway. All the Windows 7 users are missing out on (for now) is the shield stat lines, and we’re listing those out of the game as well.
I’ve had a chat with the guy I’ve been working through this with, and we were both wondering if there was any documentation out there for us to learn from? We don’t want to bother you every time with this stuff. We knew that our error from before had to do with the order in which we called things, but that was where our own insight ended.
My (very limited) understanding of how the plugins work is that they modify specific addresses in common.dll (or another dll) and then execute the code defined further down, but I have absolutely no idea what’s instructing jflp to look into common.dll or even at the addresses it does.
-
[W]e were both wondering if there was any documentation out there for us to learn from?
There’s lots of tutorials on learning assembly/reversing, but I learnt pre-internet (initially Z80 on an Amstrad CPC 464), so can make no recommendations.
[…] I have absolutely no idea what’s instructing jflp to look into common.dll or even at the addresses it does.
Finding the addresses involves analysing the disassembly, where exports and text-based ini prove very useful (which is what makes content.dll so hard, since it has no exports and little text). Then it’s off to the debugger, setting breakpoints on where it reads ini values, then hardware breakpoints to find where it uses those values. Once I have an address I try and find existing calls or jumps to use as a hook point, as that allows reusability with other hooks. That’s what [c]NEWOFS[/c] in a plugin does, replacing an existing call/jump destination with the plugin’s. If there’s no call or jump to hook, then I overwrite code with one, which is what [c]CALL[/c] and [c]JMP[/c] do. (I’m still amazed that with all the plugins out there, there’s only been one conflict, where the first version of EngClass didn’t get along with MultiCruise.)