[Plugin] Socket.io Client

Hey !

Thank you very much for the plugin it is awesome, although I have started using it in 4.15.1 and I have some strange error while emiting event, my unreal crashes with fatal error and in logs I found this:

Do you have any idea what could cause it and how to fix it?

Crash points to https://github.com//socketio-client-ue4/blob/master/Source/SocketIOClient/Private/SIOMessageConvert.cpp#L83 which likely means JsonValue->Type dereferencing is failing on a null type pointer. What method are you using to generate the data youā€™re emitting? struct->json? or manual object building? Maybe a blueprint picture or two could help replicating this crash.

This should be helpful, looks like itā€™s related to an invalid string pointer or size causing an oversized allocation. Not quite sure yet when I can carve the time to finally fix the disconnect bug. Any possibility to rig up and share a minimal example project that replicates the problem easily?

Sure I can give you whole example as itā€™s very easy, it is clean ThirdPersonExample with starter content with custom GameMode containing only what you can see on screens. It is running with dedicated server in the background with 1 client. Engine version is 4.15.1 here are the screens from Unreal:

Here is the code for my node.js app (in TypeScript):


import * as express from 'express'
import * as http from 'http'
import * as socketIO from 'socket.io'

import SelectPlayerNation from './src/SelectPlayerNation'

const app = express()
const server = http.createServer(app)
var io = socketIO(server)

io.on('connection', (socket) => {
    console.log('Game server connected from: ' + socket.handshake.address)

    socket.on('nationize', (msg) => {
        console.log('Selecting nation started...')
        if (SelectPlayerNation("a", 1)) {
            console.log('Nation selected')
            socket.emit('nation-selected')
            return
        }

        console.log('Error while selecting nation')
        socket.emit('nation-selection-error')
    })
})

server.listen(3000, () => {
    console.log('Server listen on *:3000')
})

And here is SelectPlayerNation function that is imported:



export default function GetPlayerNation(sid:string):number {
    return 0;
}


PM2 Logs when I run the server and try to run Unreal client:


C:\Users
ewicz\.pm2\pm2.log last 15 lines:
PM2        | 2017-03-29 01:01:30: ===============================================================================
PM2        | 2017-03-29 01:01:30: --- New PM2 Daemon started ----------------------------------------------------
PM2        | 2017-03-29 01:01:30: Time                 : Wed Mar 29 2017 01:01:30 GMT+0200 (Central European Daylight Time)
PM2        | 2017-03-29 01:01:30: PM2 version          : 2.4.2
PM2        | 2017-03-29 01:01:30: Node.js version      : 6.10.1
PM2        | 2017-03-29 01:01:30: Current arch         : x64
PM2        | 2017-03-29 01:01:30: PM2 home             : C:\Users
ewicz\.pm2
PM2        | 2017-03-29 01:01:30: PM2 PID file         : C:\Users
ewicz\.pm2\pm2.pid
PM2        | 2017-03-29 01:01:30: RPC socket file      : \\.\pipe\rpc.sock
PM2        | 2017-03-29 01:01:30: BUS socket file      : \\.\pipe\pub.sock
PM2        | 2017-03-29 01:01:30: Application log path : C:\Users
ewicz\.pm2\logs
PM2        | 2017-03-29 01:01:30: Process dump file    : C:\Users
ewicz\.pm2\dump.pm2
PM2        | 2017-03-29 01:01:30: Concurrent actions   : 2
PM2        | 2017-03-29 01:01:30: SIGTERM timeout      : 1600
PM2        | 2017-03-29 01:01:30: ===============================================================================

[STREAMING] Now streaming realtime logs for [all] processes
PM2        | [Watch] Start watching 0
PM2        | Starting execution sequence in -fork mode- for app name:api-app id:0
PM2        | App name:api-app id:0 online
0|api-app  | Server listen on *:3000
0|api-app  | Game server connected from: ::1

EDIT: SOLUTION FOUND
Iā€™ve found the reason it was emiting the clean event from nodejs app. Once I changed:


socket.emit('nation-selected')

to


socket.emit('nation-selected', {})

It worked just fine! Thank you for pointing me into right direction, I will leave this for others that may have problem with that.

Thatā€™s great! That said itā€™s still a bug from the plugin side, looks like I donā€™t handle an empty message case on receive, Iā€™ll add another type check in there in case the JsonValue you get is none and see if that will fix it.

Hi , Iā€™ll get you something sometime! Iā€™m running up against crazy deadlines for the next 2/3 weeks or so, our showā€™s going to air on the 18th.

No rush Dan, things always take time :slight_smile:

Exciting stuff on the show, it would be awesome to see it action, maybe at the meetup?

Update to 0.5.2
-Fixed boolean always returning false #35](https://github.com//socketio-client-ue4/issues/35)

From 0.5.1
-Fixed undefined as second emit parameter from server #36](https://github.com//socketio-client-ue4/issues/36)

From 0.5.0
-Fixes for disconnecting while communicating with an unreachable server #32](https://github.com//socketio-client-ue4/issues/32)
-Boost updated to 1.62
-Socket.io-cpp updated to latest master merge
-misc internal features for tracking and killing lambda threads

Grab the latest @ https://github.com//socketio-client-ue4/releases

This is now fixed in 0.5.1 allowing you to leave the second parameter empty.

@Dannington @Avatarochnik and anyone else who has had disconnect crashes, try the latest version for 4.15 (0.5.2) and let me know if the crashes and hangs have gone away.

