Skip to content

mod settings editor #131

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 29 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
3858414
Renamed factorioSaveTests to be less generic
knoxfighter Jan 26, 2019
e964f0d
added reading and writing of mod-settings.dat
knoxfighter Jan 26, 2019
0dec60a
added test for reading and writing mod settings & fixes
knoxfighter Feb 7, 2019
fdab3e6
made writing and reading global
knoxfighter Feb 8, 2019
a52cdbd
added go-test/deep to dependencies
knoxfighter Feb 9, 2019
db7bb90
fixed naming typo
knoxfighter Feb 25, 2019
359212d
added frontend & first backend stuff
knoxfighter Feb 26, 2019
cbce198
added 0.17 test (broken)
knoxfighter Feb 28, 2019
22f01a0
added debug output
knoxfighter Feb 28, 2019
74bb1d4
fixed wrong written bytes
knoxfighter Mar 7, 2019
4889278
Merge branch 'develop' into Feature/mod_settings
knoxfighter Mar 7, 2019
08171bb
removed test output
knoxfighter Mar 7, 2019
c5afe97
added load and show mod config
knoxfighter Mar 12, 2019
dd1f47a
added save of mod config
knoxfighter Mar 12, 2019
c05aedc
updated info
knoxfighter Mar 12, 2019
7a8c467
Merge branch 'develop' into Feature/mod_settings
knoxfighter May 30, 2019
d4de8e4
added warning
knoxfighter Jul 29, 2019
fa11a84
Merge branch 'develop' into Feature/mod_settings
knoxfighter Jan 29, 2020
bf061a3
added go-test/deep as go dependency
knoxfighter Jan 29, 2020
be69a9f
Merge branch 'develop' into Feature/mod_settings
knoxfighter Aug 5, 2021
b2274c5
mod_settings backend adjusted to new layout
knoxfighter Aug 5, 2021
362fc57
trackingoutput for EOF bug
knoxfighter Aug 6, 2021
4ba48d4
trackingoutput for EOF bug
knoxfighter Aug 6, 2021
8bbf131
dump file before reading
knoxfighter Aug 6, 2021
f2b9242
dump file in hex
knoxfighter Aug 6, 2021
eff22af
potential fix of the EOF bug
knoxfighter Aug 6, 2021
634513f
1.0 and 1.1 mod_settings.dat tests
knoxfighter Aug 7, 2021
99aa859
removed testoutput to fix mod_settings reading
knoxfighter Aug 7, 2021
e74487e
removed not used scss file
knoxfighter Aug 8, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
433 changes: 433 additions & 0 deletions src/factorio/factorio_data_types.go

Large diffs are not rendered by default.

82 changes: 82 additions & 0 deletions src/factorio/mod_settings_dat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package factorio

import (
"encoding/binary"
"fmt"
"io"
"log"
)

const (
NONE = 0
BOOL = 1
DOUBLE = 2
STRING = 3
LIST = 4
DICT = 5
)

type FModData struct {
Version version64
Data interface{}
}

func (d *FModData) Decode(file io.Reader) error {
var version version64
var versionB [8]byte

err := binary.Read(file, binary.LittleEndian, versionB[:])
if err != nil {
log.Printf("could not read version: %s", err)
}

err = version.UnmarshalBinary(versionB[:])
if err != nil {
log.Printf("Error loading Version: %s", err)
return err
}

d.Version = version

if Version(version).Greater(Version{0, 17, 0, 0}) {
//FIXME correct naming
var b [1]byte
_, err = file.Read(b[:])
if err != nil {
return fmt.Errorf("read first random 0.17 byte: %v", err)
}
}

d.Data, err = readTree(file, Version(d.Version))
if err != nil {
log.Printf("error loading Data: %s", err)
return err
}

return nil
}

func (d *FModData) Encode() ([]byte, error) {
var output []byte

_bytes, err := d.Version.MarshalBinary()
if err != nil {
log.Printf("couldn't create binary from version: %s", err)
return nil, err
}

output = append(output, _bytes...)

if Version(d.Version).Greater(Version{0, 17, 0, 0}) {
output = append(output, byte(0))
}

tree, err := writeTree(d.Data)
if err != nil {
log.Printf("error loading first tree: %s", err)
return nil, err
}
output = append(output, tree...)

return output, nil
}
218 changes: 218 additions & 0 deletions src/factorio/mod_settings_dat_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
package factorio

