Пример #1
0
        /// <summary>
        /// Called when new data has arrived from a peer via the specified Link.
        /// </summary>
        /// <param name="link"></param>
        /// <param name="contract"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        unsafe virtual protected VscResult ReceiveCallback(VscLink link, VscContract contract, VscUpdateData data)
        {
            {
                VscResult retRes;
                var       node = VsConnectNode.GetInstanceFromLink(link);

                retRes = ShouldProcessCallback(node, link);

                if (!retRes.IsError())
                {
                    VscSchema schema          = vsc_Api_V3_t.Contract_GetSchema(contract);
                    var       numSchemaFields = vsc_Api_V3_t.Schema_GetNumFields(schema);
                    var       localRole       = vsc_Api_V3_t.Contract_GetLocalRole(contract);


                    Check(localRole == VscRole.SENDER);
                    Check(localRole == VscRole.SENDER);
                    Check(schema != IntPtr.Zero);
                    Check((IntPtr)vsc_Api_V3_t.UpdateData_GetSchema(data) == (IntPtr)schema);


                    for (int fieldIndex = 0; fieldIndex < numSchemaFields; ++fieldIndex)
                    {
                        var field     = vsc_Api_V3_t.Schema_GetField(schema, fieldIndex);
                        var arraySize = vsc_Api_V3_t.Field_GetNumElements(field);
                        Check(arraySize > 0);
                        var vsVar = ToObject(vsc_Api_V3_t.Field_GetAppData(field)) as VSVarBase;

                        if (vsVar != null && vsVar.Direction == VsVarDirection.Input)
                        {
                            double *fieldValue = (double *)vsc_Api_V3_t.UpdateData_GetFieldValue(data, fieldIndex);
                            Check(fieldValue != null);

                            if (vsVar.VariableType == typeof(double))
                            {
                                ((VsConnectVar <double>)vsVar).Value = *fieldValue;
                            }
                            if (vsVar.VariableType == typeof(double[]))
                            {
                                double[] values = new double[arraySize];
                                for (int index = 0; index < arraySize; index++)
                                {
                                    values[index] = fieldValue[index];
                                }
                                ((VsConnectVar <double[]>)vsVar).Value = values;
                            }
                        }
                    }
                    retRes = VscResult.OK;
                }

                return(retRes);
            }
        }
Пример #2
0
        /// <summary>
        /// Callback that informs us when a Link is connected.
        /// </summary>
        /// <param name="connectingLink"></param>
        /// <returns></returns>
        virtual protected VscResult LinkConnectCallback(VscLink connectingLink)
        {
            VscResult retRes = VscResult.OK;

            Log($"VS Connect Link connecting: {connectingLink.ptr.ToInt64():x}.\n");

            VsConnectNode node = VsConnectNode.GetInstanceFromLink(connectingLink);

            retRes = ShouldProcessCallback(node, connectingLink);

            return(retRes);
        }
Пример #3
0
        void ContractCanceledCallback(VscLink link, VscContract contract)
        {
            var tsMode    = vsc_Api_V3_t.Contract_GetTsMode(contract);
            var localRole = vsc_Api_V3_t.Contract_GetLocalRole(contract);

            if (tsMode != VscTimeSyncMode.NONE && localRole == VscRole.RECEIVER)
            {
                // Our Incoming TS Contract is being canceled. Ensure
                // time dilation is set back to its original value:
                //auto unode = UVsConnectNode::GetInstanceFromLink(link);
                //auto uVsConnect = Cast<UVsConnect>(unode->GetOuter());
                //auto worldSettings = uVsConnect->mWorld->GetWorldSettings();
                //if ( worldSettings ) uVsConnect->RestoreOriginalTimeDilation(worldSettings);
            }
        }
Пример #4
0
        static public VsConnectNode GetInstanceFromLink(VscLink link)
        {
            VsConnectNode retNode = null;

            var vscNode = vsc_Api_V3_t.Link_GetNode(link);


            if (vscNode != IntPtr.Zero)
            {
                var nodeAppData = vsc_Api_V3_t.Node_GetAppData(vscNode);
                retNode = VsUtility.ToObject(nodeAppData) as VsConnectNode;
            }

            return(retNode);
        }
