Skip to content

Commit dc40a9f

Browse files
authored
Merge pull request #997 from Courseplay/mp-sync-workaround
fix: specialization race conditions
2 parents 7c75127 + acd1c5e commit dc40a9f

3 files changed

Lines changed: 74 additions & 70 deletions

File tree

scripts/specializations/CpCourseGenerator.lua

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,23 @@ function CpCourseGenerator.registerFunctions(vehicleType)
3333
SpecializationUtil.registerFunction(vehicleType, 'cpDrawFieldPolygon', CpCourseGenerator.cpDrawFieldPolygon)
3434
end
3535

36+
-- shortcut to access the spec
37+
function CpCourseGenerator.getSpec(self)
38+
return self["spec_" .. CpCourseGenerator.SPEC_NAME]
39+
end
40+
3641
function CpCourseGenerator:onLoad(savegame)
37-
-- create shortcut to this spec
38-
self.spec_cpCourseGenerator = self["spec_" .. CpCourseGenerator.SPEC_NAME]
39-
self.spec_cpCourseGenerator.logger = Logger(CpCourseGenerator.SPEC_NAME, nil, CpDebug.DBG_COURSES)
42+
CpCourseGenerator.getSpec(self).logger = Logger(CpCourseGenerator.SPEC_NAME, nil, CpDebug.DBG_COURSES)
4043
-- make sure cpGetFieldPosition always has spec.position
41-
self.spec_cpCourseGenerator.position = {}
44+
CpCourseGenerator.getSpec(self).position = {}
4245
end
4346

4447
---@param x number world X coordinate to start the detection at
4548
---@param z number world Z coordinate to start the detection at
4649
---@param object table|nil optional object with callback
4750
---@param onFinishedFunc function callback function to call when finished: onFinishedFunc([object,] vehicle, fieldPolygon, islandPolygons)
4851
function CpCourseGenerator:cpDetectFieldBoundary(x, z, object, onFinishedFunc)
49-
local spec = self.spec_cpCourseGenerator
52+
local spec = CpCourseGenerator.getSpec(self)
5053
if spec.isFieldBoundaryDetectionRunning then
5154
spec.logger:warning(self, 'Not starting field boundary detection for %.1f/%.1f, previous for %.1f/%.1f is still running',
5255
x, z, spec.position.x, spec.position.z)
@@ -62,18 +65,18 @@ end
6265
---@return boolean true if field boundary detection is running. Field and island polygons returned while running may
6366
--- be nil or invalid.
6467
function CpCourseGenerator:cpIsFieldBoundaryDetectionRunning()
65-
return self.spec_cpCourseGenerator.isFieldBoundaryDetectionRunning
68+
return CpCourseGenerator.getSpec(self).isFieldBoundaryDetectionRunning
6669
end
6770

6871
---@return number|nil, number|nil world X and Z coordinates of the last field boundary detection start position, nil
6972
--- if no previous detection was started
7073
function CpCourseGenerator:cpGetFieldPosition()
71-
local spec = self.spec_cpCourseGenerator
74+
local spec = CpCourseGenerator.getSpec(self)
7275
return spec.position.x, spec.position.z
7376
end
7477

7578
function CpCourseGenerator:onUpdate(dt)
76-
local spec = self.spec_cpCourseGenerator
79+
local spec = CpCourseGenerator.getSpec(self)
7780
if spec.fieldBoundaryDetector then
7881
if not spec.fieldBoundaryDetector:update(dt) then
7982
-- done
@@ -95,17 +98,17 @@ end
9598

9699
---@return table|nil [{x, y, z}] field polygon with game vertices
97100
function CpCourseGenerator:cpGetFieldPolygon()
98-
return self.spec_cpCourseGenerator.fieldPolygon
101+
return CpCourseGenerator.getSpec(self).fieldPolygon
99102
end
100103

101104
---@return table|nil [[{x, y, z}]] array of island polygons with game vertices (x, y, z)
102105
function CpCourseGenerator:cpGetIslandPolygons()
103-
return self.spec_cpCourseGenerator.islandPolygons
106+
return CpCourseGenerator.getSpec(self).islandPolygons
104107
end
105108

