LUADOC - Farming Simulator 17

Printable Version

PhysicsObject

Description
Class for physics objects
Functions

new

Description
Creating physics object
Definition
new(boolean isServer, boolean isClient, table customMt)
Arguments
booleanisServeris server
booleanisClientis client
tablecustomMtcustomMt
Return Values
tableinstanceInstance of object
Code
17function PhysicsObject:new(isServer, isClient, customMt)
18 local mt = customMt;
19 if mt == nil then
20 mt = PhysicsObject_mt;
21 end;
22
23 local self = Object:new(isServer, isClient, mt);
24 self.nodeId = 0;
25 if not self.isServer then
26 self.currentPosition = {};
27 self.targetPosition = {};
28 self.isPositionDirty = false;
29 self.interpolationTime = 2;
30 self.interpolationDuration = 30;
31 end
32 self.forcedClipDistance = 60;
33
34 self.physicsObjectDirtyFlag = self:getNextDirtyFlag();
35 return self;
36end;

delete

Description
Deleting physics object
Definition
delete()
Code
40function PhysicsObject:delete()
41 g_currentMission:removeNodeObject(self.nodeId);
42 delete(self.nodeId);
43 self.nodeId = 0;
44 PhysicsObject:superClass().delete(self);
45end;

getAllowsAutoDelete

Description
Get allows auto delete
Definition
getAllowsAutoDelete()
Return Values
booleanallowsAutoDeleteallows auto delete
Code
50function PhysicsObject:getAllowsAutoDelete()
51 return true;
52end

loadOnCreate

Description
Load on create
Definition
loadOnCreate(integer nodeId)
Arguments
integernodeIdnode id
Code
57function PhysicsObject:loadOnCreate(nodeId)
58 self:setNodeId(nodeId);
59 if not self.isServer then
60 self:onGhostRemove();
61 end;
62end;

setNodeId

Description
Set node id
Definition
setNodeId(integer nodeId)
Arguments
integernodeIdnode Id
Code
67function PhysicsObject:setNodeId(nodeId)
68 self.nodeId = nodeId;
69 setRigidBodyType(self.nodeId, self:getDefaultRigidBodyType());
70 addToPhysics(self.nodeId);
71 local x,y,z=getTranslation(self.nodeId)
72 local x_rot,y_rot,z_rot=getRotation(self.nodeId);
73 self.sendPosX, self.sendPosY, self.sendPosZ = x,y,z;
74 self.sendRotX, self.sendRotY, self.sendRotZ = x_rot,y_rot,z_rot;
75
76 if not self.isServer then
77 local currentPosition = self.currentPosition;
78 local targetPosition = self.targetPosition;
79 currentPosition.x,currentPosition.y,currentPosition.z = x,y,z;
80 targetPosition.x,targetPosition.y,targetPosition.z = x,y,z;
81 currentPosition.x_rot,currentPosition.y_rot,currentPosition.z_rot,currentPosition.w_rot = mathEulerToQuaternion(x_rot,y_rot,z_rot);
82 targetPosition.x_rot,targetPosition.y_rot,targetPosition.z_rot,targetPosition.w_rot = currentPosition.x_rot,currentPosition.y_rot,currentPosition.z_rot,currentPosition.w_rot;
83 end
84
85 self:addChildsToNodeObject(self.nodeId);
86end;

readStream

Description
Called on client side on join
Definition
readStream(integer streamId, table connection)
Arguments
integerstreamIdstream ID
tableconnectionconnection
Code
92function PhysicsObject:readStream(streamId, connection)
93 assert(self.nodeId ~= 0);
94 if connection:getIsServer() then
95 local paramsXZ = g_currentMission.vehicleXZPosCompressionParams;
96 local paramsY = g_currentMission.vehicleYPosCompressionParams;
97 local x = Utils.readCompressedWorldPosition(streamId, paramsXZ);
98 local y = Utils.readCompressedWorldPosition(streamId, paramsY);
99 local z = Utils.readCompressedWorldPosition(streamId, paramsXZ);
100 local x_rot=Utils.readCompressedAngle(streamId);
101 local y_rot=Utils.readCompressedAngle(streamId);
102 local z_rot=Utils.readCompressedAngle(streamId);
103
104 local x_rot,y_rot,z_rot,w_rot = mathEulerToQuaternion(x_rot,y_rot,z_rot);
105
106 self:setPose(x,y,z, x_rot,y_rot,z_rot,w_rot);
107 end;
108end;

writeStream

