func (p *PlayerFrontend) Mainloop() {
	nextUpdate := time.After(10 * time.Microsecond)
loop:
	for {
		select {
		case ev := <-p.eventCh:
			p.processEvent(ev)
		case <-nextUpdate:
			nextUpdate = time.After(time.Second / 60)
			p.processInput()
			if err := p.window.Update(p.getDraw()); err != nil {
				log.Fatalln(err)
			}
		case _, ok := <-p.close:
			if !ok {
				break loop
			}
		}
	}
	events.RemoveListener(p.eventCh, events.DirFront, 0)
	for _, v := range p.units {
		v.Destroy()
	}
	leaveEvent := &events.PlayerLeave{
		UUID: p.id,
	}
	events.SendEvent(leaveEvent)
}
func (u *Unit) mainloop() {
loop:
	for {
		select {
		case ev := <-u.eventCh:
			u.processEvent(ev)
		case u.drawCh <- u.getDraw():
		case _, ok := <-u.close:
			if !ok {
				break loop
			}
		}
	}
	events.RemoveListener(u.eventCh, events.DirFront, u.id)
}
func (n *Network) mainloop() {
loop:
	for {
		select {
		case ev := <-n.eventCh:
			n.handleEvent(ev)
		case _, ok := <-n.close:
			if !ok {
				break loop
			}
		}
	}
	events.RemoveListener(n.eventCh, n.dir, 0)
	n.conn.Close()
	n.afterDestroy()
}
func (u *unit) unitloop() {
	eta := time.After(frameDelta)
loop:
	for {
		select {
		case ev := <-u.eventCh:
			u.processEvent(ev)
		case <-eta:
			eta = time.After(frameDelta)
			u.updateUnit()
		case _, ok := <-u.close:
			if !ok {
				break loop
			}
		}
	}
	events.RemoveListener(u.eventCh, events.DirSystem, u.unitID)
}