// LoadLocale loads the named locale if it exists. func LoadLocale(name string) { lock.Lock() defer lock.Unlock() r, err := resource.Open("minecraft", fmt.Sprintf("lang/%s.lang", name)) if err != nil { return } defer r.Close() b := bufio.NewScanner(r) for b.Scan() { line := b.Text() line = strings.TrimSpace(line) if len(line) == 0 { continue } parts := strings.SplitN(line, "=", 2) if len(parts) != 2 { continue } values[parts[0]] = parts[1] } if err := b.Err(); err != nil { panic(err) } }
func loadJSON(plugin, name string, target interface{}) error { r, err := resource.Open(plugin, name) if err != nil { return err } defer r.Close() err = realjson.NewDecoder(r).Decode(target) if err != nil { // Take the slow path through our preprocessor. // Hopefully this can be removed in later minecraft versions.d, err := ioutil.ReadAll(r) r.Close() r, err = resource.Open(plugin, name) if err != nil { return err } d, err := ioutil.ReadAll(r) if err != nil { return err } return json.Unmarshal(d, target) } return err }
func LoadSkinBuffer() { r, err := resource.Open("minecraft", "textures/entity/steve.png") if err != nil { skinBuffer = make([]byte, 64*64*4) return } defer r.Close() i, err := png.Decode(r) if err != nil { panic(err) } out := image.NewNRGBA(image.Rect(0, 0, 64, 64)) draw.Draw(out, out.Bounds(), i, image.ZP, draw.Over) skinBuffer = out.Pix }
func loadBiomeColors(name string) *image.NRGBA { f, err := resource.Open("minecraft", fmt.Sprintf("textures/colormap/%s.png", name)) if err != nil { console.Text("loading biome colors: %s", err) return image.NewNRGBA(image.Rect(0, 0, 256, 256)) } defer f.Close() img, err := png.Decode(f) if err != nil { panic(err) } i, ok := img.(*image.NRGBA) if !ok { i = convertImage(img) } return i }
func loadFontInfo() { r, err := resource.Open("minecraft", "font/glyph_sizes.bin") if err != nil { console.Text("Error loading font info, %s", err) return } var data [0x10000]byte _, err = io.ReadFull(r, data[:]) if err != nil { panic(err) } for i := range fontCharacterInfo { // Top nibble - start position // Bottom nibble - end position fontCharacterInfo[i].Start = int(data[i] >> 4) fontCharacterInfo[i].End = int(data[i]&0xF) + 1 } }
func loadFontPage(page int) { textureLock.Lock() defer textureLock.Unlock() isFontLoaded[page] = true var p string if page == 0 { // The ascii font is the minecraft style one // which is the default page 0 instead of the // unicode one for the english locales. p = "ascii" } else { p = fmt.Sprintf("unicode_page_%02x", page) } r, err := resource.Open("minecraft", "textures/font/"+p+".png") if err != nil { return } defer r.Close() img, err := png.Decode(r) if err != nil { panic(err) } width, height := img.Bounds().Dx(), img.Bounds().Dy() pix := imgToBytes(img) info := addTexture(pix, width, height) if fontPages[page] != nil { fontPages[page].atlas = info.atlas fontPages[page].rect = info.rect } else { fontPages[page] = info } if p == "ascii" { // The font map file included with minecraft has the // wide of the unicode page 0 instead of the ascii one // we need to work this out ourselves calculateFontSizes(img) } }
func readStevenLogo() { r, _ := resource.Open("steven", "logo/logo.txt") defer r.Close() data, _ := ioutil.ReadAll(r) stevenLogo = string(data) }
func loadAnimation(file string, max int) *animatedTexture { a := &animatedTexture{} defer func() { if a != nil { a.RemainingTime = float64(a.Frames[0].Time) } }() type animation struct { FrameTime int Interpolate bool Frames []json.RawMessage } type base struct { Animation animation } meta, err := resource.Open("minecraft", file+".mcmeta") if err != nil { fmt.Printf("%s: %s\n", file+".mcmeta", err) a = nil return nil } defer meta.Close() b := &base{} err = json.NewDecoder(meta).Decode(b) if err != nil { panic(err) } frameTime := b.Animation.FrameTime if frameTime == 0 { frameTime = 1 } a.Interpolate = b.Animation.Interpolate if len(b.Animation.Frames) == 0 { a.Frames = make([]textureFrame, max) for i := range a.Frames { a.Frames[i] = textureFrame{ Index: i, Time: frameTime, } } return a } a.Frames = make([]textureFrame, len(b.Animation.Frames)) for i := range a.Frames { a.Frames[i].Time = frameTime if b.Animation.Frames[i][0] == '{' { if err = json.Unmarshal(b.Animation.Frames[i], &a.Frames[i]); err != nil { panic(err) } a.Frames[i].Time *= frameTime continue } if err = json.Unmarshal(b.Animation.Frames[i], &a.Frames[i].Index); err != nil { panic(err) } } return a }
// LoadTextures (re)loads all the block textures from the resource pack(s) // TODO(Think) better error handling (if possible to recover?) func LoadTextures() { textureLock.Lock() if texturesCreated { glTexture.Bind(gl.Texture2DArray) data := make([]byte, AtlasSize*AtlasSize*textureCount*4) glTexture.Image3D(0, AtlasSize, AtlasSize, textureCount, gl.RGBA, gl.UnsignedByte, data) } else { glTexture = gl.CreateTexture() glTexture.Bind(gl.Texture2DArray) textureDepth = len(textures) glTexture.Image3D(0, AtlasSize, AtlasSize, len(textures), gl.RGBA, gl.UnsignedByte, make([]byte, AtlasSize*AtlasSize*len(textures)*4)) glTexture.Parameter(gl.TextureMagFilter, gl.Nearest) glTexture.Parameter(gl.TextureMinFilter, gl.Nearest) glTexture.Parameter(gl.TextureWrapS, gl.ClampToEdge) glTexture.Parameter(gl.TextureWrapT, gl.ClampToEdge) for i, tex := range textures { glTexture.SubImage3D(0, 0, 0, i, AtlasSize, AtlasSize, 1, gl.RGBA, gl.UnsignedByte, tex.Buffer) textures[i] = nil } texturesCreated = true } freeTextures = nil animatedTextures = nil textures = nil pix := []byte{ 0, 0, 0, 255, 255, 0, 255, 255, 255, 0, 255, 255, 0, 0, 0, 255, } info := addTexture(pix, 2, 2) if t, ok := textureMap["missing_texture"]; ok { t.atlas = info.atlas t.rect = info.rect } else { textureMap["missing_texture"] = info } for _, t := range textureMap { t.atlas = info.atlas t.rect = info.rect } for _, s := range loadedTextures { func() { r, err := resource.Open(s.Plugin, s.File) if err == nil { defer r.Close() img, err := png.Decode(r) if err != nil { panic(fmt.Sprintf("(%s): %s", s.File, err)) } s.Image = img loadTexFile(s) } }() } pix = []byte{255, 255, 255, 255} info = addTexture(pix, 1, 1) if t, ok := textureMap["solid"]; ok { t.atlas = info.atlas t.rect = info.rect } else { textureMap["solid"] = info } for _, skin := range skins { info := getFreeTexture(skin.info.W, skin.info.H) uploadTexture(info.info, skin.data) i := skin.info.info skin.info = info i.rect = info.info.rect i.atlas = info.info.atlas skin.info.info = i } textureLock.Unlock() loadFontInfo() loadFontPage(0) for i := range isFontLoaded { if i == 0 || !isFontLoaded[i] { continue } isFontLoaded[i] = false loadFontPage(i) } }
// GetTexture returns the related TextureInfo for the requested texture. // If the texture isn't found a placeholder is returned instead. // The plugin prefix of 'minecraft:' is default func GetTexture(name string) TextureInfo { textureLock.RLock() defer textureLock.RUnlock() t, ok := textureMap[name] if !ok { textureLock.RUnlock() ret := make(chan struct{}, 1) f := func() { textureLock.Lock() defer textureLock.Unlock() // Check to see if it was already loaded between // requesting it if _, ok = textureMap[name]; ok { t = textureMap[name] ret <- struct{}{} return } ns := name plugin := "minecraft" if pos := strings.IndexRune(name, ':'); pos != -1 { plugin = name[:pos] ns = name[pos+1:] } r, err := resource.Open(plugin, "textures/"+ns+".png") if err == nil { defer r.Close() img, err := png.Decode(r) if err != nil { panic(fmt.Sprintf("(%s): %s", name, err)) } s := &loadedTexture{ Plugin: plugin, File: "textures/" + ns + ".png", Image: img, } loadedTextures = append(loadedTextures, s) loadTexFile(s) } t, ok = textureMap[name] if !ok { ti := *textureMap["missing_texture"] t = &ti textureMap[name] = t s := &loadedTexture{ Plugin: plugin, File: "textures/" + ns + ".png", Image: nil, } loadedTextures = append(loadedTextures, s) } ret <- struct{}{} } if w := glfw.GetCurrentContext(); w == nil { syncChan <- f } else { f() } <-ret textureLock.RLock() } return t }
func genStaticModelFromItem(mdl *model, block Block, mode string) (out []*render.StaticVertex, mat mgl32.Mat4) { mat = mgl32.Rotate3DZ(math.Pi).Mat4(). Mul4(mgl32.Rotate3DY(math.Pi / 2).Mat4()). Mul4(mgl32.Rotate3DZ(-math.Pi / 2).Mat4()) if gui, ok := mdl.display[mode]; ok { if gui.Scale != nil { mat = mat.Mul4(mgl32.Scale3D( float32(gui.Scale[0]), float32(gui.Scale[1]), float32(gui.Scale[2]), )) } if gui.Translation != nil { mat = mat.Mul4(mgl32.Translate3D( float32(gui.Translation[0]/32), float32(gui.Translation[1]/32), float32(gui.Translation[2]/32), )) } if gui.Rotation != nil { mat = mat.Mul4(mgl32.Rotate3DX(math.Pi + float32(gui.Rotation[0]/180)*math.Pi).Mat4()) mat = mat.Mul4(mgl32.Rotate3DZ(math.Pi + float32(gui.Rotation[2]/180)*math.Pi).Mat4()) mat = mat.Mul4(mgl32.Rotate3DY(float32(gui.Rotation[1]/180) * math.Pi).Mat4()) } } mat = mat.Mul4(mgl32.Rotate3DY(math.Pi / 2).Mat4()) mat = mat.Mul4(mgl32.Translate3D(-1/16.0, 0, 0)) tex := render.GetTexture("solid") rect := tex.Rect() tName, plugin := mdl.textureVars["layer0"], "minecraft" if pos := strings.IndexRune(tName, ':'); pos != -1 { plugin = tName[:pos] tName = tName[pos:] } f, err := resource.Open(plugin, "textures/"+tName+".png") if err != nil { return } defer f.Close() img, err := png.Decode(f) if err != nil { panic(err) } w, h := img.Bounds().Dx(), img.Bounds().Dy() sx := 1 / float32(w) sy := 1 / float32(h) isSolid := func(x, y int) bool { col := img.At(x, y) _, _, _, aa := col.RGBA() if aa == 0 { return false } return true } for x := 0; x < w; x++ { for y := 0; y < h; y++ { col := img.At(x, y) rr, gg, bb, aa := col.RGBA() if aa == 0 { continue } for i, f := range faceVertices { facing := direction.Type(i) if facing != direction.North && facing != direction.South { xx, yy, _ := facing.Offset() if isSolid(x+xx, y+yy) { continue } } var cr, cg, cb byte cr = byte(rr >> 8) cg = byte(gg >> 8) cb = byte(bb >> 8) if facing == direction.East || facing == direction.West { cr = byte(float64(cr) * 0.8) cg = byte(float64(cg) * 0.8) cb = byte(float64(cb) * 0.8) } if facing == direction.North || facing == direction.South { cr = byte(float64(cr) * 0.6) cg = byte(float64(cg) * 0.6) cb = byte(float64(cb) * 0.6) } for _, vert := range f.verts { vX, vY, vZ := float32(vert.X), float32(vert.Y), float32(vert.Z) vert := &render.StaticVertex{ Y: vY*sy - 0.5 + sy*float32(y), X: vX*sx - 0.5 + sx*float32(x), Z: (vZ - 0.5) * (1.0 / 16.0), Texture: tex, TextureX: float64(vert.TOffsetX) / float64(16*rect.Width), TextureY: float64(vert.TOffsetY) / float64(16*rect.Height), R: cr, G: cg, B: cb, A: byte(aa >> 8), } out = append(out, vert) } } } } return }
func playSoundInternal(cat soundCategory, snd sound, vol, pitch float64, rel bool, pos mgl32.Vec3, cb func()) { vol *= snd.Volume * 100 baseVol := vol vol *= float64(muVolMaster.Value()) / 100 if v, ok := volVars[cat]; ok { vol *= float64(v.Value()) / 100 } if vol <= 0 { if cb != nil { go func() { syncChan <- cb }() } return } name := snd.Name key := pluginKey{"minecraft", name} sb, ok := loadedSounds[key] if !ok { f, err := resource.Open("minecraft", "sounds/"+name+".ogg") if err != nil { v, ok := assets.Objects[fmt.Sprintf("minecraft/sounds/%s.ogg", name)] if !ok { console.Text("Missing sound %s", key) if cb != nil { cb() } return } loc := fmt.Sprintf("./resources/%s", hashPath(v.Hash)) f, err = os.Open(loc) if err != nil { console.Text("Missing sound %s", key) if cb != nil { cb() } return } } if snd.Stream { m := audio.NewMusic(f) m.SetVolume(vol) m.SetPitch(pitch) m.Play() currentMusic = append(currentMusic, music{Music: m, cb: cb, cat: cat, vol: baseVol}) return } defer f.Close() data, err := ioutil.ReadAll(f) if err != nil { panic(err) } sb = audio.NewSoundBufferData(data) loadedSounds[key] = sb } var s audio.Sound n := true for _, sn := range soundList { if sn.Status() == audio.StatStopped { s = sn n = false break } } if n { if len(soundList) >= 100 { console.Component( format.Build("WARN: Skipping playing sound due to limit"). Color(format.Yellow).Create(), ) return } s = audio.NewSound() soundList = append(soundList, s) } s.SetBuffer(sb) s.SetVolume(vol) s.SetMinDistance(5) s.SetAttenuation(0.008) s.SetPitch(pitch) s.Play() if rel { s.SetRelative(true) s.SetPosition(pos.X(), pos.Y(), pos.Z()) } else { s.SetRelative(false) } }