Noah Petherbridge
fc736abd5f
Adds several new doodads to the game and 5 new wallpapers (parchment paper in blue, green, red, white and yellow). New doodads: * Crusher: A purple block-headed mob wearing an iron helmet. It tries to crush the player when you get underneath. Its flat helmet can be ridden on like an elevator back up. * Snake: A green stationary mob that always faces toward the player. If the player is nearby and jumps, the Snake will jump too and hope to catch the player in mid-air. * Gems and Totems: A new key & lock collectible. Gems have quantity so you can collect multiple, and place them into matching Totems. A Totem gives off a power signal when its gem is placed and all other Totems it is linked to have also been activated. A single Totem may link to an Electric Door and require only one gem to open it, or it can link to other Totems and they all require gems before the power signal is sent out.
109 lines
2.7 KiB
Go
109 lines
2.7 KiB
Go
package scripting
|
|
|
|
import (
|
|
"git.kirsle.net/apps/doodle/lib/debugging"
|
|
"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)
|
|
debugging.PrintCallers()
|
|
}
|
|
}()
|
|
|
|
// Watch the Inbound channel for PubSub messages and the stop channel for Teardown.
|
|
for {
|
|
select {
|
|
case <-vm.stop:
|
|
log.Debug("JavaScript VM %s stopping PubSub goroutine", vm.Name)
|
|
return
|
|
case msg := <-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) {
|
|
vm.muPublish.Lock()
|
|
for _, channel := range vm.Outbound {
|
|
channel <- Message{
|
|
Name: name,
|
|
SenderID: vm.Name,
|
|
Args: v,
|
|
}
|
|
}
|
|
vm.muPublish.Unlock()
|
|
},
|
|
|
|
"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,
|
|
}
|
|
}
|
|
},
|
|
})
|
|
}
|