Description
Called on server side on join
Definition
writeStream(integer streamId, table connection)
Arguments
integerstreamIdstream ID
tableconnectionconnection
Code
114function PhysicsObject:writeStream(streamId, connection)
115 if not connection:getIsServer() then
116 local x,y,z = getTranslation(self.nodeId)
117 local x_rot,y_rot,z_rot = getRotation(self.nodeId);
118 local paramsXZ = g_currentMission.vehicleXZPosCompressionParams;
119 local paramsY = g_currentMission.vehicleYPosCompressionParams;
120 Utils.writeCompressedWorldPosition(streamId, x, paramsXZ);
121 Utils.writeCompressedWorldPosition(streamId, y, paramsY);
122 Utils.writeCompressedWorldPosition(streamId, z, paramsXZ);
123 Utils.writeCompressedAngle(streamId, x_rot);
124 Utils.writeCompressedAngle(streamId, y_rot);
125 Utils.writeCompressedAngle(streamId, z_rot);
126 end;
127end;

readUpdateStream

Description
Called on client side on update
Definition
readUpdateStream(integer streamId, integer timestamp, table connection)
Arguments
integerstreamIdstream ID
integertimestamptimestamp
tableconnectionconnection
Code
134function PhysicsObject:readUpdateStream(streamId, timestamp, connection)
135 if connection:getIsServer() then
136 if streamReadBool(streamId) then
137 local targetPosition = self.targetPosition;
138 local currentPosition = self.currentPosition;
139
140 local deltaTime = g_client.tickDuration;
141 if self.lastPhysicsNetworkTime ~= nil then
142 deltaTime = math.min(g_packetPhysicsNetworkTime - self.lastPhysicsNetworkTime, 3*g_client.tickDuration);
143 end
144 self.lastPhysicsNetworkTime = g_packetPhysicsNetworkTime;
145
146 -- interpTimeLeft is the time we would've continued interpolating. This should always be about g_clientInterpDelay.
147 -- If we extrapolated, reset to the full delay
148 local interpTimeLeft = g_clientInterpDelay;
149 if self.interpolationTime < 1 then
150 interpTimeLeft = (1-self.interpolationTime) * self.interpolationDuration;
151 interpTimeLeft = interpTimeLeft * 0.95 + g_clientInterpDelay * 0.05; -- slighly blend towards the expected delay
152 interpTimeLeft = math.min(interpTimeLeft, 3*g_clientInterpDelay); -- clamp to some reasonable maximum
153 end
154 self.interpolationDuration = interpTimeLeft + deltaTime;
155 self.interpolationTime = 0;
156
157 self.lastPositionX = currentPosition.x;
158 self.lastPositionY = currentPosition.y;
159 self.lastPositionZ = currentPosition.z;
160 self.lastRotationX = currentPosition.x_rot;
161 self.lastRotationY = currentPosition.y_rot;
162 self.lastRotationZ = currentPosition.z_rot;
163 self.lastRotationW = currentPosition.w_rot;
164
165 local paramsXZ = g_currentMission.vehicleXZPosCompressionParams;
166 local paramsY = g_currentMission.vehicleYPosCompressionParams;
167 targetPosition.x = Utils.readCompressedWorldPosition(streamId, paramsXZ);
168 targetPosition.y = Utils.readCompressedWorldPosition(streamId, paramsY);
169 targetPosition.z = Utils.readCompressedWorldPosition(streamId, paramsXZ);
170 local x_rot=Utils.readCompressedAngle(streamId);
171 local y_rot=Utils.readCompressedAngle(streamId);
172 local z_rot=Utils.readCompressedAngle(streamId);
173
174 targetPosition.x_rot,targetPosition.y_rot,targetPosition.z_rot,targetPosition.w_rot = mathEulerToQuaternion(x_rot,y_rot,z_rot);
175 self.isPositionDirty = true;
176
177 local dx,dy,dz = targetPosition.x-currentPosition.x, targetPosition.y-currentPosition.y, targetPosition.z-currentPosition.z;
178 if dx*dx + dy*dy + dz*dz > 25 then -- snap, if more than 5m distance
179 --print("snapping, diff: "..math.sqrt(dx*dx + dy*dy + dz*dz ));
180 self:setPose(targetPosition.x,targetPosition.y,targetPosition.z, targetPosition.x_rot,targetPosition.y_rot,targetPosition.z_rot,targetPosition.w_rot);
181 end;
182 end;
183 end;
184end;

writeUpdateStream

