Noah Petherbridge
626fd53a84
Link a Doodad to a Checkpoint Flag (like you would a Start Flag) and crossing the flag will replace the player with that doodad. Multiple checkpoint flags like this can toggle you between characters. * Azulians are now friendly to player characters who have the word "Azulian" in their title. * Improve Bird as the playable character: * Dive animation if the player flies diagonally downwards * Animation loop while hovering in the air instead of pausing * Checkpoint flags don't spam each other on PubSub so much which could sometimes lead to deadlocks! SetPlayerCharacter added to the JavaScript API. The Checkpoint Flag (not the region) can link to a doodad and replace the player character with that linked doodad when you activate the checkpoint: Actors.SetPlayerCharacter(filename string): like "boy.doodad" Add various panic catchers to make JavaScript safer and log issues to console.
98 lines
2.3 KiB
Go
98 lines
2.3 KiB
Go
package scripting
|
|
|
|
import (
|
|
"git.kirsle.net/apps/doodle/pkg/log"
|
|
"github.com/dop251/goja"
|
|
)
|
|
|
|
// Message holds data being published from one script VM with information sent
|
|
// to the linked VMs.
|
|
type Message struct {
|
|
Name string
|
|
SenderID string
|
|
Args []goja.Value
|
|
}
|
|
|
|
/*
|
|
RegisterPublishHooks adds the pub/sub hooks to a JavaScript VM.
|
|
|
|
This adds the global methods `Message.Subscribe(name, func)` and
|
|
`Message.Publish(name, args)` to the JavaScript VM's scope.
|
|
*/
|
|
func RegisterPublishHooks(s *Supervisor, vm *VM) {
|
|
// Goroutine to watch the VM's inbound channel and invoke Subscribe handlers
|
|
// for any matching messages received.
|
|
go func() {
|
|
// Catch any exceptions raised by the JavaScript VM.
|
|
defer func() {
|
|
if err := recover(); err != nil {
|
|
// TODO EXCEPTIONS
|
|
log.Error("RegisterPublishHooks(%s): %s", vm.Name, err)
|
|
}
|
|
}()
|
|
|
|
for msg := range vm.Inbound {
|
|
vm.muSubscribe.Lock()
|
|
|
|
if _, ok := vm.subscribe[msg.Name]; ok {
|
|
for _, callback := range vm.subscribe[msg.Name] {
|
|
log.Debug("PubSub: %s receives from %s: %s", vm.Name, msg.SenderID, msg.Name)
|
|
if function, ok := goja.AssertFunction(callback); ok {
|
|
function(goja.Undefined(), msg.Args...)
|
|
}
|
|
}
|
|
}
|
|
|
|
vm.muSubscribe.Unlock()
|
|
}
|
|
}()
|
|
|
|
// Register the Message.Subscribe and Message.Publish functions.
|
|
vm.vm.Set("Message", map[string]interface{}{
|
|
"Subscribe": func(name string, callback goja.Value) {
|
|
vm.muSubscribe.Lock()
|
|
defer vm.muSubscribe.Unlock()
|
|
|
|
if _, ok := goja.AssertFunction(callback); !ok {
|
|
log.Error("SUBSCRIBE(%s): callback is not a function", name)
|
|
return
|
|
}
|
|
if _, ok := vm.subscribe[name]; !ok {
|
|
vm.subscribe[name] = []goja.Value{}
|
|
}
|
|
|
|
vm.subscribe[name] = append(vm.subscribe[name], callback)
|
|
},
|
|
|
|
"Publish": func(name string, v ...goja.Value) {
|
|
for _, channel := range vm.Outbound {
|
|
channel <- Message{
|
|
Name: name,
|
|
SenderID: vm.Name,
|
|
Args: v,
|
|
}
|
|
}
|
|
},
|
|
|
|
"Broadcast": func(name string, v ...goja.Value) {
|
|
// Send the message to all actor VMs.
|
|
for _, toVM := range s.scripts {
|
|
if toVM == nil {
|
|
continue
|
|
}
|
|
|
|
if vm.Name == toVM.Name {
|
|
log.Debug("Broadcast(%s): skip to vm '%s' cuz it is the sender", name, toVM.Name)
|
|
continue
|
|
}
|
|
|
|
toVM.Inbound <- Message{
|
|
Name: name,
|
|
SenderID: vm.Name,
|
|
Args: v,
|
|
}
|
|
}
|
|
},
|
|
})
|
|
}
|