Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refill on the field, for now only stationary waiting until refilled. #3505

Merged
merged 14 commits into from
Oct 11, 2024
Merged
3 changes: 2 additions & 1 deletion Courseplay.lua
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ function Courseplay.removePlayerActionEvents(player)
end

--- Registers all cp specializations.
---@param typeManager TypeManager
---@param typeManager table
function Courseplay.register(typeManager)
--- TODO: make this function async.
for typeName, typeEntry in pairs(typeManager.types) do
Expand All @@ -352,6 +352,7 @@ function Courseplay.register(typeManager)
CpInfoTexts.register(typeManager, typeName, typeEntry.specializations)
CpShovelPositions.register(typeManager, typeName, typeEntry.specializations)
end
typeManager:addSpecialization("fillableImplement", "aiLoadable")
end
TypeManager.finalizeTypes = Utils.prependedFunction(TypeManager.finalizeTypes, Courseplay.register)

Expand Down
16 changes: 16 additions & 0 deletions config/MasterTranslations.xml
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,22 @@
<Text language="de"><![CDATA[Debuginformationen für das Fahrzeug ein- oder ausschalten. Visuell und Logeinträge.]]></Text>
<Text language="en"><![CDATA[Enables/disables debug for this vehicle.]]></Text>
</Translation>
<Translation name="CP_vehicle_setting_refillOnTheField_title">
<Text language="de"><![CDATA[Gerät auffüllen]]></Text>
<Text language="en"><![CDATA[Refill tool]]></Text>
</Translation>
<Translation name="CP_vehicle_setting_refillOnTheField_tooltip">
<Text language="de"><![CDATA[Gerät wartet auf dem Feld, um aufgefüllt zu werden.]]></Text>
<Text language="en"><![CDATA[Tool waits on the field to be refilled.]]></Text>
</Translation>
<Translation name="CP_vehicle_setting_refillOnTheField_waiting">
<Text language="de"><![CDATA[Warten]]></Text>
<Text language="en"><![CDATA[Waiting]]></Text>
</Translation>
<Translation name="CP_vehicle_setting_refillOnTheField_active">
<Text language="de"><![CDATA[Aktiv]]></Text>
<Text language="en"><![CDATA[Active]]></Text>
</Translation>
</Category>
<Category name="Vehicle bunker silo settings">
<Translation name="CP_vehicle_setting_subTitle_bunkerSilo">
Expand Down
12 changes: 12 additions & 0 deletions config/VehicleSettingsSetup.xml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,18 @@
<Setting classType="AIParameterSettingList" name="fullThreshold" min="40" max="100" incremental="5" default="85" unit="4" isVisible="areCombineUnloaderSettingsVisible"/>
<!--Silage additives needed?-->
<Setting classType="AIParameterBooleanSetting" name="useAdditiveFillUnit" defaultBool="false" isVisible="isAdditiveFillUnitSettingVisible" isExpertModeOnly="true"/>
<Setting classType="AIParameterSettingList" name="refillOnTheField" isVisible="isRefillOnTheFieldSettingVisible" default="1">
<Values>
<Value name="REFILL_ON_FIELD_DISABLED">0</Value>
<Value name="REFILL_ON_FIELD_WAITING">1</Value>
<!-- <Value name="REFILL_ON_FIELD_ACTIVE">2</Value> -->
</Values>
<Texts>
<Text prefix="false">CP_deactivated</Text>
<Text>waiting</Text>
<Text>active</Text>
</Texts>
</Setting>
</SettingSubTitle>

<SettingSubTitle title="bunkerSilo" isVisible="areBunkerSiloSettingsVisible">
Expand Down
1 change: 1 addition & 0 deletions modDesc.xml
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ Changelog 7.1.0.0:
<sourceFile filename="scripts/ai/controllers/FoldableController.lua"/>
<sourceFile filename="scripts/ai/controllers/PlowController.lua"/>
<sourceFile filename="scripts/ai/controllers/PalletFillerController.lua"/>
<sourceFile filename="scripts/ai/controllers/TreePlanterController.lua"/>

