//Returns the chunk at the coordinates, also returns if the chunk existed
//before this
func (mw *MsgpackSystem) Chunk(x, z int) (*Chunk, bool) {
	reg := mw.region(x>>5, z>>5)
	reg.RLock()
	rx := x & 0x1F
	rz := z & 0x1F
	idx := rx | (rz << 5)
	offset := reg.Offsets[idx]
	count := reg.SectionCounts[idx]
	reg.RUnlock()
	if offset == 0 {
		return &Chunk{X: x, Z: z}, false
	}

	section := io.NewSectionReader(reg.file, int64(offset)*regionSectionSize, int64(count)*regionSectionSize)
	gz, err := gzip.NewReader(section)
	if err != nil {
		panic(err)
	}
	chunk := &Chunk{}
	err = msgpack.NewDecoder(gz).Decode(chunk)
	gz.Close()

	if err != nil {
		panic(err)
	}
	return chunk, true
}
//Reads key into the passed struct pointer
func (mw *MsgpackSystem) Read(key string, v interface{}) error {
	f, err := os.Open(filepath.Join(mw.path, "data", key+".nether"))
	if err != nil {
		return err
	}
	defer f.Close()
	return msgpack.NewDecoder(f).Decode(v)
}
func (mw *MsgpackSystem) readLevel(level string) {
	f, err := os.Open(level)
	if err != nil {
		panic(err)
	}
	defer f.Close()
	err = msgpack.NewDecoder(f).Decode(mw)
	if err != nil {
		panic(err)
	}
}
func (mw *MsgpackSystem) region(x, z int) *region {
	key := (uint64(int32(x)) & 0xFFFFFFFF) | ((uint64(int32(z)) & 0xFFFFFFFF) << 32)
	mw.regionLock.RLock()
	reg, ok := mw.regions[key]
	mw.regionLock.RUnlock()
	if ok {
		return reg
	}
	mw.regionLock.Lock()
	reg, ok = mw.regions[key]
	if ok {
		mw.regionLock.Unlock()
		return reg
	}
	reg = &region{}
	file, err := os.OpenFile(filepath.Join(mw.path, "regions", fmt.Sprintf("%016X.region", key)), os.O_RDWR|os.O_CREATE, 0666)
	if err != nil {
		panic(err)
	}
	msgpack.NewDecoder(file).Decode(reg)
	reg.file = file
	reg.usedLocations = []bool{true, true, true}
	for i, off := range reg.Offsets {
		if off == 0 {
			continue
		}
		count := reg.SectionCounts[i]
		if len(reg.usedLocations) < off+count {
			temp := reg.usedLocations
			reg.usedLocations = make([]bool, off+count)
			copy(reg.usedLocations, temp)
		}
		for j := off; j < off+count; j++ {
			reg.usedLocations[j] = true
		}
	}
	reg.Save()

	mw.regions[key] = reg
	mw.regionLock.Unlock()
	return reg
}
//Loads the world by name
func GetWorld(name string, tryClose chan TryClose) *World {
	root := filepath.Join("./worlds/", name)
	f, err := os.Open(filepath.Join(root, "netherrack.meta"))
	if err != nil {
		return nil
	}
	defer f.Close()

	meta := netherrackMeta{}
	msgpack.NewDecoder(f).Decode(&meta)

	sys, ok := systems[meta.SystemName]
	if !ok {
		panic("Unknown world system")
	}
	system := sys()

	gen, ok := generators[meta.GeneratorName]
	if !ok {
		panic("Unknown world generator")
	}
	generator := gen()

	w := &World{
		Name:      name,
		system:    system,
		generator: generator,
		tryClose:  tryClose,
	}
	w.init()
	w.system.Init(filepath.Join("./worlds/", w.Name))
	w.system.Read("levelData", &w.worldData)
	go w.run()

	return w
}