miniquad icon indicating copy to clipboard operation
miniquad copied to clipboard

Allow injecting other events to support things like websockets

Open mbirtwell opened this issue 4 years ago • 5 comments

I was looking at trying to WebSockets along side miniquad. The main problem seemed to be getting the events in to the event loop, I've been playing with a modification to miniquad to allow custom events to injected in to the event loop. They way I have it websockets or other things that run asynchronously to the main UI event loop can use this to inject custom events so they can be implemented externally to miniquad. I have some code which seems to work on windows and wasm, which I'd be happy to share if this is something you'd be interested in.

mbirtwell avatar Nov 14 '20 10:11 mbirtwell

I'd be very interested in looking at your code. I'm currently tinkering on a little browser based game and I would like to make it multilayer using websockets.

I was planning to modify miniqiuad in similar way, so allow other external asynchronous code to inject custom events. However my experience with asynchronous programming in rust is somewhat limited, so any pointers would be greatly appreciated.

LongHairedHacker avatar Nov 27 '20 20:11 LongHairedHacker

I've just pushed my modifications to miniquad to https://github.com/mbirtwell/miniquad (the last 3 commits) and my websocket library to https://github.com/mbirtwell/miniquad-websockets.

The modifications to miniquad will only work on wasm and windows. Probably won't even compile for other targets at the moment it wouldn't be hard to add support for someone who had access to the platforms. They'd just need to know how to post events on to the platforms UI event loop.

The websocket library has two implementations one for wasm which uses the browsers websocket APIs and one for everything that spins up a thread to run tokio-tungstenite. I've only tested the tokio-tungstenite on windows but it should in principle work on any target that tokio-tungstenite supports if the missing parts of my modifications to miniquad were implemented. And I think it should be pretty complete. The wasm implementation works as far as running my example code but I think there's probably some error handling missing.

mbirtwell avatar Nov 27 '20 20:11 mbirtwell

Hi, thanks for the work done, custom events look interesting! But with current implementation it is possible to use only one type of custom events over the whole application, right?

Also, I am not quite sure about the necessity of injection events into the UI event loop, maybe it may be just a function call on the miniquad level? This way we will avoid a lot of platform-dependent code.

And just FYI: for my websockets implementation, I had a static function called JS that posted an event into a static queue, and then I sorted those queues in the update loop, worked quite well :)

not-fl3 avatar Nov 27 '20 22:11 not-fl3

But with current implementation it is possible to use only one type of custom events over the whole application, right?

The intention is that the application author defines a type for the custom event like:

enum CustomEvent {
    PluginEvent1(PluginEvent1),
    PluginEvent2(PluginEvent2),
}

impl From<PluginEvent1> for CustomEvent ...
impl From<PluginEvent2> for CustomEvent ...

And the plugin author would have to make their code generic over a custom event type e.g. in my websocket plugin many functions have a generic parameter EventType: Send + From<WebSocketEvent<WebSocketId>>. The CustomEventPostBox takes event: impl Into<CustomEvent> to encourage this pattern but it's not really enforced or documented at the moment. It is obviously a bit cumbersome and quite easy for the plugin author to muck up, but that's what I've come up with so far.

Aside: In my websocket library there is a second generic parameter for WebSocketId this allows the application code to define the type of the web socket id, which is cute if you only have one websocket because then it can be () or if you had a small number for well defined purposes you could use an enum. But I'm not sure that it was worth it. It worked quite well in the tungstenite version but I had to create another inner id for the wasm implementation.

Also, I am not quite sure about the necessity of injection events into the UI event loop, maybe it may be just a function call on > the miniquad level? This way we will avoid a lot of platform-dependent code.

I agree that avoiding platform dependent code would be preferable. I'm just not entirely sure I understand how you propose to do this. I don't think you can have a function at the miniquad level that calls in to the application code when a message arrives on the websocket with out having a very confusing situation with threads in the non-wasm case. I.e. I think that the websocket has to run on a different thread from the UI event loop. Or the websocket implementation has to very platform dependent and integrate with the UI event loop.

Reading the next bit and guessing a bit I think what you're proposing is that the websocket messages are posted on to a queue by js or another thread and then we poll that that queue in or just before update. I think that would work well. I just started with the assumption that I wanted the events to be handled as soon as we could after they arrived. This approach would mean that if the message arrived just after we started sleeping until it was time to draw the next frame we'd not process the event until it was time to draw the next frame. Which, thinking about it now, is absolutely fine just not what I had in mind.

Thanks for your comments, let me know what you think.

mbirtwell avatar Nov 28 '20 08:11 mbirtwell

This approach would mean that if the message arrived just after we started sleeping until it was time to draw the next frame

Yes, but it basically the same with UI event loop processing - it is going to be processed only at the beginning of the next frame anyway.

application code when a message arrives on the websocket with out having a very confusing situation with threads in the non-wasm case.

We can do our own even queue if we really need, but I would prefer to somehow avoid threading problems and leave them to the application level.

not-fl3 avatar Nov 28 '20 13:11 not-fl3