<sourceFile filename="scripts/ai/AIDriveStrategyCourse.lua"/>
<sourceFile filename="scripts/ai/AIDriveStrategyDriveToFieldWorkStart.lua"/>
Expand Down
27 changes: 14 additions & 13 deletions scripts/ai/AIDriveStrategyCourse.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ AIDriveStrategyCourse.onRaisingEvent = "onRaising"
AIDriveStrategyCourse.onLoweringEvent = "onLowering"
AIDriveStrategyCourse.onFinishedEvent = "onFinished"
AIDriveStrategyCourse.onStartEvent = "onStart"
AIDriveStrategyCourse.onStartRefillingEvent = "onStartRefilling"
AIDriveStrategyCourse.onStopRefillingEvent = "onStopRefilling"
AIDriveStrategyCourse.onUpdateRefillingEvent = "onUpdateRefilling"
AIDriveStrategyCourse.updateEvent = "update"
AIDriveStrategyCourse.deleteEvent = "delete"
--- A row has just been finished, implements are being raised and about to start the actual turn
Expand All @@ -50,6 +53,7 @@ function AIDriveStrategyCourse:init(task, job)
self.registeredInfoTexts = {}
--- To temporary hold a vehicle (will force speed to 0)
self.held = CpTemporaryObject()
self.fuelSaveActiveWhileHeld = false

self.currentTask = task
self.job = job
Expand Down Expand Up @@ -247,17 +251,7 @@ end

--- Checks if any controller disables fuel save, for example a round baler that is dropping a bale.
function AIDriveStrategyCourse:isFuelSaveAllowed()
--[[ TODO: implement this, when fuel save is implemented for every vehicle combo and not only harvesters.
for _, controller in pairs(self.controllers) do
---@type ImplementController
if controller:isEnabled() then
if not controller:isFuelSaveAllowed() then
return false
end
end
end
]]
return false
return self.fuelSaveActiveWhileHeld and self:isBeingHeld()
end

function AIDriveStrategyCourse:initializeImplementControllers(vehicle)
Expand Down Expand Up @@ -293,11 +287,15 @@ end

--- Raises a event for the controllers.
function AIDriveStrategyCourse:raiseControllerEvent(eventName, ...)
self:raiseControllerEventWithLambda(eventName, function () end, ...)
end

function AIDriveStrategyCourse:raiseControllerEventWithLambda(eventName, lambda, ...)
for _, controller in pairs(self.controllers) do
---@type ImplementController
if controller:isEnabled() then
if controller[eventName] then
controller[eventName](controller, ...)
lambda(controller[eventName](controller, ...))
end
end
end
Expand Down Expand Up @@ -499,11 +497,13 @@ end
--- Hold the vehicle (set speed to 0) temporary. This is meant to be used for other vehicles to coordinate movements,
--- for instance tell a vehicle it should not move as the other vehicle is driving around it.
---@param milliseconds number milliseconds to hold
function AIDriveStrategyCourse:hold(milliseconds)
---@param fuelSaveAllowed boolean enables the fuel save, while the vehicle is being held.
function AIDriveStrategyCourse:hold(milliseconds, fuelSaveAllowed)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably missed them, but there aren't a lot of comments on how this refill should work, are we using hold()? If so, can we update the comments to make it clear?

if not self.held:get() then
self:debug('Hold requested for %.1f seconds', milliseconds / 1000)
end
self.held:set(true, milliseconds)
self.fuelSaveActiveWhileHeld = fuelSaveAllowed
end

--- Release a hold anytime, even before it is released automatically after the time given at hold()
Expand All @@ -512,6 +512,7 @@ function AIDriveStrategyCourse:unhold()
self:debug("Hold reset")
end
self.held:reset()
self.fuelSaveActiveWhileHeld = false
end

--- Are we currently being held?
Expand Down
6 changes: 3 additions & 3 deletions scripts/ai/AIDriveStrategyFieldWorkCourse.lua
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ function AIDriveStrategyFieldWorkCourse:init(task, job)
self.aiOffsetX, self.aiOffsetZ = 0, 0
self.debugChannel = CpDebug.DBG_FIELDWORK
self.waitingForPrepare = CpTemporaryObject(false)

end

function AIDriveStrategyFieldWorkCourse:delete()
Expand Down Expand Up @@ -267,7 +266,7 @@ function AIDriveStrategyFieldWorkCourse:initializeImplementControllers(vehicle)

self:addImplementController(vehicle, SoilSamplerController, nil, defaultDisabledStates, "spec_soilSampler")
self:addImplementController(vehicle, StumpCutterController, StumpCutter, defaultDisabledStates)

