<commit_before>package main

import (
	"container/list"
	"flag"
	"log"
	"math/rand"
	"sort"
	"time"

	"github.com/afg984/thegame/server/go/src/thegame/pb"
)

var ticksPerSecond int

func init() {
	flag.IntVar(&ticksPerSecond, "tps", 30, "ticks per second")
}

type HeroControls struct {
	*Hero
	*pb.Controls
}

type joinRequest struct {
	name string
	ch   chan *list.Element
}

type Arena struct {
	polygons       [360]*Polygon
	heroCounter    int
	bulletCounter  int
	polygonCounter int
	heroes         *list.List
	bullets        []*Bullet
	controlChan    chan HeroControls
	joinChan       chan joinRequest
	quitChan       chan *list.Element
	commandChan    chan GameCommand
	viewRemotes    []chan *pb.GameState
	viewChan       chan chan *pb.GameState
}

func NewArena() *Arena {
	a := &Arena{
		heroes:      list.New(),
		controlChan: make(chan HeroControls),
		joinChan:    make(chan joinRequest),
		quitChan:    make(chan *list.Element),
		commandChan: make(chan GameCommand),
		viewChan:    make(chan chan *pb.GameState),
	}
	for i := 0; i < 30; i++ {
		a.polygons[i] = &Polygon{shape: Pentagon}
	}
	for i := 30; i < 90; i++ {
		a.polygons[i] = &Polygon{shape: Triangle}
	}
	for i := 90; i < 360; i++ {
		a.polygons[i] = &Polygon{shape: Square}
	}
	go a.Run()
	return a
}

func (a *Arena) Join(name string) *list.Element {
	c := make(chan *list.Element)
	a.joinChan <- joinRequest{name, c}
	return <-c
}

func (a *Arena) Quit(e *list.Element) {
	a.quitChan <- e
}

// gc cleans up unused objects
func (a *Arena) gc() {
	// remove disconnected and dead heroes
	var next *list.Element
	for e := a.heroes.Front(); e != nil; e = next {
		next = e.Next()

		h := e.Value.(*Hero)
		if h.health <= 0 && h.disconnected {
			a.heroes.Remove(e)
		}
	}
}

func (a *Arena) tick() {
	a.gc()

	var objects []Collidable
	for _, p := range a.polygons {
		TickPosition(p)
		if p.visible {
			objects = append(objects, p)
		}
	}
	for e := a.heroes.Front(); e != nil; e = e.Next() {
		h := e.Value.(*Hero)
		if !h.visible {
			h.TryRespawn()
		}
		if h.visible {
			TickPosition(h)
			objects = append(objects, h)
		}
	}
	for _, b := range a.bullets {
		TickPosition(b)
		if b.visible {
			objects = append(objects, b)
		}
	}

	DoCollision(objects)

	for _, b := range a.bullets {
		b.timeout--
	}
	a.bullets = filterBullets(a.bullets)

	for e := a.heroes.Front(); e != nil; e = e.Next() {
		h := e.Value.(*Hero)
		if h.visible {<commit_msg>server/go: fix: disconnected heroes should not be able to Action()<commit_after>package main

import (
	"container/list"
	"flag"
	"log"
	"math/rand"
	"sort"
	"time"

	"github.com/afg984/thegame/server/go/src/thegame/pb"
)

var ticksPerSecond int

func init() {
	flag.IntVar(&ticksPerSecond, "tps", 30, "ticks per second")
}

type HeroControls struct {
	*Hero
	*pb.Controls
}

type joinRequest struct {
	name string
	ch   chan *list.Element
}

type Arena struct {
	polygons       [360]*Polygon
	heroCounter    int
	bulletCounter  int
	polygonCounter int
	heroes         *list.List
	bullets        []*Bullet
	controlChan    chan HeroControls
	joinChan       chan joinRequest
	quitChan       chan *list.Element
	commandChan    chan GameCommand
	viewRemotes    []chan *pb.GameState
	viewChan       chan chan *pb.GameState
}

func NewArena() *Arena {
	a := &Arena{
		heroes:      list.New(),
		controlChan: make(chan HeroControls),
		joinChan:    make(chan joinRequest),
		quitChan:    make(chan *list.Element),
		commandChan: make(chan GameCommand),
		viewChan:    make(chan chan *pb.GameState),
	}
	for i := 0; i < 30; i++ {
		a.polygons[i] = &Polygon{shape: Pentagon}
	}
	for i := 30; i < 90; i++ {
		a.polygons[i] = &Polygon{shape: Triangle}
	}
	for i := 90; i < 360; i++ {
		a.polygons[i] = &Polygon{shape: Square}
	}
	go a.Run()
	return a
}

func (a *Arena) Join(name string) *list.Element {
	c := make(chan *list.Element)
	a.joinChan <- joinRequest{name, c}
	return <-c
}

func (a *Arena) Quit(e *list.Element) {
	a.quitChan <- e
}

// gc cleans up unused objects
func (a *Arena) gc() {
	// remove disconnected and dead heroes
	var next *list.Element
	for e := a.heroes.Front(); e != nil; e = next {
		next = e.Next()

		h := e.Value.(*Hero)
		if h.health <= 0 && h.disconnected {
			a.heroes.Remove(e)
		}
	}
}

func (a *Arena) tick() {
	a.gc()

	var objects []Collidable
	for _, p := range a.polygons {
		TickPosition(p)
		if p.visible {
			objects = append(objects, p)
		}
	}
	for e := a.heroes.Front(); e != nil; e = e.Next() {
		h := e.Value.(*Hero)
		if !h.visible {
			h.TryRespawn()
		}
		if h.visible {
			TickPosition(h)
			objects = append(objects, h)
		}
	}
	for _, b := range a.bullets {
		TickPosition(b)
		if b.visible {
			objects = append(objects, b)
		}
	}

	DoCollision(objects)

	for _, b := range a.bullets {
		b.timeout--
	}
	a.bullets = filterBullets(a.bullets)

	for e := a.heroes.Front(); e != nil; e = e.Next() {
		h := e.Value.(*Hero)
		if h.visible && !h.disconnected {
{'fraction_non_alphanumeric': 0.15123832724319936, 'fraction_numerical': 0.008526187576126675, 'mean_word_length': 2.986245954692557, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2951084', 'n_tokens_mistral': 2132, 'n_tokens_neox': 1944, 'n_words': 492}