Пример #5
0
        virtual protected VscResult ShouldProcessCallback(VsConnectNode node, VscLink link)
        {
            VscResult retRes;

            if (node == null || link == IntPtr.Zero)
            {
                retRes = VscResult.ERROR_INVALID_PARAM;
            }
            else if (node.ShuttingDown)
            {
                retRes = VscResult.ERROR_UNAVAILABLE;
            }
            else
            {
                retRes = VscResult.OK;
            }

            return(retRes);
        }
Пример #6
0
        /// <summary>
        /// Callback that informs us when a Link becomes disconnected.
        /// </summary>
        /// <param name="disconnectedLink"></param>
        virtual protected void LinkDisconnectCallback(VscLink link)
        {
            Log($"VS Connect Link disconnected: {link.ptr.ToInt64():x}.\n");

            var contract = vsc_Api_V3_t.Link_GetTsContract(link);

            if (contract != IntPtr.Zero)
            {
                var localRole = vsc_Api_V3_t.Contract_GetLocalRole(contract);

                if (localRole == VscRole.RECEIVER)
                {
                    // Our Incoming TS Contract is being canceled. Ensure
                    // time dilation is set back to its original value:
                    //var unode = UVsConnectNode::GetInstanceFromLink(link);
                    //var uVsConnect = Cast<UVsConnect>(unode->GetOuter());
                    //var worldSettings = uVsConnect->mWorld->GetWorldSettings();
                    //if (worldSettings) uVsConnect->RestoreOriginalTimeDilation(worldSettings);
                }
            }
        }
Пример #7
0
        /// <summary>
        /// Callback used by VS Connect to report log messages to this application.
        /// </summary>
        /// <param name="logLevel"></param>
        /// <param name="vscNode"></param>
        /// <param name="vscLink"></param>
        /// <param name="vscContract"></param>
        /// <param name="format"></param>
        /// <param name="argptr"></param>
        /// <returns></returns>
        protected unsafe int _VscLogCallback(VscLogLevel logLevel
                                             , VscNode vscNode
                                             , VscLink vscLink
                                             , VscContract vscContract
                                             , string format
                                             , IntPtr argptr)
        {
            string logMessage = $"VS Connect ";

            logMessage += logLevel == VscLogLevel.ERROR ? "ERROR" : (logLevel == VscLogLevel.WARNING ? "WARNING" : "");
            logMessage += string.Format("N:{0:x} L:{1:x} C:{2:x}", vscNode.ptr.ToInt64(), vscLink.ptr.ToInt64(), vscContract.ptr.ToInt64());


            int BUFF_SIZE = 1024;

            byte[] tempBuff = new byte[BUFF_SIZE];


            int charsOutput2 = vsprintf(tempBuff, format, argptr);

            //check(charsOutput2 > 0 );

            logMessage += System.Text.Encoding.UTF8.GetString(tempBuff, 0, charsOutput2);

            if (VscLogLevel.ERROR == logLevel)
            {
                LogError(logMessage);
            }
            else if (VscLogLevel.WARNING == logLevel)
            {
                LogWarning(logMessage);
            }
            else
            {
                Log(logMessage);
            }

            return(logMessage.Length);
        }