self:addImplementController(vehicle, TreePlanterController, TreePlanter, {})

end

Expand Down Expand Up @@ -806,7 +805,7 @@ end

-----------------------------------------------------------------------------------------------------------------------
--- Convoy management
----------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------
function AIDriveStrategyFieldWorkCourse:getProgress()
return self.fieldWorkCourse:getProgress()
end
Expand All @@ -818,6 +817,7 @@ end
function AIDriveStrategyFieldWorkCourse:getFieldWorkProximity(node)
return self.fieldWorkerProximityController:getFieldWorkProximity(node)
end

-----------------------------------------------------------------------------------------------------------------------
--- Overwrite implement functions, to enable a different cp functionality compared to giants fieldworker.
--- TODO: might have to find a better solution for these kind of problems.
Expand Down
48 changes: 48 additions & 0 deletions scripts/ai/ImplementUtil.lua
Original file line number Diff line number Diff line change
Expand Up @@ -541,3 +541,51 @@ function ImplementUtil.getCanLoadTo(loadTargetImplement, implementToLoadFrom, di
return validTarget, targetFillUnitIndex, fillType, exactFillRootNode, alternativeFillType
end

--- Checks the passed in implements for a fill level change
--- and also caches the current fill levels.
--- Example input table format: {["implement"]["fillUnitIndex"] = 200}
---@param fillLevelData table<table, table<number, number>>
---@param reset boolean|nil
function ImplementUtil.hasFillLevelChanged(fillLevelData, reset)
local hasChanged = false
for implement, data in pairs(fillLevelData) do
for fillUnitIndex, fillLevel in pairs(data) do
local curFillLevel = implement:getFillUnitFillLevel(fillUnitIndex)
if reset then
fillLevelData[implement][fillUnitIndex] = -1
else
if fillLevel > -1 and curFillLevel ~= fillLevel then
hasChanged = true
end
fillLevelData[implement][fillUnitIndex] = curFillLevel
end
end
end
return hasChanged
end

--- Trys to start loading from triggers, pallets and so on nearby.
---@param implements table<table, ...>
---@return boolean refilling is currently refilling
function ImplementUtil.tryAndCheckRefillingFillUnits(implements)
local isFilling = false
for implement, _ in pairs(implements) do
local spec = implement.spec_fillUnit
local activatable = spec.fillTrigger.activatable
if not spec.fillTrigger.isFilling then
local rootVehicle = activatable.vehicle
if rootVehicle then
local oldFunc = rootVehicle.getIsActiveForInput
rootVehicle.getIsActiveForInput = function ()
return true
end
if activatable:getIsActivatable() then
activatable:run()
end
rootVehicle.getIsActiveForInput = oldFunc
end
end
isFilling = isFilling or spec.fillTrigger.isFilling
end
return isFilling
end
51 changes: 51 additions & 0 deletions scripts/ai/controllers/SowingMachineController.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ SowingMachineController = CpObject(ImplementController)
function SowingMachineController:init(vehicle, implement)
ImplementController.init(self, vehicle, implement)
self.sowingMachineSpec = self.implement.spec_sowingMachine
self.refillData = {
timer = CpTemporaryObject(true),
hasChanged = false,
lastFillLevels = {
[self.implement] = {
[self.sowingMachineSpec.fillUnitIndex] = -1
}
}
}
end

function SowingMachineController:update()
Expand Down Expand Up @@ -37,4 +46,46 @@ end

function SowingMachineController:onFinished()
self.implement:setIsTurnedOn(false)
end

-------------------------
--- Refill handling
-------------------------

function SowingMachineController:needsRefilling()
if not g_currentMission.missionInfo.helperBuySeeds then
if self.implement:getFillUnitFillLevel(self.sowingMachineSpec.fillUnitIndex) <= 0 then
return true
end
end
end

function SowingMachineController:onStartRefilling()
if self:needsRefilling() then
if self.implement.aiPrepareLoading ~= nil then
self.implement:aiPrepareLoading(self.sowingMachineSpec.fillUnitIndex)
end
self.refillData.timer:set(false, 30 * 1000)
end
self.refillData.hasChanged = false
ImplementUtil.hasFillLevelChanged(self.refillData.lastFillLevels, true)
end

function SowingMachineController:onUpdateRefilling()
if ImplementUtil.tryAndCheckRefillingFillUnits(self.refillData.lastFillLevels) or
ImplementUtil.hasFillLevelChanged(self.refillData.lastFillLevels) then
self.refillData.timer:set(false, 10 * 1000)
self.refillData.hasChanged = true
end
return self.refillData.timer:get(), self.refillData.hasChanged
end

function SowingMachineController:onStopRefilling()
if self.implement.aiFinishLoading ~= nil then
self.implement:aiFinishLoading()
end
local spec = self.implement.spec_fillUnit
if spec.fillTrigger.isFilling then
self.implement:setFillUnitIsFilling(false)
end
end
88 changes: 88 additions & 0 deletions scripts/ai/controllers/SprayerController.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,95 @@ SprayerController = CpObject(ImplementController)
--- Dummy placeholder for now
function SprayerController:init(vehicle, sprayer)
self.sprayer = sprayer
self.sprayerSpec = sprayer.spec_sprayer
ImplementController.init(self, vehicle, self.sprayer)
self.refillData = {
timer = CpTemporaryObject(true),
hasChanged = false,
lastFillLevels = {
[self.implement] = {
[self.implement:getSprayerFillUnitIndex()] = -1
}
}
}
for _, supportedSprayType in ipairs(self.sprayerSpec.supportedSprayTypes) do
for _, src in ipairs(self.sprayerSpec.fillTypeSources[supportedSprayType]) do
self:debug("Found additional tank for refilling: %s|%d", src.vehicle, src.fillUnitIndex)
if not self.refillData.lastFillLevels[src.vehicle] then
self.refillData.lastFillLevels[src.vehicle] = {}
end
self.refillData.lastFillLevels[src.vehicle][src.fillUnitIndex] = -1
end
end
end

-------------------------
--- Refill handling
-------------------------

function SprayerController:needsRefilling()
if self.sprayerSpec.isSlurryTanker and g_currentMission.missionInfo.helperSlurrySource > 1 or
self.sprayerSpec.isManureSpreader and g_currentMission.missionInfo.helperManureSource > 1 or
self.sprayerSpec.isFertilizerSprayer and g_currentMission.missionInfo.helperBuyFertilizer then

return false
end
ImplementUtil.hasFillLevelChanged(self.refillData.lastFillLevels)
for implement, data in pairs(self.refillData.lastFillLevels) do
for fillUnitIndex, fillLevel in pairs(data) do
if fillLevel <= 0 then
return true
end
end
end
end

function SprayerController:onStartRefilling(ignore)
if self:needsRefilling() then
if self.implement.aiPrepareLoading ~= nil then
self.implement:aiPrepareLoading(self.implement:getSprayerFillUnitIndex())
end
for _, supportedSprayType in ipairs(self.sprayerSpec.supportedSprayTypes) do
for _, src in ipairs(self.sprayerSpec.fillTypeSources[supportedSprayType]) do
if src.vehicle.aiPrepareLoading ~= nil then
src.vehicle:aiPrepareLoading(src.fillUnitIndex)
end
end
end
end
ImplementUtil.hasFillLevelChanged(self.refillData.lastFillLevels, true)
self.refillData.hasChanged = false
end

function SprayerController:onUpdateRefilling()
if ImplementUtil.tryAndCheckRefillingFillUnits(self.refillData.lastFillLevels) or
ImplementUtil.hasFillLevelChanged(self.refillData.lastFillLevels) then
self:debugSparse("Waiting for refilling to finish ..")
self.refillData.timer:set(false, 10 * 1000)
self.refillData.hasChanged = true
end
return self.refillData.timer:get(), self.refillData.hasChanged
end

function SprayerController:onStopRefilling()
if self.implement.aiFinishLoading ~= nil then
self.implement:aiFinishLoading()
end
local spec = self.implement.spec_fillUnit
if spec.fillTrigger.isFilling then
self.implement:setFillUnitIsFilling(false)
end
for _, supportedSprayType in ipairs(self.sprayerSpec.supportedSprayTypes) do
for _, src in ipairs(self.sprayerSpec.fillTypeSources[supportedSprayType]) do
if src.vehicle.aiFinishLoading ~= nil then
src.vehicle:aiFinishLoading()
end
spec = src.vehicle.spec_fillUnit
if spec.fillTrigger.isFilling then
src.vehicle:setFillUnitIsFilling(false)
end
end
end
end

local function processSprayerArea(sprayer, superFunc, ...)
Expand Down
Loading
Loading