Add closed channel

This commit is contained in:
giongto35 2019-04-10 01:25:11 +08:00
parent cb604b3503
commit 7a169ac2a4
4 changed files with 66 additions and 40 deletions

34
main.go
View file

@ -44,10 +44,15 @@ type WSPacket struct {
PlayerIndex int `json:"player_index"`
}
// Room is a game session. multi webRTC sessions can connect to a same game.
// A room stores all the channel for interaction between all webRTCs session and emulator
type Room struct {
imageChannel chan *image.RGBA
inputChannel chan int
rtcSessions []*webrtc.WebRTC
// closedChannel is to fire exit event when there is no webRTC session running
closedChannel chan bool
rtcSessions []*webrtc.WebRTC
}
var rooms map[string]*Room
@ -66,8 +71,8 @@ func main() {
http.ListenAndServe(":8000", nil)
}
func startGame(path string, roomID string, imageChannel chan *image.RGBA, inputChannel chan int) {
ui.Run([]string{path}, roomID, imageChannel, inputChannel)
func startGame(path string, roomID string, imageChannel chan *image.RGBA, inputChannel chan int, closedChannel chan bool) {
ui.Run([]string{path}, roomID, imageChannel, inputChannel, closedChannel)
}
func getWeb(w http.ResponseWriter, r *http.Request) {
@ -78,18 +83,20 @@ func getWeb(w http.ResponseWriter, r *http.Request) {
w.Write(bs)
}
// init initilize room returns roomID
// init initilizes a room returns roomID
func initRoom(roomID, gameName string) string {
roomID = generateRoomID()
imageChannel := make(chan *image.RGBA, 100)
inputChannel := make(chan int, 100)
closedChannel := make(chan bool)
rooms[roomID] = &Room{
imageChannel: imageChannel,
inputChannel: inputChannel,
rtcSessions: []*webrtc.WebRTC{},
imageChannel: imageChannel,
inputChannel: inputChannel,
closedChannel: closedChannel,
rtcSessions: []*webrtc.WebRTC{},
}
go fanoutScreen(imageChannel, roomID)
go startGame("games/"+gameName, roomID, imageChannel, inputChannel)
go startGame("games/"+gameName, roomID, imageChannel, inputChannel, closedChannel)
return roomID
}
@ -208,6 +215,8 @@ func generateRoomID() string {
// fanoutScreen fanout outputs to all webrtc in the same room
func fanoutScreen(imageChannel chan *image.RGBA, roomID string) {
for image := range imageChannel {
isRoomRunning := false
yuv := util.RgbaToYuv(image)
for _, webRTC := range rooms[roomID].rtcSessions {
// Client stopped
@ -220,6 +229,11 @@ func fanoutScreen(imageChannel chan *image.RGBA, roomID string) {
if webRTC.IsConnected() {
webRTC.ImageChannel <- yuv
}
isRoomRunning = true
}
if isRoomRunning == false {
rooms[roomID].closedChannel <- true
}
}
}
@ -238,8 +252,8 @@ func faninInput(inputChannel chan int, webRTC *webrtc.WebRTC, playerIndex int) {
input := <-webRTC.InputChannel
// the first 10 bits belong to player 1
// the next 10 belongs to player 2 ...
// We standardize and put it to inputChannel (20 bytes)
input = input << ((uint(playerIndex) - 1) * ui.NumKeys / 2)
// We standardize and put it to inputChannel (20 bits)
input = input << ((uint(playerIndex) - 1) * ui.NumKeys)
inputChannel <- input
}
}

View file

@ -16,19 +16,20 @@ type View interface {
type Director struct {
// audio *Audio
view View
timestamp float64
imageChannel chan *image.RGBA
inputChannel chan int
roomID string
view View
timestamp float64
imageChannel chan *image.RGBA
inputChannel chan int
closedChannel chan bool
roomID string
}
func NewDirector(roomID string, imageChannel chan *image.RGBA, inputChannel chan int) *Director {
// func NewDirector(audio *Audio, imageChannel chan *image.RGBA, inputChannel chan int) *Director {
func NewDirector(roomID string, imageChannel chan *image.RGBA, inputChannel chan int, closedChannel chan bool) *Director {
director := Director{}
// director.audio = audio
director.imageChannel = imageChannel
director.inputChannel = inputChannel
director.closedChannel = closedChannel
director.roomID = roomID
return &director
}
@ -61,9 +62,17 @@ func (d *Director) Start(paths []string) {
}
func (d *Director) Run() {
L:
for {
// quit game
// TODO: Check if noone using
select {
// if there is event from close channel => the game is ended
case <-d.closedChannel:
log.Println("Closed game")
break L
default:
}
d.Step()
}
@ -71,6 +80,7 @@ func (d *Director) Run() {
}
func (d *Director) PlayGame(path string) {
// Generate hash that is indentifier of a room (game path + ropomID)
hash, err := hashFile(path, d.roomID)
if err != nil {
log.Fatalln(err)
@ -79,5 +89,6 @@ func (d *Director) PlayGame(path string) {
if err != nil {
log.Fatalln(err)
}
// Set GameView as current view
d.SetView(NewGameView(d, console, path, hash, d.imageChannel, d.inputChannel))
}

View file

@ -34,49 +34,57 @@ const (
save2
load2
)
const NumKeys = 20
const NumKeys = 10
type GameView struct {
director *Director
console *nes.Console
title string
hash string
record bool
frames []image.Image
// equivalent to the list key pressed const above
keyPressed [20]bool
keyPressed [NumKeys * 2]bool
imageChannel chan *image.RGBA
inputChannel chan int
}
func NewGameView(director *Director, console *nes.Console, title, hash string, imageChannel chan *image.RGBA, inputChannel chan int) View {
gameview := &GameView{director, console, title, hash, false, nil, [NumKeys]bool{false}, imageChannel, inputChannel}
gameview := &GameView{
director: director,
console: console,
title: title,
hash: hash,
keyPressed: [NumKeys * 2]bool{false},
imageChannel: imageChannel,
inputChannel: inputChannel,
}
go gameview.ListenToInputChannel()
return gameview
}
// ListenToInputChannel listen from input channel streamm, which is exposed to WebRTC session
func (view *GameView) ListenToInputChannel() {
for {
keysInBinary := <-view.inputChannel
for i := 0; i < NumKeys; i++ {
for i := 0; i < NumKeys*2; i++ {
view.keyPressed[i] = ((keysInBinary & 1) == 1)
keysInBinary = keysInBinary >> 1
}
}
}
// Enter enter the game view.
func (view *GameView) Enter() {
// Always reset game
// Legacy Audio code. TODO: Add it back to support audio
// view.console.SetAudioChannel(view.director.audio.channel)
// view.console.SetAudioSampleRate(view.director.audio.sampleRate)
// load state
//if err := view.console.LoadState(savePath(view.hash)); err == nil {
//return
//} else {
view.console.Reset()
//}
// load sram
cartridge := view.console.Cartridge
if cartridge.Battery != 0 {
@ -86,6 +94,7 @@ func (view *GameView) Enter() {
}
}
// Exit ...
func (view *GameView) Exit() {
// view.console.SetAudioChannel(nil)
// view.console.SetAudioSampleRate(0)
@ -94,29 +103,22 @@ func (view *GameView) Exit() {
if cartridge.Battery != 0 {
writeSRAM(sramPath(view.hash), cartridge.SRAM)
}
// save state
//view.console.SaveState(savePath(view.hash))
}
// Update is called for every period of time, dt is the elapsed time from the last frame
func (view *GameView) Update(t, dt float64) {
if dt > 1 {
dt = 0
}
console := view.console
//updateControllers(window, console)
view.updateControllers()
console.StepSeconds(dt)
// fps to set frame
view.imageChannel <- console.Buffer()
if view.record {
view.frames = append(view.frames, copyImage(console.Buffer()))
}
}
func (view *GameView) updateControllers() {
// TODO: switch case
// Divide keyPressed to player 1 and player 2
// First 10 keys are player 1
var player1Keys [8]bool

View file

@ -20,8 +20,8 @@ func init() {
runtime.LockOSThread()
}
func Run(paths []string, roomID string, imageChannel chan *image.RGBA, inputChannel chan int) {
// TODO: stream audio
func Run(paths []string, roomID string, imageChannel chan *image.RGBA, inputChannel chan int, closedChannel chan bool) {
// TODO: Add these code back when we support stream audio
// initialize audio
// portaudio.Initialize()
// defer portaudio.Terminate()
@ -33,7 +33,6 @@ func Run(paths []string, roomID string, imageChannel chan *image.RGBA, inputChan
// defer audio.Stop()
// run director
director := NewDirector(roomID, imageChannel, inputChannel)
// director := NewDirector(audio, imageChannel, inputChannel)
director := NewDirector(roomID, imageChannel, inputChannel, closedChannel)
director.Start(paths)
}