SUBSIM Radio Room Forums

SUBSIM Radio Room Forums (https://www.subsim.com/radioroom/index.php)
-   SHIII Mods Workshop (https://www.subsim.com/radioroom/forumdisplay.php?f=195)
-   -   [TEC] In-game save date (https://www.subsim.com/radioroom/showthread.php?t=221539)

ExFishermanBob 08-18-15 05:56 PM

In-game save date
 
I have been searching in SH3 Mods for where the date in-game (e.g. 23 January 1940) is placed when saving the game. I have written a utility to extract this information, but wondered, before polishing it too much for release, whether there was an available tool, or something simpler than reading the relevant ISF file.

Have I not used the correct search terms in the forum? Perhaps someone who has been here a long time can tell me if such a tool has been written before.

(The utility is handy when writing to the message log as you can ensure that any message WILL appear, if it is dated appropriately).

areo16 08-18-15 06:01 PM

Quote:

Originally Posted by ExFishermanBob (Post 2337411)
I have been searching in SH3 Mods for where the date in-game (e.g. 23 January 1940) is placed when saving the game. I have written a utility to extract this information, but wondered, before polishing it too much for release, whether there was an available tool, or something simpler than reading the relevant ISF file.

Have I not used the correct search terms in the forum? Perhaps someone who has been here a long time can tell me if such a tool has been written before.

(The utility is handy when writing to the message log as you can ensure that any message WILL appear, if it is dated appropriately).

How are you able to read the ISF file? Are you decoding it?

ExFishermanBob 08-18-15 06:07 PM

Just open it as a binary file in python (or your language of choice).
There are a few parts with the name of your submarine-type (e.g. SSTypeVIIB) - you'll see it with a hex editor. Offset from the first one, at 330 bytes after the end of the submarine-type, is a pair of words with the year (e.g. \x07\x94 which is 1940: see http://coolconversion.com/math/binar...n_hexadecimal_)

After that comes the month, day, hour and minute (although the latter can be off by one if the minute has just changed).

ExFishermanBob 08-18-15 06:13 PM

I suspect that there is lat-long, or distance from 0 and equator somewhere in there too, but I don't need that yet (I have a distance to latlong converter, but not a distance / latlong to grid converter - would be handy for finding out the 6-figure grid reference as the logs only seem to hold 4-figures, such as AM76)

areo16 08-18-15 06:19 PM

Quote:

Originally Posted by ExFishermanBob (Post 2337417)
I suspect that there is lat-long, or distance from 0 and equator somewhere in there too, but I don't need that yet (I have a distance to latlong converter, but not a distance / latlong to grid converter - would be handy for finding out the 6-figure grid reference as the logs only seem to hold 4-figures, such as AM76)


LGN1's Tracking Room mod has a perl function in it that converts to or from the grid system using the meters from equator system that the game uses.

ExFishermanBob 08-18-15 06:23 PM

Quote:

Originally Posted by areo16 (Post 2337419)
LGN1's Tracking Room mod has a perl function in it that converts to or from the grid system using the meters from equator system that the game uses.

That would be interesting to look at - does it just take the user's typed input, or read from the files, I wonder.

areo16 08-18-15 06:32 PM

Quote:

Originally Posted by ExFishermanBob (Post 2337420)
That would be interesting to look at - does it just take the user's typed input, or read from the files, I wonder.


It takes two params I think. Let me look....

I guess it doesn't take any params, as it is using a global variable called "position_grid"

But the function is called "pos_lat_long" and its the last function in his script.
You could add parameters to it easily. Info here:

http://stackoverflow.com/questions/5...meters-in-perl

ExFishermanBob 08-18-15 06:33 PM

Many thanks - once I work out what is in the ISF regarding latlong...

ExFishermanBob 08-19-15 02:02 PM

OK, here is the python3 code for reading the date and time of a save from the relevant ISF file. Explanation in next post. Python3 is available (free) at: https://www.python.org/downloads/

Code:

#! /usr/bin/python3
# -*- coding: utf-8 -*-


import sys

if sys.version_info < (3,4,0):
    sys.stderr.write("You need python 3.4.0 or later to run this script\n")
    exit(1)

import os

class ISFFile:
   
    def __init__(self):
        # look_for needs to come from the relevant psc file...
        # MAKE SURE IT IS PASSED AS BYTES
        self.look_for = b"SSTypeVIIB"
        self.year_offset = -461
        self.extract = None
        self.year = 0
        self.month = 0
        self.day = 0
        self.hour = None
        self.minute = None
        self.file_name = None
       
       
    def dump(self):
        if self.extract:
            print(self.file_name, self.year, self.month, self.day, self.hour, self.minute)
        else:
            print("No valid result")
   
    def extract_bytes(self, file_name):
        if type(self.look_for) == bytes:
            with open(file_name, 'rb') as f:
                all_data = f.read()
            if self.look_for in all_data:
                # find the submarine's type-name...
                start = all_data.index(self.look_for)
                # ...and snip to just the data that follows
                first_part = all_data[start+len(self.look_for):]
                # Now we search for a recurrence of the type-name text...
                if self.look_for in first_part:
                    end = first_part.index(self.look_for)
                    # Now get just the part that we need to process
                    snip = first_part[:end]
                    # The data we want is 461 bytes (self.year_offset which is negative) BACK from the end...
                    self.extract = snip[self.year_offset:]
                    self.file_name = file_name
                else:
                    #print("Extract does not contain the second occurence of", self.look_for)
                    self.extract = None
            else:
                #print("File does not contain", self.look_for)
                self.extract = None
        else:
            #print("self.look_for must be bytes!")
            self.extract = None
   
    def extract_date_and_time(self):
        if self.extract:
            # year starts at self.year_offset and is of a format, for example, like:
            # \x07\x94\x00\x00\x00\x01\x00\x00\x00\x15\
            # 0794 is hex for 1940,   
            s = self.extract[self.year_offset:]
            year_hex = s[0:2]
            month_hex = s[4:6]
            day_hex = s[8:10]
            self.year = int.from_bytes(year_hex, byteorder='big')
            self.month = int.from_bytes(month_hex, byteorder='big')
            self.day = int.from_bytes(day_hex, byteorder='big')
            # Time field appears to follow
            hour_hex = s[12:14]
            min_hex = s[16:18]
            self.hour = int.from_bytes(hour_hex, byteorder='big')
            self.minute = int.from_bytes(min_hex, byteorder='big')


ExFishermanBob 08-19-15 02:11 PM

The ISF file has a section starting with the submarine's type-name (e.g. SSTypeVIIB) and ending with the same.

So, it looks a bit like this (but bigger):

................
.............SST
ypeVIIB.........
................
....007400110004
00200043........
................
.....SSTypeVIIB.
................
................

extract_bytes()
looks for the first occurrance of the type-name (SSTypeVIIB), and gets all the bytes following,

.........
................
....007400110004
00200043........
................
.....SSTypeVIIB.
................
................

then looks in what it has got and removes the second type-name (SSTypeVIIB), leaving a 'snip' of the required bytes.

.........
................
....007400110004
00200043........
................
.....

The year, month, date, hour and minute start at 461 bytes back from the end of the 'snip', so that bit is put into self.extract.

007400110004
00200043

extract_date_and_time() uses the values in self.extract and computes the integer values from the bytes using big-endian conversion.

To use it:-
Code:

isf = ISFFile()
isf.look_for = b"SSTypeVIIB"
isf.extract_bytes(r"some_file_path\some_filename.isf")
isf.extract_date_and_time()

isf.year, isf.month, isf.day, isf.hour and isf.minute then hold the values.

NOTES:
The look_for value must be bytes (note the leading b)
In Windows, you need to make sure the path is 'raw' or reverse the slashes because the career saves are stored in numbered subfolders: '0', which, of course, with a slash becomes '\0', the 'NUL' character, and '9' which is a tab might cause problems.


The code / algorithm should be easily convertable into your favourite programming language.

areo16 08-19-15 03:01 PM

Quote:

Originally Posted by ExFishermanBob (Post 2337954)
The ISF file has a section starting with the submarine's type-name (e.g. SSTypeVIIB) and ending with the same.

So, it looks a bit like this (but bigger):

................
.............SST
ypeVIIB.........
................
....007400110004
00200043........
................
.....SSTypeVIIB.

extract_bytes() looks for the first occurrance of the type-name (SSTypeVIIB), and gets all the bytes following,

.........
................
....007400110004
00200043........
................
.....SSTypeVIIB.

then looks in what it has got and removes the second type-name (SSTypeVIIB), leaving a 'snip' of the required bytes.

.........
................
....007400110004
00200043........
................
.....

The year, month, date, hour and minute start at 461 bytes back from the end of the 'snip', so that bit is put into self.extract.

007400110004
00200043

extract_date_and_time() uses the values in self.extract and computes the integer values from the bytes using big-endian conversion.

To use it:-
Code:

isf = ISFFile()
isf.look_for = b"SSTypeVIIB"
isf.extract_bytes(r"some_file_path\some_filename.isf")
isf.extract_date_and_time()

isf.year, isf.month, isf.day, isf.hour and isf.minute then hold the values.

NOTES:
The look_for value must be bytes (note the leading b)
In Windows, you need to make sure the path is 'raw' or reverse the slashes because the career saves are stored in the subfolder '0', which, of course, with a slash becomes '\0', the 'NUL' character.


The code / algorithm should be easily convertable into your favourite programming language.


I thought career saves are put in the "CareerName"\"Patrol number minus 1" folder?
So the 0 sub folder is actually the 1st patrol of the career, 5 subfolder is 6 patrol, etc...

I'm excited about the script!

ExFishermanBob 08-21-15 09:53 AM

Yes, I should have stated that the careers are saved in a numbered folder, so '0' will cause problems, as will (probably) 9 (tab) and possibly 7 (bell).

areo16 08-21-15 02:23 PM

Quote:

Originally Posted by ExFishermanBob (Post 2338439)
Yes, I should have stated that the careers are saved in a numbered folder, so '0' will cause problems, as will (probably) 9 (tab) and possibly 7 (bell).

Your not actually talking about a directory name?

This is an example:
"C:\Users\John\Documents\SH3\data\cfg\Careers\Test \5"

The above career is called "Test" and the Patrol number is 6. As far as I know you can only save in a career when you are on patrol. If you are not on patrol and in the office you cannot save the game. The game just keeps track of when you are out on patrol or not. The .isf file is in its corresponding patrol number folder.

It keeps track when you are on patrol in the Patrols_0.cfg file. This is the file with patrol that hasn't finished. Patrols.cfg holds patrols that have finished only.

ExFishermanBob 08-21-15 03:49 PM

I think you have missed my point. I know all about the saving and so on - what I was pointing out was, that in python, running under Windows a string with only single backslashes for path separators will, for certain values (particularly zero), be evaluated by python as an escape character when passed to file-handling routines.

Thus: "C:\somewhere\anywhere\but\this\0" will be interpreted as
"C:\somewhere\anywhere\but<tab>NUL" and an error will occur. \t is tab, \0 is null.

You must, therefore, in Windows (when programming in Python): use double backslashes (\\0) or forward slashes (/) or use a (so-called) "raw" string (prefixed by r: r"C:\etc") or decompose and recompose the path using the relevant python functions.

The original was easier to read.

So yes, I'm talking about the sub-directory of the "Career/name/" - which, for the first patrol, will be zero, for which see above IF you are using python in Windows and need to specify a path in a string. It catches me every single time, hence my note to others who might either encounter it for the first time, or, like me, continually forget.

For the full horror:

http://www.cisco.com/c/en/us/td/docs...n_r/frf019.pdf

areo16 08-22-15 03:54 AM

Quote:

Originally Posted by ExFishermanBob (Post 2338482)
I think you have missed my point. I know all about the saving and so on - what I was pointing out was, that in python, running under Windows a string with only single backslashes for path separators will, for certain values (particularly zero), be evaluated by python as an escape character when passed to file-handling routines.

Thus: "C:\somewhere\anywhere\but\this\0" will be interpreted as
"C:\somewhere\anywhere\but<tab>NUL" and an error will occur. \t is tab, \0 is null.

You must, therefore, in Windows (when programming in Python): use double backslashes (\\0) or forward slashes (/) or use a (so-called) "raw" string (prefixed by r: r"C:\etc") or decompose and recompose the path using the relevant python functions.

The original was easier to read.

So yes, I'm talking about the sub-directory of the "Career/name/" - which, for the first patrol, will be zero, for which see above IF you are using python in Windows and need to specify a path in a string. It catches me every single time, hence my note to others who might either encounter it for the first time, or, like me, continually forget.

For the full horror:

http://www.cisco.com/c/en/us/td/docs...n_r/frf019.pdf

Understood. Escape characters.


All times are GMT -5. The time now is 11:12 AM.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Copyright © 1995- 2024 Subsim®
"Subsim" is a registered trademark, all rights reserved.