diff --git a/objects/objects.go b/objects/objects.go index b7ce17c..a60a519 100644 --- a/objects/objects.go +++ b/objects/objects.go @@ -3,10 +3,11 @@ package objects import ( "ModCreator/bundler" "ModCreator/file" + "log" "path" "regexp" + "sort" "strings" - "log" "fmt" ) @@ -16,6 +17,7 @@ type objArray []map[string]interface{} type objConfig struct { guid string + order int64 data j luascriptPath string luascriptstatePath string @@ -23,6 +25,7 @@ type objConfig struct { subObj []*objConfig } +// TODO can I reuse parseFromJSON? func (o *objConfig) parseFromFile(filepath string, j file.JSONReader) error { d, err := j.ReadObj(filepath) if err != nil { @@ -44,6 +47,7 @@ func (o *objConfig) parseFromFile(filepath string, j file.JSONReader) error { tryParseIntoStr(&o.data, "LuaScript_path", &o.luascriptPath) tryParseIntoStr(&o.data, "LuaScriptState_path", &o.luascriptstatePath) tryParseIntoStr(&o.data, "ContainedObjects_path", &o.subObjDir) + tryParseIntoInt(&o.data, "tts_mod_order", &o.order) return nil } @@ -56,6 +60,20 @@ func tryParseIntoStr(m *j, k string, dest *string) { } } } +func tryParseIntoInt(m *j, k string, dest *int64) { + if raw, ok := (*m)[k]; ok { + if in, ok := raw.(int64); ok { + *dest = in + delete((*m), k) + return + } + if fl, ok := raw.(float64); ok { + *dest = int64(fl) + delete((*m), k) + return + } + } +} func (o *objConfig) parseFromJSON(data map[string]interface{}) error { o.data = data @@ -69,6 +87,9 @@ func (o *objConfig) parseFromJSON(data map[string]interface{}) error { } o.guid = guid o.subObj = []*objConfig{} + + tryParseIntoInt(&o.data, "tts_mod_order", &o.order) + if rawObjs, ok := o.data["ContainedObjects"]; ok { rawArr, ok := rawObjs.([]interface{}) if !ok { @@ -119,6 +140,9 @@ func (o *objConfig) print(l file.LuaReader) (j, error) { o.data["LuaScript"] = bundleReqs } } + sort.Slice(o.subObj, func(i int, j int) bool { + return o.subObj[i].order < o.subObj[j].order + }) subs := []j{} for _, sub := range o.subObj { @@ -184,6 +208,9 @@ func (o *objConfig) printToFile(filepath string, l file.LuaWriter, j file.JSONWr } } + // add order to data when saving + o.data["tts_mod_order"] = o.order + // print self fname := path.Join(filepath, o.getAGoodFileName()+".json") return j.WriteObj(o.data, fname) @@ -240,16 +267,22 @@ func (d *db) addObj(o, parent *objConfig) error { parent.subObj = append(parent.subObj, o) } if _, ok := d.all[o.guid]; ok { - log.Printf("Found duplicate guid %s\n",o.guid) + log.Printf("Found duplicate guid %s\n", o.guid) } else { - d.all[o.guid]=o + d.all[o.guid] = o } return nil } func (d *db) print(l file.LuaReader) (objArray, error) { var oa objArray + sort.Slice(d.root, func(i int, j int) bool { + return d.root[i].order < d.root[j].order + }) for _, o := range d.root { + if o.order == -1 { + return nil, fmt.Errorf("Invalid order detected on obj %v", o.guid) + } printed, err := o.print(l) if err != nil { return objArray{}, fmt.Errorf("obj (%s) did not print : %v", o.guid, err) @@ -315,6 +348,7 @@ func (d *db) parseFromFolder(relpath string, parent *objConfig) error { func (d *db) parseFromFile(relpath string, parent *objConfig) (*objConfig, error) { var o objConfig + o.order = -1 err := o.parseFromFile(relpath, d.j) if err != nil { return nil, fmt.Errorf("parseFromFile(%s) : %v", relpath, err) @@ -326,8 +360,11 @@ func (d *db) parseFromFile(relpath string, parent *objConfig) (*objConfig, error // PrintObjectStates takes a list of json objects and prints them in the // expected format outlined by ParseAllObjectStates func PrintObjectStates(root string, f file.LuaWriter, j file.JSONWriter, dir file.DirCreator, objs []map[string]interface{}) error { - for _, rootObj := range objs { - oc := objConfig{} + for i, rootObj := range objs { + oc := objConfig{ + order: int64(i), + } + err := oc.parseFromJSON(rootObj) if err != nil { return err diff --git a/objects/objects_test.go b/objects/objects_test.go index ed4c62f..518b535 100644 --- a/objects/objects_test.go +++ b/objects/objects_test.go @@ -1,6 +1,7 @@ package objects import ( + "encoding/json" "fmt" "log" "path" @@ -20,6 +21,15 @@ func (f *fakeFiles) EncodeFromFile(s string) (string, error) { } return f.fs[s], nil } +func (f *fakeFiles) ReadObj(s string) (map[string]interface{}, error) { + if _, ok := f.data[s]; !ok { + return nil, fmt.Errorf("fake file <%s> not found", s) + } + return f.data[s], nil +} +func (f *fakeFiles) ReadObjArray(s string) ([]map[string]interface{}, error) { + return nil, fmt.Errorf("unimplemented") +} func (f *fakeFiles) WriteObj(data map[string]interface{}, path string) error { f.data[path] = data return nil @@ -46,9 +56,35 @@ func TestObjPrinting(t *testing.T) { data: j{ "GUID": "123456", }, + subObj: []*objConfig{ + { + guid: "1234563", + data: j{ + "GUID": "1234563", + }, + order: 3, + }, { + guid: "1234561", + data: j{ + "GUID": "1234561", + }, + order: 1, + }, { + guid: "1234562", + data: j{ + "GUID": "1234562", + }, + order: 2, + }, + }, }, want: j{ "GUID": "123456", + "ContainedObjects": []j{ + {"GUID": "1234561"}, + {"GUID": "1234562"}, + {"GUID": "1234563"}, + }, }, }, } { @@ -86,7 +122,8 @@ func TestObjPrintingToFile(t *testing.T) { }, folder: "foo", want: j{ - "GUID": "123456", + "GUID": "123456", + "tts_mod_order": int64(0), }, }, { o: &objConfig{ @@ -100,6 +137,7 @@ func TestObjPrintingToFile(t *testing.T) { want: j{ "GUID": "123456", "LuaScriptState": "fav color = green", + "tts_mod_order": int64(0), }, // want no LSS file because it's short }, { @@ -114,6 +152,7 @@ func TestObjPrintingToFile(t *testing.T) { want: j{ "GUID": "123456", "LuaScriptState_path": "foo/123456.luascriptstate", + "tts_mod_order": int64(0), }, wantLSS: fileContent{ file: "foo/123456.luascriptstate", @@ -154,7 +193,6 @@ func TestObjPrintingToFile(t *testing.T) { } } - func TestName(t *testing.T) { for _, tc := range []struct { data j @@ -250,3 +288,139 @@ func TestName(t *testing.T) { } } + +func TestPrintAllObjs(t *testing.T) { + type wantFile struct { + name string + content j + } + for _, tc := range []struct { + objs []map[string]interface{} + wants []wantFile + }{ + { + objs: []map[string]interface{}{ + {"GUID": "123456"}, + {"GUID": "123457"}, + }, + wants: []wantFile{ + { + name: "123456.json", + content: j{"GUID": "123456", "tts_mod_order": int64(0)}, + }, { + name: "123457.json", + content: j{"GUID": "123457", "tts_mod_order": int64(1)}, + }, + }, + }, + } { + ff := &fakeFiles{ + data: map[string]j{}, + fs: map[string]string{}, + } + err := PrintObjectStates("", ff, ff, ff, tc.objs) + if err != nil { + t.Fatalf("error not expected %v", err) + } + for _, w := range tc.wants { + got, ok := ff.data[w.name] + if !ok { + t.Errorf("wanted filename %s not present in data", w.name) + } + if diff := cmp.Diff(w.content, got); diff != "" { + t.Errorf("want != got:\n%v\n", diff) + } + } + } + +} + +func TestDBPrint(t *testing.T) { + ff := &fakeFiles{ + fs: map[string]string{}, + data: map[string]j{}, + } + for _, tc := range []struct { + root []*objConfig + want objArray + }{ + { + root: []*objConfig{ + &objConfig{ + data: j{"GUID": "123"}, + order: 3, + }, + &objConfig{ + data: j{"GUID": "121"}, + order: 1, + }, + &objConfig{ + data: j{"GUID": "122"}, + order: 2, + }, + }, + want: objArray{ + {"GUID": "121"}, + {"GUID": "122"}, + {"GUID": "123"}, + }, + }, + } { + db := db{ + root: tc.root, + } + got, err := db.print(ff) + if err != nil { + t.Fatalf("got unexpected err %v", err) + } + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("want != got:\n%v\n", diff) + } + + } +} + +func jn(i int) json.Number { + return json.Number(fmt.Sprint(i)) +} + +func TestParseFromFile(t *testing.T) { + + ff := &fakeFiles{ + data: map[string]j{}, + } + for _, tc := range []struct { + name string + input j + want objConfig + }{ + { + name: "mod order", + input: j{ + "GUID": "123", + "tts_mod_order": float64(3), + }, + want: objConfig{ + order: int64(3), + guid: "123", + data: j{"GUID": "123"}, + }, + }, + } { + ff.data[tc.name] = tc.input + o := objConfig{} + err := o.parseFromFile(tc.name, ff) + if err != nil { + t.Fatalf("failed to preset data in %s\n", tc.name) + } + if diff := cmp.Diff(tc.want.data, o.data); diff != "" { + t.Errorf("want != got:\n%v\n", diff) + } + if tc.want.guid != o.guid { + t.Errorf("guid mismatch want %s got %s", tc.want.guid, o.guid) + } + if tc.want.order != o.order { + t.Errorf("order mismatch want %v got %v", tc.want.order, o.order) + } + } +}