import (
"bytes"
"encoding/json"
"github.com/go-test/deep"
"io/ioutil"
"os"
"testing"
)

func TestModSettings0_16(t *testing.T) {
// Read dat and compare to JSON
file, err := os.Open("../factorio_mod_settings_testfiles/mod_settings_0.16.dat")
if err != nil {
t.Fatalf("could not open mod-settings.dat: %s", err)
}

var modData FModData
err = modData.Decode(file)
if err != nil {
t.Fatalf("could not decode FModData: %s", err)
}

modDataJson, err := ioutil.ReadFile("../factorio_mod_settings_testfiles/mod_settings_0.16.json")
if err != nil {
t.Fatalf("could not read json-file: %s", err)
}

var test interface{}
err = json.Unmarshal(modDataJson, &test)
if err != nil {
t.Fatalf("could not Unmarshal JSON: %s", err)
}

diff := deep.Equal(modData.Data, test)
if len(diff) > 0 {
t.Fatalf("Data has %d differences: %s", len(diff), diff)
}

// Change some value
modData.Data.(map[string]interface{})["runtime-per-user"].(map[string]interface{})["folk-fill-fuel-stack-size"].(map[string]interface{})["value"] = 150
test.(map[string]interface{})["runtime-per-user"].(map[string]interface{})["folk-fill-fuel-stack-size"].(map[string]interface{})["value"] = float64(150)

// write new data
newBytes, err := modData.Encode()
newBytesReader := bytes.NewReader(newBytes)
if err != nil {
t.Fatalf("couldn't Encode modData: %s", err)
}

var newData FModData
err = newData.Decode(newBytesReader)
if err != nil {
t.Fatalf("couldn't Decode newBytes: %s", err)
}

diff2 := deep.Equal(newData.Data, test)
if len(diff2) > 0 {
t.Fatalf("Data has %d differences: %s", len(diff2), diff2)
}
}

func TestModSettings0_17(t *testing.T) {
// Read data and compare to JSON
file, err := os.Open("../factorio_mod_settings_testfiles/mod_settings_0.17.dat")
if err != nil {
t.Fatalf("could not open mod-settings.dat: %s", err)
}

var modData FModData
err = modData.Decode(file)
if err != nil {
t.Fatalf("could not decode FModData: %s", err)
}

modDataJson, err := ioutil.ReadFile("../factorio_mod_settings_testfiles/mod_settings_0.17.json")
if err != nil {
t.Fatalf("could not read json-file: %s", err)
}

var test interface{}
err = json.Unmarshal(modDataJson, &test)
if err != nil {
t.Fatalf("could not Unmarshal JSON: %s", err)
}

diff := deep.Equal(modData.Data, test)
if len(diff) > 0 {
t.Fatalf("Data has %d differences: %s", len(diff), diff)
}

// Change some value
modData.Data.(map[string]interface{})["runtime-per-user"].(map[string]interface{})["max-inventory-cleanup-drop-range"].(map[string]interface{})["value"] = 150
test.(map[string]interface{})["runtime-per-user"].(map[string]interface{})["max-inventory-cleanup-drop-range"].(map[string]interface{})["value"] = float64(150)

// write new data
newBytes, err := modData.Encode()
newBytesReader := bytes.NewReader(newBytes)
if err != nil {
t.Fatalf("couldn't Encode modData: %s", err)
}

var newData FModData
err = newData.Decode(newBytesReader)
if err != nil {
t.Fatalf("couldn't Decode newBytes: %s", err)
}

diff2 := deep.Equal(newData.Data, test)
if len(diff2) > 0 {
t.Fatalf("Data has %d differences: %s", len(diff2), diff2)
}
}

