OpenLoco icon indicating copy to clipboard operation
OpenLoco copied to clipboard

Create a Save Game Compare command line tool

Open duncanspumpkin opened this issue 4 years ago • 11 comments

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.

duncanspumpkin avatar Jun 22 '21 17:06 duncanspumpkin

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).

AaronVanGeffen avatar Jun 22 '21 17:06 AaronVanGeffen

Well once you have the S5File its already broken into its constituent parts.

duncanspumpkin avatar Jun 22 '21 19:06 duncanspumpkin

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.

AaronVanGeffen avatar Jun 22 '21 19:06 AaronVanGeffen

https://github.com/OpenRCT2/OpenRCT2/blob/develop/src/openrct2/cmdline/CommandLine.hpp this is what is used for OpenRCT2. Suggest it is copied.

duncanspumpkin avatar Jun 23 '21 06:06 duncanspumpkin

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.

AaronVanGeffen avatar Aug 06 '22 14:08 AaronVanGeffen

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?

memellis avatar Oct 24 '23 21:10 memellis

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 avatar Oct 24 '23 22:10 LeftofZen

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.

AaronVanGeffen avatar Oct 25 '23 08:10 AaronVanGeffen

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.

memellis avatar Oct 25 '23 18:10 memellis

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.

duncanspumpkin avatar Oct 25 '23 19:10 duncanspumpkin

Ok, thanks for the steer I'll have a go at what has been suggested.

memellis avatar Oct 25 '23 20:10 memellis