Hi @.

My PC is currently in a box coming back from France, but iā€™ll test it as soon as I get back. Something I realised is that I nearly always do my builds as development builds rather than shipping so I can get access to the console, but for a presentation I did yesterday I made a shipping build and it was a lot less likely to crash (It did only once over the last 3 days on exit, whereas with a development build it would happen more often than not).

Thanks

Hi @.

On 4.15 and the most recent SocketIO, Iā€™m also getting the bug where, when not using auto-connect, my packaged project crashes on loading a level.

Thanks for this @! I would like to use this within an Online Subsystem. Is it possible? Do you have any suggestions on how to implement the client in c++ at this (sub actor) level?

Not too familiar with the online subsystem layout, do you have some code scaffold of what you want to do?

Noted, does it only happen in packaged projects? and do you have any logs you can PM me (found under Saved/Logs)?

[QUOTE=;701473]
Not too familiar with the online subsystem layout, do you have some code scaffold of what you want to do?

Yes, all of the online subsystems have the same interface.

There are no actors involved, so using the actor component isnā€™t going to work, right?

I started experimenting with it, but I havenā€™t been having much success so far.

I should be able to refactor the plugin to encapsulate the C++ functionality in a pure C++ class e.g. FSocketIOClient which can then be used as a rebase for the ActorComponent (keep a local shared ptr, and forward all calls). This would allow you to add it anywhere in C++ via raw ptrs e.g. new FSocketIOClient or shared ptrs e.g. MakeSharedPtr(new FSocketIOClient) and not break any ActorComponent functionality while keeping a common core.

Iā€™ve added the enhancement suggestion as an issue to the repo: https://github.com//socketio-client-ue4/issues/43

@ I did some more testing. As far as I can tell, yes, it only happens in packaged builds. Doesnā€™t matter if itā€™s packaged for shipping or development. Using Windows 64-bit build.

The situation is this: I load into a level just fine. Then I have seven blueprints with SocketIO components which all connect properly to my server. Everything is fine.

Then one of these seven blueprints emits a signal to the server, all of them disconnect from the server, and then I switch the level.

Iā€™ll PM you the logs, but it doesnā€™t look like itā€™s too helpful. Iā€™ve narrowed it down to the disconnecting step causing the crash in the packaged version. It works without hitch in the editor. Thanks!

I managed to get the base implementation working. I ripped all of your code out of the plugin to do it though, so itā€™s not really useful as a plugin anymore. Iā€™ll post what I did one I get a bit more testing on it.

Try this branch instead (awaiting a few more tests before merging to master, but it seems solid): https://github.com//socketio-client-ue4/tree/fclass-refactor

Itā€™s still a plugin and you can make a FSocketIONative wherever you like and use the same methods. E.g. the component spawns it on initialize component https://github.com//socketio-client-ue4/blob/fclass-refactor/Source/SocketIOClient/Private/SocketIOClientComponent.cpp#L25 but you can use your own life cycle. Instead of the multicast delegate system for connected/disconnected you just use raw lambdas as callbacks, these are set before I connect in the component to forward to the multicast delegates: https://github.com//socketio-client-ue4/blob/fclass-refactor/Source/SocketIOClient/Private/SocketIOClientComponent.cpp#L138

I got connecting and emitting events to work. Yay!

Iā€™m stuck on how to receive events.

In your c++ docs:
https://github.com//socketio-client-ue4
You have:

OnRawEvent(&](const FString& Name, const sio::message::ptr& Message)

This gives a compilation error:
no suitable user-defined conversion from ā€œlambda ]void (const FString &Name, const sio::message::ptr &Message)->voidā€ to ā€œconst FStringā€ exists

Digging through the code, I see you use this instead:
OnRawEvent(EventName, &](const FString& Event, const sio::message::ptr& RawMessage)

I canā€™t get this to work either.

Can you show how to receive events in c++ in context? I feel like Iā€™m doing it totally wrong.

Looks like I missed a key C++ documentation bit, bind events in c++ not using the raw format, thanks for catching this! Generally OnRawEvent should be avoided unless you want to use sio::message data types (these are not UE4 native).

Iā€™ve now added the UE4 native section here: https://github.com//socketio-client-ue4/blob/master/README.md#receiving-events

Since weā€™re using the FSocketIONative the function is https://github.com//socketio-client-ue4/blob/fclass-refactor/Source/SocketIOClient/Public/FSocketIONative.h#L212

So the syntax for that should be:




//Smart pointer method
TSharedPtr<FSocketIONative> NativeClient; //assuming this is valid

or

//Raw pointer method
FSocketIONative* NativeClient; //assuming this is valid

...

NativeClient->OnEvent(FString("MyEvent"), ](const FString& Event, const TSharedPtr<FJsonValue>& Message)
	{
		//Called when the event is received
	}, FString("Optional Namespace"));



note that youā€™ll need to add variables you use in the lambda capture to


]

so that they are captured. E.g. if you call the above inside a member function


[this]

would normally be sufficient. See Lambda expressions (since C++11) - cppreference.com for reference on C++ lambdas.

You bet.

Thanks for the detailed explanation. Iā€™ll report back with my findings, after I dig in.

OnNativeEvent(FString(ā€œMyEventā€), ](const FString& Event, const TSharedPtr<FJsonValue>& Message)
{
//Called when the event is received
}, FString(ā€œOptional Namespaceā€));

Thank you! This is working.