Trajectory2 1.2 - by Bob Le Gob ******************************* Update from v1.1 1) Fixing the non operational srvAutoStart feature ************************************************** The main explanation of the problem lies in the server part of the original Trajectory plugin: trajs.pkg fun newOb(o)= UcbComm this ObUi o mkfun5 @cbcomm [(ObName o) 0 0]; ObRegisterAction o (strcatn (ObName o)::".playonceS"::nil) mkfun7 @activate [(ObName o) 0 0]; ObRegisterAction o (strcatn (ObName o)::".playloopS"::nil) mkfun7 @activate [(ObName o) 0 0]; ObRegisterAction o (strcatn (ObName o)::".stopS"::nil) mkfun7 @activate [(ObName o) 0 0]; 0;; The proper coding should have been: fun newOb(o)= let [(ObName o) 0 0] -> a in ( UcbComm this ObUi o mkfun5 @cbcomm a; ObRegisterAction o (strcatn (ObName o)::".playonceS"::nil) mkfun7 @activate a; ObRegisterAction o (strcatn (ObName o)::".playloopS"::nil) mkfun7 @activate a; ObRegisterAction o (strcatn (ObName o)::".stopS"::nil) mkfun7 @activate a; ); 0;; Simply changing this solves the main problem. In the original coding, we work with four different variables that have no link with each other. In the new coding, we only have one single variable "shared" for all actions. This will allow the srvAutoStart functionality to work. 2) Modifying the srvAutoStart a little bit further ************************************************** - The original version takes three possibilities into account for the srvAutoStart: - playonce - playloop - stop But there's another possibility: maybe the server never triggered an action. And if this is the case, we shouldn't get any conflict with an existing local autostart on clients. In the original code, not triggering an action is like having triggered the stop action, thus stopping any started autostart on new clients. In the original code, the tracking of the actions was performed in the following tuple: [ObName playFlag playOnceFlag] In the new code, it's handled in this one: [ObName playFlag playOnceFlag srvActionFlag timerPeriod timer] The most important right now is the 'srvActionFlag'. This one is set only if the server triggered one of its actions. When a new client connects, he now has the possibility to get a 'noaction' message. Parallel to this, the client local autostart starts only after getting this message from the server, which will allow to avoid conflicts. To implement this on client, a TAinit field has been added to the TrajAnim structure which stores the local autostart option until we get the message from the server. Modifications have thus been added in the client code part: - in newOb(), for the structure creation. - in cbcomm(), to handle the 'noaction' message. - The other modification I added in the code is a timer for the 'playonceS' server action. My point of view is that the server should trigger only 'playloopS' or 'stopS' actions for long term purpose, regarding the possible conflicts with local autostarts. The above tuple includes a 'timerPeriod' as well as a 'timer' fields. - timerPeriod: when starting, the server estimates how long a 'playonce' action will last, depending on the trajectory size and the framerate. cf newOb(). - timer: this field is set only when the server triggers a 'playonceS' action. It's reseted to nil each time the server triggers a server action. It's reseted to nil when the server estimates that the delay to run the 'playonce' actions have been played on clients. Three functions handle the timer behaviour: - ResetTimer() - StartTimer() - cbTick() - the timer's callback You can have a look at the activate() function to see how and when these functions are called. How does that help ? Imagine you trigger a 30 seconds trajectory through a playonceS action. All new clients with defined local autostart connecting during these 30 secs will get a 'playonce' action instead of the autostart. The ones connecting after the 30 secs (and thus after the temporary and now lost event that triggered the server action) will get their normal defined autostart action. 3) Code changes *************** Global: - All functions have been documented in the code. Server part: - Functions names changes: - IniPlug() -> unchanged - newOb() -> cbNewOb() - cbcomm() -> cbComm() - activate() -> cbActivate() - New functions: - ResetTimer() - StartTimer() - cbTick() - Variables changes: - cbComm(): - playstop -> playFlag - more logical when you see what this variable is used for - onceloop -> playOnceFlag - more logical when you see what this variable is used for - Nothing else special, critical or incomprehensible beyond what has been explained above. Client part: - Functions names changes: - IniPlug() -> unchanged - newOb() -> cbNewOb() - FrameEventList() -> unchanged - InsertFrameEvent() -> unchanged - cbcomm() -> cbComm() - activate() -> cbActivate() - prepanch() -> PrepAnchor() - slidepos() -> cbSlidePos() - CheckFrameEvents() -> unchanged - slidepos2() -> cbSlidePos2() - BLG_PrepareOptimization() -> PrepareOptimization() - BLG_PrepareOptimization2() -> PrepareOptimization2() - BLG_OptimizeDestinationsAngle() -> OptimizeDestinationOrientation() - BLG_OptSingleAng() -> OptSingleAngle() - Functions not yet explained main updates: - cbNewOb(): The interpolateFlag variable has been removed from the TrajAnim structure. It's now part of the tuple which describes the trajectory progress. - cbSlidePos(): Few changes to reflect the above structure change, removal of a few lines with no use. - cbSlidePos2(): The function was using a 'param' parameter which contained the trajectory progress tuple, the interpolateFlag variable and an unused other parameter. It now uses only the new tuple structure. This allowed to optimize the code of the function. - Variables changes: - Nothing special, critical or incomprehensible beyond what has been explained above. 4) Current behaviour of the plugin regarding series of events ************************************************************* A triggered action doesn't really interrupt a running trajectory but it updates its status: - playonce or playonceS: starts a trajectory if it's not running. If it's running, it will stop at the end (even if it was a playloop one). - playloop or playloopS: starts a looping trajectory if it's not running. If it's running, it will start again at the end as a looping trajectory (even if it was a playonce one). - playstop or playstopS: pauses a running trajectory. Triggering a playonce or playloop action will resume the trajectory with the proper looping feature. 5) Current behaviour of the plugin regarding srvAutoStart ********************************************************* - a triggered playonceS will trigger local playonce actions by new clients only during a period equal to the time needed to run the trajectory. After this period, nothing will be triggered except if the client has some local autostart enabled. - Multiple triggered playonceS reset the period and thus may increase the total time for triggering the first playonceS. - playloopS and stopS actions destroy an existing period, starting a looping trajectory by the client or hindering it to run its local autostarted trajectory.