func TestModSettings1_0(t *testing.T) {
// Read data and compare to JSON
file, err := os.Open("../factorio_mod_settings_testfiles/mod_settings_1.0.dat")
if err != nil {
t.Fatalf("could not open mod-settings.dat: %s", err)
}

var modData FModData
err = modData.Decode(file)
if err != nil {
t.Fatalf("could not decode FModData: %s", err)
}

modDataJson, err := ioutil.ReadFile("../factorio_mod_settings_testfiles/mod_settings_1.0.json")
if err != nil {
t.Fatalf("could not read json-file: %s", err)
}

var test interface{}
err = json.Unmarshal(modDataJson, &test)
if err != nil {
t.Fatalf("could not Unmarshal JSON: %s", err)
}

diff := deep.Equal(modData.Data, test)
if len(diff) > 0 {
t.Fatalf("Data has %d differences: %s", len(diff), diff)
}

// Change some value
modData.Data.(map[string]interface{})["startup"].(map[string]interface{})["angels-pavement-stack-size"].(map[string]interface{})["value"] = 200
test.(map[string]interface{})["startup"].(map[string]interface{})["angels-pavement-stack-size"].(map[string]interface{})["value"] = float64(200)

// write new data
newBytes, err := modData.Encode()
newBytesReader := bytes.NewReader(newBytes)
if err != nil {
t.Fatalf("couldn't Encode modData: %s", err)
}

var newData FModData
err = newData.Decode(newBytesReader)
if err != nil {
t.Fatalf("couldn't Decode newBytes: %s", err)
}

diff2 := deep.Equal(newData.Data, test)
if len(diff2) > 0 {
t.Fatalf("Data has %d differences: %s", len(diff2), diff2)
}
}

func TestModSettings1_1(t *testing.T) {
// Read data and compare to JSON
file, err := os.Open("../factorio_mod_settings_testfiles/mod_settings_1.1.dat")
if err != nil {
t.Fatalf("could not open mod-settings.dat: %s", err)
}

var modData FModData
err = modData.Decode(file)
if err != nil {
t.Fatalf("could not decode FModData: %s", err)
}

modDataJson, err := ioutil.ReadFile("../factorio_mod_settings_testfiles/mod_settings_1.1.json")
if err != nil {
t.Fatalf("could not read json-file: %s", err)
}

var test interface{}
err = json.Unmarshal(modDataJson, &test)
if err != nil {
t.Fatalf("could not Unmarshal JSON: %s", err)
}

diff := deep.Equal(modData.Data, test)
if len(diff) > 0 {
t.Fatalf("Data has %d differences: %s", len(diff), diff)
}

// Change some value
modData.Data.(map[string]interface{})["startup"].(map[string]interface{})["angels-pavement-stack-size"].(map[string]interface{})["value"] = 200
test.(map[string]interface{})["startup"].(map[string]interface{})["angels-pavement-stack-size"].(map[string]interface{})["value"] = float64(200)

// write new data
newBytes, err := modData.Encode()
newBytesReader := bytes.NewReader(newBytes)
if err != nil {
t.Fatalf("couldn't Encode modData: %s", err)
}

var newData FModData
err = newData.Decode(newBytesReader)
if err != nil {
t.Fatalf("couldn't Decode newBytes: %s", err)
}

diff2 := deep.Equal(newData.Data, test)
if len(diff2) > 0 {
t.Fatalf("Data has %d differences: %s", len(diff2), diff2)
}
}
58 changes: 0 additions & 58 deletions src/factorio/save.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,64 +235,6 @@ func (h *SaveHeader) ReadFrom(r io.Reader) (err error) {
return nil
}

func readOptimUint(r io.Reader, v Version, bitSize int) (uint32, error) {
var b [4]byte
if !v.Less(Version{0, 14, 14, 0}) {
_, err := r.Read(b[:1])
if err != nil {
return 0, err
}
if b[0] != 0xFF {
return uint32(b[0]), nil
}
}

if bitSize < 0 || bitSize > 64 || (bitSize%8 != 0) {
panic("invalid bit size")
}

_, err := r.Read(b[:bitSize/8])
if err != nil {
return 0, err
}

switch bitSize {
case 16:
return uint32(binary.LittleEndian.Uint16(b[:2])), nil
case 32:
return binary.LittleEndian.Uint32(b[:4]), nil
default:
panic("invalid bit size")
}
}

func readString(r io.Reader, game Version, forceOptimized bool) (s string, err error) {
var n uint32

// since 0.16 read optimized uint
if !game.Less(Version{0, 16, 0, 0}) || forceOptimized {
n, err = readOptimUint(r, game, 32)
if err != nil {
return "", err
}
} else {
var b [4]byte
_, err := r.Read(b[:])
if err != nil {
return "", fmt.Errorf("failed to read string length: %v", err)
}
n = uint32(binary.LittleEndian.Uint32(b[:]))
}

d := make([]byte, n)
_, err = r.Read(d)
if err != nil {
return "", fmt.Errorf("failed to read string: %v", err)
}

return string(d), nil
}

func (h SaveHeader) readStats(r io.Reader) (stats map[byte][]map[uint16]uint32, err error) {
var scratch [4]byte
stats = make(map[byte][]map[uint16]uint32)
Expand Down
Binary file not shown.
Loading