/* ----------------------------------------------------------------------------- This source file is part of OpenSpace3D For the latest info, see http://www.openspace3d.com Copyright (c) 2018 I-maginer This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA, or go to http://www.gnu.org/copyleft/lesser.txt ----------------------------------------------------------------------------- */ var sOS3DMsgSep =";%OS3Dmsg%;";; var sMsgSep = ";%msg%;";; var sKeySep = ";%key%;";; var sObjSep = ";%obj%;";; var iReconInterval = 10000;; var iPingInterval = 4000;; var fPosTolerance = 0.001;; var fQuatTolerance = 0.01;; var fScaleTolerance = 0.0001;; var fMaxInterpolatedDist = 2.0;; //UDP defcom SendUdpPing = GetUdpPing S I;; defcom SendUdpPingBack = GetUdpPingBack;; defcom SendUdpMessage = GetUdpMessage S;; defcom SendUdpConnectMessage = GetUdpConnectMessage S I;; defcom SendUdpUserList = GetUdpUserList S;; defcom SendUdpUserDisconnect = GetUdpUserDisconnect S I;; //TCP defcom SendTcpSrvPing = GetTcpSrvPing;; defcom SendTcpSrvMsg = GetTcpSrvMsg S S;; defcom SendTcpClientPingBack = GetTcpClientPingBack;; defcom SendTcpClientMsg = GetTcpClientMsg S S;; defcom SendObjectsSyncTcpCli = GetObjectsSyncTcpCli S;; proto cbRetryTcpConnection = fun [Timer PlugLocalNetwork] I;; proto cbRetryUdpConnection = fun [Timer PlugLocalNetwork] I;; //Common defcom SendObjectsSync = GetObjectsSync S;; var sTcpCliScript=" fun __GetObjectsSyncTcpCli(msglist)= let switch lLocalNetwork iObId -> obstr in execch thisplug.PLUG_channel @UpdateObjects [obstr msglist]; 0;; fun __GetTcpClientMsg(keyword, msg)= let switch lLocalNetwork iObId -> obstr in ( if (!strcmp \\\"srvPing\\\" keyword) then ( execch thisplug.PLUG_channel @cbSrvPingBack [obstr (atoi msg)]; 0; ) else ( execch thisplug.PLUG_channel @SendPluginEvent [obstr.LNK_inst (strcat keyword \\\" message\\\") msg nil]; 0; ); ); 0;; fun __GetTcpClientPingBack()= let switch lLocalNetwork iObId -> obstr in execch thisplug.PLUG_channel @cbPingBack [obstr]; 0;; fun _connected()= let switch lLocalNetwork iObId -> obstr in ( set obstr.LNK_bState = 1; addLogMessage strcatn (loc \\\"OS3DLOCALNETWORK_0021\\\")::\\\" \\\"::(_channelIP _channel)::\\\":\\\"::(itoa (_channelport _channel))::nil; execch thisplug.PLUG_channel @SendPluginEvent [obstr.LNK_inst \\\"Connected\\\" nil nil]; if (obstr.LNK_trmPing == nil) then nil else _deltimer obstr.LNK_trmPing; set obstr.LNK_trmPing = _rfltimer _starttimer thisplug.PLUG_channel iPingInterval @cbPingTimer obstr; ); 0;; fun _closed()= let switch lLocalNetwork iObId -> obstr in ( addLogMessage strcatn (loc \\\"OS3DLOCALNETWORK_0025\\\")::\\\" \\\"::(_channelIP _channel)::\\\":\\\"::(itoa (_channelport _channel))::nil; set obstr.LNK_TcpServer.TCPS_cClientChan = nil; if (obstr.LNK_trmPing == nil) then nil else ( _deltimer obstr.LNK_trmPing; set obstr.LNK_trmPing = nil; ); if (!obstr.LNK_bState) then nil else execch thisplug.PLUG_channel @SendPluginEvent [obstr.LNK_inst \\\"Disconnected\\\" nil nil]; set obstr.LNK_bState = 0; execch thisplug.PLUG_channel @delayRetryTcpConnection [obstr]; ); 0;; ";; var sTcpSrvScript=" fun _connected()= let switch lLocalNetwork iObId -> obstr in ( set obstr.LNK_TcpServer.TCPS_lUserList = _channel::obstr.LNK_TcpServer.TCPS_lUserList; addLogMessage strcatn (loc \\\"OS3DLOCALNETWORK_0020\\\")::\\\" \\\"::(_channelIP _channel)::\\\":\\\"::(itoa (_channelport _channel))::nil; ); 0;; fun _closed()= addLogMessage strcatn (loc \\\"OS3DLOCALNETWORK_0019\\\")::\\\" \\\"::(_channelIP _channel)::\\\":\\\"::(itoa (_channelport _channel))::nil; let switch lLocalNetwork iObId -> obstr in ( set obstr.LNK_TcpServer.TCPS_lUserList = remove_from_list obstr.LNK_TcpServer.TCPS_lUserList _channel; ); 0;; fun __GetTcpSrvPing()= _on _channel SendTcpClientPingBack []; 0;; //server receive fun __GetTcpSrvMsg(keyword, msg)= //broad to connected clients let switch lLocalNetwork iObId -> obstr in let obstr.LNK_TcpServer.TCPS_lUserList -> userList in while (userList != nil) do ( let (hd userList) -> uchan in if (!obstr.LNK_bEcho && (uchan == _channel)) then nil else ( _on uchan SendTcpClientMsg [keyword msg]; ); set userList = tl userList; ); 0;; //object receive (server side) fun __GetObjectsSync(msglist)= //broad to connected clients let switch lLocalNetwork iObId -> obstr in let obstr.LNK_TcpServer.TCPS_lUserList -> userList in while (userList != nil) do ( let (hd userList) -> uchan in if (uchan == _channel) then nil else ( _on uchan SendObjectsSyncTcpCli [msglist]; ); set userList = tl userList; ); 0;; ";; var sUdpSrvScript=" fun __GetUdpMessage(msg)= let switch lLocalNetwork iObId -> obstr in execch thisplug.PLUG_channel @UnpackUdpMessages [obstr msg]; 0;; fun __GetObjectsSync(msglist)= let switch lLocalNetwork iObId -> obstr in execch thisplug.PLUG_channel @UpdateObjects [obstr msglist]; 0;; fun __GetUdpPing(ip, port)= let switch lLocalNetwork iObId -> obstr in _sendUDP strcatn ip::\\\":\\\"::(itoa port)::nil SendUdpPingBack []; 0;; fun __GetUdpPingBack()= let switch lLocalNetwork iObId -> obstr in execch thisplug.PLUG_channel @cbPingBack [obstr]; 0;; fun __GetUdpConnectMessage(ip, port)= addLogMessage strcatn (loc \\\"OS3DLOCALNETWORK_0020\\\")::\\\" \\\"::ip::\\\":\\\"::(itoa port)::nil; //add user ip + port in list let switch lLocalNetwork iObId -> obstr in ( execch thisplug.PLUG_channel @addUdpUser [obstr ip port]; //send user list back to all clients let packList (if (isUdpUserInList obstr.LNK_UdpServer.UDPS_lUserList _hostIP obstr.LNK_iSrvPort) then obstr.LNK_UdpServer.UDPS_lUserList else ([_hostIP obstr.LNK_iSrvPort]::obstr.LNK_UdpServer.UDPS_lUserList)) \\\"\\\" -> users in let obstr.LNK_UdpServer.UDPS_lUserList -> l in while (l != nil) do ( let hd l -> [ip port] in ( //addLogMessage strcatn \\\"Send ulist to : \\\"::ip::\\\":\\\"::(itoa port)::nil; _sendUDP strcatn ip::\\\":\\\"::(itoa port)::nil SendUdpUserList [users]; ); set l = tl l; ); ); 0;; fun __GetUdpUserDisconnect(ip, port)= let switch lLocalNetwork iObId -> obstr in ( execch thisplug.PLUG_channel @removeUdpUser [obstr ip port]; if ((!strcmp ip obstr.LNK_sDstAddr) && (port == obstr.LNK_iDstport)) then ( addLogMessage strcatn (loc \\\"OS3DLOCALNETWORK_0025\\\")::\\\" \\\"::ip::\\\":\\\"::(itoa port)::nil; //if ((!strcmp ip _hostIP) && (port == obstr.LNK_iSrvPort)) then nil else // reconnect only if we are not the server if ((!strcmp ip _hostIP) && (port == obstr.LNK_iSrvPort)) then nil else execch thisplug.PLUG_channel @delayRetryUdpConnection [obstr]; 0; ) else ( addLogMessage strcatn (loc \\\"OS3DLOCALNETWORK_0019\\\")::\\\" \\\"::ip::\\\":\\\"::(itoa port)::nil; 0; ); ); 0;; fun __GetUdpUserList(users)= let switch lLocalNetwork iObId -> obstr in ( execch thisplug.PLUG_channel @unPackList [users obstr]; if (obstr.LNK_bState) then nil else execch thisplug.PLUG_channel @cbRetryUdpConnection [nil obstr]; ); 0;; ";; struct TcpServer = [ TCPS_sSrvTcp : Srv, TCPS_lUserList : [Chn r1], TCPS_cClientChan : Chn ]mkTcpServer;; struct UdpServer = [ UDPS_lUserList : [[S I] r1], UDPS_cSrvChan : Chn, UDPS_sBuffer : S ]mkUdpServer;; var iObjUpdateReceived = 2;; var iObjUpdateSend = 4;; var iObjUpdatingPos = 8;; var iObjUpdatingOrient = 16;; var iObjUpdatingScale = 32;; var iObjUpdatingVelocity = 64;; var iObjUpdatingOmega = 128;; var iObjUpdateForce = 256;; struct SyncObject = [ SOB_node : SO3_OBJECT, SOB_vPosition : S, SOB_vOrientation : S, SOB_vScale : S, SOB_vtPosition : [F F F], SOB_vtOrientation : [F F F F], SOB_vtScale : [F F F], SOB_vtVelocity : [F F F], SOB_vtOmega : [F F F], SOB_vcPosition : [F F F], SOB_vcOrientation : [F F F F], SOB_vcScale : [F F F], SOB_fPosCoef : F, SOB_fOrientCoef : F, SOB_fScaleCoef : F, SOB_bUpdate : I, SOB_bGlobal : I, SOB_iLocalFlags : I, SOB_iDistFlags : I, SOB_iLastMessTime : I, SOB_iUpdateTick : I, SOB_iLastObTick : I ]mkSyncObject;; struct PlugLocalNetwork = [ LNK_inst : PInstance, LNK_netcom : NetComm, LNK_sDstAddr : S, LNK_iDstport : I, LNK_iSrvPort : I, LNK_iIndex : I, LNK_iProtocol : I, LNK_bEcho : I, LNK_trmConnect : Timer, LNK_TcpServer : TcpServer, LNK_UdpServer : UdpServer, LNK_iMode : I, // 0 = both 1 = send only 2 = receive only LNK_bEnable : I, LNK_bState : I, LNK_iTick : I, LNK_iPingTick : I, LNK_iSendTime : I, LNK_iSendMaxTime : I, LNK_lSyncObject : [[S SyncObject] r1], LNK_trmPing : Timer, LNK_iSrvPingTick : I, LNK_bPingState : I ]mkPlugLocalNetwork;; //let switchstr LNK_lSyncObject name -> obsyncstr in typeof lLocalNetwork = [[I PlugLocalNetwork] r1];; proto sendMessage = fun [PlugLocalNetwork S S] I;; fun SendObjSyncMessageInTcpServer(obstr, msglist)= _on obstr.LNK_TcpServer.TCPS_cClientChan SendObjectsSync [msglist]; 0;; fun SendObjSyncMessageInUdpServer(obstr, msglist)= let obstr.LNK_UdpServer.UDPS_lUserList -> l in while (l != nil) do ( let hd l -> [ip port] in if ((port == obstr.LNK_iSrvPort) && (!strcmp _hostIP ip)) then nil else _sendUDP strcatn ip::":"::(itoa port)::nil SendObjectsSync [msglist]; set l = tl l; ); 0;; fun SendObjSyncMessageInOS3DNetCommServer(obstr, msglist)= netSendBroadMessage obstr.LNK_netcom (strtoweb (strcatn (getPluginInstanceName obstr.LNK_inst)::sOS3DMsgSep::"SyncMessage"::nil)) msglist obstr.LNK_bEcho; 0;; fun SendObjSyncMessage(obstr, msglist)= let zip msglist -> msglist in if (obstr.LNK_iProtocol == 0) then SendObjSyncMessageInTcpServer obstr msglist else if (obstr.LNK_iProtocol == 1) then SendObjSyncMessageInUdpServer obstr msglist else SendObjSyncMessageInOS3DNetCommServer obstr msglist; 0;; fun isParentInList(obstr, obsyncstr)= let SO3ObjectGetParent obsyncstr.SOB_node -> parentnode in let SO3ObjectGetName parentnode -> parentname in let switchstr obstr.LNK_lSyncObject parentname -> parentstr in if (parentstr != nil) then 1 else 0;; fun checkVectorEquality(vec1, vec2, epsilon)= let vec1 -> [vx1 vy1 vz1] in let vec2 -> [vx2 vy2 vz2] in let absf (vx2 -. vx1) -> dx in let absf (vy2 -. vy1) -> dy in let absf (vz2 -. vz1) -> dz in if ((dx <=. epsilon) && (dy <=. epsilon) && (dz <=. epsilon)) then 1 else 0;; fun checkQuatEquality(vec1, vec2, epsilon)= let vec1 -> [vx1 vy1 vz1 vw1] in let vec2 -> [vx2 vy2 vz2 vw2] in let absf (vx2 -. vx1) -> dx in let absf (vy2 -. vy1) -> dy in let absf (vz2 -. vz1) -> dz in let absf (vw2 -. vw1) -> dw in if ((dx <=. epsilon) && (dy <=. epsilon) && (dz <=. epsilon) && (dw <=. epsilon)) then 1 else 0;; fun makePosMessage(pos)= let pos -> [px py pz] in strcatn "\np "::(ftoa px)::" "::(ftoa py)::" "::(ftoa pz)::nil;; fun makeOrientMessage(quat)= let quat -> [qx qy qz qw] in strcatn "\no "::(ftoa qx)::" "::(ftoa qy)::" "::(ftoa qz)::" "::(ftoa qw)::nil;; fun makeScaleMessage(scale)= let scale -> [sx sy sz] in strcatn "\ns "::(ftoa sx)::" "::(ftoa sy)::" "::(ftoa sz)::nil;; fun makeVelMessage(vel)= let vel -> [px py pz] in strcatn "\nv "::(ftoa px)::" "::(ftoa py)::" "::(ftoa pz)::nil;; fun makeOmegaMessage(omega)= let omega -> [px py pz] in strcatn "\nm "::(ftoa px)::" "::(ftoa py)::" "::(ftoa pz)::nil;; fun makeFlagsMessage(flags)= strcatn "\nf "::(itoa flags)::nil;; fun cbPingBack(obstr)= set obstr.LNK_iSendTime = max obstr.LNK_iSendTime (_tickcount - obstr.LNK_iPingTick); set obstr.LNK_iSendMaxTime = max obstr.LNK_iSendMaxTime obstr.LNK_iSendTime; //addLogMessage strcat "Ping time: " itoa obstr.LNK_iSendTime; sendMessage obstr "srvPing" (itoa obstr.LNK_iSendTime); set obstr.LNK_bPingState = 0; 0;; fun cbSrvPingBack(obstr, t)= if ((_tickcount - obstr.LNK_iSrvPingTick) < 10000) then ( set obstr.LNK_iSendMaxTime = max obstr.LNK_iSendMaxTime t; ) else ( set obstr.LNK_iSrvPingTick = _tickcount; set obstr.LNK_iSendMaxTime = max obstr.LNK_iSendTime t; ); //addLogMessage strcat "Max update time: " (itoa obstr.LNK_iSendMaxTime); 0;; fun pingSrv(obstr)= if (obstr.LNK_bPingState) then nil else ( //addLogMessage "Ping!"; set obstr.LNK_bPingState = 1; set obstr.LNK_iPingTick = _tickcount; if (obstr.LNK_iProtocol == 0) then _on obstr.LNK_TcpServer.TCPS_cClientChan SendTcpSrvPing [] else if (obstr.LNK_iProtocol == 1) then _sendUDP strcatn obstr.LNK_sDstAddr::":"::(itoa obstr.LNK_iDstport)::nil SendUdpPing [_hostIP obstr.LNK_iSrvPort] else netSendPrivateMessage obstr.LNK_netcom (netThisUser obstr.LNK_netcom) (strtoweb (strcatn (getPluginInstanceName obstr.LNK_inst)::sOS3DMsgSep::"cliPing"::nil)) "1"; ); 0;; fun getValidBody(obsyncstr)= let SO3SceneNodeGetBody obsyncstr.SOB_node -> body in let SO3BodyGetMassMatrix body -> [mass _] in if ((body != nil) && !((SO3BodyGetType body) & 4) && (mass >. 0.0)) then body else nil;; fun getBodyFlags(node)= let SO3SceneNodeGetBody node -> body in if (body != nil) then SO3BodyGetType body else 0;; fun hasBodyFlags(flags)= (flags & 1) || (flags & 2);; fun UpdateObjects(obstr, msglist)= //addLogMessage strcat "Gets " msglist; //update local objects if (obstr.LNK_iMode == 1) then nil else ( let unzip msglist -> msglist in let strToListSep msglist sObjSep -> lobj in while (lobj != nil) do ( let strextr (hd lobj) -> lobjparam in let switchstr lobjparam "Obj" -> lname in let switchstr lobjparam "p" -> lpos in let switchstr lobjparam "o" -> lorient in let switchstr lobjparam "s" -> lscale in let switchstr lobjparam "v" -> lvelocity in let switchstr lobjparam "m" -> lomega in let switchstr lobjparam "f" -> lflag in let atoi (hd lflag) -> flags in let strcatnSep lname " " -> objname in let switchstr obstr.LNK_lSyncObject objname -> obsyncstr in if (obsyncstr == nil) then nil else ( if ((obsyncstr.SOB_bUpdate & iObjUpdateSend) || ((obsyncstr.SOB_iLocalFlags & iObjUpdateForce) && !(flags & iObjUpdateForce))) then nil else ( if (lpos == nil) then nil else ( let atof (nth_list lpos 0) -> cpx in let atof (nth_list lpos 1) -> cpy in let atof (nth_list lpos 2) -> cpz in let if (obsyncstr.SOB_bGlobal) then SO3ObjectGetGlobalPosition obsyncstr.SOB_node else SO3ObjectGetPosition obsyncstr.SOB_node -> cpos in ( set obsyncstr.SOB_vcPosition = cpos; set obsyncstr.SOB_vtPosition = [cpx cpy cpz]; set obsyncstr.SOB_fPosCoef = 0.0; set obsyncstr.SOB_bUpdate = obsyncstr.SOB_bUpdate | iObjUpdatingPos; ); ); if (lorient == nil) then nil else ( let atof (nth_list lorient 0) -> cox in let atof (nth_list lorient 1) -> coy in let atof (nth_list lorient 2) -> coz in let atof (nth_list lorient 3) -> cow in let if (obsyncstr.SOB_bGlobal) then SO3ObjectGetGlobalOrientation obsyncstr.SOB_node else SO3ObjectGetOrientation obsyncstr.SOB_node -> cquat in ( set obsyncstr.SOB_vcOrientation = cquat; set obsyncstr.SOB_vtOrientation = [cox coy coz cow]; set obsyncstr.SOB_fOrientCoef = 0.0; set obsyncstr.SOB_bUpdate = obsyncstr.SOB_bUpdate | iObjUpdatingOrient; ); ); if (lscale == nil) then nil else ( let atof (nth_list lscale 0) -> csx in let atof (nth_list lscale 1) -> csy in let atof (nth_list lscale 2) -> csz in let if (obsyncstr.SOB_bGlobal) then SO3ObjectGetGlobalScale obsyncstr.SOB_node else SO3ObjectGetScale obsyncstr.SOB_node -> cscale in ( set obsyncstr.SOB_vcScale = cscale; set obsyncstr.SOB_vtScale = [csx csy csz]; set obsyncstr.SOB_fScaleCoef = 0.0; set obsyncstr.SOB_bUpdate = obsyncstr.SOB_bUpdate | iObjUpdatingScale; ); ); if (lvelocity == nil) then nil else ( let atof (nth_list lvelocity 0) -> cvx in let atof (nth_list lvelocity 1) -> cvy in let atof (nth_list lvelocity 2) -> cvz in ( set obsyncstr.SOB_vtVelocity = [cvx cvy cvz]; set obsyncstr.SOB_bUpdate = obsyncstr.SOB_bUpdate | iObjUpdatingVelocity; ); ); if (lomega == nil) then nil else ( let atof (nth_list lomega 0) -> cox in let atof (nth_list lomega 1) -> coy in let atof (nth_list lomega 2) -> coz in ( set obsyncstr.SOB_vtOmega = [cox coy coz]; set obsyncstr.SOB_bUpdate = obsyncstr.SOB_bUpdate | iObjUpdatingOmega; ); ); if (lflag == nil) then nil else ( set obsyncstr.SOB_iDistFlags = flags; if !(flags & iObjUpdateForce) then nil else set obsyncstr.SOB_iLocalFlags = obsyncstr.SOB_iLocalFlags & ~(iObjUpdateForce); ); if (obsyncstr.SOB_iUpdateTick == nil) then nil else ( set obsyncstr.SOB_iLastMessTime = _tickcount - obsyncstr.SOB_iUpdateTick; //addLogMessage strcat "mess time : " (itoa obsyncstr.SOB_iLastMessTime); ); set obsyncstr.SOB_iUpdateTick = _tickcount; set obsyncstr.SOB_bUpdate = obsyncstr.SOB_bUpdate | iObjUpdateReceived; ); ); set lobj = tl lobj; ); ); 0;; fun vecLerp(v1, v2, coef)= let multiplyVectorF v2 [coef coef coef] -> v1t in let multiplyVectorF v1 [(1.0 -. coef) (1.0 -. coef) (1.0 -. coef)] -> v2t in addVectorF v1t v2t;; fun LerpPosition(obsyncstr, ftime, force)= if !(obsyncstr.SOB_bUpdate & iObjUpdatingPos) then nil else ( let if (obsyncstr.SOB_bGlobal) then SO3ObjectGetGlobalPosition obsyncstr.SOB_node else SO3ObjectGetPosition obsyncstr.SOB_node -> cpos in let getValidBody obsyncstr -> body in if (force || (obsyncstr.SOB_fPosCoef +. ftime) >=. 1.0) then ( set obsyncstr.SOB_fPosCoef = 1.0; set obsyncstr.SOB_bUpdate = obsyncstr.SOB_bUpdate & ~(iObjUpdatingPos); if (obsyncstr.SOB_bGlobal) then ( SO3ObjectSetGlobalPosition obsyncstr.SOB_node obsyncstr.SOB_vtPosition; if (body == nil) then nil else ( SO3BodySetVelocity body obsyncstr.SOB_vtVelocity; SO3BodySetOmega body obsyncstr.SOB_vtOmega; SO3BodySetFreeze body ((hasBodyFlags obsyncstr.SOB_iDistFlags) || ((zeroVectorF obsyncstr.SOB_vtVelocity) && (zeroVectorF obsyncstr.SOB_vtOmega))); ); ) else ( SO3ObjectSetPosition obsyncstr.SOB_node obsyncstr.SOB_vtPosition; ); ) else ( set obsyncstr.SOB_fPosCoef = obsyncstr.SOB_fPosCoef +. ftime; let vecLerp obsyncstr.SOB_vcPosition obsyncstr.SOB_vtPosition obsyncstr.SOB_fPosCoef -> dvec in if (obsyncstr.SOB_bGlobal) then ( SO3ObjectSetGlobalPosition obsyncstr.SOB_node dvec; if (body == nil) then nil else ( SO3BodySetVelocity body obsyncstr.SOB_vtVelocity; SO3BodySetOmega body obsyncstr.SOB_vtOmega; SO3BodySetFreeze body ((hasBodyFlags obsyncstr.SOB_iDistFlags) || ((zeroVectorF obsyncstr.SOB_vtVelocity) && (zeroVectorF obsyncstr.SOB_vtOmega))); ); ) else ( SO3ObjectSetPosition obsyncstr.SOB_node dvec; ); ); ); 0;; fun LerpOrientation(obsyncstr, ftime, force)= if !(obsyncstr.SOB_bUpdate & iObjUpdatingOrient) then nil else ( let if (obsyncstr.SOB_bGlobal) then SO3ObjectGetGlobalOrientation obsyncstr.SOB_node else SO3ObjectGetOrientation obsyncstr.SOB_node -> cquat in let getValidBody obsyncstr -> body in if (force || ((obsyncstr.SOB_fOrientCoef +. ftime) >=. 1.0)) then ( set obsyncstr.SOB_fOrientCoef = 1.0; set obsyncstr.SOB_bUpdate = obsyncstr.SOB_bUpdate & ~(iObjUpdatingOrient); if (obsyncstr.SOB_bGlobal) then ( SO3ObjectSetGlobalOrientation obsyncstr.SOB_node obsyncstr.SOB_vtOrientation; if (body == nil) then nil else ( SO3BodySetVelocity body obsyncstr.SOB_vtVelocity; SO3BodySetOmega body obsyncstr.SOB_vtOmega; SO3BodySetFreeze body ((hasBodyFlags obsyncstr.SOB_iDistFlags) || ((zeroVectorF obsyncstr.SOB_vtVelocity) && (zeroVectorF obsyncstr.SOB_vtOmega))); ); ) else ( SO3ObjectSetOrientation obsyncstr.SOB_node obsyncstr.SOB_vtOrientation; ); ) else ( set obsyncstr.SOB_fOrientCoef = obsyncstr.SOB_fOrientCoef +. ftime; let SO3MathsQuatInterpolate obsyncstr.SOB_vcOrientation obsyncstr.SOB_vtOrientation obsyncstr.SOB_fOrientCoef 1 -> dquat in if (obsyncstr.SOB_bGlobal) then ( SO3ObjectSetGlobalOrientation obsyncstr.SOB_node dquat; if (body == nil) then nil else ( SO3BodySetVelocity body obsyncstr.SOB_vtVelocity; SO3BodySetOmega body obsyncstr.SOB_vtOmega; SO3BodySetFreeze body ((hasBodyFlags obsyncstr.SOB_iDistFlags) || ((zeroVectorF obsyncstr.SOB_vtVelocity) && (zeroVectorF obsyncstr.SOB_vtOmega))); ); 0; ) else ( SO3ObjectSetOrientation obsyncstr.SOB_node dquat; ); ); ); 0;; fun LerpScale(obsyncstr, ftime, force)= if !(obsyncstr.SOB_bUpdate & iObjUpdatingScale) then nil else ( let if (obsyncstr.SOB_bGlobal) then SO3ObjectGetGlobalScale obsyncstr.SOB_node else SO3ObjectGetScale obsyncstr.SOB_node -> cscale in let if (hasBodyFlags obsyncstr.SOB_iDistFlags) then nil else getValidBody obsyncstr -> body in if ((obsyncstr.SOB_fScaleCoef +. ftime) >=. 1.0) then ( set obsyncstr.SOB_fScaleCoef = 1.0; set obsyncstr.SOB_bUpdate = obsyncstr.SOB_bUpdate & ~(iObjUpdatingScale); if (obsyncstr.SOB_bGlobal) then ( SO3ObjectSetGlobalScale obsyncstr.SOB_node obsyncstr.SOB_vtScale; ) else ( SO3ObjectSetScale obsyncstr.SOB_node obsyncstr.SOB_vtScale; ); if ((body == nil) || !force) then nil else ( SO3BodySetVelocity body [0.0 0.0 0.0]; SO3BodySetOmega body [0.0 0.0 0.0]; SO3BodySetFreeze body 1; ); ) else ( set obsyncstr.SOB_fScaleCoef = obsyncstr.SOB_fScaleCoef +. ftime; let vecLerp obsyncstr.SOB_vcScale obsyncstr.SOB_vtScale obsyncstr.SOB_fScaleCoef -> dvec in if (obsyncstr.SOB_bGlobal) then ( SO3ObjectSetGlobalScale obsyncstr.SOB_node dvec; ) else ( SO3ObjectSetScale obsyncstr.SOB_node dvec; ); ); ); 0;; fun cbObjSyncPreRender(inst, sessionstr, etime, obstr)= //check changes in obj list and format the sync message let obstr.LNK_lSyncObject -> lsyncobjext in let itof (max 1 (etime / 1000)) -> rtime in // send message slowly to prevent java server to saturate let if (obstr.LNK_iProtocol == 2) then max obstr.LNK_iSendMaxTime 90 else max obstr.LNK_iSendMaxTime 33 -> mint in let if (((obstr.LNK_iTick + etime) / 1000) < mint) then 0 else 1 -> nupdate in let "" -> msglist in ( set obstr.LNK_iTick = obstr.LNK_iTick + etime; if (!nupdate) then nil else set obstr.LNK_iTick = 0; while (lsyncobjext != nil) do ( let hd lsyncobjext -> [name obsyncstr] in let getValidBody obsyncstr -> body in let (getBodyFlags obsyncstr.SOB_node) | (if (obsyncstr.SOB_iLocalFlags & iObjUpdateForce) then iObjUpdateForce else 0) -> flags in let obsyncstr.SOB_node -> node in //let if ((obsyncstr.SOB_iLastObTick == 0) || ((_tickcount - obsyncstr.SOB_iLastObTick) > 33) || (hasBodyFlags flags)) then 1 else 0 -> netupdate in ( set obsyncstr.SOB_bUpdate = obsyncstr.SOB_bUpdate & ~(iObjUpdateSend); // if the move between the local is bigger than distant then update local if ((((obsyncstr.SOB_bUpdate & iObjUpdateReceived) && (obstr.LNK_iMode != 1)) || (obsyncstr.SOB_bUpdate & iObjUpdatingPos) || (obsyncstr.SOB_bUpdate & iObjUpdatingOrient) || (obsyncstr.SOB_bUpdate & iObjUpdatingScale)) && (!(hasBodyFlags flags) && !(flags & iObjUpdateForce))) then //force synchnronise object to be at the last recieved (position, orientation, scale). Avoid bug due to physics for the receiver ( let if (obsyncstr.SOB_bGlobal) then SO3ObjectGetGlobalPosition obsyncstr.SOB_node else SO3ObjectGetPosition obsyncstr.SOB_node -> cpos in let getVectorDistanceF cpos obsyncstr.SOB_vtPosition -> cdist in let if (obsyncstr.SOB_iLastMessTime == 0) then rtime else (itof obsyncstr.SOB_iLastMessTime) -> mtime in let 1.0 /. (mtime /. rtime) -> ftime in let if ((body != nil) && (cdist >=. fMaxInterpolatedDist)) then 1 else 0 -> force in ( //if (ftime == 1.0) then nil else //addLogMessage strcatn "tm : "::(ftoa mtime)::" "::(ftoa rtime)::" > "::(ftoa ftime)::nil; LerpPosition obsyncstr ftime force; LerpOrientation obsyncstr ftime force; LerpScale obsyncstr ftime force; //set obsyncstr.SOB_iLastObTick = _tickcount; ); ) else if (!nupdate /*|| !netupdate*/ || (obstr.LNK_iMode == 2)) then nil else ( let if (obsyncstr.SOB_bGlobal) then SO3ObjectGetGlobalPosition node else SO3ObjectGetPosition node -> cpos in let checkVectorEquality obsyncstr.SOB_vtPosition cpos fPosTolerance -> mpos in let if (obsyncstr.SOB_bGlobal) then SO3ObjectGetGlobalOrientation node else SO3ObjectGetOrientation node -> cquat in let checkQuatEquality obsyncstr.SOB_vtOrientation cquat fQuatTolerance -> mquat in let if (obsyncstr.SOB_bGlobal) then SO3ObjectGetGlobalScale node else SO3ObjectGetScale node -> cscale in let checkVectorEquality obsyncstr.SOB_vtScale cscale fScaleTolerance -> mscale in ( let hasBodyFlags flags -> bforce in if (mpos && mquat && mscale && (flags == obsyncstr.SOB_iLocalFlags) && (!bforce)) then nil else ( set msglist = strcatn msglist::"Obj "::name::nil; if (mpos && (!bforce)) then nil else ( set msglist = strcat msglist (makePosMessage cpos); set obsyncstr.SOB_vtPosition = cpos; set obsyncstr.SOB_vcPosition = cpos; if (body == nil) then nil else let SO3BodyGetVelocity body -> vel in ( set msglist = strcat msglist (makeVelMessage vel); set obsyncstr.SOB_vtVelocity = [0.0 0.0 0.0]; ); ); if (mquat && (!bforce)) then nil else ( set msglist = strcat msglist (makeOrientMessage cquat); set obsyncstr.SOB_vtOrientation = cquat; set obsyncstr.SOB_vcOrientation = cquat; if (body == nil) then nil else let SO3BodyGetOmega body -> omega in ( set msglist = strcat msglist (makeOmegaMessage omega); set obsyncstr.SOB_vtOmega = [0.0 0.0 0.0]; ); ); if (mscale) then nil else ( set msglist = strcat msglist (makeScaleMessage cscale); set obsyncstr.SOB_vtScale = cscale; set obsyncstr.SOB_vcScale = cscale; ); if (flags == obsyncstr.SOB_iLocalFlags) then nil else ( set obsyncstr.SOB_iLocalFlags = flags; set msglist = strcat msglist (makeFlagsMessage flags); ); set msglist = strcat msglist sObjSep; set obsyncstr.SOB_bUpdate = obsyncstr.SOB_bUpdate | iObjUpdateSend; //set obsyncstr.SOB_iUpdateTick = _tickcount; ); set obsyncstr.SOB_bUpdate = obsyncstr.SOB_bUpdate & ~(iObjUpdatingPos); set obsyncstr.SOB_bUpdate = obsyncstr.SOB_bUpdate & ~(iObjUpdatingOrient); set obsyncstr.SOB_bUpdate = obsyncstr.SOB_bUpdate & ~(iObjUpdatingScale); ); ); /*if ((obsyncstr.SOB_bUpdate & iObjUpdatingPos) || (obsyncstr.SOB_bUpdate & iObjUpdatingOrient) || (obsyncstr.SOB_bUpdate & iObjUpdatingScale) || (!(obsyncstr.SOB_bUpdate & iObjUpdateSend) && !(obsyncstr.SOB_bUpdate & iObjUpdateReceived)) || ((obsyncstr.SOB_iUpdateTick != nil) && ((_tickcount - obsyncstr.SOB_iUpdateTick) < 250))) then nil else ( set obsyncstr.SOB_iUpdateTick = nil; );*/ set obsyncstr.SOB_bUpdate = obsyncstr.SOB_bUpdate & ~(iObjUpdateReceived); ); set lsyncobjext = tl lsyncobjext; ); if ((obstr.LNK_iMode == 2) || !strcmp msglist "") then nil else ( SendObjSyncMessage obstr msglist; ); ); 0;; fun cbPingTimer(trm, obstr)= execch thisplug.PLUG_channel @pingSrv [obstr]; //_deltimer trm; //set obstr.LNK_trmPing = nil; 0;; fun packList(l, out)= if (l == nil) then out else ( let hd l -> [ip port] in set out = strcatn out::ip::" "::(itoa port)::"\n"::nil; packList (tl l) out; );; fun unPackList(str, obstr)= set obstr.LNK_UdpServer.UDPS_lUserList = nil; let strextr str -> l in while (l != nil) do ( let hd l -> lu in let hd lu -> ip in let atoi (hd tl lu) -> port in set obstr.LNK_UdpServer.UDPS_lUserList = [ip port]::obstr.LNK_UdpServer.UDPS_lUserList; set l = tl l; ); 0;; fun isUdpUserInList(l, ip, port)= if (l==nil) then 0 else let l -> [a nxt] in let a -> [uip uport] in if (!strcmp uip ip) && (uport == port) then 1 else isUdpUserInList nxt ip port;; fun removeUdpUserFromList(obstr, l, ip, port)= if (l==nil) then nil else let l -> [a nxt] in let a -> [uip uport] in if (!strcmp uip ip) && (uport == port) then nxt else a::removeUdpUserFromList obstr nxt ip port;; fun addUdpUser(obstr, ip, port)= set obstr.LNK_UdpServer.UDPS_lUserList = [ip port]::(removeUdpUserFromList obstr obstr.LNK_UdpServer.UDPS_lUserList ip port); 0;; fun removeUdpUser(obstr, ip, port)= set obstr.LNK_UdpServer.UDPS_lUserList = removeUdpUserFromList obstr obstr.LNK_UdpServer.UDPS_lUserList ip port; 0;; fun SendMessageInTcpServer(obstr, keyword, param)= _on obstr.LNK_TcpServer.TCPS_cClientChan SendTcpSrvMsg [keyword param]; 0;; fun SendMessageInUpdServer(obstr, param)= let obstr.LNK_UdpServer.UDPS_lUserList -> l in while (l != nil) do ( let hd l -> [ip port] in if ((port == obstr.LNK_iSrvPort) && (!strcmp _hostIP ip) && (!obstr.LNK_bEcho)) then nil else _sendUDP strcatn ip::":"::(itoa port)::nil SendUdpMessage [param]; set l = tl l; ); 0;; fun UnpackUdpMessages(obstr, mess)= let strToListSep mess sMsgSep -> lmess in while (lmess != nil) do ( let strToListSep (hd lmess) sKeySep -> [keyword [msg _]] in if (!strcmp "srvPing" keyword) then ( execch thisplug.PLUG_channel @cbSrvPingBack [obstr (atoi msg)]; 0; ) else ( SendPluginEvent obstr.LNK_inst (strcat keyword " message") msg nil; 0; ); set lmess = tl lmess; ); 0;; fun AddUdpMessageBuffer(obstr, keyword, mess)= set obstr.LNK_UdpServer.UDPS_sBuffer = strcatn obstr.LNK_UdpServer.UDPS_sBuffer::keyword::sKeySep::mess::sMsgSep::nil; 0;; fun cbUdpPreRender(inst, sessionstr, etime, obstr)= if ((obstr.LNK_UdpServer.UDPS_sBuffer == nil) || (!strcmp obstr.LNK_UdpServer.UDPS_sBuffer "")) then nil else ( SendMessageInUpdServer obstr obstr.LNK_UdpServer.UDPS_sBuffer; set obstr.LNK_UdpServer.UDPS_sBuffer = ""; ); 0;; fun cbRetryUdpConnection(trm, obstr)= if (obstr.LNK_UdpServer.UDPS_lUserList != nil) then ( if (obstr.LNK_trmConnect == nil) then nil else ( _deltimer obstr.LNK_trmConnect; set obstr.LNK_trmConnect = nil; ); if (obstr.LNK_trmPing == nil) then nil else ( _deltimer obstr.LNK_trmPing; set obstr.LNK_trmPing = nil; ); SendPluginEvent obstr.LNK_inst "Connected" nil nil; set obstr.LNK_bState = 1; addLogMessage strcatn (loc "OS3DLOCALNETWORK_0014")::" "::obstr.LNK_sDstAddr::":"::(itoa obstr.LNK_iDstport)::nil; set obstr.LNK_trmPing = _rfltimer _starttimer _channel iPingInterval @cbPingTimer obstr; 0; ) else ( addLogMessage strcatn (loc "OS3DLOCALNETWORK_0018")::" "::obstr.LNK_sDstAddr::":"::(itoa obstr.LNK_iDstport)::nil; _sendUDP strcatn obstr.LNK_sDstAddr::":"::(itoa obstr.LNK_iDstport)::nil SendUdpConnectMessage [_hostIP obstr.LNK_iSrvPort]; 0; ); 0;; fun delayRetryUdpConnection(obstr)= if (obstr.LNK_trmConnect == nil) then nil else ( _deltimer obstr.LNK_trmConnect; set obstr.LNK_trmConnect = nil; ); if (obstr.LNK_trmPing == nil) then nil else ( _deltimer obstr.LNK_trmPing; set obstr.LNK_trmPing = nil; ); if (!obstr.LNK_bEnable) then nil else ( if (!obstr.LNK_bState) then nil else SendPluginEvent obstr.LNK_inst "Disconnected" nil nil; set obstr.LNK_bState = 0; set obstr.LNK_UdpServer.UDPS_lUserList = nil; cbRetryUdpConnection nil obstr; set obstr.LNK_trmConnect = _rfltimer _starttimer thisplug.PLUG_channel iReconInterval @cbRetryUdpConnection obstr; ); 0;; fun createUpdServer(obstr)= let strcatn "_loadS \""::"var iObId = "::(itoa obstr.LNK_iIndex)::";;\n"::sUdpSrvScript::"\""::nil -> netscript in let _setUDP (_envchannel thisplug.PLUG_channel) obstr.LNK_iSrvPort netscript -> newchan in ( while (newchan == nil) do ( set obstr.LNK_iSrvPort = obstr.LNK_iSrvPort + 1; set newchan = _setUDP (_envchannel thisplug.PLUG_channel) obstr.LNK_iSrvPort netscript; ); set obstr.LNK_UdpServer = mkUdpServer [nil newchan ""]; addLogMessage strcatn (loc "OS3DLOCALNETWORK_0017")::" "::_hostIP::":"::(itoa obstr.LNK_iSrvPort)::nil; ); addLogMessage strcatn (loc "OS3DLOCALNETWORK_0016")::" "::obstr.LNK_sDstAddr::":"::(itoa obstr.LNK_iDstport)::nil; _sendUDP strcatn obstr.LNK_sDstAddr::":"::(itoa obstr.LNK_iDstport)::nil SendUdpConnectMessage [_hostIP obstr.LNK_iSrvPort]; set obstr.LNK_trmConnect = _rfltimer _starttimer thisplug.PLUG_channel iReconInterval @cbRetryUdpConnection obstr; setPluginInstanceCbScenePreRender obstr.LNK_inst mkfun4 @cbUdpPreRender obstr; 0;; fun cbRetryTcpConnection(trm, obstr)= if (obstr.LNK_trmConnect == nil) then nil else ( _deltimer obstr.LNK_trmConnect; set obstr.LNK_trmConnect = nil; ); if (obstr.LNK_trmPing == nil) then nil else ( _deltimer obstr.LNK_trmPing; set obstr.LNK_trmPing = nil; ); if (obstr.LNK_TcpServer.TCPS_cClientChan != nil) then nil else ( let strcatn "_loadS \""::"var iObId = "::(itoa obstr.LNK_iIndex)::";;\n"::sTcpCliScript::"\""::nil -> cliscript in set obstr.LNK_TcpServer.TCPS_cClientChan = _openchannel strcatn obstr.LNK_sDstAddr::":"::(itoa obstr.LNK_iDstport)::nil cliscript (_envchannel thisplug.PLUG_channel); ); 0;; fun delayRetryTcpConnection(obstr)= if (!obstr.LNK_bEnable) then nil else ( addLogMessage strcatn (loc "OS3DLOCALNETWORK_0015")::" "::obstr.LNK_sDstAddr::":"::(itoa obstr.LNK_iDstport)::" "::(loc "OS3DLOCALNETWORK_0024")::nil; set obstr.LNK_trmConnect = _rfltimer _starttimer thisplug.PLUG_channel iReconInterval @cbRetryTcpConnection obstr; ); 0;; fun createTcpServer(obstr)= let strcatn "_loadS \""::"var iObId = "::(itoa obstr.LNK_iIndex)::";;\n"::sTcpSrvScript::"\""::nil -> netscript in let _setserver (_envchannel thisplug.PLUG_channel) obstr.LNK_iSrvPort netscript -> srvTcp in ( if (srvTcp != nil) then ( addLogMessage strcatn (loc "OS3DLOCALNETWORK_0023")::" "::obstr.LNK_sDstAddr::":"::(itoa obstr.LNK_iDstport)::nil; ) else ( addLogMessage strcatn (loc "OS3DLOCALNETWORK_0022")::" "::(itoa obstr.LNK_iDstport)::nil; ); set obstr.LNK_TcpServer = mkTcpServer [srvTcp nil nil]; cbRetryTcpConnection nil obstr; ); 0;; fun createServer(obstr)= if (obstr.LNK_trmConnect == nil) then nil else ( _deltimer obstr.LNK_trmConnect; set obstr.LNK_trmConnect = nil; ); set lLocalNetwork = [obstr.LNK_iIndex obstr]::lLocalNetwork; if (!obstr.LNK_iProtocol) then ( if (obstr.LNK_UdpServer != nil) then nil else createTcpServer obstr; ) else ( if (obstr.LNK_TcpServer != nil) then nil else createUpdServer obstr; );; fun deleteUpdServer(obstr)= setPluginInstanceCbScenePreRender obstr.LNK_inst nil; set obstr.LNK_UdpServer.UDPS_sBuffer = ""; //send disconnect message to all other cliens let obstr.LNK_UdpServer.UDPS_lUserList -> l in while (l != nil) do ( let hd l -> [ip port] in if ((port == obstr.LNK_iSrvPort) && (!strcmp _hostIP ip)) then nil else _sendUDP strcatn ip::":"::(itoa port)::nil SendUdpUserDisconnect [_hostIP obstr.LNK_iSrvPort]; set l = tl l; ); _killchannel obstr.LNK_UdpServer.UDPS_cSrvChan; set obstr.LNK_UdpServer = nil; 0;; fun deleteTcpServer(obstr)= while (obstr.LNK_TcpServer.TCPS_lUserList != nil) do ( _killchannel (hd obstr.LNK_TcpServer.TCPS_lUserList); set obstr.LNK_TcpServer.TCPS_lUserList = tl obstr.LNK_TcpServer.TCPS_lUserList; ); _killchannel obstr.LNK_TcpServer.TCPS_cClientChan; _closeserver obstr.LNK_TcpServer.TCPS_sSrvTcp; set obstr.LNK_TcpServer = nil; 0;; fun deleteServer(obstr)= if (obstr.LNK_trmConnect == nil) then nil else ( _deltimer obstr.LNK_trmConnect; set obstr.LNK_trmConnect = nil; ); if (obstr.LNK_trmPing == nil) then nil else ( _deltimer obstr.LNK_trmPing; set obstr.LNK_trmPing = nil; ); if (obstr.LNK_TcpServer == nil) then nil else deleteTcpServer obstr; if (obstr.LNK_UdpServer == nil) then nil else deleteUpdServer obstr; if (!obstr.LNK_bState) then nil else SendPluginEvent obstr.LNK_inst "Disconnected" nil nil; set obstr.LNK_bState = 0; 0;; fun SendMessageInNetcommServer(obstr, keyword, param)= //addLogMessage strcat "send OD3Dnetcomm msg " param; netSendBroadMessage obstr.LNK_netcom (strtoweb (strcatn (getPluginInstanceName obstr.LNK_inst)::sOS3DMsgSep::keyword::nil)) param obstr.LNK_bEcho; 0;; fun sendMessage(obstr, keyword, param)= if (obstr.LNK_iProtocol == 0) then SendMessageInTcpServer obstr keyword param else if (obstr.LNK_iProtocol == 1) then AddUdpMessageBuffer obstr keyword param else SendMessageInNetcommServer obstr keyword param; 0;; fun cbSendMessage(inst, from, action, param, rep, obstr, keyword)= sendMessage obstr keyword param; 0;; fun cbRecievedPrivateNetcomMsg(inst, netstr, userstr, cmd, message, arg, obstr)= let strToListSep (webtostr cmd) sOS3DMsgSep -> lcmd in let hd lcmd -> instancename in let hd (tl lcmd) -> param in ( if (strcmp instancename (getPluginInstanceName inst)) then nil else ( if (!strcmp "cliPing" param) then ( execch thisplug.PLUG_channel @cbPingBack [obstr]; 0; ); ); );; fun cbRecievedNetcomMsg(inst, netstr, userstr, cmd, message, arg, obstr)= let strToListSep (webtostr cmd) sOS3DMsgSep -> lcmd in let hd lcmd -> instancename in let hd (tl lcmd) -> param in ( if (strcmp instancename (getPluginInstanceName inst)) then nil else ( if (!strcmp param "SyncMessage") then ( execch thisplug.PLUG_channel @UpdateObjects [obstr message]; 0; ) else if (!strcmp "srvPing" param) then ( execch thisplug.PLUG_channel @cbSrvPingBack [obstr (atoi message)]; 0; ) else ( execch thisplug.PLUG_channel @SendPluginEvent [obstr.LNK_inst (strcat param " message") message nil]; 0; ); ); );; fun cbEnable(inst, from, action, param, rep, obstr)= set obstr.LNK_bEnable = 1; if (obstr.LNK_iProtocol == 2) then ( setPluginInstanceCbNetUserMessage inst mkfun7 @cbRecievedNetcomMsg obstr; setPluginInstanceCbNetUserPrivateMessage inst mkfun7 @cbRecievedPrivateNetcomMsg obstr; set obstr.LNK_trmPing = _rfltimer _starttimer _channel iPingInterval @cbPingTimer obstr; 0; ) else ( createServer obstr; 0; ); if (obstr.LNK_lSyncObject == nil) then nil else ( setPluginInstanceCbScenePreRender2 obstr.LNK_inst mkfun4 @cbObjSyncPreRender obstr; ); 0;; fun cbDisable(inst, from, action, param, rep, obstr)= set obstr.LNK_bEnable = 0; setPluginInstanceCbScenePreRender2 obstr.LNK_inst nil; deleteServer obstr; setPluginInstanceCbNetUserMessage inst nil; setPluginInstanceCbNetUserPrivateMessage inst nil; remove_idx_from_list lLocalNetwork obstr.LNK_iIndex; 0;; fun cbChangeHostAddr(inst, from, action, param, rep, obstr)= let strToListSep param ":" -> [ip [port _]] in let (atoi port) -> port in if (ip == nil || port == nil) then nil else ( set obstr.LNK_bEnable = 0; if (obstr.LNK_trmConnect == nil) then nil else ( _deltimer obstr.LNK_trmConnect; set obstr.LNK_trmConnect = nil; ); if (obstr.LNK_trmPing == nil) then nil else ( _deltimer obstr.LNK_trmPing; set obstr.LNK_trmPing = nil; ); set obstr.LNK_sDstAddr = ip; set obstr.LNK_iDstport = port; if (obstr.LNK_TcpServer != nil) then ( _killchannel obstr.LNK_TcpServer.TCPS_cClientChan; if (!obstr.LNK_bState) then nil else SendPluginEvent obstr.LNK_inst "Disconnected" nil nil; set obstr.LNK_bState = 0; set obstr.LNK_TcpServer.TCPS_cClientChan = nil; set obstr.LNK_bEnable = 1; cbRetryTcpConnection nil obstr; 0; ) else if (obstr.LNK_UdpServer != nil) then ( // send disconnect message to all other clients let obstr.LNK_UdpServer.UDPS_lUserList -> l in while (obstr.LNK_UdpServer.UDPS_lUserList != nil) do ( let hd obstr.LNK_UdpServer.UDPS_lUserList -> [ip port] in _sendUDP strcatn ip::":"::(itoa port)::nil SendUdpUserDisconnect [_hostIP obstr.LNK_iSrvPort]; set obstr.LNK_UdpServer.UDPS_lUserList = tl obstr.LNK_UdpServer.UDPS_lUserList; ); if (!obstr.LNK_bState) then nil else SendPluginEvent obstr.LNK_inst "Disconnected" nil nil; set obstr.LNK_bState = 0; set obstr.LNK_bEnable = 1; set obstr.LNK_UdpServer.UDPS_sBuffer = ""; _sendUDP strcatn obstr.LNK_sDstAddr::":"::(itoa obstr.LNK_iDstport)::nil SendUdpConnectMessage [_hostIP obstr.LNK_iSrvPort]; set obstr.LNK_trmConnect = _rfltimer _starttimer thisplug.PLUG_channel iReconInterval @cbRetryUdpConnection obstr; 0; ) else nil; ); 0;; fun deleteOb(inst, obstr)= cbDisable inst nil nil nil nil obstr; 0;; fun cbChangeCamera(inst, viewstr, sessionstr, camera, obstr)= if (obstr.LNK_lSyncObject == nil) then nil else ( let switchstr obstr.LNK_lSyncObject "Current camera" -> obsyncstr in if (obsyncstr == nil) then nil else set obsyncstr.SOB_node = V3DgetObjectByName c3dXsession "Current camera"; let switchstr obstr.LNK_lSyncObject "Current camera shell" -> obsyncstr in if (obsyncstr == nil) then nil else set obsyncstr.SOB_node = V3DgetObjectByName c3dXsession "Current camera shell" ; ); 0;; fun LoadSelectedList(obstr)= let SO3ObjectGetSceneRoot (V3DgetSession c3dXsession) -> rootnode in let nil -> elem in let 0 -> i in ( while ((set elem = (getPluginInstanceParam obstr.LNK_inst (strcat "node_" (itoa i)))) != nil) do ( let V3DgetObjectByName c3dXsession elem -> node in ( if (node == nil) then nil else ( set obstr.LNK_lSyncObject = [elem mkSyncObject[node nil nil nil nil nil nil nil nil nil nil nil 0.0 0.0 0.0 0 1 (getBodyFlags node) 0 0 nil 0]]::obstr.LNK_lSyncObject; /* if (strcmp elem "Current camera") then nil else ( while(((set node = SO3ObjectGetParent node) != nil) && (node != rootnode)) do set obstr.LNK_lSyncObject = [(SO3ObjectGetName node) mkSyncObject[node nil nil nil nil nil nil 0 0 0]]::obstr.LNK_lSyncObject; ); */ ); ); set i = i + 1; ); ); if (obstr.LNK_lSyncObject == nil) then nil else ( let obstr.LNK_lSyncObject -> lobjectstr in ( while (lobjectstr != nil) do ( let hd lobjectstr -> [name objectstr] in let isParentInList obstr objectstr -> found in ( let getValidBody objectstr -> body in let if (body == nil) && found then SO3ObjectGetPosition objectstr.SOB_node else SO3ObjectGetGlobalPosition objectstr.SOB_node -> pos in let if (body == nil) && found then SO3ObjectGetOrientation objectstr.SOB_node else SO3ObjectGetGlobalOrientation objectstr.SOB_node -> quat in let if (body == nil) && found then SO3ObjectGetScale objectstr.SOB_node else SO3ObjectGetGlobalScale objectstr.SOB_node -> scale in ( set objectstr.SOB_vcPosition = pos; set objectstr.SOB_vcOrientation = quat; set objectstr.SOB_vcScale = scale; set objectstr.SOB_vtPosition = pos; set objectstr.SOB_vtOrientation = quat; set objectstr.SOB_vtScale = scale; set objectstr.SOB_iLocalFlags = getBodyFlags objectstr.SOB_node; set objectstr.SOB_bGlobal = !((body == nil) && found); ); ); set lobjectstr = tl lobjectstr; ); ); setPluginInstanceCbCameraChange obstr.LNK_inst mkfun5 @cbChangeCamera obstr; ); 0;; fun cbPhysicsGeneric(inst, type, value, param, obstr)= let switchstr obstr.LNK_lSyncObject value -> obsyncstr1 in let strextr param -> lparam in let strcatnSep hd lparam " " -> second in let switchstr obstr.LNK_lSyncObject second -> obsyncstr2 in if (!hasBodyFlags obsyncstr1.SOB_iLocalFlags) && (!hasBodyFlags obsyncstr2.SOB_iLocalFlags) then nil else ( if (type == 16) then // "Ray intersect in" 0 else if (type == 17) then // "Ray intersect out" 0 else if (type == 18) then // "Contact" ( set obsyncstr1.SOB_iLocalFlags = obsyncstr1.SOB_iLocalFlags | iObjUpdateForce; set obsyncstr2.SOB_iLocalFlags = obsyncstr2.SOB_iLocalFlags | iObjUpdateForce; 0; ) else if (type == 19) then // "Overlap started" 0 else if (type == 20) then // "Overlap stopped" 0 else if (type == 21) then // "Grabed" 0 else if (type == 22) then // "Ungrabed" 0 else nil; ); 0;; fun cbLoaded(inst, obstr, init)= LoadSelectedList obstr; if !init then nil else cbEnable inst nil nil nil nil obstr; 0;; fun newOb(inst)= let (getPluginInstanceParam inst "dstaddress") -> dstaddress in let atoi (getPluginInstanceParam inst "dstport") -> dstport in let atoi (getPluginInstanceParam inst "srvport") -> srvport in let atoi (getPluginInstanceParam inst "isprotocol") -> isprotocol in let atoi (getPluginInstanceParam inst "ismode") -> ismode in let atoi (getPluginInstanceParam inst "init") -> init in let atoi (getPluginInstanceParam inst "echo") -> isecho in let getPluginInstanceUserEvents inst -> levent in let if (isprotocol == 2) then netcomOS3D else nil -> netcom in let mkPlugLocalNetwork [inst netcom dstaddress dstport srvport dstport isprotocol isecho nil nil nil ismode 0 0 0 0 0 200 nil nil 0 0] -> obstr in ( while (levent != nil) do ( let hd levent -> evt in let strToWordList evt -> line in let strcatnSep (revertlist tl (revertlist line)) " " -> keyword in PluginRegisterAction inst (strcat "Send " keyword) mkfun6 mkfun7 @cbSendMessage keyword obstr; set levent = tl levent; ); if inst.INST_groupstr.GRP_project.PRJ_bPluginsLoaded then ( cbLoaded inst obstr init; 0; ) else ( setPluginInstanceCbAllPluginsLoaded inst mkfun2 mkfun3 @cbLoaded init obstr; 0; ); PluginRegisterAction inst "Enable" mkfun6 @cbEnable obstr; PluginRegisterAction inst "Disable" mkfun6 @cbDisable obstr; if (isprotocol == 2) then nil else PluginRegisterAction inst "Change connection address" mkfun6 @cbChangeHostAddr obstr; setPluginInstanceCbGeneric inst mkfun5 @cbPhysicsGeneric obstr; setPluginInstanceCbDel inst mkfun2 @deleteOb obstr; ); 0;; fun IniPlug(file)= PlugRegister @newOb nil; setPluginEditor @dynamicedit; 0;;