func reinitBlocks() { blockStateModels = map[pluginKey]*blockStateModel{} missingModel := findStateModel("steven", "missing_block") // Flatten the ids for _, bs := range blockSetsByID { if bs == nil { continue } for _, b := range bs.Blocks { br := reflect.ValueOf(b).Elem() // Liquids have custom rendering if _, ok := b.(*blockLiquid); ok || !b.Renderable() { continue } if model := findStateModel(b.Plugin(), b.ModelName()); model != nil { if variants := model.variant(b.ModelVariant()); variants != nil { br.FieldByName("BlockVariants").Set( reflect.ValueOf(variants), ) continue } console.Text("Missing block variant (%s) for %s", b.ModelVariant(), b) } else { console.Text("Missing block model for %s", b) } br.FieldByName("BlockVariants").Set( reflect.ValueOf(missingModel.variant("normal")), ) } } }
func initBlocks() { missingModel := findStateModel("steven", "missing_block") // Flatten the ids for _, bs := range blockSetsByID { if bs == nil { continue } for i, b := range bs.Blocks { br := reflect.ValueOf(b).Elem() br.FieldByName("Index").SetInt(int64(i)) br.FieldByName("StevenID").SetUint(uint64(len(allBlocks))) allBlocks = append(allBlocks, b) if len(allBlocks) > math.MaxUint16 { panic("ran out of ids, time to do this correctly :(") } data := b.toData() if data != -1 { blocks[(bs.ID<<4)|data] = b } // Liquids have custom rendering if l, ok := b.(*blockLiquid); ok { if l.Lava { l.Tex = render.GetTexture("blocks/lava_still") } else { l.Tex = render.GetTexture("blocks/water_still") } continue } if !b.Renderable() { continue } if model := findStateModel(b.Plugin(), b.ModelName()); model != nil { if variants := model.variant(b.ModelVariant()); variants != nil { br.FieldByName("BlockVariants").Set( reflect.ValueOf(variants), ) continue } if variants := model.matchPart(bs, b); variants != nil { br.FieldByName("BlockVariants").Set( reflect.ValueOf(variants), ) continue } console.Text("Missing block variant (%s) for %s", b.ModelVariant(), b) } else { console.Text("Missing block model for %s", b) } br.FieldByName("BlockVariants").Set( reflect.ValueOf(missingModel.variant("normal")), ) } } }
func parseBlockStateVariant(plugin string, js realjson.RawMessage) *model { type jsType struct { Model string X, Y float64 UVLock bool Weight *int } var data jsType err := json.Unmarshal(js, &data) if err != nil { console.Text("%s", err) return nil } var bdata jsModel err = loadJSON(plugin, "models/block/"+data.Model+".json", &bdata) if err != nil { return nil } bm := parseModel(plugin, &bdata) bm.y = data.Y bm.x = data.X bm.uvLock = data.UVLock if data.Weight != nil { bm.weight = *data.Weight } else { bm.weight = 1 } return bm }
func handleErrors() { handle: for { select { case err := <-Client.network.Error(): if !connected { continue } connected = false Client.network.Close() console.Text("Disconnected: %s", err) // Reset the ready state to stop packets from being // sent. ready = false if err != errManualDisconnect && disconnectReason.Value == nil { txt := &format.TextComponent{Text: err.Error()} txt.Color = format.Red disconnectReason.Value = txt } if Client.entity != nil && Client.entityAdded { Client.entityAdded = false Client.entities.container.RemoveEntity(Client.entity) } setScreen(newServerList()) default: break handle } } }
func getAssetIndex() { console.Text("Getting asset index") defLocation := "./resources" resp, err := http.Get(fmt.Sprintf(assetIndexURL, assetsVersion)) if err != nil { panic(err) } defer resp.Body.Close() if err := json.NewDecoder(resp.Body).Decode(&assets); err != nil { panic(err) } os.MkdirAll("./resources", 0777) f, err := os.Create(fmt.Sprintf("%s/%s.index", defLocation, assetsVersion)) if err != nil { panic(err) } defer f.Close() json.NewEncoder(f).Encode(assets) console.Text("Got asset index for %s", assetsVersion) }
func parseModel(plugin string, data *jsModel) *model { var bm *model if data.Parent != "" && !strings.HasPrefix(data.Parent, "builtin/") { var pdata jsModel err := loadJSON(plugin, "models/"+data.Parent+".json", &pdata) if err != nil { console.Text("Error loading model %s: %s", data.Parent, err) loadJSON("steven", "models/block/missing_block.json", &pdata) } bm = parseModel(plugin, &pdata) } else { bm = &model{ textureVars: map[string]string{}, display: map[string]modelDisplay{}, } if strings.HasPrefix(data.Parent, "builtin/") { switch data.Parent { case "builtin/generated": bm.builtIn = builtInGenerated case "builtin/entity": bm.builtIn = builtInEntity case "builtin/compass": bm.builtIn = builtInCompass case "builtin/clock": bm.builtIn = builtInClock } } } if data.Textures != nil { for k, v := range data.Textures { bm.textureVars[k] = v } } for _, e := range data.Elements { bm.elements = append(bm.elements, parseBlockElement(e)) } if data.AmbientOcclusion != nil { bm.ambientOcclusion = *data.AmbientOcclusion bm.aoSet = true } else if !bm.aoSet { bm.ambientOcclusion = true } if data.Display != nil { for k, v := range data.Display { bm.display[k] = v } } return bm }
func (h handler) handlePluginMessage(channel string, r io.Reader, serverbound bool) { var pm reflect.Type var ok bool if serverbound { pm, ok = pluginMessagesServerbound[channel] } else { pm, ok = pluginMessagesClientbound[channel] } if !ok { console.Text("Unhandled plugin message %s", channel) return } p := reflect.New(pm).Interface().(pluginMessage) err := p.read(r) if err != nil { console.Text("Failed to handle plugin message %s: %s", channel, err) return } h.Handle(p) }
func AddPack(path string) { console.Text("Adding pack " + path) if err := resource.LoadZip(path); err != nil { fmt.Println("Failed to load pack", path) return } if resourcePacks.Value() != "" { resourcePacks.SetValue(resourcePacks.Value() + "," + path) } else { resourcePacks.SetValue(path) } reloadResources() }
func loadStateModel(key pluginKey) *blockStateModel { type partCase struct { When map[string]interface{} Apply realjson.RawMessage } type jsType struct { Variants map[string]realjson.RawMessage Multipart []partCase } var data jsType err := loadJSON(key.Plugin, fmt.Sprintf("blockstates/%s.json", key.Name), &data) if err != nil { console.Text("Error loading state %s: %s", key.Name, err) return nil } bs := &blockStateModel{} if data.Variants != nil { bs.variants = map[string]*blockVariants{} for k, v := range data.Variants { bs.variants[k] = parseModelList(key, v) } } if data.Multipart != nil { for _, part := range data.Multipart { p := &blockPart{} bs.multipart = append(bs.multipart, p) if part.When == nil { p.When = func(bs *BlockSet, block Block) bool { return true } } else if or, ok := part.When["OR"].([]interface{}); ok { var checks []func(bs *BlockSet, block Block) bool for _, rules := range or { checks = append(checks, parseBlockRuleList(rules.(map[string]interface{}))) } p.When = func(bs *BlockSet, block Block) bool { for _, rule := range checks { if rule(bs, block) { return true } } return false } } else { p.When = parseBlockRuleList(part.When) } p.Apply = parseModelList(key, part.Apply) } } return bs }
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 RemovePack(path string) { console.Text("Removing pack " + path) resource.RemovePack(path) var buf bytes.Buffer for _, pck := range strings.Split(resourcePacks.Value(), ",") { if pck != path { buf.WriteString(pck) buf.WriteRune(',') } } val := buf.String() if strings.HasPrefix(val, ",") { val = val[:len(val)-1] } resourcePacks.SetValue(val) reloadResources() }
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 loadStateModel(key pluginKey) *blockStateModel { type jsType struct { Variants map[string]realjson.RawMessage } var data jsType err := loadJSON(key.Plugin, fmt.Sprintf("blockstates/%s.json", key.Name), &data) if err != nil { console.Text("Error loading state %s: %s", key.Name, err) return nil } bs := &blockStateModel{ variants: map[string]blockVariants{}, } variants := data.Variants for k, v := range variants { var models blockVariants switch v[0] { case '[': var list []realjson.RawMessage json.Unmarshal(v, &list) for _, vv := range list { mdl := parseBlockStateVariant(key.Plugin, vv) if mdl != nil { models = append(models, precomputeModel(mdl)) } } default: mdl := parseBlockStateVariant(key.Plugin, v) if mdl != nil { models = append(models, precomputeModel(mdl)) } } bs.variants[k] = models } return bs }
func reloadResources() { console.Text("Bringing everything to a stop") for freeBuilders < maxBuilders { select { case pos := <-completeBuilders: freeBuilders++ if c := chunkMap[chunkPosition{pos.X, pos.Z}]; c != nil { if s := c.Sections[pos.Y]; s != nil { s.building = false } } } } locale.Clear() render.LoadSkinBuffer() modelCache = map[string]*model{} console.Text("Reloading textures") render.LoadTextures() console.Text("Reloading biomes") loadBiomes() ui.ForceDraw() console.Text("Reloading blocks") reinitBlocks() console.Text("Marking chunks for rebuild") for _, c := range chunkMap { for _, s := range c.Sections { if s != nil { s.dirty = true } } } console.Text("Rebuilding static models") render.RefreshModels() console.Text("Reloading inventory") Client.playerInventory.Update() }
func (handler) ServerMessage(msg *protocol.ServerMessage) { console.Text("MSG(%d): %s", msg.Type, msg.Message.Value) Client.chat.Add(msg.Message) }
func (handler) Disconnect(d *protocol.Disconnect) { disconnectReason = d.Reason console.Text("Disconnect: %s", disconnectReason) Client.network.SignalClose(errManualDisconnect) }
func (f Framebuffer) Check() { console.Text("%04X", gl.CheckFramebufferStatus(gl.FRAMEBUFFER)) }
func (n *networkManager) Connect(profile mojang.Profile, server string) { logLevel := networkLog.Value() go func() { var err error n.conn, err = protocol.Dial(server) if err != nil { n.SignalClose(err) return } if logLevel > 0 { n.conn.Logger = func(read bool, packet protocol.Packet) { if !read && logLevel < 2 { return } if logLevel < 3 { switch packet.(type) { case *protocol.ChunkData: return } } dir := "read" if !read { dir = "write" } console.Text("%s[%s] %T%+v", server, dir, packet, packet) } } err = n.conn.LoginToServer(profile) if err != nil { n.SignalClose(err) return } preLogin: for { packet, err := n.conn.ReadPacket() if err != nil { n.SignalClose(err) return } switch packet := packet.(type) { case *protocol.SetInitialCompression: n.conn.SetCompression(int(packet.Threshold)) case *protocol.LoginSuccess: n.conn.State = protocol.Play break preLogin case *protocol.LoginDisconnect: n.SignalClose(errors.New(packet.Reason.String())) return default: n.SignalClose(fmt.Errorf("unhandled packet %T", packet)) return } } first := true for { packet, err := n.conn.ReadPacket() if err != nil { n.SignalClose(err) return } if first { go n.writeHandler() first = false } // Handle keep alives async as there is no need to process them switch packet := packet.(type) { case *protocol.KeepAliveClientbound: n.Write(&protocol.KeepAliveServerbound{ID: packet.ID}) case *protocol.SetCompression: n.conn.SetCompression(int(packet.Threshold)) default: n.readChan <- packet } } }() }
func downloadAssets() { defLocation := "./resources" total := newProgressBar() var totalSize, totalCount int64 for _, v := range assets.Objects { totalSize += int64(v.Size) } limiter := make(chan struct{}, 4) for i := 0; i < 4; i++ { limiter <- struct{}{} } go func() { var wg sync.WaitGroup for file, v := range assets.Objects { v := v file := file path := hashPath(v.Hash) loc := fmt.Sprintf("%s/%s", defLocation, path) _, err := os.Stat(loc) if !os.IsNotExist(err) { continue } <-limiter wg.Add(1) go func() { defer wg.Done() var prog *progressBar wait := make(chan struct{}) syncChan <- func() { prog = newProgressBar(); wait <- struct{}{} } <-wait func() { resp, err := http.Get(fmt.Sprintf(assetResourceURL, path)) if err != nil { panic(err) } defer resp.Body.Close() os.MkdirAll(filepath.Dir(loc), 0777) f, err := os.Create(loc + ".tmp") if err != nil { panic(err) } defer f.Close() n, err := prog.watchCopy(f, resp.Body, resp.ContentLength, fmt.Sprintf("Downloading %s: %%v/100", file)) if err != nil { panic(err) } if n != int64(v.Size) { panic(fmt.Sprintf("Got: %d, Wanted: %d for %s", n, v.Size, fmt.Sprintf(assetResourceURL, path))) } console.Text("Downloaded: %s", loc) }() os.Rename(loc+".tmp", loc) syncChan <- func() { prog.remove() totalCount += int64(v.Size) progress := float64(totalCount) / float64(totalSize) total.update(progress, fmt.Sprintf("Downloading assets: %v/100", int(100*progress))) } limiter <- struct{}{} }() } wg.Wait() syncChan <- func() { total.remove() loadSoundData() } }() }
func downloadDefault(tick TickFunc, sync chan<- func(), target string) { console.Text("Obtaining vanilla resources for %s, please wait...", ResourcesVersion) resp, err := http.Get(fmt.Sprintf(vanillaURL, ResourcesVersion)) if err != nil { panic(err) } defer resp.Body.Close() os.MkdirAll("./", 0777) f, err := os.Create(target + ".tmp") if err != nil { panic(err) } defer os.Remove(target + ".tmp") defer f.Close() _, err = io.Copy(f, &progressRead{ max: resp.ContentLength, tick: tick, sync: sync, r: resp.Body, }) if err != nil { panic(err) } f.Seek(0, 0) // Go back to the start fr, err := zip.NewReader(f, resp.ContentLength) if err != nil { panic(err) } os.MkdirAll(target, 0777) // Copy the assets (not the classes) in the new zip fCount := float64(len(fr.File)) for i, f := range fr.File { if !strings.HasPrefix(f.Name, "assets/") { continue } func() { path := filepath.Join(target, f.Name) os.MkdirAll(filepath.Dir(path), 0777) w, err := os.Create(path) if err != nil { panic(err) } defer w.Close() r, err := f.Open() if err != nil { panic(err) } defer r.Close() _, err = io.Copy(w, r) if err != nil { panic(err) } }() sync <- func() { tick(0.75+(float64(i)/fCount)*0.25, false) } } lFile, err := os.Create(fmt.Sprintf("%s/steven.assets", target)) if err != nil { panic(err) } defer lFile.Close() lFile.WriteString(ResourcesVersion) }
// DebugLog enables OpenGL's debug messages and logs them to stdout. func DebugLog() { gl.DebugMessageCallback(func( source uint32, gltype uint32, id uint32, severity uint32, length int32, message string, userParam unsafe.Pointer) { // Source strSource := "unknown" switch source { case gl.DEBUG_SOURCE_API: strSource = "api" case gl.DEBUG_SOURCE_WINDOW_SYSTEM: strSource = "windowSystem" case gl.DEBUG_SOURCE_SHADER_COMPILER: strSource = "shaderCompiler" case gl.DEBUG_SOURCE_THIRD_PARTY: strSource = "thirdParty" case gl.DEBUG_SOURCE_APPLICATION: strSource = "application" case gl.DEBUG_SOURCE_OTHER: strSource = "other" } // Type strType := "unknown" switch gltype { case gl.DEBUG_TYPE_ERROR: strType = "error" case gl.DEBUG_TYPE_DEPRECATED_BEHAVIOR: strType = "deprecatedBehavior" case gl.DEBUG_TYPE_UNDEFINED_BEHAVIOR: strType = "undefinedBehavior" case gl.DEBUG_TYPE_PORTABILITY: strType = "portability" case gl.DEBUG_TYPE_PERFORMANCE: strType = "performance" case gl.DEBUG_TYPE_MARKER: strType = "marker" case gl.DEBUG_TYPE_PUSH_GROUP: strType = "pushGroup" case gl.DEBUG_TYPE_POP_GROUP: strType = "popGroup" case gl.DEBUG_TYPE_OTHER: strType = "other" } // Severity strSeverity := "unknown" switch severity { case gl.DEBUG_SEVERITY_HIGH: strSeverity = "high" case gl.DEBUG_SEVERITY_MEDIUM: strSeverity = "medium" case gl.DEBUG_SEVERITY_LOW: strSeverity = "low" case gl.DEBUG_SEVERITY_NOTIFICATION: return } console.Text("[%s][%s][%s]: %s", strSource, strType, strSeverity, message) }, nil) }
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) } }