Pre/Post attach RMI's always fail + attach RMI's not arriving with aspects.

#1
Issue #1)

Basically pre/post attach RMI's in CE don't work.

The message definition reliability has to be eNRT_UnreliableX
(Not the message reliability....)
otherwise Post/Pre-attach will fail with this ASSERT:
UpdateMessage.cpp NET_ASSERT(pDef->reliability == eNRT_UnreliableOrdered || pDef->reliability == eNRT_UnreliableUnordered);

But the only place that I've been able to find that has the definition reliability set is in GameObjectDispatch.cpp (and unrelated to the new RMI setup)
// Everything else's reliability/orderedness is based on the object they're attached to
md.reliability = eNRT_UnreliableOrdered;
However the md by default in UpdateMessage goes ahead and has 'eNRT_ReliableOrdered'.....
Since it isn't set anywhere I presume thats the default (0) being initialized etc.

Any suggestions/solutions appreciated. The above issue is easy to reproduce, just make an RMI with pre-attach as usual.

Edit:
When not a GameObjectExtension RMI, the message definition is the exact same across all NetEntity RMI's: CryAction_RMI.cpp

Code: Select all

// Accepts two types of RMIs: of CGameObject and of NetEntity. // The only distinction between them is that NetEntity RMIs share the one // message definition for all of them, which is registered and known only in this file. // This has previously been CGameObject::DoInvokeRMI. if (!isGameObjectRmi) { pBody->pMessageDef = &s_entity_rmi_msg; }
Had to edit the source code to get Pre/Post-attach messages working at all:

Code: Select all

void CCryAction::DefineProtocolRMI(IProtocolBuilder* pBuilder) { // I need only one RMI message registered for all entities. s_entity_rmi_msg.handler = ProcessPacketRMI; s_entity_rmi_msg.description = "RMI:Entity"; s_entity_rmi_msg.reliability = eNRT_UnreliableOrdered; // SMALL PERSONAL EDIT SNetProtocolDef protoSendingReceiving; protoSendingReceiving.nMessages = 1; protoSendingReceiving.vMessages = &s_entity_rmi_msg; pBuilder->AddMessageSink(nullptr /* ignored */, protoSendingReceiving, protoSendingReceiving); }
Issue #2)
Really hoping that Cry-Flare or someone from networking can shed light on the following.
Here are some of my logs:

Code: Select all

The #'s are 'OldStateFlags, NewStateFlags, TimeOnLastFrameCall timestamp' <11:19:51> TESTING: STARTED RMI SYNCING 0 0 18262 <11:19:51> TESTING: ENDED RMI SYNCING 18262 <11:19:51> TESTING: STARTED RMI SYNCING 0 0 18262 <11:19:51> TESTING: ENDED RMI SYNCING 18262 <11:19:51> TESTING: ENDED SERIALIZATION 0 0 18262 <11:19:51> TESTING: STARTED RMI SYNCING 0 0 18402 <11:19:51> TESTING: ENDED RMI SYNCING 18402 <11:19:51> TESTING: STARTED RMI SYNCING 0 0 18402 <11:19:51> TESTING: ENDED RMI SYNCING 18402 <11:19:51> TESTING: ENDED SERIALIZATION 0 0 18402
They key point to note is that I trigger an RMI function once per frame during the Actor's update; To create/destroy as well as serialize misc.variable state data.(edited)
I can't put it into aspects because states get created/destroyed often and making each one a component has more overhead etc.....(and there are more states than aspects)(edited)
Anyway, the main issue is that the RMI's obv are read out of sync compared to how often the net-serialization happens
I assumed since they're attachments they'd go with the aspects sent, so each block of sent aspects would have 1 RMI attached to it. To make sure aspects are sent every frame, I mark them dirty (each frame) and flip a variable (so there is always a 'change' and the aspect gets sent)
The RMI's stack up, even though the server and client have the same forced frame/tick rate of 1 frame every 0.07 seconds.

The 'Target Functionality' can be aptly summarized as the following:
Triggering an RMI function to serialize X data and run a few functions/processes.
The trigger has to happen after NetSerialization() but before the systems/components/etc. are updated.
Said RMI should be paired with the dependent aspect data, e.g. Aspect's for frame #27 will be sent and recieved with the 1 RMI call from frame #27 + processed in the same frame.
As it is the RMI post-attach flag isn't working properly (according to logs looks like it's doing a pre-attach?)

Issue #3)
Welp, found the issue with out-of-sync calls. SerializeWith() on RMI's is run on the Network thread! NetSerialization() (aspects) and RMI Functions calls are on the Main thread.
However, now that I moved my SyncState() code to the RMI function call itself, I need to somehow pass in the SerializeWith() TSerialize param.

Original Setup (shortened):

Code: Select all

void SerializeWith(TSerialize ser) { // Ser could be read/written here just fine! However it was out-of-sync with the Main thread.... StateMachine->SyncStates(ser) }
Now:

Code: Select all

bool SyncState(CParams&& p, INetChannel* p2){ // Where to get 'ser' from? How to store? etc. StateMachine->SyncStates(ser) }
Ideally I don't have to duplicate the packet data, or serialize it to XML etc.


tl;dr
issue 1) post-pre attach flags will never work unless you edit source code/
Issue 2) RMI's are out of sync and not triggered properly according to logs
Issue 3) Can't access ser object from the function trigger itself when 'reading'. Writing out-of-sync with thread is fine, reading HAS to be done in sync with thread for me.


According to CE team (10 min cursory conversation) RMI's should NOT be used on a per-frame basis because it screws with compression policies and will kill bandwidth.

Ok, well, here are the requirements (sample problem that demonstrates issue):

You have a state machine. Said state machine has the capacity to, in the future, have more than 32 states (# of aspects/entity not per component AFAIK). You need to sync the variables from Server->Client (all of them, assume they change often so every frame).

Using RMI's has the 3 issues above + bandwidth death, so its also impossible to use.
Using aspects is impossible because you can't have 1 aspect/state and aspects also don't accept variable-size data.

The ONLY solution I can think of is to have several state machines components on fake entities that are just there to get a higher # of aspects ('slave state machine component') and one master machine that handles interruptions/state-overriding/etc on the main entity.

Which sounds really dang convoluted.....because it's obviously a workaround (e.g. just have several entities with tons of aspects to bypass the usual limit)


Hmm, and a few more Q's)

This along with many other things just confuses everything:
//! This enum describes different reliability mechanisms for packet delivery.
//! Do not change ordering here without updating ServerContextView, ClientContextView.
//! \note This is pretty much deprecated; new code should use the message queue facilities
//! to order messages, and be declared either ReliableUnordered or UnreliableUnordered.
There's also no explanation on what 'Reliable' Or 'Unreliable' do/how they differ AND the fact that 'Ordered' and 'Unordered' are deprecated and should just be 'Unordered'
Comments conflict with docs etc.

So, what do the various ordered/reliable etc. flags change?

Who is online

Users browsing this forum: No registered users and 1 guest

cron