106109
-- For debug, if there is a field polygon or island polygons, draw them
107110
function CpCourseGenerator:cpDrawFieldPolygon()
108-
local spec = self.spec_cpCourseGenerator
111+
local spec= CpCourseGenerator.getSpec(self)
109112
local function drawPolygon(polygon)
110113
for i = 2, #polygon do
111114
local p, n = polygon[i - 1], polygon[i]
@@ -124,7 +127,7 @@ function CpCourseGenerator:cpDrawFieldPolygon()
124127
end
125128

126129
function CpCourseGenerator:onReadStream(streamId, connection)
127-
local spec = self.spec_cpCourseGenerator
130+
local spec= CpCourseGenerator.getSpec(self)
128131
local numVertices = streamReadInt32(streamId)
129132
if numVertices == 0 then
130133
spec.fieldPolygon = nil
@@ -140,7 +143,7 @@ function CpCourseGenerator:onReadStream(streamId, connection)
140143
end
141144

142145
function CpCourseGenerator:onWriteStream(streamId, connection)
143-
local spec = self.spec_cpCourseGenerator
146+
local spec= CpCourseGenerator.getSpec(self)
144147
if spec.fieldPolygon then
145148
streamWriteInt32(streamId, #spec.fieldPolygon)
146149
for _, point in ipairs(spec.fieldPolygon) do

scripts/specializations/CpCourseGeneratorSettings.lua

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -60,38 +60,41 @@ function CpCourseGeneratorSettings.registerFunctions(vehicleType)
6060
SpecializationUtil.registerFunction(vehicleType, 'validateCourseGeneratorSettings', CpCourseGeneratorSettings.validateSettings)
6161
end
6262

63+
-- shortcut to access the spec
64+
function CpCourseGeneratorSettings.getSpec(self)
65+
return self["spec_" .. CpCourseGeneratorSettings.SPEC_NAME]
66+
end
67+
6368
--- Gets all settings.
6469
---@return table
6570
function CpCourseGeneratorSettings:getSettings()
66-
local spec = self.spec_cpCourseGeneratorSettings
71+
local spec = CpCourseGeneratorSettings.getSpec(self)
6772
return spec
6873
end
6974

7075
--- Gets all settings.
7176
---@return table
7277
function CpCourseGeneratorSettings:getSettingsTable()
73-
local spec = self.spec_cpCourseGeneratorSettings
78+
local spec = CpCourseGeneratorSettings.getSpec(self)
7479
return spec.settings
7580
end
7681

7782
--- Gets all vine settings.
7883
---@return table
7984
function CpCourseGeneratorSettings:getCpVineSettings()
80-
local spec = self.spec_cpCourseGeneratorSettings
85+
local spec = CpCourseGeneratorSettings.getSpec(self)
8186
return spec.vineSettings
8287
end
8388

8489
--- Gets all settings.
8590
---@return table
8691
function CpCourseGeneratorSettings:getCpVineSettingsTable()
87-
local spec = self.spec_cpCourseGeneratorSettings
92+
local spec = CpCourseGeneratorSettings.getSpec(self)
8893
return spec.vineSettings.settings
8994
end
9095

9196
function CpCourseGeneratorSettings:onLoad(savegame)
92-
--- Register the spec: spec_cpCourseGeneratorSettings
93-
self.spec_cpCourseGeneratorSettings = self["spec_" .. CpCourseGeneratorSettings.SPEC_NAME]
94-
local spec = self.spec_cpCourseGeneratorSettings
97+
local spec = CpCourseGeneratorSettings.getSpec(self)
9598

9699
--- Clones the generic settings to create different settings containers for each vehicle.
97100
CpSettingsUtil.cloneSettingsTable(spec,CpCourseGeneratorSettings.settings,self,CpCourseGeneratorSettings)
@@ -114,76 +117,76 @@ function CpCourseGeneratorSettings:onUpdate(savegame)
114117
if self.propertyState == VehiclePropertyState.SHOP_CONFIG then
115118
return
116119
end
117-
local spec = self.spec_cpCourseGeneratorSettings
120+
local spec = CpCourseGeneratorSettings.getSpec(self)
118121
if not spec.finishedFirstUpdate then
119122
spec.workWidth:resetToLoadedValue()
120123
end
121124
spec.finishedFirstUpdate = true
122125
end
123126

124127
function CpCourseGeneratorSettings:onReadStream(streamId, connection)
125-
local spec = self.spec_cpCourseGeneratorSettings
128+
local spec = CpCourseGeneratorSettings.getSpec(self)
126129
for i, setting in ipairs(spec.settings) do
127130
setting:readStream(streamId, connection)
128131
end
129132
end
130133

131134
function CpCourseGeneratorSettings:onWriteStream(streamId, connection)
132-
local spec = self.spec_cpCourseGeneratorSettings
135+
local spec = CpCourseGeneratorSettings.getSpec(self)
133136
for i, setting in ipairs(spec.settings) do
134137
setting:writeStream(streamId, connection)
135138
end
136139
end
137140

138141
function CpCourseGeneratorSettings:isRowsToSkipVisible()
139-
local spec = self.spec_cpCourseGeneratorSettings
142+
local spec = CpCourseGeneratorSettings.getSpec(self)
140143
local rowPatternNumber = spec.centerMode:getValue()
141144
return rowPatternNumber == CourseGenerator.RowPattern.ALTERNATING
142145
end
143146

144147
function CpCourseGeneratorSettings:isNumberOfCirclesVisible()
145-
local spec = self.spec_cpCourseGeneratorSettings
148+
local spec = CpCourseGeneratorSettings.getSpec(self)
146149
local rowPatternNumber = spec.centerMode:getValue()
147150
return rowPatternNumber == CourseGenerator.RowPattern.RACETRACK
148151
end
149152

150153
function CpCourseGeneratorSettings:isRowsPerLandVisible()
151-
local spec = self.spec_cpCourseGeneratorSettings
154+
local spec = CpCourseGeneratorSettings.getSpec(self)
152155
local rowPatternNumber = spec.centerMode:getValue()
153156
return rowPatternNumber == CourseGenerator.RowPattern.LANDS
154157
end
155158

156159
function CpCourseGeneratorSettings:isSpiralFromInsideVisible()
157-
local spec = self.spec_cpCourseGeneratorSettings
160+
local spec = CpCourseGeneratorSettings.getSpec(self)
158161
local rowPatternNumber = spec.centerMode:getValue()
159162
return rowPatternNumber == CourseGenerator.RowPattern.SPIRAL
160163
end
161164

162165
function CpCourseGeneratorSettings:isManualRowAngleVisible()
163-
local spec = self.spec_cpCourseGeneratorSettings
166+
local spec = CpCourseGeneratorSettings.getSpec(self)
164167
return spec.autoRowAngle:getValue() == false
165168
end
166169

167170
--- Makes sure the automatic work width gets recalculated after the variable work width was changed by the user.
168171
function CpCourseGeneratorSettings.onVariableWorkWidthSectionChanged(object)
169172
--- Object could be an implement, so make sure we use the root vehicle.
170173
local self = object.rootVehicle
171-
if self:getIsSynchronized() and self.spec_cpCourseGeneratorSettings then
174+
if self:getIsSynchronized() then
172175
CpCourseGeneratorSettings.setAutomaticWorkWidthAndOffset(self)
173176
end
174177
end
175178
VariableWorkWidth.updateSections = Utils.appendedFunction(VariableWorkWidth.updateSections,CpCourseGeneratorSettings.onVariableWorkWidthSectionChanged)
176179

177180
function CpCourseGeneratorSettings:setAutomaticWorkWidthAndOffset()
178-
local spec = self.spec_cpCourseGeneratorSettings
181+
local spec = CpCourseGeneratorSettings.getSpec(self)
179182
local width, offset, _, _ = WorkWidthUtil.getAutomaticWorkWidthAndOffset(self)
180183
spec.workWidth:refresh()
181184
spec.workWidth:setFloatValue(width, nil, true)
182185
self:getCpSettings().toolOffsetX:setFloatValue(offset, nil, true)
183186
end
184187

185188
function CpCourseGeneratorSettings:setDefaultTurningRadius()
186-
local spec = self.spec_cpCourseGeneratorSettings
189+
local spec = CpCourseGeneratorSettings.getSpec(self)
187190
spec.turningRadius:setFloatValue(AIUtil.getTurningRadius(self), nil, true)
188191
end
189192

@@ -208,7 +211,7 @@ end
208211

209212
function CpCourseGeneratorSettings:loadSettings(savegame)
210213
if savegame == nil or savegame.resetVehicles then return end
211-
local spec = self.spec_cpCourseGeneratorSettings
214+
local spec = CpCourseGeneratorSettings.getSpec(self)
212215
--- Old save format
213216
savegame.xmlFile:iterate(savegame.key..CpCourseGeneratorSettings.KEY, function (ix, key)
214217
local name = savegame.xmlFile:getValue(key.."#name")
@@ -229,7 +232,7 @@ function CpCourseGeneratorSettings:loadSettings(savegame)
229232
end
230233

231234
function CpCourseGeneratorSettings:saveToXMLFile(xmlFile, baseKey, usedModNames)
232-
local spec = self.spec_cpCourseGeneratorSettings
235+
local spec = CpCourseGeneratorSettings.getSpec(self)
233236

234237
--- Saves the normal course generator settings.
235238
CpSettingsUtil.saveToXmlFile(spec.settings, xmlFile,
@@ -253,7 +256,7 @@ function CpCourseGeneratorSettings:raiseDirtyFlag(setting)
253256
end
254257

255258
function CpCourseGeneratorSettings:validateSettings()
256-
local spec = self.spec_cpCourseGeneratorSettings
259+
local spec = CpCourseGeneratorSettings.getSpec(self)
257260
for i,setting in ipairs(spec.settings) do
258261
setting:refresh()
259262
end
@@ -263,7 +266,7 @@ function CpCourseGeneratorSettings:validateSettings()
263266
end
264267

265268
function CpCourseGeneratorSettings:onCpUnitChanged()
266-
local spec = self.spec_cpCourseGeneratorSettings
269+
local spec = CpCourseGeneratorSettings.getSpec(self)
267270
for i,setting in ipairs(spec.settings) do
268271
setting:validateTexts()
269272
end
@@ -276,12 +279,12 @@ end
276279
--- Callbacks for the settings to manipulate the gui elements.
277280
------------------------------------------------------------------------------------------------------------------------
278281
function CpCourseGeneratorSettings:hasMoreThenOneVehicle()
279-
local spec = self.spec_cpCourseGeneratorSettings
282+
local spec = CpCourseGeneratorSettings.getSpec(self)
280283
return spec.multiTools:getValue() > 1
281284
end
282285

283286
function CpCourseGeneratorSettings:hasHeadlandsSelected()
284-
local spec = self.spec_cpCourseGeneratorSettings
287+
local spec = CpCourseGeneratorSettings.getSpec(self)
285288
return spec.numberOfHeadlands:getValue() > 0
286289
end
287290

@@ -292,7 +295,7 @@ function CpCourseGeneratorSettings:isNarrowFieldEnabled()
292295
end
293296

294297
function CpCourseGeneratorSettings:canStartOnRows()
295-
local spec = self.spec_cpCourseGeneratorSettings
298+
local spec = CpCourseGeneratorSettings.getSpec(self)
296299
-- start on rows does not work for narrow field patterns
297300
return spec.numberOfHeadlands:getValue() > 0 and not spec.narrowField:getValue()
298301
end
@@ -333,7 +336,7 @@ function CpCourseGeneratorSettings:consoleCommandPrintSetting(name)
333336
CpUtil.info("Not entered a valid vehicle!")
334337
return
335338
end
336-
local spec = vehicle.spec_cpCourseGeneratorSettings
339+
local spec = CpCourseGeneratorSettings.getSpec(self)
337340
if not spec then
338341
CpUtil.infoVehicle(vehicle, "has no course generator settings!")
339342
return

0 commit comments

Comments
 (0)