OpenLoco
OpenLoco copied to clipboard
Create a Save Game Compare command line tool
We have the ability to load s5 files with std::unique_ptr<S5File> load(const fs::path& path) and it would be very useful to be able to compare two files when working on vehicle functions. Therefore we should make a simple commandline tool to do that. This can be split into two main tasks:
- [ ] Handle command line arguments. We do not currently process the command line. This will need to be implemented/use a lib.
- [ ] Create an S5File compare function that can output useful comparison information to the console or to a file.
Perhaps we could go so far as to do chunk-based comparison. It would help to know what chunks/sections are different (e.g. tile elements, companies, stations).
Well once you have the S5File its already broken into its constituent parts.
Yeah, that's what I was thinking as well. I was just adding that I'd like to see it in the diff report as well.
https://github.com/OpenRCT2/OpenRCT2/blob/develop/src/openrct2/cmdline/CommandLine.hpp this is what is used for OpenRCT2. Suggest it is copied.
A command line tool to run simulations for a certain number of ticks has since been implemented. This should help make it easier to implement a comparison tool.
Hi I thought I would have a go at implementing:
- [ ] Create an S5File compare function that can output useful comparison information to the console or to a file.
- [ ] Put the compare function in S5 namespace?
- [ ] Add a compare [options]
command line option in CommandLine.cpp Any other thoughts, advice?
Just have a check with @duncanspumpkin and @AaronVanGeffen about exactly what they want here, as we already have a simulation tool to check for similar things like this.
I believe the idea was to extend the existing CLI simulation tool, adding an optional reference file to compare against. This would load an additional game state into memory for the reference data frame. The game state for the main simulation should then be checked against this reference game state at the end of the simulation (i.e. after X game ticks).
The initial version doesn't necessarily need to provide output for each of the GameState struct members, but the members at the beginning and end should be covered at least, imo. The stuff in the middle can be covered as miscellaneous using byte offsets.
Core::Prng rng; // 0x000000 (0x00525E18)
Core::Prng unkRng; // 0x000008 (0x00525E20)
GameStateFlags flags; // 0x000010 (0x00525E28)
uint32_t currentDay; // 0x000014 (0x00525E2C)
uint16_t dayCounter; // 0x000018 (0x00525E30)
uint16_t currentYear; // 0x00001A (0x00525E32)
uint8_t currentMonth; // 0x00001C (0x00525E34)
uint8_t currentDayOfMonth; // 0x00001D
// ...
uint16_t numMessages; // 0x0013B6 (0x005271CE)
MessageId activeMessageIndex; // 0x0013B8 (0x005271D0)
Message messages[Limits::kMaxMessages]; // 0x0013BA (0x005271D2)
// ...
Company companies[Limits::kMaxCompanies]; // 0x00B96C (0x00531784)
Town towns[Limits::kMaxTowns]; // 0x092444 (0x005B825C)
Industry industries[Limits::kMaxIndustries]; // 0x09E744 (0x005C455C)
Station stations[Limits::kMaxStations]; // 0x0C10C4 (0x005E6EDC)
Entity entities[Limits::kMaxEntities]; // 0x1B58C4 (0x006DB6DC)
World::Animation animations[Limits::kMaxAnimations]; // 0x4268C4 (0x0094C6DC)
World::Wave waves[Limits::kMaxWaves]; // 0x4328C4 (0x009586DC)
char userStrings[Limits::kMaxUserStrings][32]; // 0x432A44 (0x0095885C)
uint16_t routings[Limits::kMaxVehicles][Limits::kMaxRoutingsPerVehicle]; // 0x442A44 (0x0096885C)
uint8_t orders[Limits::kMaxOrders]; // 0x461E44 (0x00987C5C)
Perhaps @duncanspumpkin is of a different mind on this, though. Let's wait for him to reply as well.
Just have a check with @duncanspumpkin and @AaronVanGeffen about exactly what they want here, as we already have a simulation tool to check for similar things like this. @LeftofZen will do!
@AaronVanGeffen thanks for the latest thinking on this.
- Is the optional reference file just another S5 save file?
Very happy to wait for @duncanspumpkin reply.
Yes pretty much same as what aaron said. We have two game state structures the s5 one that doesn't have type info (it's all just uintx) and the main one. Eventually they won't be the same though. S5File is actually a bit more than just the game state as it also has the tile elements and objects. For the first version just knowing the offset of the difference in the struct is all we need.
For example if we had two files and the only difference was entity 5 with a difference at offset 0xC. I would like it to print:
DIVERGENCE
ENTITY: 5
OFFSET: 0xC
LHS: 0xAA
RHS: 0xAB
Thinking about it more entities and tile elements you will pretty much always also want to know the type as well.
Ok, thanks for the steer I'll have a go at what has been suggested.