314 | function Washable:addToLocalWashableNode(node, updateFunc, customIndex, extraParams) |
315 | local spec = self.spec_washable |
316 | |
317 | local nodeData = {} |
318 | |
319 | --if washableNode already exists we add node to existing washableNode |
320 | if customIndex ~= nil then |
321 | if spec.washableNodesByIndex[customIndex] ~= nil then |
322 | table.insert(spec.washableNodesByIndex[customIndex].nodes, node) |
323 | return |
324 | else |
325 | spec.washableNodesByIndex[customIndex] = nodeData |
326 | end |
327 | end |
328 | |
329 | --if washableNode doesn't exists we create a new one |
330 | nodeData.nodes = {node} |
331 | nodeData.updateFunc = updateFunc |
332 | nodeData.dirtAmount = 0 |
333 | nodeData.dirtAmountSent = 0 |
334 | if extraParams ~= nil then |
335 | for i, v in pairs(extraParams) do |
336 | nodeData[i] = v |
337 | end |
338 | end |
339 | |
340 | table.insert(spec.washableNodes, nodeData) |
341 | end |
61 | function Washable:onLoad(savegame) |
62 | local spec = self.spec_washable |
63 | |
64 | spec.washableNodes = {} |
65 | spec.washableNodesByIndex = {} |
66 | self:addToLocalWashableNode(nil, Washable.updateDirtAmount, nil, nil) -- create global / default washableNode |
67 | |
68 | spec.dirtDuration = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.washable#dirtDuration"), 90) * 60 * 1000 |
69 | if spec.dirtDuration ~= 0 then |
70 | spec.dirtDuration = 1 / spec.dirtDuration |
71 | end |
72 | |
73 | spec.washDuration = math.max(Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.washable#washDuration"), 1) * 60 * 1000, 0.00001) -- washDuration == 0 washes vehicle immediately |
74 | |
75 | spec.workMultiplier = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.washable#workMultiplier"), 4) |
76 | spec.fieldMultiplier = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.washable#fieldMultiplier"), 2) |
77 | |
78 | spec.blockedWashTypes = {} |
79 | local blockedWashTypesStr = getXMLString(self.xmlFile, "vehicle.washable#blockedWashTypes") |
80 | if blockedWashTypesStr ~= nil then |
81 | local blockedWashTypes = StringUtil.splitString(" ", blockedWashTypesStr) |
82 | for _, typeStr in pairs(blockedWashTypes) do |
83 | typeStr = "WASHTYPE_" .. typeStr |
84 | if Washable[typeStr] ~= nil then |
85 | spec.blockedWashTypes[Washable[typeStr]] = true |
86 | else |
87 | g_logManager:xmlWarning(self.configFileName, "Unknown wash type '%s' in '%s'", typeStr, "vehicle.washable#blockedWashTypes") |
88 | end |
89 | end |
90 | end |
91 | |
92 | spec.dirtyFlag = self:getNextDirtyFlag() |
93 | end |
97 | function Washable:onPostLoad(savegame) |
98 | local spec = self.spec_washable |
99 | |
100 | -- getting als washable nodes in postLoad to make sure also linked nodes are washable |
101 | if spec.washableNodes ~= nil then |
102 | for _, component in pairs(self.components) do |
103 | self:addAllSubWashableNodes(component.node) |
104 | end |
105 | |
106 | if savegame ~= nil and Washable.getIntervalMultiplier() ~= 0 then |
107 | for i, nodeData in ipairs(spec.washableNodes) do |
108 | local nodeKey = string.format("%s.washable.dirtNode(%d)", savegame.key, i-1) |
109 | local amount = Utils.getNoNil(getXMLFloat(savegame.xmlFile, nodeKey.."#amount"), 0) |
110 | self:setNodeDirtAmount(nodeData, amount, true) |
111 | end |
112 | else |
113 | for _, nodeData in ipairs(spec.washableNodes) do |
114 | self:setNodeDirtAmount(nodeData, 0, true) |
115 | end |
116 | end |
117 | end |
118 | end |
160 | function Washable:onReadUpdateStream(streamId, timestamp, connection) |
161 | local spec = self.spec_washable |
162 | |
163 | if connection:getIsServer() then |
164 | if spec.washableNodes ~= nil then |
165 | if streamReadBool(streamId) then |
166 | for _, nodeData in ipairs(spec.washableNodes) do |
167 | local dirtAmount = streamReadUIntN(streamId, Washable.SEND_NUM_BITS) / Washable.SEND_MAX_VALUE |
168 | self:setNodeDirtAmount(nodeData, dirtAmount, true) |
169 | end |
170 | end |
171 | end |
172 | end |
173 | end |
193 | function Washable:onUpdateTick(dt, isActive, isActiveForInput, isSelected) |
194 | local spec = self.spec_washable |
195 | |
196 | if spec.washableNodes ~= nil then |
197 | if self.isServer then |
198 | for _, nodeData in ipairs(spec.washableNodes) do |
199 | local changedAmount = nodeData.updateFunc(self, nodeData, dt) |
200 | if changedAmount ~= 0 then |
201 | self:setNodeDirtAmount(nodeData, self:getNodeDirtAmount(nodeData) + changedAmount) |
202 | end |
203 | end |
204 | end |
205 | end |
206 | end |
177 | function Washable:onWriteUpdateStream(streamId, connection, dirtyMask) |
178 | local spec = self.spec_washable |
179 | |
180 | if not connection:getIsServer() then |
181 | if spec.washableNodes ~= nil then |
182 | if streamWriteBool(streamId, bitAND(dirtyMask, spec.dirtyFlag) ~= 0) then |
183 | for _, nodeData in ipairs(spec.washableNodes) do |
184 | streamWriteUIntN(streamId, math.floor(self:getNodeDirtAmount(nodeData) * Washable.SEND_MAX_VALUE + 0.5), Washable.SEND_NUM_BITS) |
185 | end |
186 | end |
187 | end |
188 | end |
189 | end |
49 | function Washable.registerEventListeners(vehicleType) |
50 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", Washable) |
51 | SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", Washable) |
52 | SpecializationUtil.registerEventListener(vehicleType, "onReadStream", Washable) |
53 | SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", Washable) |
54 | SpecializationUtil.registerEventListener(vehicleType, "onReadUpdateStream", Washable) |
55 | SpecializationUtil.registerEventListener(vehicleType, "onWriteUpdateStream", Washable) |
56 | SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", Washable) |
57 | end |
29 | function Washable.registerFunctions(vehicleType) |
30 | SpecializationUtil.registerFunction(vehicleType, "updateDirtAmount", Washable.updateDirtAmount) |
31 | SpecializationUtil.registerFunction(vehicleType, "addDirtAmount", Washable.addDirtAmount) |
32 | SpecializationUtil.registerFunction(vehicleType, "setNodeDirtAmount", Washable.setNodeDirtAmount) |
33 | SpecializationUtil.registerFunction(vehicleType, "getNodeDirtAmount", Washable.getNodeDirtAmount) |
34 | SpecializationUtil.registerFunction(vehicleType, "addAllSubWashableNodes", Washable.addAllSubWashableNodes) |
35 | SpecializationUtil.registerFunction(vehicleType, "addWashableNodes", Washable.addWashableNodes) |
36 | SpecializationUtil.registerFunction(vehicleType, "validateWashableNode", Washable.validateWashableNode) |
37 | SpecializationUtil.registerFunction(vehicleType, "addToGlobalWashableNode", Washable.addToGlobalWashableNode) |
38 | SpecializationUtil.registerFunction(vehicleType, "addToLocalWashableNode", Washable.addToLocalWashableNode) |
39 | SpecializationUtil.registerFunction(vehicleType, "removeAllSubWashableNodes", Washable.removeAllSubWashableNodes) |
40 | SpecializationUtil.registerFunction(vehicleType, "removeWashableNode", Washable.removeWashableNode) |
41 | SpecializationUtil.registerFunction(vehicleType, "getDirtMultiplier", Washable.getDirtMultiplier) |
42 | SpecializationUtil.registerFunction(vehicleType, "getWorkDirtMultiplier", Washable.getWorkDirtMultiplier) |
43 | SpecializationUtil.registerFunction(vehicleType, "getWashDuration", Washable.getWashDuration) |
44 | SpecializationUtil.registerFunction(vehicleType, "getAllowsWashingByType", Washable.getAllowsWashingByType) |
45 | end |
122 | function Washable:saveToXMLFile(xmlFile, key, usedModNames) |
123 | local spec = self.spec_washable |
124 | |
125 | if spec.washableNodes ~= nil then |
126 | for i, nodeData in ipairs(spec.washableNodes) do |
127 | local nodeKey = string.format("%s.dirtNode(%d)", key, i-1) |
128 | setXMLFloat(xmlFile, nodeKey.."#amount", self:getNodeDirtAmount(nodeData)) |
129 | end |
130 | end |
131 | end |
247 | function Washable:setNodeDirtAmount(nodeData, dirtAmount, force) |
248 | local spec = self.spec_washable |
249 | nodeData.dirtAmount = MathUtil.clamp(dirtAmount, 0, 1) |
250 | |
251 | local diff = nodeData.dirtAmountSent - nodeData.dirtAmount |
252 | if math.abs(diff) > Washable.SEND_THRESHOLD or force then |
253 | for _, node in pairs(nodeData.nodes) do |
254 | local x, _, z, w = getShaderParameter(node, "RDT") |
255 | setShaderParameter(node, "RDT", x, nodeData.dirtAmount, z, w, false) |
256 | end |
257 | |
258 | if self.isServer then |
259 | self:raiseDirtyFlags(spec.dirtyFlag) |
260 | nodeData.dirtAmountSent = nodeData.dirtAmount |
261 | end |
262 | end |
263 | end |
428 | function Washable:updateDebugValues(values) |
429 | local spec = self.spec_washable |
430 | if spec.washableNodes ~= nil then |
431 | if self.isServer then |
432 | for i, nodeData in ipairs(spec.washableNodes) do |
433 | local changedAmount = nodeData.updateFunc(self, nodeData, 3600000) |
434 | table.insert(values, {name="WashableNode"..i, value=string.format("%.4f a/h (%.2f)", changedAmount, self:getNodeDirtAmount(nodeData))}) |
435 | end |
436 | end |
437 | end |
438 | end |
210 | function Washable:updateDirtAmount(nodeData, dt) |
211 | local spec = self.spec_washable |
212 | local change = 0 |
213 | |
214 | if self:getAllowsWashingByType(Washable.WASHTYPE_RAIN) then |
215 | local weather = g_currentMission.environment.weather |
216 | local rainScale = weather:getRainFallScale() |
217 | local timeSinceLastRain = weather:getTimeSinceLastRain() |
218 | if rainScale > 0.1 and timeSinceLastRain < 30 then |
219 | local amount = self:getNodeDirtAmount(nodeData) |
220 | if amount > 0.5 then |
221 | change = -(dt / spec.washDuration) |
222 | end |
223 | end |
224 | end |
225 | |
226 | local dirtMultiplier = self:getDirtMultiplier() |
227 | if dirtMultiplier ~= 0 then |
228 | change = dt * spec.dirtDuration * dirtMultiplier * Washable.getIntervalMultiplier() |
229 | end |
230 | |
231 | return change |
232 | end |