Sprache Deutsch Language English

Script Dokumentation LS 2015 - PhysicsObject (Patch 1.3)

Script Dokumentation Übersicht

scripts/objects/PhysicsObject.lua

Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
1-- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved.
2
3PhysicsObject= {};
4PhysicsObject_mt = Class(PhysicsObject, Object);
5
6InitStaticObjectClass(PhysicsObject, "PhysicsObject", ObjectIds.OBJECT_PHYSICS_OBJECT);
7
8function PhysicsObject:new(isServer, isClient, customMt)
9 local mt = customMt;
10 if mt == nil then
11 mt = PhysicsObject_mt;
12 end;
13
14 local self = Object:new(isServer, isClient, mt);
15 self.nodeId = 0;
16 if not self.isServer then
17 self.currentPosition = {};
18 self.targetPosition = {};
19 self.isPositionDirty = false;
20 self.interpolationTime = 2;
21 self.interpolationDuration = 30;
22 end
23 self.forcedClipDistance = 30;
24
25 self.physicsObjectDirtyFlag = self:getNextDirtyFlag();
26 return self;
27end;
28
29function PhysicsObject:delete()
30 g_currentMission:removeNodeObject(self.nodeId);
31 delete(self.nodeId);
32 self.nodeId = 0;
33 PhysicsObject:superClass().delete(self);
34end;
35
36function PhysicsObject:getAllowsAutoDelete()
37 return true;
38end
39
40function PhysicsObject:loadOnCreate(nodeId)
41 self:setNodeId(nodeId);
42 if not self.isServer then
43 self:onGhostRemove();
44 end;
45end;
46
47function PhysicsObject:setNodeId(nodeId)
48 self.nodeId = nodeId;
49 setRigidBodyType(self.nodeId, self:getDefaultRigidBodyType());
50 addToPhysics(self.nodeId);
51 local x,y,z=getTranslation(self.nodeId)
52 local x_rot,y_rot,z_rot=getRotation(self.nodeId);
53 self.sendPosX, self.sendPosY, self.sendPosZ = x,y,z;
54 self.sendRotX, self.sendRotY, self.sendRotZ = x_rot,y_rot,z_rot;
55
56 if not self.isServer then
57 local currentPosition = self.currentPosition;
58 local targetPosition = self.targetPosition;
59 currentPosition.x,currentPosition.y,currentPosition.z = x,y,z;
60 targetPosition.x,targetPosition.y,targetPosition.z = x,y,z;
61 currentPosition.x_rot,currentPosition.y_rot,currentPosition.z_rot,currentPosition.w_rot = mathEulerToQuaternion(x_rot,y_rot,z_rot);
62 targetPosition.x_rot,targetPosition.y_rot,targetPosition.z_rot,targetPosition.w_rot = currentPosition.x_rot,currentPosition.y_rot,currentPosition.z_rot,currentPosition.w_rot;
63 end
64
65 self:addChildsToNodeObject(self.nodeId);
66end;
67
68function PhysicsObject:readStream(streamId, connection)
69 assert(self.nodeId ~= 0);
70 if connection:getIsServer() then
71 local paramsXZ = g_currentMission.vehicleXZPosCompressionParams;
72 local paramsY = g_currentMission.vehicleYPosCompressionParams;
73 local x = Utils.readCompressedWorldPosition(streamId, paramsXZ);
74 local y = Utils.readCompressedWorldPosition(streamId, paramsY);
75 local z = Utils.readCompressedWorldPosition(streamId, paramsXZ);
76 local x_rot=Utils.readCompressedAngle(streamId);
77 local y_rot=Utils.readCompressedAngle(streamId);
78 local z_rot=Utils.readCompressedAngle(streamId);
79
80 local x_rot,y_rot,z_rot,w_rot = mathEulerToQuaternion(x_rot,y_rot,z_rot);
81
82 self:setPose(x,y,z, x_rot,y_rot,z_rot,w_rot);
83 end;
84end;
85
86function PhysicsObject:writeStream(streamId, connection)
87 if not connection:getIsServer() then
88 local x,y,z = getTranslation(self.nodeId)
89 local x_rot,y_rot,z_rot = getRotation(self.nodeId);
90 local paramsXZ = g_currentMission.vehicleXZPosCompressionParams;
91 local paramsY = g_currentMission.vehicleYPosCompressionParams;
92 Utils.writeCompressedWorldPosition(streamId, x, paramsXZ);
93 Utils.writeCompressedWorldPosition(streamId, y, paramsY);
94 Utils.writeCompressedWorldPosition(streamId, z, paramsXZ);
95 Utils.writeCompressedAngle(streamId, x_rot);
96 Utils.writeCompressedAngle(streamId, y_rot);
97 Utils.writeCompressedAngle(streamId, z_rot);
98 end;
99end;
100
101function PhysicsObject:readUpdateStream(streamId, timestamp, connection)
102 if connection:getIsServer() then
103 if streamReadBool(streamId) then
104 local targetPosition = self.targetPosition;
105 local currentPosition = self.currentPosition;
106
107 local deltaTime = g_client.tickDuration;
108 if self.lastPhysicsNetworkTime ~= nil then
109 deltaTime = math.min(g_packetPhysicsNetworkTime - self.lastPhysicsNetworkTime, 3*g_client.tickDuration);
110 end
111 self.lastPhysicsNetworkTime = g_packetPhysicsNetworkTime;
112
113 -- interpTimeLeft is the time we would've continued interpolating. This should always be about g_clientInterpDelay.
114 -- If we extrapolated, reset to the full delay
115 local interpTimeLeft = g_clientInterpDelay;
116 if self.interpolationTime < 1 then
117 interpTimeLeft = (1-self.interpolationTime) * self.interpolationDuration;
118 interpTimeLeft = interpTimeLeft * 0.95 + g_clientInterpDelay * 0.05; -- slighly blend towards the expected delay
119 interpTimeLeft = math.min(interpTimeLeft, 3*g_clientInterpDelay); -- clamp to some reasonable maximum
120 end
121 self.interpolationDuration = interpTimeLeft + deltaTime;
122 self.interpolationTime = 0;
123
124 self.lastPositionX = currentPosition.x;
125 self.lastPositionY = currentPosition.y;
126 self.lastPositionZ = currentPosition.z;
127 self.lastRotationX = currentPosition.x_rot;
128 self.lastRotationY = currentPosition.y_rot;
129 self.lastRotationZ = currentPosition.z_rot;
130 self.lastRotationW = currentPosition.w_rot;
131
132 local paramsXZ = g_currentMission.vehicleXZPosCompressionParams;
133 local paramsY = g_currentMission.vehicleYPosCompressionParams;
134 targetPosition.x = Utils.readCompressedWorldPosition(streamId, paramsXZ);
135 targetPosition.y = Utils.readCompressedWorldPosition(streamId, paramsY);
136 targetPosition.z = Utils.readCompressedWorldPosition(streamId, paramsXZ);
137 local x_rot=Utils.readCompressedAngle(streamId);
138 local y_rot=Utils.readCompressedAngle(streamId);
139 local z_rot=Utils.readCompressedAngle(streamId);
140
141 targetPosition.x_rot,targetPosition.y_rot,targetPosition.z_rot,targetPosition.w_rot = mathEulerToQuaternion(x_rot,y_rot,z_rot);
142 self.isPositionDirty = true;
143
144 local dx,dy,dz = targetPosition.x-currentPosition.x, targetPosition.y-currentPosition.y, targetPosition.z-currentPosition.z;
145 if dx*dx + dy*dy + dz*dz > 25 then -- snap, if more than 5m distance
146 --print("snapping, diff: "..math.sqrt(dx*dx + dy*dy + dz*dz ));
147 self:setPose(targetPosition.x,targetPosition.y,targetPosition.z, targetPosition.x_rot,targetPosition.y_rot,targetPosition.z_rot,targetPosition.w_rot);
148 end;
149 end;
150 end;
151end;
152
153function PhysicsObject:writeUpdateStream(streamId, connection, dirtyMask)
154 if not connection:getIsServer() then
155 if streamWriteBool(streamId, bitAND(dirtyMask, self.physicsObjectDirtyFlag) ~= 0) then
156 local paramsXZ = g_currentMission.vehicleXZPosCompressionParams;
157 local paramsY = g_currentMission.vehicleYPosCompressionParams;
158 Utils.writeCompressedWorldPosition(streamId, self.sendPosX, paramsXZ);
159 Utils.writeCompressedWorldPosition(streamId, self.sendPosY, paramsY);
160 Utils.writeCompressedWorldPosition(streamId, self.sendPosZ, paramsXZ);
161
162 Utils.writeCompressedAngle(streamId, self.sendRotX);
163 Utils.writeCompressedAngle(streamId, self.sendRotY);
164 Utils.writeCompressedAngle(streamId, self.sendRotZ);
165 end;
166 end;
167end;
168
169function PhysicsObject:update(dt)
170 if not self.isServer then
171 if self.isPositionDirty then
172 local maxIntrpAlpha = 1.05;
173 local intrpAlpha = self.interpolationTime + g_physicsDtUnclamped / self.interpolationDuration;
174 --local intrpAlpha = math.max((g_physicsNetworkTime-g_clientInterpDelay - self.lastPoseTime) / (self.targetPoseTime - self.lastPoseTime), 0);
175 --self.curPoseTime = g_physicsNetworkTime-g_clientInterpDelay;
176 if intrpAlpha >= maxIntrpAlpha then
177 intrpAlpha = maxIntrpAlpha;
178 self.isPositionDirty = false;
179 end;
180 self.interpolationTime = intrpAlpha;
181
182 local curPos = self.currentPosition;
183 local targetPos = self.targetPosition;
184
185 curPos.x = self.lastPositionX + (targetPos.x-self.lastPositionX)*intrpAlpha;
186 curPos.y = self.lastPositionY + (targetPos.y-self.lastPositionY)*intrpAlpha;
187 curPos.z = self.lastPositionZ + (targetPos.z-self.lastPositionZ)*intrpAlpha;
188 curPos.x_rot, curPos.y_rot, curPos.z_rot, curPos.w_rot = Utils.nlerpQuaternionShortestPath(
189 self.lastRotationX, self.lastRotationY, self.lastRotationZ, self.lastRotationW, targetPos.x_rot, targetPos.y_rot, targetPos.z_rot, targetPos.w_rot, intrpAlpha);
190
191 setTranslation(self.nodeId, curPos.x,curPos.y,curPos.z);
192 setQuaternion(self.nodeId, curPos.x_rot, curPos.y_rot, curPos.z_rot, curPos.w_rot);
193 end
194 end;
195end;
196
197-- NB: called directly by some subclasses (e.g. MountableObject) that do more things if hasMoved is true
198function PhysicsObject:updateMove()
199 local x,y,z=getTranslation(self.nodeId)
200 local x_rot,y_rot,z_rot=getRotation(self.nodeId);
201 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
202 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;
203
204 if hasMoved then
205 self:raiseDirtyFlags(self.physicsObjectDirtyFlag);
206 self.sendPosX, self.sendPosY, self.sendPosZ = x,y,z;
207 self.sendRotX, self.sendRotY, self.sendRotZ = x_rot,y_rot,z_rot;
208 end;
209
210 return hasMoved;
211end;
212
213function PhysicsObject:updateTick(dt)
214 if self.isServer then
215 self:updateMove();
216 end;
217end;
218
219function PhysicsObject:needsUpdate()
220 if g_currentMission.missionDynamicInfo.isMultiplayer and not self.isServer then
221 -- multiplayer game needs updates on the client
222 return true;
223 end;
224 if self.update ~= PhysicsObject.update then
225 -- subclass redefines update, so we must call it (subclass can redefine needsUpdate to override this)
226 return true;
227 end;
228 -- optimize update away, we're just a PhysicsObject in a single-player game
229 return false;
230end;
231
232function PhysicsObject:needsUpdateTick()
233 if g_currentMission.missionDynamicInfo.isMultiplayer and self.isServer then
234 -- multiplayer game needs updateTicks on the server
235 return true;
236 end;
237 if self.updateTick ~= PhysicsObject.updateTick then
238 -- subclass redefines updateTick, so we must call it (subclass can redefine needsUpdateTick to override this)
239 return true;
240 end;
241 -- optimize updateTick away, we're just a PhysicsObject in a single-player game
242 return false;
243end;
244
245function PhysicsObject:testScope(x,y,z, coeff)
246 local x1, y1, z1 = getWorldTranslation(self.nodeId);
247 local dist = (x1-x)*(x1-x) + (y1-y)*(y1-y) + (z1-z)*(z1-z);
248 local clipDist = math.min(getClipDistance(self.nodeId)*coeff, self.forcedClipDistance);
249 if dist < clipDist*clipDist then
250 return true;
251 else
252 return false;
253 end;
254end;
255
256function PhysicsObject:getUpdatePriority(skipCount, x, y, z, coeff, connection)
257 local x1, y1, z1 = getWorldTranslation(self.nodeId);
258 local dist = math.sqrt((x1-x)*(x1-x) + (y1-y)*(y1-y) + (z1-z)*(z1-z));
259 local clipDist = math.min(getClipDistance(self.nodeId)*coeff, self.forcedClipDistance);
260 return (1-dist/clipDist)* 0.8 + 0.5*skipCount * 0.2;
261end;
262
263function PhysicsObject:onGhostRemove()
264 setVisibility(self.nodeId, false);
265 removeFromPhysics(self.nodeId);
266end;
267
268function PhysicsObject:onGhostAdd()
269 setVisibility(self.nodeId, true);
270 addToPhysics(self.nodeId);
271end;
272
273function PhysicsObject:setPose(x,y,z, x_rot,y_rot,z_rot,w_rot)
274 if not self.isServer then
275 local curPos = self.currentPosition;
276 local targetPos = self.targetPosition;
277 curPos.x, targetPos.x = x, x;
278 curPos.y, targetPos.y = y, y;
279 curPos.z, targetPos.z = z, z;
280 curPos.x_rot, targetPos.x_rot = x_rot, x_rot;
281 curPos.y_rot, targetPos.y_rot = y_rot, y_rot;
282 curPos.z_rot, targetPos.z_rot = z_rot, z_rot;
283 curPos.w_rot, targetPos.w_rot = w_rot, w_rot;
284 self.isPositionDirty = false;
285 self.interpolationTime = 2;
286 end
287
288 setTranslation(self.nodeId, x,y,z);
289 setQuaternion(self.nodeId, x_rot, y_rot, z_rot, w_rot);
290end
291
292function PhysicsObject:getDefaultRigidBodyType()
293 if self.isServer then
294 return "Dynamic";
295 else
296 return "Kinematic";
297 end
298end
299
300function PhysicsObject:addChildsToNodeObject(nodeId)
301 for i=0,getNumOfChildren(nodeId)-1 do
302 self:addChildsToNodeObject(getChildAt(nodeId, i));
303 end
304 local rigidBodyType = getRigidBodyType(nodeId);
305 if rigidBodyType ~= "NoRigidBody" then
306 g_currentMission:addNodeObject(nodeId, self);
307 end
308end
Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
Script Dokumentation Übersicht