Пример #8
0
        virtual protected void DisconnectAllLinks()
        {
            foreach (var node in mVscNodes)
            {
                Check(node != null);
                if (node.VscNode != IntPtr.Zero)
                {
                    int numLinks = vsc_Api_V3_t.Node_GetNumLinks(node.VscNode);

                    for (int i = 0; i < numLinks; ++i)
                    {
                        VscLink link = vsc_Api_V3_t.Node_GetLink(node.VscNode, i);
                        Check(link != IntPtr.Zero);
                        Check(vsc_Api_V3_t.Link_GetConnectionStatus(link) != VscConnectionStatus.UNCONNECTED);
                        VscResult disconnectRes = vsc_Api_V3_t.Link_Disconnect(link);
                        //check(!vsc_IsError(disconnectRes));
                    }
                }
            }

            bool  done    = false;
            float timeout = 5.0f;

            while (!done && timeout > 0)
            {
                done = true;  // We're done unless we find a Node with Links that are not disconnected.

                foreach (var node in mVscNodes)
                {
                    Check(node != null);

                    if (node.VscNode != IntPtr.Zero)
                    {
                        vsc_Api_V3_t.Node_Service(node.VscNode, vsc_Api_V3_t.GetInvalidSimtime(), vsc_Api_V3_t.GetInvalidSimtime(), true);
                    }
                }

                foreach (var node in mVscNodes)
                {
                    Check(node != null);

                    if (node.VscNode != IntPtr.Zero)
                    {
                        if (0 == vsc_Api_V3_t.Node_GetNumLinks(node.VscNode))
                        {
                        }
                        else
                        {
                            done = false;
                            vsc_Api_V3_t.Node_Service(node.VscNode, vsc_Api_V3_t.GetInvalidSimtime(), vsc_Api_V3_t.GetInvalidSimtime(), true);
                        }
                    }
                }

                if (!done)
                {
                    const float sleepTime = 0.100f;  ///< Seconds to sleep during each iteration while disconnecting.
                    System.Threading.Thread.Sleep((int)(1000 * sleepTime));
                    timeout -= sleepTime;
                }
            }
        }
Пример #9
0
        virtual protected VscResult ProcessContractRequest(VscLink link, VscContract contract)
        {
            VscResult retRes;
            var       node = VsConnectNode.GetInstanceFromLink(link);

            retRes = ShouldProcessCallback(node, link);

            if (retRes.IsError())
            {
                LogWarning("VS Connect - Ignoring Contract Request.");
            }
            else
            {
                var tsMode = vsc_Api_V3_t.Contract_GetTsMode(contract);

                if (vsc_Api_V3_t.Contract_GetLocalRole(contract) == VscRole.RECEIVER &&
                    VS_TS_REQUIRE_FIXED_FRAME_RATE == 1 &&
                    tsMode != VscTimeSyncMode.NONE
                    //&& !GEngine->bUseFixedFrameRate

                    )
                {
                    LogError("VS Connect - Rejecting Incoming Contract with Time Sync (TS) enabled. Unity must be operating in fixed framerate mode to use TS.");
                    retRes = VscResult.ERROR_UNSUPPORTED;
                }
                else
                {
                    VscSchema schema          = vsc_Api_V3_t.Contract_GetSchema(contract);
                    var       numSchemaFields = vsc_Api_V3_t.Schema_GetNumFields(schema);
                    var       localRole       = vsc_Api_V3_t.Contract_GetLocalRole(contract);
                    Check(schema != IntPtr.Zero);


                    if (localRole == VscRole.SENDER)
                    {
                        Log($"VS Connect outgoing Contract request received: {contract.ptr.ToInt64():x}.\n");
                    }
                    else if (localRole == VscRole.RECEIVER)
                    {
                        Log($"VS Connect outgoing Contract request received: {contract.ptr.ToInt64():x}.\n");
                    }
                    else
                    {
                        LogWarning($"VS Connect outgoing Contract request received: {contract.ptr.ToInt64():x}.\n");
                    }

                    for (int fieldIndex = 0; fieldIndex < numSchemaFields; ++fieldIndex)
                    {
                        var    field      = vsc_Api_V3_t.Schema_GetField(schema, fieldIndex);
                        string objectName = "";
                        objectName = (vsc_Api_V3_t.Field_GetObjectName(field)).ToString();



                        var solver = GetObject(objectName);
                        if (solver == null)
                        {
                            LogWarning($"Unable to locate VS Connect Object {objectName} for Contract request {contract.ptr.ToInt64():x}.");
                        }
                        else
                        {
                            string fieldName   = vsc_Api_V3_t.Field_GetPropertyName(field);
                            string fieldParams = vsc_Api_V3_t.Field_GetParams(field);

                            var arraySize   = vsc_Api_V3_t.Field_GetNumElements(field);
                            var vscDataType = vsc_Api_V3_t.Field_GetDataType(field);
                            var dataSize    = vsc_Api_V3_t.Field_GetElementSizeInBits(field);

                            fieldName.TrimAndUnquoteInPlace();
                            fieldParams.TrimAndUnquoteInPlace();

                            VSVarBase vsVar = null;

                            if (localRole == VscRole.SENDER)
                            {
                                if (vscDataType == VscDataType.FLOAT && dataSize == 64 && arraySize == 1)
                                {
                                    vsVar = new VsConnectVar <double>(solver, fieldName, solver.GetDoubleFuncs[fieldName]);
                                }
                                if (vscDataType == VscDataType.FLOAT && dataSize == 64 && arraySize > 1)
                                {
                                    vsVar = new VsConnectVar <double[]>(solver, fieldName, solver.GetDoubleArrayFuncs[fieldName]);
                                }

                                if (vsVar == null)
                                {
                                    LogWarning($"VS Connect - Contract request %llx, Object {objectName}: No output Property {fieldName} with params {fieldParams}) for .");
                                }
                            }
                            else if (localRole == VscRole.RECEIVER)
                            {
                                if (vscDataType == VscDataType.FLOAT && dataSize == 64 && arraySize == 1)
                                {
                                    vsVar = new VsConnectVar <double>(solver, fieldName, solver.SetDoubleActions[fieldName]);
                                }
                                if (vscDataType == VscDataType.FLOAT && dataSize == 64 && arraySize > 1)
                                {
                                    vsVar = new VsConnectVar <double[]>(solver, fieldName, solver.SetDoubleArrayActions[fieldName]);
                                }


                                if (vsVar == null)
                                {
                                    LogWarning($"VS Connect - Contract request {contract.ptr.ToInt64():x}, Object {objectName}: No input Property {fieldName} with params {fieldParams}) for .");
                                }
                            }
                            else
                            {
                                vsVar = null;
                                LogError(("VS Connect - Unhandled VS Connect Role.\n"));
                            }


                            Check(vsc_Api_V3_t.Field_GetAppData(field) == IntPtr.Zero);

                            if (vsVar != null)
                            {
                                // Store the handle in the schema:
                                vsc_Api_V3_t.Field_SetAppData(field, ToPtr(vsVar));
                            }
                        }
                    }


                    Check(vsc_Api_V3_t.Contract_GetAppData(contract) == IntPtr.Zero);
                    vsc_Api_V3_t.Contract_SetAppData(contract, ToPtr(Singleton));
                    vsc_Api_V3_t.Contract_SetPreDestroyCallback(contract, SPreDestroyContract_);


                    retRes = VscResult.OK;
                }
            }

            return(retRes);
        }