Description
Called on server side on update
Definition
writeUpdateStream(integer streamId, table connection, integer dirtyMask)
Arguments
integerstreamIdstream ID
tableconnectionconnection
integerdirtyMaskdirty mask
Code
191function PhysicsObject:writeUpdateStream(streamId, connection, dirtyMask)
192 if not connection:getIsServer() then
193 if streamWriteBool(streamId, bitAND(dirtyMask, self.physicsObjectDirtyFlag) ~= 0) then
194 local paramsXZ = g_currentMission.vehicleXZPosCompressionParams;
195 local paramsY = g_currentMission.vehicleYPosCompressionParams;
196 Utils.writeCompressedWorldPosition(streamId, self.sendPosX, paramsXZ);
197 Utils.writeCompressedWorldPosition(streamId, self.sendPosY, paramsY);
198 Utils.writeCompressedWorldPosition(streamId, self.sendPosZ, paramsXZ);
199
200 Utils.writeCompressedAngle(streamId, self.sendRotX);
201 Utils.writeCompressedAngle(streamId, self.sendRotY);
202 Utils.writeCompressedAngle(streamId, self.sendRotZ);
203 end;
204 end;
205end;

update

Description
Update
Definition
update(float dt)
Arguments
floatdttime since last call in ms
Code
210function PhysicsObject:update(dt)
211 if not self.isServer then
212 if self.isPositionDirty then
213 local maxIntrpAlpha = 1.05;
214 local intrpAlpha = self.interpolationTime + g_physicsDtUnclamped / self.interpolationDuration;
215 --local intrpAlpha = math.max((g_physicsNetworkTime-g_clientInterpDelay - self.lastPoseTime) / (self.targetPoseTime - self.lastPoseTime), 0);
216 --self.curPoseTime = g_physicsNetworkTime-g_clientInterpDelay;
217 if intrpAlpha >= maxIntrpAlpha then
218 intrpAlpha = maxIntrpAlpha;
219 self.isPositionDirty = false;
220 end;
221 self.interpolationTime = intrpAlpha;
222
223 local curPos = self.currentPosition;
224 local targetPos = self.targetPosition;
225
226 curPos.x = self.lastPositionX + (targetPos.x-self.lastPositionX)*intrpAlpha;
227 curPos.y = self.lastPositionY + (targetPos.y-self.lastPositionY)*intrpAlpha;
228 curPos.z = self.lastPositionZ + (targetPos.z-self.lastPositionZ)*intrpAlpha;
229 curPos.x_rot, curPos.y_rot, curPos.z_rot, curPos.w_rot = Utils.nlerpQuaternionShortestPath(
230 self.lastRotationX, self.lastRotationY, self.lastRotationZ, self.lastRotationW, targetPos.x_rot, targetPos.y_rot, targetPos.z_rot, targetPos.w_rot, intrpAlpha);
231
232 setTranslation(self.nodeId, curPos.x,curPos.y,curPos.z);
233 setQuaternion(self.nodeId, curPos.x_rot, curPos.y_rot, curPos.z_rot, curPos.w_rot);
234 end
235 end;
236end;

updateMove

Description
Update move
Definition
updateMove()
Return Values
booleanhasMovedhas moved
Code
242function PhysicsObject:updateMove()
243 local x,y,z=getTranslation(self.nodeId)
244 local x_rot,y_rot,z_rot=getRotation(self.nodeId);
245 local hasMoved = math.abs(self.sendPosX-x)>0.005 or math.abs(self.sendPosY-y)>0.005 or math.abs(self.sendPosZ-z)>0.005 or
246 math.abs(self.sendRotX-x_rot)>0.02 or math.abs(self.sendRotY-y_rot)>0.02 or math.abs(self.sendRotZ-z_rot)>0.02;
247
248 if hasMoved then
249 self:raiseDirtyFlags(self.physicsObjectDirtyFlag);
250 self.sendPosX, self.sendPosY, self.sendPosZ = x,y,z;
251 self.sendRotX, self.sendRotY, self.sendRotZ = x_rot,y_rot,z_rot;
252 end;
253
254 return hasMoved;
255end;

updateTick

Description
updateTick
Definition
updateTick(float dt)
Arguments
floatdttime since last call in ms
Code
260function PhysicsObject:updateTick(dt)
261 if self.isServer then
262 self:updateMove();
263 end;
264end;

needsUpdate

Description
Needs update
Definition
needsUpdate()
Return Values
booleanneedsUpdateneeds update
Code
269function PhysicsObject:needsUpdate()
270 if g_currentMission.missionDynamicInfo.isMultiplayer and not self.isServer then
271 -- multiplayer game needs updates on the client
272 return true;
273 end;
274 if self.update ~= PhysicsObject.update then
275 -- subclass redefines update, so we must call it (subclass can redefine needsUpdate to override this)
276 return true;
277 end;
278 -- optimize update away, we're just a PhysicsObject in a single-player game
279 return false;
280end;

needsUpdateTick

