diff --git a/save/region/mca.go b/save/region/mca.go index 6357a98..f009013 100644 --- a/save/region/mca.go +++ b/save/region/mca.go @@ -67,6 +67,26 @@ func OpenRegion(name string) (r *Region, err error) { } func (r *Region) Close() error { + _, err := r.f.Seek(0, 0) + if err != nil { + return err + } + + // read the offsets + err = binary.Write(r.f, binary.BigEndian, &r.offsets) + if err != nil { + _ = r.f.Close() + return err + } + r.sectors[0] = true + + // read the timestamps + err = binary.Write(r.f, binary.BigEndian, &r.timestamps) + if err != nil { + _ = r.f.Close() + return err + } + return r.f.Close() } @@ -97,3 +117,57 @@ func (r *Region) ReadSector(x, y int) (data []byte, err error) { return } + +func (r *Region) WriteSector(x, y int, data []byte) error { + sectorsNeeded := int32(len(data)+4)/4096 + 1 + sectorNumber, sectorsAllocated := sectorLoc(r.offsets[x][y]) + + // maximum chunk size is 1MB + if sectorsNeeded >= 256 { + return errors.New("data too large") + } + + if sectorNumber != 0 && sectorsAllocated == sectorsNeeded { + // we can simply overwrite the old sectors + } else { + // we need to allocate new sectors + + // mark the sectors previously used for this chunk as free + for i := int32(0); i < sectorsAllocated; i++ { + r.sectors[sectorNumber+i] = false + } + + // scan for a free space large enough to store this chunk + sectorNumber = 0 + for i := int32(0); i < sectorsNeeded; i++ { + if r.sectors[sectorNumber+i] { + sectorNumber += i + 1 + i = -1 + } + } + + // mark the sectors previously used for this chunk as used + sectorsAllocated = sectorsNeeded + for i := int32(0); i < sectorsNeeded; i++ { + r.sectors[sectorNumber+i] = true + } + r.offsets[x][y] = (sectorNumber << 8) | (sectorsNeeded & 0xFF) + } + + _, err := r.f.Seek(4096*int64(sectorNumber), 0) + if err != nil { + return err + } + //data length + err = binary.Write(r.f, binary.BigEndian, int32(len(data))) + if err != nil { + return err + } + //data + _, err = r.f.Write(data) + if err != nil { + return err + } + + return nil +} diff --git a/save/region/mca_test.go b/save/region/mca_test.go index a20a51b..cc3859c 100644 --- a/save/region/mca_test.go +++ b/save/region/mca_test.go @@ -44,3 +44,39 @@ func TestReadRegion(t *testing.T) { t.Log(s) } + +func TestSectorsFinder(t *testing.T) { + sectors := []byte{ + 1, 1, + 0, 1, //2 + 0, 0, 1, //4 + 0, 0, 0, 1, 1, //7 + 0, 0, 0, 0, 0, 1, //12 + 0, 0, 0, 0, 0, 0, 0, //18 + } + + scan := func(need int) (index int) { + for i := 0; i < need; i++ { + if sectors[index+i] != 0 { + index += i + 1 + i = -1 // 0 for next loop + } + } + return + } + + for _, test := range []struct{ need, index int }{ + {0, 0}, + {1, 2}, + {2, 4}, + {3, 7}, + {4, 12}, + {5, 12}, + {6, 18}, + } { + i := scan(test.need) + if i != test.index { + t.Errorf("scan sctors fail: get %d, want %d", i, test.index) + } + } +}