SUBSIM Radio Room Forums



SUBSIM: The Web's #1 resource for all submarine & naval simulations since 1997

Go Back   SUBSIM Radio Room Forums > Silent Hunter 3 - 4 - 5 > SHIII Mods Workshop
Forget password? Reset here

Reply
 
Thread Tools Display Modes
Old 08-18-15, 05:56 PM   #1
ExFishermanBob
Difficulties Numbing
 
Join Date: Aug 2013
Location: AN19
Posts: 470
Downloads: 43
Uploads: 0


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

Last edited by ExFishermanBob; 08-18-15 at 05:58 PM. Reason: Clarified!
ExFishermanBob is offline   Reply With Quote
Old 08-18-15, 06:01 PM   #2
areo16
Sonar Guy
 
Join Date: Oct 2013
Posts: 377
Downloads: 64
Uploads: 0
Default

Quote:
Originally Posted by ExFishermanBob View Post
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?
areo16 is offline   Reply With Quote
Old 08-18-15, 06:07 PM   #3
ExFishermanBob
Difficulties Numbing
 
Join Date: Aug 2013
Location: AN19
Posts: 470
Downloads: 43
Uploads: 0


Default

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 is offline   Reply With Quote
Old 08-18-15, 06:13 PM   #4
ExFishermanBob
Difficulties Numbing
 
Join Date: Aug 2013
Location: AN19
Posts: 470
Downloads: 43
Uploads: 0


Default

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)
ExFishermanBob is offline   Reply With Quote
Old 08-18-15, 06:19 PM   #5
areo16
Sonar Guy
 
Join Date: Oct 2013
Posts: 377
Downloads: 64
Uploads: 0
Default

Quote:
Originally Posted by ExFishermanBob View Post
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.
areo16 is offline   Reply With Quote
Old 08-18-15, 06:23 PM   #6
ExFishermanBob
Difficulties Numbing
 
Join Date: Aug 2013
Location: AN19
Posts: 470
Downloads: 43
Uploads: 0


Default

Quote:
Originally Posted by areo16 View Post
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.
ExFishermanBob is offline   Reply With Quote
Old 08-18-15, 06:32 PM   #7
areo16
Sonar Guy
 
Join Date: Oct 2013
Posts: 377
Downloads: 64
Uploads: 0
Default

Quote:
Originally Posted by ExFishermanBob View Post
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
areo16 is offline   Reply With Quote
Old 08-18-15, 06:33 PM   #8
ExFishermanBob
Difficulties Numbing
 
Join Date: Aug 2013
Location: AN19
Posts: 470
Downloads: 43
Uploads: 0


Default

Many thanks - once I work out what is in the ISF regarding latlong...
ExFishermanBob is offline   Reply With Quote
Old 08-19-15, 02:02 PM   #9
ExFishermanBob
Difficulties Numbing
 
Join Date: Aug 2013
Location: AN19
Posts: 470
Downloads: 43
Uploads: 0


Default

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

Last edited by ExFishermanBob; 08-21-15 at 09:57 AM.
ExFishermanBob is offline   Reply With Quote
Old 08-19-15, 02:11 PM   #10
ExFishermanBob
Difficulties Numbing
 
Join Date: Aug 2013
Location: AN19
Posts: 470
Downloads: 43
Uploads: 0


Default

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.

Last edited by ExFishermanBob; 08-21-15 at 09:55 AM. Reason: Notes added
ExFishermanBob is offline   Reply With Quote
Old 08-19-15, 03:01 PM   #11
areo16
Sonar Guy
 
Join Date: Oct 2013
Posts: 377
Downloads: 64
Uploads: 0
Default

Quote:
Originally Posted by ExFishermanBob View Post
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!
areo16 is offline   Reply With Quote
Old 08-21-15, 09:53 AM   #12
ExFishermanBob
Difficulties Numbing
 
Join Date: Aug 2013
Location: AN19
Posts: 470
Downloads: 43
Uploads: 0


Default

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).
ExFishermanBob is offline   Reply With Quote
Old 08-21-15, 02:23 PM   #13
areo16
Sonar Guy
 
Join Date: Oct 2013
Posts: 377
Downloads: 64
Uploads: 0
Default

Quote:
Originally Posted by ExFishermanBob View Post
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.
areo16 is offline   Reply With Quote
Old 08-21-15, 03:49 PM   #14
ExFishermanBob
Difficulties Numbing
 
Join Date: Aug 2013
Location: AN19
Posts: 470
Downloads: 43
Uploads: 0


Default

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
ExFishermanBob is offline   Reply With Quote
Old 08-22-15, 03:54 AM   #15
areo16
Sonar Guy
 
Join Date: Oct 2013
Posts: 377
Downloads: 64
Uploads: 0
Default

Quote:
Originally Posted by ExFishermanBob View Post
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.
areo16 is offline   Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -5. The time now is 01:19 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.