Description
Needs updateTick
Definition
needsUpdateTick()
Return Values
booleanneedsUpdateTickneeds update tick
Code
285function PhysicsObject:needsUpdateTick()
286 if g_currentMission.missionDynamicInfo.isMultiplayer and self.isServer then
287 -- multiplayer game needs updateTicks on the server
288 return true;
289 end;
290 if self.updateTick ~= PhysicsObject.updateTick then
291 -- subclass redefines updateTick, so we must call it (subclass can redefine needsUpdateTick to override this)
292 return true;
293 end;
294 -- optimize updateTick away, we're just a PhysicsObject in a single-player game
295 return false;
296end;

testScope

Description
Test scope
Definition
testScope(float x, float y, float z, float coeff)
Arguments
floatxx position
floatyy position
floatzz position
floatcoeffcoeff
Return Values
booleaninScopein scope
Code
305function PhysicsObject:testScope(x,y,z, coeff)
306 local x1, y1, z1 = getWorldTranslation(self.nodeId);
307 local dist = (x1-x)*(x1-x) + (y1-y)*(y1-y) + (z1-z)*(z1-z);
308 local clipDist = math.min(getClipDistance(self.nodeId)*coeff, self.forcedClipDistance);
309 if dist < clipDist*clipDist then
310 return true;
311 else
312 return false;
313 end;
314end;

getUpdatePriority

Description
Get update priority
Definition
getUpdatePriority(float skipCount, float x, float y, float z, float coeff, table connection)
Arguments
floatskipCountskip count
floatxx position
floatyy position
floatzz position
floatcoeffcoeff
tableconnectionconnection
Return Values
floatprioritypriority
Code
325function PhysicsObject:getUpdatePriority(skipCount, x, y, z, coeff, connection)
326 local x1, y1, z1 = getWorldTranslation(self.nodeId);
327 local dist = math.sqrt((x1-x)*(x1-x) + (y1-y)*(y1-y) + (z1-z)*(z1-z));
328 local clipDist = math.min(getClipDistance(self.nodeId)*coeff, self.forcedClipDistance);
329 return (1-dist/clipDist)* 0.8 + 0.5*skipCount * 0.2;
330end;

onGhostRemove

Description
On ghost remove
Definition
onGhostRemove()
Code
334function PhysicsObject:onGhostRemove()
335 setVisibility(self.nodeId, false);
336 removeFromPhysics(self.nodeId);
337end;

onGhostAdd

Description
On ghost add
Definition
onGhostAdd()
Code
341function PhysicsObject:onGhostAdd()
342 setVisibility(self.nodeId, true);
343 addToPhysics(self.nodeId);
344end;

setPose

Description
Set pose
Definition
setPose(float x, float y, float z, float x_rot, float y_rot, float z_rot, float w_rot)
Arguments
floatxx position
floatyz position
floatzz position
floatx_rotx rotation
floaty_roty rotation
floatz_rotz rotation
floatw_rotw rotation
Code
355function PhysicsObject:setPose(x,y,z, x_rot,y_rot,z_rot,w_rot)
356 if not self.isServer then
357 local curPos = self.currentPosition;
358 local targetPos = self.targetPosition;
359 curPos.x, targetPos.x = x, x;
360 curPos.y, targetPos.y = y, y;
361 curPos.z, targetPos.z = z, z;
362 curPos.x_rot, targetPos.x_rot = x_rot, x_rot;
363 curPos.y_rot, targetPos.y_rot = y_rot, y_rot;
364 curPos.z_rot, targetPos.z_rot = z_rot, z_rot;
365 curPos.w_rot, targetPos.w_rot = w_rot, w_rot;
366 self.isPositionDirty = false;
367 self.interpolationTime = 2;
368 end
369
370 setTranslation(self.nodeId, x,y,z);
371 setQuaternion(self.nodeId, x_rot, y_rot, z_rot, w_rot);
372end

getDefaultRigidBodyType

Description
Get default rigid body type
Definition
getDefaultRigidBodyType()
Return Values
stringrigidBodyTyperigid body type
Code
377function PhysicsObject:getDefaultRigidBodyType()
378 if self.isServer then
379 return "Dynamic";
380 else
381 return "Kinematic";
382 end
383end

addChildsToNodeObject

Description
Add childs to node object
Definition
addChildsToNodeObject(integer nodeId)
Arguments
integernodeIdid of node
Code
388function PhysicsObject:addChildsToNodeObject(nodeId)
389 for i=0,getNumOfChildren(nodeId)-1 do
390 self:addChildsToNodeObject(getChildAt(nodeId, i));
391 end
392 local rigidBodyType = getRigidBodyType(nodeId);
393 if rigidBodyType ~= "NoRigidBody" then
394 g_currentMission:addNodeObject(nodeId, self);
395 end;
396end;