// AddPlayers adds numPlayers to the specified side. In standard game mode side // should be zero, otherwise it should be between 0 and number of side - 1, // inclusive. func (g *Game) AddPlayers(engineIds []int64, side int) []Gid { switch { case g.Standard != nil: if side != 0 { base.Error().Fatalf("AddPlayers expects side == 0 for Standard game mode.") } case g.Moba != nil: if side < 0 || side >= len(g.Levels[GidInvadersStart].Room.Starts) { base.Error().Fatalf("Got side %d, but this level only supports sides from 0 to %d.", len(g.Levels[GidInvadersStart].Room.Starts)-1) } default: base.Error().Fatalf("Cannot add players without first specifying a game mode.") } var gids []Gid for i, engineId := range engineIds { var p PlayerEnt p.StatsInst = stats.Make(stats.Base{ Health: 1000, Mass: 750, Acc: 1000.0, Turn: 0.07, Rate: 0.5, Size: 12, Vision: 600, }) p.CurrentLevel = GidInvadersStart // Evenly space the players on a circle around the starting position. rot := (linear.Vec2{25, 0}).Rotate(float64(i) * 2 * 3.1415926535 / float64(len(engineIds))) p.Position = g.Levels[GidInvadersStart].Room.Starts[side].Add(rot) // NEXT: REthing Gids and how the levels are laid out - should they just // be indexed by gids? p.Side_ = side p.Gid = Gid(fmt.Sprintf("Engine:%d", engineId)) p.Processes = make(map[int]Process) p.SetLevel(GidInvadersStart) g.AddEnt(&p) gids = append(gids, p.Gid) } return gids }
func (ms *ManaSource) Init(options *ManaSourceOptions) { ms.options = *options if options.NumNodeCols < 2 || options.NumNodeRows < 2 { base.Error().Fatalf(fmt.Sprintf("Invalid options: %v", options)) } r := rand.New(options.Rng) seeds := make([]nodeSeed, options.NumSeeds) for i := range seeds { seed := &seeds[i] seed.x = options.BoardLeft + r.Float64()*(options.BoardRight-options.BoardLeft) seed.y = options.BoardTop + r.Float64()*(options.BoardBottom-options.BoardTop) seed.color = r.Intn(3) } ms.rawNodes = newNodes(options.NumNodeCols * options.NumNodeRows) // ms.rawNodes = make([]node, options.NumNodeCols*options.NumNodeRows) ms.nodes = make([][]node, options.NumNodeCols) for col := 0; col < options.NumNodeCols; col++ { ms.nodes[col] = ms.rawNodes[col*options.NumNodeRows : (col+1)*options.NumNodeRows] for row := 0; row < options.NumNodeRows; row++ { x := options.BoardLeft + float64(col)/float64(options.NumNodeCols-1)*(options.BoardRight-options.BoardLeft) y := options.BoardTop + float64(row)/float64(options.NumNodeRows-1)*(options.BoardBottom-options.BoardTop) maxWeightByColor := [3]float64{0.0, 0.0, 0.0} for _, seed := range seeds { c := seed.color dx := x - seed.x dy := y - seed.y distSquared := dx*dx + dy*dy weight := 1 / (distSquared + 1.0) if weight > maxWeightByColor[c] { maxWeightByColor[c] = weight } } normalizeWeights(options.NodeMagnitude, maxWeightByColor[:]) var weightsCopy [3]float64 copy(weightsCopy[:], maxWeightByColor[:]) ms.nodes[col][row] = node{ X: x, Y: y, RegenPerFrame: options.RegenPerFrame, Mana: maxWeightByColor, MaxMana: weightsCopy, } } } }
func (ms *ManaSource) regenerateMana() { for i := range ms.rawNodes { node := &ms.rawNodes[i] for c := range node.Mana { if node.MaxMana[c] == 0 { continue } maxRecovery := node.MaxMana[c] * node.RegenPerFrame scale := (node.MaxMana[c] - node.Mana[c]) / node.MaxMana[c] node.Mana[c] += scale * maxRecovery if scale != scale || maxRecovery != maxRecovery { base.Error().Fatalf("NaN showed up somewhere!") } } } }
func setupSound() { soundInit.Do(func() { var err error // fmodSys, err = fmod.CreateSystem() if err != nil { // base.Error().Fatalf("Unable to initialize fmod: %v", err) } // err = fmodSys.Init(2, 0, nil) if err != nil { // base.Error().Fatalf("Unable to initialize fmod: %v", err) } target := filepath.Join(base.GetDataDir(), "sound/ping.wav") base.Log().Printf("Trying to load ", target) // sound, err = fmodSys.CreateSound_FromFilename(target, fmod.MODE_DEFAULT) if err != nil { base.Error().Fatalf("Unable to load sound: %v", err) } }) }
func newLocalDataHelper(engine *cgf.Engine, sys system.System, mode LocalMode) *LocalData { var local LocalData if local.engine != nil { base.Error().Fatalf("Engine has already been set.") } local.engine = engine local.mode = mode local.setup = &localSetupData{} if mode == LocalModeArchitect { // local.architect.abs.abilities = // append( // local.architect.abs.abilities, // ability_makers["placePoly"](map[string]int{"wall": 1})) // local.architect.abs.abilities = // append( // local.architect.abs.abilities, // ability_makers["placePoly"](map[string]int{"pests": 1})) // local.architect.abs.abilities = append(local.architect.abs.abilities, ability_makers["removePoly"](nil)) } local.sys = sys gin.In().RegisterEventListener(&gameResponderWrapper{&local}) return &local }
func main() { defer base.StackCatcher() fmt.Printf("sys.Startup()...") sys.Startup() fmt.Printf("successful.\n") fmt.Printf("gl.Init()...") err := gl.Init() fmt.Printf("successful.\n") if err != nil { base.Error().Fatalf("%v", err) } fmt.Printf("render.Init()...") render.Init() fmt.Printf("successful.\n") render.Queue(func() { fmt.Printf("sys.CreateWindow()...") sys.CreateWindow(10, 10, wdx, wdy) fmt.Printf("successful.\n") sys.EnableVSync(true) }) base.InitShaders() runtime.GOMAXPROCS(10) fmt.Printf("sys.Think()...") sys.Think() fmt.Printf("successful.\n") base.LoadAllDictionaries() if Version() != "standard" { engine, local := debugHookup(Version()) mainLoop(engine, local, "standard") } else { standardHookup() } }
func main() { fmt.Printf("%v\n", key_map) sys.Startup() err := gl.Init() if err != nil { panic(err) } render.Init() render.Queue(func() { sys.CreateWindow(10, 10, wdx, wdy) sys.EnableVSync(true) err := gl.Init() if err != nil { panic(err) } }) base.InitShaders() runtime.GOMAXPROCS(2) ui, err = gui.Make(gin.In(), gui.Dims{wdx, wdy}, filepath.Join(datadir, "fonts", "skia.ttf")) if err != nil { panic(err) } sys.Think() for false && len(sys.GetActiveDevices()[gin.DeviceTypeController]) < 2 { time.Sleep(time.Millisecond * 100) sys.Think() } var ids []int var engine *cgf.Engine var room game.Room err = base.LoadJson(filepath.Join(base.GetDataDir(), "rooms/basic.json"), &room) if err != nil { panic(err) } if IsHost() { sys.Think() var g game.Game g.Rng = cmwc.MakeGoodCmwc() g.Rng.SeedWithDevRand() g.Dx = 900 g.Dy = 600 g.Friction = 0.97 g.Friction_lava = 0.85 g.Room = room var p game.Player p.Color.R = 255 err := json.NewDecoder(bytes.NewBuffer([]byte(` { "Base": { "Max_turn": 0.07, "Max_acc": 0.2, "Mass": 750, "Max_rate": 10, "Influence": 75, "Health": 1000 }, "Dynamic": { "Health": 1000 } } `))).Decode(&p.Stats) if err != nil { panic(err) } Nx := 2 Ny := 1 p.X = float64(g.Dx-Nx)/2 - 200 p.Y = float64(g.Dy-Ny)/2 - 200 for x := 0; x < Nx; x++ { for y := 0; y < Ny; y++ { p.X += float64(x * 25) p.Y += float64(y * 25) p.Gid++ // p.Mass += float64(x+y) * 150 p.Processes = make(map[int]game.Process) temp := p ids = append(ids, g.AddEnt(&temp)) // p.Mass -= float64(x+y) * 150 p.X -= float64(x * 25) p.Y -= float64(y * 25) } } g.Ents[0].(*game.Player).X = 500 g.Ents[0].(*game.Player).Y = 300 g.Ents[1].(*game.Player).X = 550 g.Ents[1].(*game.Player).Y = 300 g.SetLocalData() d := sys.GetActiveDevices() base.Log().Printf("%v\n", d) n := 0 base.Log().Printf("%v\n", d[gin.DeviceTypeController]) for _, index := range d[gin.DeviceTypeController] { // panic("ASD") g.SetLocalPlayer(g.Ents[n].(*game.Player), index) n++ if n > 2 { break } } if len(d[gin.DeviceTypeController]) == 0 { g.SetLocalPlayer(g.Ents[0].(*game.Player), 0) } // g.Ents[0], g.Ents[(N*N)/2+(1-N%2)*N/2] = g.Ents[(N*N)/2+(1-N%2)*N/2], g.Ents[0] g.Init() // engine, err = cgf.NewLocalEngine(&g, 17, base.Log()) engine, err = cgf.NewHostEngine(&g, 17, "", 1231, base.Log()) if err != nil { panic(err.Error()) } g.SetEngine(engine) } else { engine, err = cgf.NewClientEngine(17, "", 1231, base.Log()) if err != nil { panic(err.Error()) } engine.CopyState().(*game.Game).SetEngine(engine) } anchor := gui.MakeAnchorBox(gui.Dims{wdx, wdy}) ui.AddChild(anchor) anchor.AddChild(&game.GameWindow{Engine: engine}, gui.Anchor{0.5, 0.5, 0.5, 0.5}) var v float64 var profile_output *os.File var num_mem_profiles int // ui.AddChild(base.MakeConsole()) base.LoadAllDictionaries() for gin.In().GetKey(gin.AnyEscape).FramePressCount() == 0 { sys.Think() render.Queue(func() { ui.Draw() }) render.Queue(func() { sys.SwapBuffers() }) render.Purge() game.LocalThink() if IsHost() { for i := 0; i <= 0; i++ { // down_axis := gin.In().GetKeyFlat(gin.ControllerAxis0Positive+1, gin.DeviceTypeController, gin.DeviceIndexAny) // up_axis := gin.In().GetKeyFlat(gin.ControllerAxis0Negative+1, gin.DeviceTypeController, gin.DeviceIndexAny) // right_axis := gin.In().GetKeyFlat(gin.ControllerAxis0Positive, gin.DeviceTypeController, gin.DeviceIndexAny) // left_axis := gin.In().GetKeyFlat(gin.ControllerAxis0Negative, gin.DeviceTypeController, gin.DeviceIndexAny) // up := key_map[fmt.Sprintf("%dup", i)].FramePressAvg() // down := key_map[fmt.Sprintf("%ddown", i)].FramePressAvg() // left := key_map[fmt.Sprintf("%dleft", i)].FramePressAvg() // right := key_map[fmt.Sprintf("%dright", i)].FramePressAvg() // up = axisControl(up_axis.FramePressAmt()) // down = axisControl(down_axis.FramePressAmt()) // left = axisControl(left_axis.FramePressAmt()) // right = axisControl(right_axis.FramePressAmt()) // if up-down != 0 { // engine.ApplyEvent(game.Accelerate{ids[i], 2 * (up - down)}) // } // if left-right != 0 { // engine.ApplyEvent(game.Turn{ids[i], (left - right)}) // } // if key_map[fmt.Sprintf("%d-1", i)].FramePressCount() > 0 { // engine.ApplyEvent(game.Pull{ids[i], 0, 20000}) // } // if key_map[fmt.Sprintf("%d-2", i)].FramePressCount() > 0 { // engine.ApplyEvent(game.MoonFire{ids[i], 1, 50, 50}) // } // if gin.In().GetKeyFlat(gin.ControllerButton0, gin.DeviceTypeController, gin.DeviceTypeAny).FramePressCount() > 0 { // if key_map[fmt.Sprintf("%d-3", i)].FramePressCount() > 0 { // engine.ApplyEvent(game.Burst{ids[i], 2, 3, 100000}) // } } } // TODO: Replace the 'P' key with an appropriate keybind if gin.In().GetKey(gin.AnyKeyP).FramePressCount() > 0 { if profile_output == nil { profile_output, err = os.Create(filepath.Join(datadir, "cpu.prof")) if err == nil { err = pprof.StartCPUProfile(profile_output) if err != nil { fmt.Printf("Unable to start CPU profile: %v\n", err) profile_output.Close() profile_output = nil } fmt.Printf("profout: %v\n", profile_output) } else { fmt.Printf("Unable to start CPU profile: %v\n", err) } } else { pprof.StopCPUProfile() profile_output.Close() profile_output = nil } } // TODO: Replace the 'M' key with an appropriate keybind if gin.In().GetKey(gin.AnyKeyM).FramePressCount() > 0 { f, err := os.Create(filepath.Join(datadir, fmt.Sprintf("mem.%d.prof", num_mem_profiles))) if err != nil { base.Error().Printf("Unable to write mem profile: %v", err) } pprof.WriteHeapProfile(f) f.Close() num_mem_profiles++ } v += 0.01 } }
func (g *Game) Think() { g.GameThinks++ if g.Setup != nil { return } defer base.StackCatcher() // cache wall data if g.temp.AllWalls == nil || g.temp.AllWallsDirty { g.temp.AllWalls = make(map[Gid][]linear.Seg2) g.temp.WallCache = make(map[Gid]*wallCache) g.temp.VisibleWallCache = make(map[Gid]*wallCache) for gid := range g.Levels { var allWalls []linear.Seg2 base.DoOrdered(g.Levels[gid].Room.Walls, func(a, b string) bool { return a < b }, func(_ string, walls linear.Poly) { for i := range walls { allWalls = append(allWalls, walls.Seg(i)) } }) // g.DoForEnts(func(entGid Gid, ent Ent) { // if ent.Level() == gid { // for _, walls := range ent.Walls() { // for i := range walls { // allWalls = append(allWalls, walls.Seg(i)) // } // } // } // }) g.temp.AllWalls[gid] = allWalls g.temp.WallCache[gid] = &wallCache{} g.temp.WallCache[gid].SetWalls(g.Levels[gid].Room.Dx, g.Levels[gid].Room.Dy, allWalls, 100) g.temp.VisibleWallCache[gid] = &wallCache{} g.temp.VisibleWallCache[gid].SetWalls(g.Levels[gid].Room.Dx, g.Levels[gid].Room.Dy, allWalls, stats.LosPlayerHorizon) base.Log().Printf("WallCache: %v", g.temp.WallCache) } g.Moba.losCache.SetWallCache(g.temp.VisibleWallCache[GidInvadersStart]) } // cache ent data for _, ent := range g.temp.AllEnts { if ent.Dead() { if _, ok := ent.(*PlayerEnt); ok { var id int64 _, err := fmt.Sscanf(string(ent.Id()), "Engine:%d", &id) if err != nil { base.Error().Printf("Unable to parse player id '%v'", ent.Id()) } else { if engineData, ok := g.Engines[id]; ok { if !ok { base.Error().Printf("Unable to find engine %d for player %v", id, ent.Id()) } else { engineData.CountdownFrames = 60 * 10 } } } } ent.OnDeath(g) g.RemoveEnt(ent.Id()) } } // Death countdown for engineId, engineData := range g.Engines { if engineData.CountdownFrames > 0 { engineData.CountdownFrames-- if engineData.CountdownFrames == 0 { // TODO: It's a bit janky to do it like this, right? g.AddPlayers([]int64{engineId}, engineData.Side) } } } if g.temp.AllEnts == nil || g.temp.AllEntsDirty { g.temp.AllEnts = g.temp.AllEnts[0:0] g.DoForEnts(func(gid Gid, ent Ent) { g.temp.AllEnts = append(g.temp.AllEnts, ent) }) g.temp.AllEntsDirty = false } for _, proc := range g.Processes { proc.Think(g) } algorithm.Choose(&g.Processes, func(proc Process) bool { return proc.Phase() != PhaseComplete }) // Advance players, check for collisions, add segments for _, ent := range g.temp.AllEnts { ent.Think(g) pos := ent.Pos() eps := 1.0e-3 pos.X = clamp(pos.X, eps, float64(g.Levels[ent.Level()].Room.Dx)-eps) pos.Y = clamp(pos.Y, eps, float64(g.Levels[ent.Level()].Room.Dy)-eps) ent.SetPos(pos) } for i := 0; i < len(g.temp.AllEnts); i++ { for j := i + 1; j < len(g.temp.AllEnts); j++ { outerEnt := g.temp.AllEnts[i] innerEnt := g.temp.AllEnts[j] distSq := outerEnt.Pos().Sub(innerEnt.Pos()).Mag2() colDist := outerEnt.Stats().Size() + innerEnt.Stats().Size() if distSq > colDist*colDist { continue } if distSq < 0.0001 { continue } if distSq <= 0.25 { distSq = 0.25 } dist := math.Sqrt(distSq) force := 50.0 * (colDist - dist) outerEnt.ApplyForce(outerEnt.Pos().Sub(innerEnt.Pos()).Scale(force / dist)) innerEnt.ApplyForce(innerEnt.Pos().Sub(outerEnt.Pos()).Scale(force / dist)) } } switch { case g.Moba != nil: g.ThinkMoba() case g.Standard != nil: panic("Thinkgs aren't implemented, like thinking on mana sources") // Do standard thinking default: panic("Game mode not set") } }
func (u SetupComplete) Apply(_g interface{}) { g := _g.(*Game) if g.Setup == nil { return } g.Engines = make(map[int64]*PlayerData) for _, id := range g.Setup.EngineIds { g.Engines[id] = &PlayerData{ PlayerGid: Gid(fmt.Sprintf("Engine:%d", id)), Side: g.Setup.Sides[id].Side, } } // Add a single Ai player to side 0 g.Engines[123123] = &PlayerData{ PlayerGid: Gid(fmt.Sprintf("Engine:%d", 123123)), Side: 0, Ai: &AiPlayerData{}, } g.Setup.Sides[123123] = &SetupSideData{ Champ: 0, Side: 0, } var room Room dx, dy := 1024, 1024 generated := generator.GenerateRoom(float64(dx), float64(dy), 100, 64, u.Seed) data, err := json.Marshal(generated) if err != nil { base.Error().Fatalf("%v", err) } err = json.Unmarshal(data, &room) // err = base.LoadJson(filepath.Join(base.GetDataDir(), "rooms/basic.json"), &room) if err != nil { base.Error().Fatalf("%v", err) } g.Levels = make(map[Gid]*Level) g.Levels[GidInvadersStart] = &Level{} g.Levels[GidInvadersStart].Room = room g.Rng = cmwc.MakeGoodCmwc() g.Rng.Seed(12313131) g.Ents = make(map[Gid]Ent) g.Friction = 0.97 // g.Standard = &GameModeStandard{} g.Moba = &GameModeMoba{ Sides: make(map[int]*GameModeMobaSideData), } sides := make(map[int][]int64) for id, data := range g.Engines { sides[data.Side] = append(sides[data.Side], id) } for _, players := range sides { var ids []int64 for _, id := range players { ids = append(ids, id) } side := g.Setup.Sides[ids[0]].Side gids := g.AddPlayers(ids, side) g.Moba.Sides[side] = &GameModeMobaSideData{} for i := range ids { player := g.Ents[gids[i]].(*PlayerEnt) player.Champ = g.Setup.Sides[ids[i]].Champ } } g.Moba.losCache = makeLosCache(dx, dy) g.MakeControlPoints() g.Init() base.Log().Printf("Nillifying g.Setup()") g.Setup = nil }
func debugHookup(version string) (*cgf.Engine, *game.LocalData) { // if version != "standard" && version != "moba" && version != "host" && version != "client" { // base.Log().Fatalf("Unable to handle Version() == '%s'", Version()) // } for false && len(sys.GetActiveDevices()[gin.DeviceTypeController]) < 2 { time.Sleep(time.Millisecond * 100) sys.Think() } var engine *cgf.Engine var room game.Room generated := generator.GenerateRoom(1024, 1024, 100, 64, 64522029961391019) data, err := json.Marshal(generated) if err != nil { base.Error().Fatalf("%v", err) } err = json.Unmarshal(data, &room) // err = base.LoadJson(filepath.Join(base.GetDataDir(), "rooms/basic.json"), &room) if err != nil { base.Error().Fatalf("%v", err) } var players []game.Gid var localData *game.LocalData var g *game.Game if version != "host" { res, err := cgf.SearchLANForHosts(20007, 20002, 500) if err != nil || len(res) == 0 { base.Log().Printf("Unable to connect: %v", err) base.Error().Fatalf("%v", err.Error()) } engine, err = cgf.NewClientEngine(17, res[0].Ip, 20007, base.EmailCrashReport, base.Log()) if err != nil { base.Log().Printf("Unable to connect: %v", err) base.Error().Fatalf("%v", err.Error()) } localData = game.NewLocalDataArchitect(engine, sys) g = engine.GetState().(*game.Game) for _, ent := range g.Ents { if _, ok := ent.(*game.PlayerEnt); ok { players = append(players, ent.Id()) } } } else { sys.Think() g = game.MakeGame() if version == "host" { engine, err = cgf.NewHostEngine(g, 17, "", 20007, base.EmailCrashReport, base.Log()) if err != nil { panic(err) } err = cgf.Host(20007, "thunderball") if err != nil { panic(err) } } else { engine, err = cgf.NewLocalEngine(g, 17, base.EmailCrashReport, base.Log()) } if err != nil { base.Error().Fatalf("%v", err.Error()) } } localData = game.NewLocalDataMoba(engine, gin.DeviceIndexAny, sys) // localData = game.NewLocalDataInvaders(engine, sys) // Hook the players up regardless of in we're architect or not, since we can // switch between the two in debug mode. // d := sys.GetActiveDevices() // n := 0 // for _, index := range d[gin.DeviceTypeController] { // localData.SetLocalPlayer(g.Ents[players[n]], index) // n++ // if n > len(players) { // break // } // } // if len(d[gin.DeviceTypeController]) == 0 { // localData.SetLocalPlayer(g.Ents[players[0]], 0) // } base.Log().Printf("Engine Id: %v", engine.Id()) base.Log().Printf("All Ids: %v", engine.Ids()) return engine, localData }
func mainLoop(engine *cgf.Engine, local *game.LocalData, mode string) { defer engine.Kill() var profile_output *os.File var contention_output *os.File var num_mem_profiles int // ui.AddChild(base.MakeConsole()) ticker := time.Tick(time.Millisecond * 17) ui := g2.Make(0, 0, wdx, wdy) ui.AddChild(&game.GameWindow{Engine: engine, Local: local, Dims: g2.Dims{wdx, wdy}}, g2.AnchorDeadCenter) ui.AddChild(g2.MakeConsole(wdx, wdy), g2.AnchorDeadCenter) side0Index := gin.In().BindDerivedKeyFamily("Side0", gin.In().MakeBindingFamily(gin.Key1, []gin.KeyIndex{gin.EitherControl}, []bool{true})) side1Index := gin.In().BindDerivedKeyFamily("Side1", gin.In().MakeBindingFamily(gin.Key2, []gin.KeyIndex{gin.EitherControl}, []bool{true})) side2Index := gin.In().BindDerivedKeyFamily("Side2", gin.In().MakeBindingFamily(gin.Key3, []gin.KeyIndex{gin.EitherControl}, []bool{true})) side0Key := gin.In().GetKeyFlat(side0Index, gin.DeviceTypeAny, gin.DeviceIndexAny) side1Key := gin.In().GetKeyFlat(side1Index, gin.DeviceTypeAny, gin.DeviceIndexAny) side2Key := gin.In().GetKeyFlat(side2Index, gin.DeviceTypeAny, gin.DeviceIndexAny) defer ui.StopEventListening() for { <-ticker if gin.In().GetKey(gin.AnyEscape).FramePressCount() != 0 { return } if mode == "moba" { if side0Key.FramePressCount() > 0 { local.DebugCyclePlayers() } // if side0Key.FramePressCount() > 0 { // local.DebugSetSide(0) // } // if side1Key.FramePressCount() > 0 { // local.DebugSetSide(1) // } } if mode == "standard" { if side0Key.FramePressCount() > 0 { local.DebugChangeMode(game.LocalModeInvaders) } if side1Key.FramePressCount() > 0 { local.DebugChangeMode(game.LocalModeArchitect) } if side2Key.FramePressCount() > 0 { local.DebugChangeMode(game.LocalModeEditor) } } sys.Think() render.Queue(func() { ui.Draw() }) render.Queue(func() { sys.SwapBuffers() }) render.Purge() // TODO: Replace the 'P' key with an appropriate keybind var err error if gin.In().GetKey(gin.AnyKeyP).FramePressCount() > 0 { if profile_output == nil { profile_output, err = os.Create(filepath.Join(datadir, "cpu.prof")) if err == nil { err = pprof.StartCPUProfile(profile_output) if err != nil { base.Log().Printf("Unable to start CPU profile: %v\n", err) profile_output.Close() profile_output = nil } base.Log().Printf("cpu prof: %v\n", profile_output) } else { base.Log().Printf("Unable to start CPU profile: %v\n", err) } } else { pprof.StopCPUProfile() profile_output.Close() profile_output = nil } } if gin.In().GetKey(gin.AnyKeyL).FramePressCount() > 0 { if contention_output == nil { contention_output, err = os.Create(filepath.Join(datadir, "contention.prof")) if err == nil { runtime.SetBlockProfileRate(1) base.Log().Printf("contention prof: %v\n", contention_output) } else { base.Log().Printf("Unable to start contention profile: %v\n", err) } } else { pprof.Lookup("block").WriteTo(contention_output, 0) contention_output.Close() contention_output = nil } } // TODO: Replace the 'M' key with an appropriate keybind if gin.In().GetKey(gin.AnyKeyM).FramePressCount() > 0 { f, err := os.Create(filepath.Join(datadir, fmt.Sprintf("mem.%d.prof", num_mem_profiles))) if err != nil { base.Error().Printf("Unable to write mem profile: %v", err) } pprof.WriteHeapProfile(f) f.Close() num_mem_profiles++ } } }