diff --git a/README.md b/README.md index 5288691..db4e6f1 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ For proxies the recommended setup is to create one game object per screen and pe * **Timestep below Popup (number)** - Timestep to set on screen proxy when it is below a popup. This is useful when pausing animations and gameplay while a popup is open. * **Transition Url (url)** - Optional URL to post messages to when the screen is about to be shown/hidden. Use this to trigger a transition (see the section on [transitions](#transitions)). * **Focus Url (url)** - Optional URL to post messages to when the screen gains or loses focus (see the section on [screen focus](#screen-focus-gainloss)). +* **Receiver Url (url)** - Optional URL to post messages to using monarch.post(). * **Preload (boolean)** - Check this if the screen should be preloaded and kept loaded at all times. For a collection proxy it means that it will be async loaded but not enabled at all times while not visible. This can also temporarily be achieved through the `monarch.preload()` function. ![](docs/setup_proxy.png) @@ -441,6 +442,19 @@ Remove a previously added listener. * ```url``` (url) - URL to remove. Will use current URL if omitted. +### monarch.post(screen_id, message_id, [message]) +Post a message to a visible screen. If the screen is created through a collection proxy it must have specified a receiver url. If the screen is created through a collection factory the function will post the message to all game objects within the collection. + +**PARAMETERS** +* ```screen_id``` (string|hash) - Id of the screen to post message to +* ```message_id``` (string|hash) - Id of the message to send +* ```message``` (table|nil) - Optional message data to send + +**RETURN** +* ```result``` (boolean) - True if the message was sent +* ```error``` (string|nil) - Error message if unable to send message + + ### monarch.debug() Enable verbose logging of the internals of Monarch. diff --git a/monarch/monarch.lua b/monarch/monarch.lua index 9ce8f05..096442f 100644 --- a/monarch/monarch.lua +++ b/monarch/monarch.lua @@ -170,6 +170,8 @@ end -- screen transitions -- * focus_url - URL to a script that is to be notified of focus -- lost/gained events +-- * receiver_url - URL to a script that is to receive messages sent +-- using monarch.send() -- * timestep_below_popup - Timestep to set on proxy when below a popup -- * auto_preload - true if the screen should be automatically preloaded function M.register_proxy(id, proxy, settings) @@ -178,6 +180,7 @@ function M.register_proxy(id, proxy, settings) screen.proxy = proxy screen.transition_url = settings and settings.transition_url screen.focus_url = settings and settings.focus_url + screen.receiver_url = settings and settings.receiver_url screen.auto_preload = settings and settings.auto_preload if screen.auto_preload then M.preload(id) @@ -814,6 +817,43 @@ function M.unload(id, cb) end +--- Post a message to a screen (using msg.post) +-- @param id (string|hash) Id of the screen to send message to +-- @param message_id (string|hash) Id of the message to send +-- @param message (table|nil) Optional message data to send +-- @return result (boolean) true if successful +-- @return error (string|nil) Error message if unable to send message +function M.post(id, message_id, message) + assert(id, "You must provide a screen id") + if not M.is_visible(id) then + return false, "Unable to post message to screen if it isn't visible" + end + + assert(message_id, "You must provide a message_id") + id = tohash(id) + assert(screens[id], ("There is no screen registered with id %s"):format(tostring(id))) + local screen = screens[id] + + if screen.proxy then + if screen.receiver_url then + log("post() sending message to", screen.receiver_url) + msg.post(screen.receiver_url, message_id, message) + else + return false, "Unable to post message since screen has no receiver url specified" + end + else + run_coroutine(screen, nil, function() + change_context(screen) + log("post() sending message to", screen.receiver_url) + for id,instance in pairs(screen.factory_ids) do + msg.post(instance, message_id, message) + end + end) + end + return true +end + + function M.on_message(message_id, message, sender) if message_id == PROXY_LOADED then local screen = screen_from_proxy(sender) diff --git a/monarch/screen_proxy.script b/monarch/screen_proxy.script index e956cc0..c48651c 100644 --- a/monarch/screen_proxy.script +++ b/monarch/screen_proxy.script @@ -7,6 +7,7 @@ go.property("popup_on_popup", false) go.property("timestep_below_popup", 1) go.property("transition_url", msg.url()) go.property("focus_url", msg.url()) +go.property("receiver_url", msg.url()) go.property("preload", false) @@ -22,6 +23,7 @@ function init(self) popup_on_popup = self.popup_on_popup, transition_url = self.transition_url ~= url and self.transition_url or nil, focus_url = self.focus_url ~= url and self.focus_url or nil, + receiver_url = self.receiver_url ~= url and self.receiver_url or nil, timestep_below_popup = self.timestep_below_popup, auto_preload = self.preload, } diff --git a/test/data/screen1.gui_script b/test/data/screen1.gui_script index c9837ba..f6e48b7 100644 --- a/test/data/screen1.gui_script +++ b/test/data/screen1.gui_script @@ -7,6 +7,7 @@ function final(self) end function on_message(self, message_id, message, sender) - -- Add message-handling code here - -- Remove this function if not needed + if message_id == hash("foobar") then + _G.screen1_foobar = message or true + end end diff --git a/test/data/screen2.gui_script b/test/data/screen2.gui_script index d2f107a..2e8ad23 100644 --- a/test/data/screen2.gui_script +++ b/test/data/screen2.gui_script @@ -7,6 +7,7 @@ function final(self) end function on_message(self, message_id, message, sender) - -- Add message-handling code here - -- Remove this function if not needed + if message_id == hash("foobar") then + _G.screen2_foobar = message or true + end end diff --git a/test/data/screens.collection b/test/data/screens.collection index a5df750..4f6c625 100644 --- a/test/data/screens.collection +++ b/test/data/screens.collection @@ -21,6 +21,11 @@ embedded_instances { " value: \"screen1\"\n" " type: PROPERTY_TYPE_HASH\n" " }\n" + " properties {\n" + " id: \"receiver_url\"\n" + " value: \"screen1:/go\"\n" + " type: PROPERTY_TYPE_URL\n" + " }\n" "}\n" "embedded_components {\n" " id: \"collectionproxy\"\n" diff --git a/test/test.script b/test/test.script index 9fb53ba..563963e 100644 --- a/test/test.script +++ b/test/test.script @@ -9,6 +9,6 @@ function init(self) deftest.add(test_callback_tracker) deftest.run({ coverage = { enabled = true }, - --pattern = "preload", + pattern = "", }) end diff --git a/test/test_monarch.lua b/test/test_monarch.lua index 59cff0a..0fb48ad 100644 --- a/test/test_monarch.lua +++ b/test/test_monarch.lua @@ -416,5 +416,69 @@ return function() assert(wait_until_hidden(FOCUS1), "Focus1 was never hidden") assert(_G.focus1_lost) end) + + + it("should be able to post messages without message data to visible screens", function() + _G.screen1_foobar = nil + _G.screen2_foobar = nil + + -- proxy screen + monarch.show(SCREEN1) + wait_until_shown(SCREEN1) + assert(monarch.post(SCREEN1, "foobar"), "Expected monarch.post() to return true") + cowait(0.1) + assert(_G.screen1_foobar, "Screen1 never received a message") + + -- factory screen + monarch.show(SCREEN2) + wait_until_shown(SCREEN2) + assert(monarch.post(SCREEN2, "foobar"), "Expected monarch.post() to return true") + cowait(0.1) + assert(_G.screen2_foobar, "Screen2 never received a message") + end) + + + it("should be able to post messages with message data to visible screens", function() + _G.screen1_foobar = nil + _G.screen2_foobar = nil + + -- proxy screen + monarch.show(SCREEN1) + wait_until_shown(SCREEN1) + assert(monarch.post(SCREEN1, "foobar", { foo = "bar" }), "Expected monarch.post() to return true") + cowait(0.1) + assert(_G.screen1_foobar, "Screen1 never received a message") + assert(_G.screen1_foobar.foo == "bar", "Screen1 never received message data") + + -- factory screen + monarch.show(SCREEN2) + wait_until_shown(SCREEN2) + assert(monarch.post(SCREEN2, "foobar", { foo = "bar" }), "Expected monarch.post() to return true") + cowait(0.1) + assert(_G.screen2_foobar, "Screen2 never received a message") + assert(_G.screen2_foobar.foo == "bar", "Screen2 never received message data") + end) + + + it("should not be able to post messages to hidden screens", function() + _G.screen1_foobar = nil + + monarch.show(SCREEN1) + wait_until_shown(SCREEN1) + monarch.show(SCREEN2) + wait_until_shown(SCREEN2) + local ok, err = monarch.post(SCREEN1, "foobar") + assert(not ok and err, "Expected monarch.post() to return false plus an error message") + cowait(0.1) + assert(not _G.screen1_foobar, "Screen1 should not have received a message") + end) + + + it("should not be able to post messages to proxy screens without a receiver url", function() + monarch.show(POPUP1) + wait_until_shown(POPUP1) + local ok, err = monarch.post(POPUP1, "foobar") + assert(not ok and err, "Expected monarch.post() to return false plus an error message") + end) end) end