Пример #10
0
        void PingCallback(VscNode vscNode, VscLink link)
        {
            /* Note that Ping Statistics include system times from both the Requester
             * (us) and the Responder (our peer). When both peers are running on the same
             * system and within the same session, they MIGHT both use a common reference
             * clock, and therefore the "system time" of the two peers can be directly
             * compared with one another. HOWEVER, this is not guaranteed on on all
             * operating systems, or even on different versions of the same operating
             * system.
             *
             * To be safe, you should always assume that the system clocks of two peers do
             * not refer to the same underlying reference clock, and can therefore NOT be
             * compared with one another.
             */
            /// Peer's system time when VS Connect received our Ping request.
            double peerReceiveTime =
                vsc_Api_V3_t.Link_PingGetStat(link
                                              , PingMilestone.RESPONDER_REQUEST_RECEIVED
                                              , TimeMomentAttr.SYSTEM_TIME);

            /// Peer's system time when it processed our request inside of its
            /// Node_Service() call.
            double peerProcessTime =
                vsc_Api_V3_t.Link_PingGetStat(link
                                              , PingMilestone.RESPONDER_REQUEST_PROCESSED
                                              , TimeMomentAttr.SYSTEM_TIME);

            /// Peer's system time when it queued the Ping reponse. This happens during
            /// the the next call to Node_Service() after the Ping request is processed.
            double peerResponseTime =
                vsc_Api_V3_t.Link_PingGetStat(link
                                              , PingMilestone.RESPONDER_RESPONSE_QUEUED
                                              , TimeMomentAttr.SYSTEM_TIME);

            /// The deduced period at which the Peer is calling Node_Service().
            double peerApparentSericePeriod = peerResponseTime - peerProcessTime;

            /// The time it took for the peer to process and respond to our request.
            double peerTotalProcessingTime = peerResponseTime - peerReceiveTime;

            /// The time that VS Connect queued our initial request for transmission.
            double ourRequestTransmitTime =
                vsc_Api_V3_t.Link_PingGetStat(link
                                              , PingMilestone.REQUESTER_REQUEST_QUEUED
                                              , TimeMomentAttr.SYSTEM_TIME);

            /// The time that VS Connect receved the peer's response.
            double ourResponseReceiveTime =
                vsc_Api_V3_t.Link_PingGetStat(link
                                              , PingMilestone.REQUESTER_RESPONSE_RECEIVED
                                              , TimeMomentAttr.SYSTEM_TIME);

            /// Time between when we sent the request and when we received the response.
            double totalRoundTripTime = ourResponseReceiveTime - ourRequestTransmitTime;

            /** This value will vary dramatically in this example due to the slow
             * service frequency of both peers. The higher the service frequency of the
             * peers, the lower and more stable this value will be, and the closer it will
             * be to the actual network transport latency.
             */
            double apparentTotalRoundNetworkLatency =
                totalRoundTripTime - peerTotalProcessingTime;

            // We set manual ping's appData to 1 so we can tell the difference between
            // automatic/periodic ping requests and those that we initiated manually.
            bool isManualPing = (vsc_Api_V3_t.Link_PingGetAppData(link).ToInt64() == 1);

            /*
             * printf( "\nPing Results%s: Peer update period: %g"
             * "\tRound-trip communication time: %g"
             * , isManualPing? " (manual)" : " (automatic)"
             * , peerApparentSericePeriod
             * , apparentTotalRoundNetworkLatency            );
             */
        }
