Jump to content

programmatically update saved game time


learvlieg
 Share

Recommended Posts

Spoiler
const fs = require('fs');
const got = require('got');
const { execFile } = require('child_process');

const url = 'https://api.truckersmp.com/v2/game_time';
const exeRegex = /^(?:[a-z]:)?[\/\\]{0,2}(?:[.\/\\ ](?![.\/\\\n])|[^<>:"|?*.\/\\ \n])+\.exe$/gmi;
const siiRegex = /^(?:[a-z]:)?[\/\\]{0,2}(?:[.\/\\ ](?![.\/\\\n])|[^<>:"|?*.\/\\ \n])+\.sii$/gmi;

const prefixUrl = '';
const headers = {
  Accept: "application/json"
};
const isStream = false;

const options = {
  prefixUrl,
  ...headers,
  isStream
}

let executable = "./SII_Decrypt.exe";
let inputfile = "info.sii";
let outputfile = `updated-${inputfile}`;

const useArguments = () => {
  const args = process.argv.slice(2);
  let optionValueIndex;
  args.forEach((value, index) => {
    switch (value) {
      case "-d":
        optionValueIndex = index + 1;
        try {
          executable = args[optionValueIndex].match(exeRegex).toString();
        } catch (e) {
          console.log('invalid decryptor executable specified, using SII_Decrypt.exe as default');
        }
        break;
      case "-i":
        optionValueIndex = index + 1;
        try {
          inputfile = args[optionValueIndex].match(siiRegex).toString();
        } catch (e) {
          console.log(`invalid save game file specified ${args[optionValueIndex]}. Using info.sii instead`);
        }
        console.log(`args set inputfile to: ${inputfile}`);
        break;
      case "-o":
        optionValueIndex = index + 1;
        try {
          outputfile = args[optionValueIndex].match(siiRegex).toString();
        } catch (e) {
          console.log(`invalid output time format specified ${args[optionValueIndex]}. Using 'updated-info.sii' instead`);
        }
        console.log(`args set outputfile to: ${outputfile}`);
        break;
      default:
        console.log(`args value ${value}`);
    }
  });
}

const getResponseHeaders = (url, options) => {
  return got(url, options);
}

const decryptSaveGame = (
  decryptionExecutable,
  inputFile,
  outputFile) => {
  try {
    const proc = execFile(decryptionExecutable, [inputFile, outputFile]);
    proc.on("close", (code) => {
      if (code === 0) {
        console.log(`decryption successful`);
      } else {
        console.log(`decryption process closed with code ${code}`);
      }
    });
  } catch (error) {
    console.log(`error while trying to decrypt save game: ${error}`);
  }
}

const getMPTimestamp = async () => {
  try {
    const response = await getResponseHeaders(url, options);
    console.log(`response : ${response.body}`);
    return JSON.parse(response.body).game_time;
  } catch (error) {
    if (error.response) {
      //HTTP rejection
      const code = error.response.statusCode;
      const message = error.response.statusMessage;
      console.log(`
            statusCode ${code}\n
            message: ${message}\n
            options: ${JSON.stringify(options)}\n
            url: ${error.response.requestUrl}
            `);
    } else {
      //bug
      console.log(`ERROR\n ${error.stack}`);
    }
  }
};

const updateTimeStamp = (async () => {
  useArguments();
  decryptSaveGame(executable, inputfile, outputfile);
  const time = await getMPTimestamp();
  const file = fs.readFileSync(`${outputfile}`);
  const updatedFile = Buffer.from(file.toString().replace(/^(\s+)?time:\s\d*/gm, ` time: ${time}`));
  fs.writeFileSync(`${outputfile}`, updatedFile);
})();

 

 

Just felt like having a bit of a mess around practicing some random JS stuff using a simple API call and in place editing of a save game related file. Code in the spoiler is result of quarantine Sunday :)

Basically what it's supposed to do:
- get MP game time using the API
- decrypt the (provided) info.sii file

- update the info.sii file time

 

Say you've been offline for a couple days and the MP Server clock been ticking away while your save-game time sat there statically in your file-system and you start the game, straight away your clock is behind the servers' and your little AI workers have not progressed at all. Now if you'd run this update script to pull the save-game time forward in your file-system to quite close to the server time prior starting the game, you'll have jumped forward in time and suddenly your AI workers will have completed their rides as current game-time is most likely beyond their completion time :D (theoretically anyway).

 

What do you need?

- You need follow and complete the guide found elsewhere in this forum to change the way save-games are saved. (change a value '0' into a '2' in your game config file pertaining to save-game format)
- download the SII_Decrypt.exe you can find linked in places on this forum/website. This executable needs to be called by the script in order to decrypt it.

- nodejs installed

- node package 'got' installed ('npm install got'). This is a simple http library to make the API calls with.

- save the code in a JS file (e.g.  "index.js")

Once saved in a file you should be able to simply call it as:

node index.js

The script out of the box assumes files are present in it's current directory where it is run.
Default assumptions are the decryption executable filename (SII_Decrypt.exe), the info.sii filename (info.sii) and the output will be a new file called 'updated-info.sii' as not to override the original provided file. These values can be overridden by using flags. An example:

node index.js -d decrypt.exe -i info-copy.sii -o my-new-info.sii

where:
-d            name/location of the decryption executable (e.g. you might have renamed SII_Decrypt.exe)
- i            input filename
- o           output filename
Full paths to absolute locations/filenames "should" also work (fingers crossed) as input, but has not been thoroughly tested or anything. (e.g. "C:\Users\Yourmum\documents\save-game-edit\info.sii")

 


*** Disclaimer ***
Again, for me it was just a bit about trying to get my head around some concepts as I go along learning stuff, fighting boredom and thought it might be fun for people to mess with, so why not share the fun! I feel some of the things set out might be extensible as well (e.g. programmatic updating of 'save.sii' in particular areas, like grabbing a list of cities from a flat-file and inserting them into a bunch of discovered dealers and recruitment agencies :D ). I realize it by no means represents a full project or clean/proper best practices coding ?, it was also not intended to be!
 

  • Thanks 1
Link to comment
Share on other sites

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.