func (s *chunkStoreAlpha) WriteChunk(writer IChunkWriter) (err error) { nbtWriter, ok := writer.(*nbtChunkWriter) if !ok { return fmt.Errorf("%T is incorrect IChunkWriter implementation for %T", writer, s) } destName := s.chunkPath(writer.ChunkLoc()) dirName, _ := path.Split(destName) if err = os.MkdirAll(dirName, 0777); err != nil { return } file, err := util.OpenFileUniqueName(destName, os.O_WRONLY, 0666) if err != nil { return } defer file.Close() gzipWriter := gzip.NewWriter(file) defer gzipWriter.Close() if err = nbt.Write(gzipWriter, nbtWriter.RootTag()); err != nil { return } // Atomically move the newly written file into place. return os.Rename(file.Name(), destName) }
// serializeChunkData produces the compressed chunk NBT data. func serializeChunkData(w *nbtChunkWriter) (chunkData []byte, err os.Error) { // Reserve room for the chunk data header at the start. buffer := bytes.NewBuffer(make([]byte, chunkDataHeaderSize, chunkDataGuessSize)) if zlibWriter, err := zlib.NewWriter(buffer); err != nil { return nil, err } else { if err = nbt.Write(zlibWriter, w.RootTag()); err != nil { zlibWriter.Close() return nil, err } if err = zlibWriter.Close(); err != nil { return nil, err } } chunkData = buffer.Bytes() // Write chunk data header header := chunkDataHeader{ DataSize: uint32(len(chunkData)) - chunkDataHeaderSize, Version: chunkCompressionZlib, } buffer = bytes.NewBuffer(chunkData[:0]) if err = binary.Write(buffer, binary.BigEndian, header); err != nil { return nil, err } return chunkData, nil }
func (is *ItemSlot) MinecraftMarshal(writer io.Writer, ps *PacketSerializer) error { err := ps.writeUint16(writer, uint16(is.ItemTypeId)) if err != nil { return err } if is.ItemTypeId != -1 { err = ps.writeUint8(writer, uint8(is.Count)) if err != nil { return err } err = ps.writeUint16(writer, uint16(is.Data)) if err != nil { return err } if _, requiresNbt := nbtItemIds[is.ItemTypeId]; requiresNbt { // Write NBT data. if is.Nbt == nil || len(is.Nbt) == 0 { // No tags. err = ps.writeUint16(writer, uint16(0xffff)) if err != nil { return err } } else { // Have tags. var buf bytes.Buffer zWriter := gzip.NewWriter(&buf) err = nbt.Write(zWriter, is.Nbt) if err != nil { return err } err = zWriter.Close() if err != nil { return err } data := buf.Bytes() err = ps.writeUint16(writer, uint16(len(data))) if err != nil { return err } _, err = writer.Write(data) if err != nil { return err } } } } return nil }
// Creates a new world at 'worldPath' func CreateWorld(worldPath string) (err os.Error) { source := rand.NewSource(time.Nanoseconds()) seed := source.Int63() data := &nbt.Compound{ map[string]nbt.ITag{ "Data": &nbt.Compound{ map[string]nbt.ITag{ "Time": &nbt.Long{0}, "rainTime": &nbt.Int{0}, "thunderTime": &nbt.Int{0}, "version": &nbt.Int{19132}, // TODO: What should this be? "thundering": &nbt.Byte{0}, "raining": &nbt.Byte{0}, "LevelName": &nbt.String{"world"}, // TODO: Should be specifyable "SpawnX": &nbt.Int{0}, // TODO: Figure this out from chunk generator? "SpawnY": &nbt.Int{75}, // TODO: Figure this out from chunk generator? "SpawnZ": &nbt.Int{0}, // TODO: Figure this out from chunk generator? "LastPlayed": &nbt.Long{0}, "SizeOnDisk": &nbt.Long{0}, // Needs to be accurate? "RandomSeed": &nbt.Long{seed}, }, }, }, } if err = os.MkdirAll(worldPath, 0777); err != nil { return } filename := path.Join(worldPath, "level.dat") file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0666) if err != nil { return err } gzipWriter, err := gzip.NewWriter(file) if err != nil { return err } err = nbt.Write(gzipWriter, data) gzipWriter.Close() file.Close() return nil }
func (world *WorldStore) WritePlayerData(user string, data nbt.Compound) (err error) { playerDir := path.Join(world.WorldPath, "players") if err = os.MkdirAll(playerDir, 0777); err != nil { return } filename := path.Join(world.WorldPath, "players", user+".dat") file, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE, 0666) if err != nil { return err } defer file.Close() gzipWriter := gzip.NewWriter(file) err = nbt.Write(gzipWriter, data) gzipWriter.Close() return }