Пример #11
0
        /// <summary>
        /// Called by VS Connect when it needs new data to send.
        /// </summary>
        /// <param name="link"></param>
        /// <param name="contract"></param>
        /// <param name="out_data"></param>
        /// <returns></returns>
        unsafe virtual protected VscResult SendCallback(VscLink link, VscContract contract, VscUpdateData out_data)
        {
            VscResult retRes;

            var node = VsConnectNode.GetInstanceFromLink(link);

            retRes = ShouldProcessCallback(node, link);

            if (!retRes.IsError())
            {
                VscSchema schema          = vsc_Api_V3_t.Contract_GetSchema(contract);
                var       numSchemaFields = vsc_Api_V3_t.Schema_GetNumFields(schema);
                var       localRole       = vsc_Api_V3_t.Contract_GetLocalRole(contract);

                Check(localRole == VscRole.SENDER);
                Check(schema != IntPtr.Zero);
                Check((IntPtr)vsc_Api_V3_t.UpdateData_GetSchema(out_data) == (IntPtr)schema);

                retRes = VscResult.OK;
                for (int fieldIndex = 0; VscResult.OK == retRes && fieldIndex < numSchemaFields; ++fieldIndex)
                {
                    var     field      = vsc_Api_V3_t.Schema_GetField(schema, fieldIndex);
                    double *fieldValue = (double *)vsc_Api_V3_t.UpdateData_GetFieldValue(out_data, fieldIndex);

                    var vsVar = ToObject(vsc_Api_V3_t.Field_GetAppData(field)) as VSVarBase;


                    Check(fieldValue != null);

                    if (vsVar == null)
                    {
                        vsc_Api_V3_t.InvalidateDouble(fieldValue);
                    }
                    else
                    {
                        var arraySize   = vsc_Api_V3_t.Field_GetNumElements(field);
                        var vscDataType = vsc_Api_V3_t.Field_GetDataType(field);
                        var dataSize    = vsc_Api_V3_t.Field_GetElementSizeInBits(field);

                        Check(vscDataType == VscDataType.FLOAT);
                        Check(64 == dataSize);
                        Check(arraySize > 0);

                        if (vsVar.VariableType == typeof(double))
                        {
                            *fieldValue = ((VsConnectVar <double>)vsVar).Value;
                        }
                        if (vsVar.VariableType == typeof(double[]))
                        {
                            int index = 0;
                            foreach (var value in ((VsConnectVar <double[]>)vsVar).Value)
                            {
                                fieldValue[index] = value;
                                index++;
                            }
                        }
                    }
                }
            }

            return(retRes);
        }