Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions modDesc.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -404,6 +404,10 @@ Changelog 8.1.0.3
<actionBinding action="CP_GENERATE_COURSE">
<binding device="KB_MOUSE_DEFAULT" input="KEY_lctrl KEY_g" />
</actionBinding>
<!--- Only used in the course generator menu while creating a job, where KEY_v is free. -->
<actionBinding action="CP_SET_POSITIONS_TO_VEHICLE">
<binding device="KB_MOUSE_DEFAULT" input="KEY_v" />
</actionBinding>

<actionBinding action="CP_CHANGE_SELECTED_JOB">
<binding device="" input="" />
Expand DownExpand Up@@ -451,6 +455,7 @@ Changelog 8.1.0.3
<action name="CP_START_STOP_AT_NEAREST_WAYPOINT"/>
<action name="CP_START_STOP_AT_LAST_WAYPOINT"/>
<action name="CP_GENERATE_COURSE" />
<action name="CP_SET_POSITIONS_TO_VEHICLE" />

<action name="CP_CHANGE_SELECTED_JOB"/>
<action name="CP_CHANGE_STARTING_POINT"/>
Expand Down
113 changes: 103 additions & 10 deletions scripts/gui/pages/CpCourseGeneratorFrame.lua
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,14 +35,17 @@ CpCourseGeneratorFrame = {
CONTEXT_ACTIONS = {
ENTER_VEHICLE = 1,
CREATE_JOB = 2,
START_JOB = 3,
STOP_JOB = 4,
GENERATE_COURSE = 5,
DELETE_CUSTOM_FIELD = 6,
RENAME_CUSTOM_FIELD = 7,
EDIT_CUSTOM_FIELD = 8,
DRAW_CUSTOM_FIELD = 9,
HOTSPOT_SELECT_ALL = 10
--- These three show up in the create job button list in this order, which is also
--- the usual work flow: set the positions, generate the course, start the job.
SET_POSITIONS_TO_VEHICLE = 3,
GENERATE_COURSE = 4,
START_JOB = 5,
STOP_JOB = 6,
DELETE_CUSTOM_FIELD = 7,
RENAME_CUSTOM_FIELD = 8,
EDIT_CUSTOM_FIELD = 9,
DRAW_CUSTOM_FIELD = 10,
HOTSPOT_SELECT_ALL = 11
},
AI_MODE_OVERVIEW = 1,
AI_MODE_CREATE = 2,
Expand DownExpand Up@@ -945,6 +948,63 @@ function CpCourseGeneratorFrame:getIsPicking()
return self.isPickingRotation or self.isPickingLocation
end

--- Sets the target position (the position the helper drives to first, with the vehicle's direction)
--- and the field/silo position of the job currently being created to the vehicle's position, so
--- these don't have to be picked on the map when standing on the field already.
function CpCourseGeneratorFrame:setJobPositionsToVehiclePosition()
local vehicle = self.currentJobVehicle
if self.currentJob == nil or vehicle == nil or vehicle.rootNode == nil or self:getIsPicking() then
return
end
local x, _, z = getWorldTranslation(vehicle.rootNode)
local dirX, _, dirZ = localDirectionToWorld(vehicle.rootNode, 0, 0, 1)
local angle = MathUtil.getYRotationFromDirection(dirX, dirZ)
local changed = false
for _, element in ipairs(self.currentJobElements) do
local parameter = element.aiParameter
if parameter and parameter.is_a and parameter:is_a(CpAIParameterPosition) and parameter:getCanBeChanged() then
local positionType = parameter:getPositionType()
if positionType == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO then
parameter:setPosition(x, z)
if parameter.setAngle then
--- the target of the drive to task also has a direction, use the one the vehicle is facing
parameter:setAngle(angle)
end
changed = true
elseif positionType == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
parameter:setPosition(x, z)
changed = true
end
end
end
if changed then
--- this also restarts the field boundary detection for the new field position
self:validateParameters()
self:updateParameterValueTexts()
end
end

--- Adds a button to the job parameter list, which sets the target and the field position
--- to the vehicle's current position. It gets a group of its own so it is separated from
--- the position rows above and isn't clicked by accident.
function CpCourseGeneratorFrame:addSetPositionsToVehicleButton()
local titleElement = self.createTitleTemplate:clone(self.jobMenuLayout)
titleElement:setText(g_i18n:getText("CP_ai_page_positions_to_vehicle_title"))
--- Using the position parameter template, so the button looks and behaves exactly
--- like the position rows above it.
local element = self.createPositionTemplate:clone(self.jobMenuLayout)
FocusManager:loadElementFromCustomValues(element)
element:setText(g_i18n:getText("CP_ai_page_positions_to_vehicle"))
local invalidElement = element:getDescendantByName("invalid")
if invalidElement then
invalidElement:setVisible(false)
end
element.onClickCallback = function()
self:setJobPositionsToVehiclePosition()
end
return element
end

function CpCourseGeneratorFrame:validateParameters()
local isValid = true
local errorText = ""
Expand DownExpand Up@@ -1153,7 +1213,7 @@ function CpCourseGeneratorFrame:getNumberOfItemsInSection(list, section)
end
if list == self.contextButtonList then
self.contextActionMapping = {}
for index, action in pairs(self.contextActions) do
for index, action in ipairs(self.contextActions) do
if action.isActive and not action.actionOnly then
table.insert(self.contextActionMapping, index)
end
Expand All@@ -1165,7 +1225,7 @@ function CpCourseGeneratorFrame:getNumberOfItemsInSection(list, section)
end
if list == self.contextButtonCustomFieldList then
self.contextActionMapping = {}
for index, action in pairs(self.contextActions) do
for index, action in ipairs(self.contextActions) do
if action.isActive and not action.actionOnly then
table.insert(self.contextActionMapping, index)
end
Expand DownExpand Up@@ -1455,6 +1515,12 @@ function CpCourseGeneratorFrame:initializeContextActions()
callback = self.onCreateJob,
isActive = false
},
[self.CONTEXT_ACTIONS.SET_POSITIONS_TO_VEHICLE] = {
text = g_i18n:getText("CP_ai_page_positions_to_vehicle"),
action = InputAction.CP_SET_POSITIONS_TO_VEHICLE,
callback = self.setJobPositionsToVehiclePosition,
isActive = false
},
[self.CONTEXT_ACTIONS.START_JOB] = {
text = g_i18n:getText("button_startJob"),
action = InputAction.MENU_EXTRA_1,
Expand DownExpand Up@@ -1547,6 +1613,9 @@ function CpCourseGeneratorFrame:updateContextActions()
end
end
self.contextActions[self.CONTEXT_ACTIONS.CREATE_JOB].isActive = self.canCreateJob and self.mode ~= self.AI_MODE_CREATE
self.contextActions[self.CONTEXT_ACTIONS.SET_POSITIONS_TO_VEHICLE].isActive =
self.mode == self.AI_MODE_CREATE and self.currentJob ~= nil and
self.currentJobVehicle ~= nil and not self:getIsPicking()
self.contextActions[self.CONTEXT_ACTIONS.START_JOB].isActive = self:getCanStartJob()
self.contextActions[self.CONTEXT_ACTIONS.STOP_JOB].isActive = self:getCanCancelJob() and self.mode ~= self.AI_MODE_CREATE
self.contextActions[self.CONTEXT_ACTIONS.GENERATE_COURSE].isActive = self:getCanGenerateFieldWorkCourse()
Expand DownExpand Up@@ -1765,11 +1834,27 @@ function CpCourseGeneratorFrame:setActiveJobTypeSelection(jobTypeIndex)
end
self.currentJob:applyCurrentState(self.currentJobVehicle, g_currentMission, farmId, false)
self.currentJobElements = {}
--- The button setting the positions to the vehicle position goes right below the field/silo
--- position, or below the target position for jobs without a field position (silo loader).
local buttonAnchorPositionType = nil
for _, group in ipairs(self.currentJob:getGroupedParameters()) do
for _, item in ipairs(group:getParameters()) do
local positionType = item.getPositionType and item:getPositionType()
if positionType == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
buttonAnchorPositionType = positionType
elseif positionType == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO and
buttonAnchorPositionType == nil then
buttonAnchorPositionType = positionType
end
end
end
local isButtonAdded = false
for _, group in ipairs(self.currentJob:getGroupedParameters()) do
local titleElement = self.createTitleTemplate:clone(self.jobMenuLayout)

titleElement:setText(group:getTitle())

local isButtonAnchorGroup = false
for _, item in ipairs(group:getParameters()) do
local element = nil
local parameterType = item:getType()
Expand DownExpand Up@@ -1797,8 +1882,16 @@ function CpCourseGeneratorFrame:setActiveJobTypeSelection(jobTypeIndex)
end
element:setDisabled(not item:getCanBeChanged())
table.insert(self.currentJobElements, element)
if buttonAnchorPositionType ~= nil and item.getPositionType and
item:getPositionType() == buttonAnchorPositionType then
isButtonAnchorGroup = true
end
end
end
if isButtonAnchorGroup and not isButtonAdded then
self:addSetPositionsToVehicleButton()
isButtonAdded = true
end
end
self:validateParameters()
self:updateParameterValueTexts()
Expand Down
3 changes: 3 additions & 0 deletions translations/translation_de.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,6 +108,8 @@
<text name="CP_job_bunkerSilo" text="CP: Siloarbeit"/>
<text name="CP_job_siloLoader" text="CP: Silo laden"/>
<text name="CP_ai_page_generate_course" text="CP: Feldkurs generieren"/>
<text name="CP_ai_page_positions_to_vehicle" text="Ziel &amp; Feld auf Fahrzeug"/>
<text name="CP_ai_page_positions_to_vehicle_title" text="Positionen setzen"/>
<text name="CP_ai_page_open_course_generator" text="CP: Kursgenerator öffnen/schließen"/>
<!---->
<!--AI error messages-->
Expand DownExpand Up@@ -1076,6 +1078,7 @@ Das Kreuz sollte jetzt, wie im Bild dargestellt, gelb sein.
<text name="input_CP_START_STOP_AT_NEAREST_WAYPOINT" text="CP: CP-Helfer starten/stoppen (am nächsten Wegpunkt)"/>
<text name="input_CP_START_STOP_AT_LAST_WAYPOINT" text="CP: CP-Helfer starten/stoppen (am letzten Wegpunkt)"/>
<text name="input_CP_GENERATE_COURSE" text="CP: Kurs generieren"/>
<text name="input_CP_SET_POSITIONS_TO_VEHICLE" text="CP: Ziel &amp; Feld auf Fahrzeugposition setzen"/>
<text name="input_CP_CHANGE_SELECTED_JOB" text="CP: Aktuell ausgewählten Job ändern"/>
<text name="input_CP_CHANGE_STARTING_POINT" text="CP: Startpunkt ändern"/>
<text name="input_CP_CLEAR_COURSE" text="CP: Aktuell geladenen Kurs löschen"/>
Expand Down
3 changes: 3 additions & 0 deletions translations/translation_en.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,6 +108,8 @@
<text name="CP_job_bunkerSilo" text="CP: Silo work"/>
<text name="CP_job_siloLoader" text="CP: Silo loading"/>
<text name="CP_ai_page_generate_course" text="CP: Generate fieldwork course"/>
<text name="CP_ai_page_positions_to_vehicle" text="Target &amp; field to vehicle"/>
<text name="CP_ai_page_positions_to_vehicle_title" text="Set positions"/>
<text name="CP_ai_page_open_course_generator" text="CP: Open/close course generator"/>
<!---->
<!--AI error messages-->
Expand DownExpand Up@@ -1092,6 +1094,7 @@ Now your selection should look similar to the image.
<text name="input_CP_START_STOP_AT_NEAREST_WAYPOINT" text="CP: Start/stop driver (at nearest waypoint)"/>
<text name="input_CP_START_STOP_AT_LAST_WAYPOINT" text="CP: Start/stop driver (at last waypoint)"/>
<text name="input_CP_GENERATE_COURSE" text="CP: Generate course"/>
<text name="input_CP_SET_POSITIONS_TO_VEHICLE" text="CP: Set target &amp; field to vehicle position"/>
<text name="input_CP_CHANGE_SELECTED_JOB" text="CP: Change current selected job"/>
<text name="input_CP_CHANGE_STARTING_POINT" text="CP: Change starting point"/>
<text name="input_CP_CLEAR_COURSE" text="CP: Clear currently loaded course"/>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Add a button to set the job positions to the vehicle position by helgehelge123 · Pull Request #1314 · Courseplay/Courseplay_FS25 · GitHub
Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions modDesc.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -404,6 +404,10 @@ Changelog 8.1.0.3
<actionBinding action="CP_GENERATE_COURSE">
<binding device="KB_MOUSE_DEFAULT" input="KEY_lctrl KEY_g" />
</actionBinding>
<!--- Only used in the course generator menu while creating a job, where KEY_v is free. -->
<actionBinding action="CP_SET_POSITIONS_TO_VEHICLE">
<binding device="KB_MOUSE_DEFAULT" input="KEY_v" />
</actionBinding>

<actionBinding action="CP_CHANGE_SELECTED_JOB">
<binding device="" input="" />
Expand DownExpand Up@@ -451,6 +455,7 @@ Changelog 8.1.0.3
<action name="CP_START_STOP_AT_NEAREST_WAYPOINT"/>
<action name="CP_START_STOP_AT_LAST_WAYPOINT"/>
<action name="CP_GENERATE_COURSE" />
<action name="CP_SET_POSITIONS_TO_VEHICLE" />

<action name="CP_CHANGE_SELECTED_JOB"/>
<action name="CP_CHANGE_STARTING_POINT"/>
Expand Down
113 changes: 103 additions & 10 deletions scripts/gui/pages/CpCourseGeneratorFrame.lua
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,14 +35,17 @@ CpCourseGeneratorFrame = {
CONTEXT_ACTIONS = {
ENTER_VEHICLE = 1,
CREATE_JOB = 2,
START_JOB = 3,
STOP_JOB = 4,
GENERATE_COURSE = 5,
DELETE_CUSTOM_FIELD = 6,
RENAME_CUSTOM_FIELD = 7,
EDIT_CUSTOM_FIELD = 8,
DRAW_CUSTOM_FIELD = 9,
HOTSPOT_SELECT_ALL = 10
--- These three show up in the create job button list in this order, which is also
--- the usual work flow: set the positions, generate the course, start the job.
SET_POSITIONS_TO_VEHICLE = 3,
GENERATE_COURSE = 4,
START_JOB = 5,
STOP_JOB = 6,
DELETE_CUSTOM_FIELD = 7,
RENAME_CUSTOM_FIELD = 8,
EDIT_CUSTOM_FIELD = 9,
DRAW_CUSTOM_FIELD = 10,
HOTSPOT_SELECT_ALL = 11
},
AI_MODE_OVERVIEW = 1,
AI_MODE_CREATE = 2,
Expand DownExpand Up@@ -945,6 +948,63 @@ function CpCourseGeneratorFrame:getIsPicking()
return self.isPickingRotation or self.isPickingLocation
end

--- Sets the target position (the position the helper drives to first, with the vehicle's direction)
--- and the field/silo position of the job currently being created to the vehicle's position, so
--- these don't have to be picked on the map when standing on the field already.
function CpCourseGeneratorFrame:setJobPositionsToVehiclePosition()
local vehicle = self.currentJobVehicle
if self.currentJob == nil or vehicle == nil or vehicle.rootNode == nil or self:getIsPicking() then
return
end
local x, _, z = getWorldTranslation(vehicle.rootNode)
local dirX, _, dirZ = localDirectionToWorld(vehicle.rootNode, 0, 0, 1)
local angle = MathUtil.getYRotationFromDirection(dirX, dirZ)
local changed = false
for _, element in ipairs(self.currentJobElements) do
local parameter = element.aiParameter
if parameter and parameter.is_a and parameter:is_a(CpAIParameterPosition) and parameter:getCanBeChanged() then
local positionType = parameter:getPositionType()
if positionType == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO then
parameter:setPosition(x, z)
if parameter.setAngle then
--- the target of the drive to task also has a direction, use the one the vehicle is facing
parameter:setAngle(angle)
end
changed = true
elseif positionType == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
parameter:setPosition(x, z)
changed = true
end
end
end
if changed then
--- this also restarts the field boundary detection for the new field position
self:validateParameters()
self:updateParameterValueTexts()
end
end

--- Adds a button to the job parameter list, which sets the target and the field position
--- to the vehicle's current position. It gets a group of its own so it is separated from
--- the position rows above and isn't clicked by accident.
function CpCourseGeneratorFrame:addSetPositionsToVehicleButton()
local titleElement = self.createTitleTemplate:clone(self.jobMenuLayout)
titleElement:setText(g_i18n:getText("CP_ai_page_positions_to_vehicle_title"))
--- Using the position parameter template, so the button looks and behaves exactly
--- like the position rows above it.
local element = self.createPositionTemplate:clone(self.jobMenuLayout)
FocusManager:loadElementFromCustomValues(element)
element:setText(g_i18n:getText("CP_ai_page_positions_to_vehicle"))
local invalidElement = element:getDescendantByName("invalid")
if invalidElement then
invalidElement:setVisible(false)
end
element.onClickCallback = function()
self:setJobPositionsToVehiclePosition()
end
return element
end

function CpCourseGeneratorFrame:validateParameters()
local isValid = true
local errorText = ""
Expand DownExpand Up@@ -1153,7 +1213,7 @@ function CpCourseGeneratorFrame:getNumberOfItemsInSection(list, section)
end
if list == self.contextButtonList then
self.contextActionMapping = {}
for index, action in pairs(self.contextActions) do
for index, action in ipairs(self.contextActions) do
if action.isActive and not action.actionOnly then
table.insert(self.contextActionMapping, index)
end
Expand All@@ -1165,7 +1225,7 @@ function CpCourseGeneratorFrame:getNumberOfItemsInSection(list, section)
end
if list == self.contextButtonCustomFieldList then
self.contextActionMapping = {}
for index, action in pairs(self.contextActions) do
for index, action in ipairs(self.contextActions) do
if action.isActive and not action.actionOnly then
table.insert(self.contextActionMapping, index)
end
Expand DownExpand Up@@ -1455,6 +1515,12 @@ function CpCourseGeneratorFrame:initializeContextActions()
callback = self.onCreateJob,
isActive = false
},
[self.CONTEXT_ACTIONS.SET_POSITIONS_TO_VEHICLE] = {
text = g_i18n:getText("CP_ai_page_positions_to_vehicle"),
action = InputAction.CP_SET_POSITIONS_TO_VEHICLE,
callback = self.setJobPositionsToVehiclePosition,
isActive = false
},
[self.CONTEXT_ACTIONS.START_JOB] = {
text = g_i18n:getText("button_startJob"),
action = InputAction.MENU_EXTRA_1,
Expand DownExpand Up@@ -1547,6 +1613,9 @@ function CpCourseGeneratorFrame:updateContextActions()
end
end
self.contextActions[self.CONTEXT_ACTIONS.CREATE_JOB].isActive = self.canCreateJob and self.mode ~= self.AI_MODE_CREATE
self.contextActions[self.CONTEXT_ACTIONS.SET_POSITIONS_TO_VEHICLE].isActive =
self.mode == self.AI_MODE_CREATE and self.currentJob ~= nil and
self.currentJobVehicle ~= nil and not self:getIsPicking()
self.contextActions[self.CONTEXT_ACTIONS.START_JOB].isActive = self:getCanStartJob()
self.contextActions[self.CONTEXT_ACTIONS.STOP_JOB].isActive = self:getCanCancelJob() and self.mode ~= self.AI_MODE_CREATE
self.contextActions[self.CONTEXT_ACTIONS.GENERATE_COURSE].isActive = self:getCanGenerateFieldWorkCourse()
Expand DownExpand Up@@ -1765,11 +1834,27 @@ function CpCourseGeneratorFrame:setActiveJobTypeSelection(jobTypeIndex)
end
self.currentJob:applyCurrentState(self.currentJobVehicle, g_currentMission, farmId, false)
self.currentJobElements = {}
--- The button setting the positions to the vehicle position goes right below the field/silo
--- position, or below the target position for jobs without a field position (silo loader).
local buttonAnchorPositionType = nil
for _, group in ipairs(self.currentJob:getGroupedParameters()) do
for _, item in ipairs(group:getParameters()) do
local positionType = item.getPositionType and item:getPositionType()
if positionType == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
buttonAnchorPositionType = positionType
elseif positionType == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO and
buttonAnchorPositionType == nil then
buttonAnchorPositionType = positionType
end
end
end
local isButtonAdded = false
for _, group in ipairs(self.currentJob:getGroupedParameters()) do
local titleElement = self.createTitleTemplate:clone(self.jobMenuLayout)

titleElement:setText(group:getTitle())

local isButtonAnchorGroup = false
for _, item in ipairs(group:getParameters()) do
local element = nil
local parameterType = item:getType()
Expand DownExpand Up@@ -1797,8 +1882,16 @@ function CpCourseGeneratorFrame:setActiveJobTypeSelection(jobTypeIndex)
end
element:setDisabled(not item:getCanBeChanged())
table.insert(self.currentJobElements, element)
if buttonAnchorPositionType ~= nil and item.getPositionType and
item:getPositionType() == buttonAnchorPositionType then
isButtonAnchorGroup = true
end
end
end
if isButtonAnchorGroup and not isButtonAdded then
self:addSetPositionsToVehicleButton()
isButtonAdded = true
end
end
self:validateParameters()
self:updateParameterValueTexts()
Expand Down
3 changes: 3 additions & 0 deletions translations/translation_de.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,6 +108,8 @@
<text name="CP_job_bunkerSilo" text="CP: Siloarbeit"/>
<text name="CP_job_siloLoader" text="CP: Silo laden"/>
<text name="CP_ai_page_generate_course" text="CP: Feldkurs generieren"/>
<text name="CP_ai_page_positions_to_vehicle" text="Ziel &amp; Feld auf Fahrzeug"/>
<text name="CP_ai_page_positions_to_vehicle_title" text="Positionen setzen"/>
<text name="CP_ai_page_open_course_generator" text="CP: Kursgenerator öffnen/schließen"/>
<!---->
<!--AI error messages-->
Expand DownExpand Up@@ -1076,6 +1078,7 @@ Das Kreuz sollte jetzt, wie im Bild dargestellt, gelb sein.
<text name="input_CP_START_STOP_AT_NEAREST_WAYPOINT" text="CP: CP-Helfer starten/stoppen (am nächsten Wegpunkt)"/>
<text name="input_CP_START_STOP_AT_LAST_WAYPOINT" text="CP: CP-Helfer starten/stoppen (am letzten Wegpunkt)"/>
<text name="input_CP_GENERATE_COURSE" text="CP: Kurs generieren"/>
<text name="input_CP_SET_POSITIONS_TO_VEHICLE" text="CP: Ziel &amp; Feld auf Fahrzeugposition setzen"/>
<text name="input_CP_CHANGE_SELECTED_JOB" text="CP: Aktuell ausgewählten Job ändern"/>
<text name="input_CP_CHANGE_STARTING_POINT" text="CP: Startpunkt ändern"/>
<text name="input_CP_CLEAR_COURSE" text="CP: Aktuell geladenen Kurs löschen"/>
Expand Down
3 changes: 3 additions & 0 deletions translations/translation_en.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,6 +108,8 @@
<text name="CP_job_bunkerSilo" text="CP: Silo work"/>
<text name="CP_job_siloLoader" text="CP: Silo loading"/>
<text name="CP_ai_page_generate_course" text="CP: Generate fieldwork course"/>
<text name="CP_ai_page_positions_to_vehicle" text="Target &amp; field to vehicle"/>
<text name="CP_ai_page_positions_to_vehicle_title" text="Set positions"/>
<text name="CP_ai_page_open_course_generator" text="CP: Open/close course generator"/>
<!---->
<!--AI error messages-->
Expand DownExpand Up@@ -1092,6 +1094,7 @@ Now your selection should look similar to the image.
<text name="input_CP_START_STOP_AT_NEAREST_WAYPOINT" text="CP: Start/stop driver (at nearest waypoint)"/>
<text name="input_CP_START_STOP_AT_LAST_WAYPOINT" text="CP: Start/stop driver (at last waypoint)"/>
<text name="input_CP_GENERATE_COURSE" text="CP: Generate course"/>
<text name="input_CP_SET_POSITIONS_TO_VEHICLE" text="CP: Set target &amp; field to vehicle position"/>
<text name="input_CP_CHANGE_SELECTED_JOB" text="CP: Change current selected job"/>
<text name="input_CP_CHANGE_STARTING_POINT" text="CP: Change starting point"/>
<text name="input_CP_CLEAR_COURSE" text="CP: Clear currently loaded course"/>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add a button to set the job positions to the vehicle position by helgehelge123 · Pull Request #1314 · Courseplay/Courseplay_FS25 · GitHub
Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions modDesc.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -404,6 +404,10 @@ Changelog 8.1.0.3
<actionBinding action="CP_GENERATE_COURSE">
<binding device="KB_MOUSE_DEFAULT" input="KEY_lctrl KEY_g" />
</actionBinding>
<!--- Only used in the course generator menu while creating a job, where KEY_v is free. -->
<actionBinding action="CP_SET_POSITIONS_TO_VEHICLE">
<binding device="KB_MOUSE_DEFAULT" input="KEY_v" />
</actionBinding>

<actionBinding action="CP_CHANGE_SELECTED_JOB">
<binding device="" input="" />
Expand DownExpand Up@@ -451,6 +455,7 @@ Changelog 8.1.0.3
<action name="CP_START_STOP_AT_NEAREST_WAYPOINT"/>
<action name="CP_START_STOP_AT_LAST_WAYPOINT"/>
<action name="CP_GENERATE_COURSE" />
<action name="CP_SET_POSITIONS_TO_VEHICLE" />

<action name="CP_CHANGE_SELECTED_JOB"/>
<action name="CP_CHANGE_STARTING_POINT"/>
Expand Down
113 changes: 103 additions & 10 deletions scripts/gui/pages/CpCourseGeneratorFrame.lua
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,14 +35,17 @@ CpCourseGeneratorFrame = {
CONTEXT_ACTIONS = {
ENTER_VEHICLE = 1,
CREATE_JOB = 2,
START_JOB = 3,
STOP_JOB = 4,
GENERATE_COURSE = 5,
DELETE_CUSTOM_FIELD = 6,
RENAME_CUSTOM_FIELD = 7,
EDIT_CUSTOM_FIELD = 8,
DRAW_CUSTOM_FIELD = 9,
HOTSPOT_SELECT_ALL = 10
--- These three show up in the create job button list in this order, which is also
--- the usual work flow: set the positions, generate the course, start the job.
SET_POSITIONS_TO_VEHICLE = 3,
GENERATE_COURSE = 4,
START_JOB = 5,
STOP_JOB = 6,
DELETE_CUSTOM_FIELD = 7,
RENAME_CUSTOM_FIELD = 8,
EDIT_CUSTOM_FIELD = 9,
DRAW_CUSTOM_FIELD = 10,
HOTSPOT_SELECT_ALL = 11
},
AI_MODE_OVERVIEW = 1,
AI_MODE_CREATE = 2,
Expand DownExpand Up@@ -945,6 +948,63 @@ function CpCourseGeneratorFrame:getIsPicking()
return self.isPickingRotation or self.isPickingLocation
end

--- Sets the target position (the position the helper drives to first, with the vehicle's direction)
--- and the field/silo position of the job currently being created to the vehicle's position, so
--- these don't have to be picked on the map when standing on the field already.
function CpCourseGeneratorFrame:setJobPositionsToVehiclePosition()
local vehicle = self.currentJobVehicle
if self.currentJob == nil or vehicle == nil or vehicle.rootNode == nil or self:getIsPicking() then
return
end
local x, _, z = getWorldTranslation(vehicle.rootNode)
local dirX, _, dirZ = localDirectionToWorld(vehicle.rootNode, 0, 0, 1)
local angle = MathUtil.getYRotationFromDirection(dirX, dirZ)
local changed = false
for _, element in ipairs(self.currentJobElements) do
local parameter = element.aiParameter
if parameter and parameter.is_a and parameter:is_a(CpAIParameterPosition) and parameter:getCanBeChanged() then
local positionType = parameter:getPositionType()
if positionType == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO then
parameter:setPosition(x, z)
if parameter.setAngle then
--- the target of the drive to task also has a direction, use the one the vehicle is facing
parameter:setAngle(angle)
end
changed = true
elseif positionType == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
parameter:setPosition(x, z)
changed = true
end
end
end
if changed then
--- this also restarts the field boundary detection for the new field position
self:validateParameters()
self:updateParameterValueTexts()
end
end

--- Adds a button to the job parameter list, which sets the target and the field position
--- to the vehicle's current position. It gets a group of its own so it is separated from
--- the position rows above and isn't clicked by accident.
function CpCourseGeneratorFrame:addSetPositionsToVehicleButton()
local titleElement = self.createTitleTemplate:clone(self.jobMenuLayout)
titleElement:setText(g_i18n:getText("CP_ai_page_positions_to_vehicle_title"))
--- Using the position parameter template, so the button looks and behaves exactly
--- like the position rows above it.
local element = self.createPositionTemplate:clone(self.jobMenuLayout)
FocusManager:loadElementFromCustomValues(element)
element:setText(g_i18n:getText("CP_ai_page_positions_to_vehicle"))
local invalidElement = element:getDescendantByName("invalid")
if invalidElement then
invalidElement:setVisible(false)
end
element.onClickCallback = function()
self:setJobPositionsToVehiclePosition()
end
return element
end

function CpCourseGeneratorFrame:validateParameters()
local isValid = true
local errorText = ""
Expand DownExpand Up@@ -1153,7 +1213,7 @@ function CpCourseGeneratorFrame:getNumberOfItemsInSection(list, section)
end
if list == self.contextButtonList then
self.contextActionMapping = {}
for index, action in pairs(self.contextActions) do
for index, action in ipairs(self.contextActions) do
if action.isActive and not action.actionOnly then
table.insert(self.contextActionMapping, index)
end
Expand All@@ -1165,7 +1225,7 @@ function CpCourseGeneratorFrame:getNumberOfItemsInSection(list, section)
end
if list == self.contextButtonCustomFieldList then
self.contextActionMapping = {}
for index, action in pairs(self.contextActions) do
for index, action in ipairs(self.contextActions) do
if action.isActive and not action.actionOnly then
table.insert(self.contextActionMapping, index)
end
Expand DownExpand Up@@ -1455,6 +1515,12 @@ function CpCourseGeneratorFrame:initializeContextActions()
callback = self.onCreateJob,
isActive = false
},
[self.CONTEXT_ACTIONS.SET_POSITIONS_TO_VEHICLE] = {
text = g_i18n:getText("CP_ai_page_positions_to_vehicle"),
action = InputAction.CP_SET_POSITIONS_TO_VEHICLE,
callback = self.setJobPositionsToVehiclePosition,
isActive = false
},
[self.CONTEXT_ACTIONS.START_JOB] = {
text = g_i18n:getText("button_startJob"),
action = InputAction.MENU_EXTRA_1,
Expand DownExpand Up@@ -1547,6 +1613,9 @@ function CpCourseGeneratorFrame:updateContextActions()
end
end
self.contextActions[self.CONTEXT_ACTIONS.CREATE_JOB].isActive = self.canCreateJob and self.mode ~= self.AI_MODE_CREATE
self.contextActions[self.CONTEXT_ACTIONS.SET_POSITIONS_TO_VEHICLE].isActive =
self.mode == self.AI_MODE_CREATE and self.currentJob ~= nil and
self.currentJobVehicle ~= nil and not self:getIsPicking()
self.contextActions[self.CONTEXT_ACTIONS.START_JOB].isActive = self:getCanStartJob()
self.contextActions[self.CONTEXT_ACTIONS.STOP_JOB].isActive = self:getCanCancelJob() and self.mode ~= self.AI_MODE_CREATE
self.contextActions[self.CONTEXT_ACTIONS.GENERATE_COURSE].isActive = self:getCanGenerateFieldWorkCourse()
Expand DownExpand Up@@ -1765,11 +1834,27 @@ function CpCourseGeneratorFrame:setActiveJobTypeSelection(jobTypeIndex)
end
self.currentJob:applyCurrentState(self.currentJobVehicle, g_currentMission, farmId, false)
self.currentJobElements = {}
--- The button setting the positions to the vehicle position goes right below the field/silo
--- position, or below the target position for jobs without a field position (silo loader).
local buttonAnchorPositionType = nil
for _, group in ipairs(self.currentJob:getGroupedParameters()) do
for _, item in ipairs(group:getParameters()) do
local positionType = item.getPositionType and item:getPositionType()
if positionType == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
buttonAnchorPositionType = positionType
elseif positionType == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO and
buttonAnchorPositionType == nil then
buttonAnchorPositionType = positionType
end
end
end
local isButtonAdded = false
for _, group in ipairs(self.currentJob:getGroupedParameters()) do
local titleElement = self.createTitleTemplate:clone(self.jobMenuLayout)

titleElement:setText(group:getTitle())

local isButtonAnchorGroup = false
for _, item in ipairs(group:getParameters()) do
local element = nil
local parameterType = item:getType()
Expand DownExpand Up@@ -1797,8 +1882,16 @@ function CpCourseGeneratorFrame:setActiveJobTypeSelection(jobTypeIndex)
end
element:setDisabled(not item:getCanBeChanged())
table.insert(self.currentJobElements, element)
if buttonAnchorPositionType ~= nil and item.getPositionType and
item:getPositionType() == buttonAnchorPositionType then
isButtonAnchorGroup = true
end
end
end
if isButtonAnchorGroup and not isButtonAdded then
self:addSetPositionsToVehicleButton()
isButtonAdded = true
end
end
self:validateParameters()
self:updateParameterValueTexts()
Expand Down
3 changes: 3 additions & 0 deletions translations/translation_de.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,6 +108,8 @@
<text name="CP_job_bunkerSilo" text="CP: Siloarbeit"/>
<text name="CP_job_siloLoader" text="CP: Silo laden"/>
<text name="CP_ai_page_generate_course" text="CP: Feldkurs generieren"/>
<text name="CP_ai_page_positions_to_vehicle" text="Ziel &amp; Feld auf Fahrzeug"/>
<text name="CP_ai_page_positions_to_vehicle_title" text="Positionen setzen"/>
<text name="CP_ai_page_open_course_generator" text="CP: Kursgenerator öffnen/schließen"/>
<!---->
<!--AI error messages-->
Expand DownExpand Up@@ -1076,6 +1078,7 @@ Das Kreuz sollte jetzt, wie im Bild dargestellt, gelb sein.
<text name="input_CP_START_STOP_AT_NEAREST_WAYPOINT" text="CP: CP-Helfer starten/stoppen (am nächsten Wegpunkt)"/>
<text name="input_CP_START_STOP_AT_LAST_WAYPOINT" text="CP: CP-Helfer starten/stoppen (am letzten Wegpunkt)"/>
<text name="input_CP_GENERATE_COURSE" text="CP: Kurs generieren"/>
<text name="input_CP_SET_POSITIONS_TO_VEHICLE" text="CP: Ziel &amp; Feld auf Fahrzeugposition setzen"/>
<text name="input_CP_CHANGE_SELECTED_JOB" text="CP: Aktuell ausgewählten Job ändern"/>
<text name="input_CP_CHANGE_STARTING_POINT" text="CP: Startpunkt ändern"/>
<text name="input_CP_CLEAR_COURSE" text="CP: Aktuell geladenen Kurs löschen"/>
Expand Down
3 changes: 3 additions & 0 deletions translations/translation_en.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,6 +108,8 @@
<text name="CP_job_bunkerSilo" text="CP: Silo work"/>
<text name="CP_job_siloLoader" text="CP: Silo loading"/>
<text name="CP_ai_page_generate_course" text="CP: Generate fieldwork course"/>
<text name="CP_ai_page_positions_to_vehicle" text="Target &amp; field to vehicle"/>
<text name="CP_ai_page_positions_to_vehicle_title" text="Set positions"/>
<text name="CP_ai_page_open_course_generator" text="CP: Open/close course generator"/>
<!---->
<!--AI error messages-->
Expand DownExpand Up@@ -1092,6 +1094,7 @@ Now your selection should look similar to the image.
<text name="input_CP_START_STOP_AT_NEAREST_WAYPOINT" text="CP: Start/stop driver (at nearest waypoint)"/>
<text name="input_CP_START_STOP_AT_LAST_WAYPOINT" text="CP: Start/stop driver (at last waypoint)"/>
<text name="input_CP_GENERATE_COURSE" text="CP: Generate course"/>
<text name="input_CP_SET_POSITIONS_TO_VEHICLE" text="CP: Set target &amp; field to vehicle position"/>
<text name="input_CP_CHANGE_SELECTED_JOB" text="CP: Change current selected job"/>
<text name="input_CP_CHANGE_STARTING_POINT" text="CP: Change starting point"/>
<text name="input_CP_CLEAR_COURSE" text="CP: Clear currently loaded course"/>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add a button to set the job positions to the vehicle position by helgehelge123 · Pull Request #1314 · Courseplay/Courseplay_FS25 · GitHub
Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions modDesc.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -404,6 +404,10 @@ Changelog 8.1.0.3
<actionBinding action="CP_GENERATE_COURSE">
<binding device="KB_MOUSE_DEFAULT" input="KEY_lctrl KEY_g" />
</actionBinding>
<!--- Only used in the course generator menu while creating a job, where KEY_v is free. -->
<actionBinding action="CP_SET_POSITIONS_TO_VEHICLE">
<binding device="KB_MOUSE_DEFAULT" input="KEY_v" />
</actionBinding>

<actionBinding action="CP_CHANGE_SELECTED_JOB">
<binding device="" input="" />
Expand DownExpand Up@@ -451,6 +455,7 @@ Changelog 8.1.0.3
<action name="CP_START_STOP_AT_NEAREST_WAYPOINT"/>
<action name="CP_START_STOP_AT_LAST_WAYPOINT"/>
<action name="CP_GENERATE_COURSE" />
<action name="CP_SET_POSITIONS_TO_VEHICLE" />

<action name="CP_CHANGE_SELECTED_JOB"/>
<action name="CP_CHANGE_STARTING_POINT"/>
Expand Down
113 changes: 103 additions & 10 deletions scripts/gui/pages/CpCourseGeneratorFrame.lua
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,14 +35,17 @@ CpCourseGeneratorFrame = {
CONTEXT_ACTIONS = {
ENTER_VEHICLE = 1,
CREATE_JOB = 2,
START_JOB = 3,
STOP_JOB = 4,
GENERATE_COURSE = 5,
DELETE_CUSTOM_FIELD = 6,
RENAME_CUSTOM_FIELD = 7,
EDIT_CUSTOM_FIELD = 8,
DRAW_CUSTOM_FIELD = 9,
HOTSPOT_SELECT_ALL = 10
--- These three show up in the create job button list in this order, which is also
--- the usual work flow: set the positions, generate the course, start the job.
SET_POSITIONS_TO_VEHICLE = 3,
GENERATE_COURSE = 4,
START_JOB = 5,
STOP_JOB = 6,
DELETE_CUSTOM_FIELD = 7,
RENAME_CUSTOM_FIELD = 8,
EDIT_CUSTOM_FIELD = 9,
DRAW_CUSTOM_FIELD = 10,
HOTSPOT_SELECT_ALL = 11
},
AI_MODE_OVERVIEW = 1,
AI_MODE_CREATE = 2,
Expand DownExpand Up@@ -945,6 +948,63 @@ function CpCourseGeneratorFrame:getIsPicking()
return self.isPickingRotation or self.isPickingLocation
end

--- Sets the target position (the position the helper drives to first, with the vehicle's direction)
--- and the field/silo position of the job currently being created to the vehicle's position, so
--- these don't have to be picked on the map when standing on the field already.
function CpCourseGeneratorFrame:setJobPositionsToVehiclePosition()
local vehicle = self.currentJobVehicle
if self.currentJob == nil or vehicle == nil or vehicle.rootNode == nil or self:getIsPicking() then
return
end
local x, _, z = getWorldTranslation(vehicle.rootNode)
local dirX, _, dirZ = localDirectionToWorld(vehicle.rootNode, 0, 0, 1)
local angle = MathUtil.getYRotationFromDirection(dirX, dirZ)
local changed = false
for _, element in ipairs(self.currentJobElements) do
local parameter = element.aiParameter
if parameter and parameter.is_a and parameter:is_a(CpAIParameterPosition) and parameter:getCanBeChanged() then
local positionType = parameter:getPositionType()
if positionType == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO then
parameter:setPosition(x, z)
if parameter.setAngle then
--- the target of the drive to task also has a direction, use the one the vehicle is facing
parameter:setAngle(angle)
end
changed = true
elseif positionType == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
parameter:setPosition(x, z)
changed = true
end
end
end
if changed then
--- this also restarts the field boundary detection for the new field position
self:validateParameters()
self:updateParameterValueTexts()
end
end

--- Adds a button to the job parameter list, which sets the target and the field position
--- to the vehicle's current position. It gets a group of its own so it is separated from
--- the position rows above and isn't clicked by accident.
function CpCourseGeneratorFrame:addSetPositionsToVehicleButton()
local titleElement = self.createTitleTemplate:clone(self.jobMenuLayout)
titleElement:setText(g_i18n:getText("CP_ai_page_positions_to_vehicle_title"))
--- Using the position parameter template, so the button looks and behaves exactly
--- like the position rows above it.
local element = self.createPositionTemplate:clone(self.jobMenuLayout)
FocusManager:loadElementFromCustomValues(element)
element:setText(g_i18n:getText("CP_ai_page_positions_to_vehicle"))
local invalidElement = element:getDescendantByName("invalid")
if invalidElement then
invalidElement:setVisible(false)
end
element.onClickCallback = function()
self:setJobPositionsToVehiclePosition()
end
return element
end

function CpCourseGeneratorFrame:validateParameters()
local isValid = true
local errorText = ""
Expand DownExpand Up@@ -1153,7 +1213,7 @@ function CpCourseGeneratorFrame:getNumberOfItemsInSection(list, section)
end
if list == self.contextButtonList then
self.contextActionMapping = {}
for index, action in pairs(self.contextActions) do
for index, action in ipairs(self.contextActions) do
if action.isActive and not action.actionOnly then
table.insert(self.contextActionMapping, index)
end
Expand All@@ -1165,7 +1225,7 @@ function CpCourseGeneratorFrame:getNumberOfItemsInSection(list, section)
end
if list == self.contextButtonCustomFieldList then
self.contextActionMapping = {}
for index, action in pairs(self.contextActions) do
for index, action in ipairs(self.contextActions) do
if action.isActive and not action.actionOnly then
table.insert(self.contextActionMapping, index)
end
Expand DownExpand Up@@ -1455,6 +1515,12 @@ function CpCourseGeneratorFrame:initializeContextActions()
callback = self.onCreateJob,
isActive = false
},
[self.CONTEXT_ACTIONS.SET_POSITIONS_TO_VEHICLE] = {
text = g_i18n:getText("CP_ai_page_positions_to_vehicle"),
action = InputAction.CP_SET_POSITIONS_TO_VEHICLE,
callback = self.setJobPositionsToVehiclePosition,
isActive = false
},
[self.CONTEXT_ACTIONS.START_JOB] = {
text = g_i18n:getText("button_startJob"),
action = InputAction.MENU_EXTRA_1,
Expand DownExpand Up@@ -1547,6 +1613,9 @@ function CpCourseGeneratorFrame:updateContextActions()
end
end
self.contextActions[self.CONTEXT_ACTIONS.CREATE_JOB].isActive = self.canCreateJob and self.mode ~= self.AI_MODE_CREATE
self.contextActions[self.CONTEXT_ACTIONS.SET_POSITIONS_TO_VEHICLE].isActive =
self.mode == self.AI_MODE_CREATE and self.currentJob ~= nil and
self.currentJobVehicle ~= nil and not self:getIsPicking()
self.contextActions[self.CONTEXT_ACTIONS.START_JOB].isActive = self:getCanStartJob()
self.contextActions[self.CONTEXT_ACTIONS.STOP_JOB].isActive = self:getCanCancelJob() and self.mode ~= self.AI_MODE_CREATE
self.contextActions[self.CONTEXT_ACTIONS.GENERATE_COURSE].isActive = self:getCanGenerateFieldWorkCourse()
Expand DownExpand Up@@ -1765,11 +1834,27 @@ function CpCourseGeneratorFrame:setActiveJobTypeSelection(jobTypeIndex)
end
self.currentJob:applyCurrentState(self.currentJobVehicle, g_currentMission, farmId, false)
self.currentJobElements = {}
--- The button setting the positions to the vehicle position goes right below the field/silo
--- position, or below the target position for jobs without a field position (silo loader).
local buttonAnchorPositionType = nil
for _, group in ipairs(self.currentJob:getGroupedParameters()) do
for _, item in ipairs(group:getParameters()) do
local positionType = item.getPositionType and item:getPositionType()
if positionType == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
buttonAnchorPositionType = positionType
elseif positionType == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO and
buttonAnchorPositionType == nil then
buttonAnchorPositionType = positionType
end
end
end
local isButtonAdded = false
for _, group in ipairs(self.currentJob:getGroupedParameters()) do
local titleElement = self.createTitleTemplate:clone(self.jobMenuLayout)

titleElement:setText(group:getTitle())

local isButtonAnchorGroup = false
for _, item in ipairs(group:getParameters()) do
local element = nil
local parameterType = item:getType()
Expand DownExpand Up@@ -1797,8 +1882,16 @@ function CpCourseGeneratorFrame:setActiveJobTypeSelection(jobTypeIndex)
end
element:setDisabled(not item:getCanBeChanged())
table.insert(self.currentJobElements, element)
if buttonAnchorPositionType ~= nil and item.getPositionType and
item:getPositionType() == buttonAnchorPositionType then
isButtonAnchorGroup = true
end
end
end
if isButtonAnchorGroup and not isButtonAdded then
self:addSetPositionsToVehicleButton()
isButtonAdded = true
end
end
self:validateParameters()
self:updateParameterValueTexts()
Expand Down
3 changes: 3 additions & 0 deletions translations/translation_de.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,6 +108,8 @@
<text name="CP_job_bunkerSilo" text="CP: Siloarbeit"/>
<text name="CP_job_siloLoader" text="CP: Silo laden"/>
<text name="CP_ai_page_generate_course" text="CP: Feldkurs generieren"/>
<text name="CP_ai_page_positions_to_vehicle" text="Ziel &amp; Feld auf Fahrzeug"/>
<text name="CP_ai_page_positions_to_vehicle_title" text="Positionen setzen"/>
<text name="CP_ai_page_open_course_generator" text="CP: Kursgenerator öffnen/schließen"/>
<!---->
<!--AI error messages-->
Expand DownExpand Up@@ -1076,6 +1078,7 @@ Das Kreuz sollte jetzt, wie im Bild dargestellt, gelb sein.
<text name="input_CP_START_STOP_AT_NEAREST_WAYPOINT" text="CP: CP-Helfer starten/stoppen (am nächsten Wegpunkt)"/>
<text name="input_CP_START_STOP_AT_LAST_WAYPOINT" text="CP: CP-Helfer starten/stoppen (am letzten Wegpunkt)"/>
<text name="input_CP_GENERATE_COURSE" text="CP: Kurs generieren"/>
<text name="input_CP_SET_POSITIONS_TO_VEHICLE" text="CP: Ziel &amp; Feld auf Fahrzeugposition setzen"/>
<text name="input_CP_CHANGE_SELECTED_JOB" text="CP: Aktuell ausgewählten Job ändern"/>
<text name="input_CP_CHANGE_STARTING_POINT" text="CP: Startpunkt ändern"/>
<text name="input_CP_CLEAR_COURSE" text="CP: Aktuell geladenen Kurs löschen"/>
Expand Down
3 changes: 3 additions & 0 deletions translations/translation_en.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,6 +108,8 @@
<text name="CP_job_bunkerSilo" text="CP: Silo work"/>
<text name="CP_job_siloLoader" text="CP: Silo loading"/>
<text name="CP_ai_page_generate_course" text="CP: Generate fieldwork course"/>
<text name="CP_ai_page_positions_to_vehicle" text="Target &amp; field to vehicle"/>
<text name="CP_ai_page_positions_to_vehicle_title" text="Set positions"/>
<text name="CP_ai_page_open_course_generator" text="CP: Open/close course generator"/>
<!---->
<!--AI error messages-->
Expand DownExpand Up@@ -1092,6 +1094,7 @@ Now your selection should look similar to the image.
<text name="input_CP_START_STOP_AT_NEAREST_WAYPOINT" text="CP: Start/stop driver (at nearest waypoint)"/>
<text name="input_CP_START_STOP_AT_LAST_WAYPOINT" text="CP: Start/stop driver (at last waypoint)"/>
<text name="input_CP_GENERATE_COURSE" text="CP: Generate course"/>
<text name="input_CP_SET_POSITIONS_TO_VEHICLE" text="CP: Set target &amp; field to vehicle position"/>
<text name="input_CP_CHANGE_SELECTED_JOB" text="CP: Change current selected job"/>
<text name="input_CP_CHANGE_STARTING_POINT" text="CP: Change starting point"/>
<text name="input_CP_CLEAR_COURSE" text="CP: Clear currently loaded course"/>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Add a button to set the job positions to the vehicle position by helgehelge123 · Pull Request #1314 · Courseplay/Courseplay_FS25 · GitHub
Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions modDesc.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -404,6 +404,10 @@ Changelog 8.1.0.3
<actionBinding action="CP_GENERATE_COURSE">
<binding device="KB_MOUSE_DEFAULT" input="KEY_lctrl KEY_g" />
</actionBinding>
<!--- Only used in the course generator menu while creating a job, where KEY_v is free. -->
<actionBinding action="CP_SET_POSITIONS_TO_VEHICLE">
<binding device="KB_MOUSE_DEFAULT" input="KEY_v" />
</actionBinding>

<actionBinding action="CP_CHANGE_SELECTED_JOB">
<binding device="" input="" />
Expand DownExpand Up@@ -451,6 +455,7 @@ Changelog 8.1.0.3
<action name="CP_START_STOP_AT_NEAREST_WAYPOINT"/>
<action name="CP_START_STOP_AT_LAST_WAYPOINT"/>
<action name="CP_GENERATE_COURSE" />
<action name="CP_SET_POSITIONS_TO_VEHICLE" />

<action name="CP_CHANGE_SELECTED_JOB"/>
<action name="CP_CHANGE_STARTING_POINT"/>
Expand Down
113 changes: 103 additions & 10 deletions scripts/gui/pages/CpCourseGeneratorFrame.lua
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,14 +35,17 @@ CpCourseGeneratorFrame = {
CONTEXT_ACTIONS = {
ENTER_VEHICLE = 1,
CREATE_JOB = 2,
START_JOB = 3,
STOP_JOB = 4,
GENERATE_COURSE = 5,
DELETE_CUSTOM_FIELD = 6,
RENAME_CUSTOM_FIELD = 7,
EDIT_CUSTOM_FIELD = 8,
DRAW_CUSTOM_FIELD = 9,
HOTSPOT_SELECT_ALL = 10
--- These three show up in the create job button list in this order, which is also
--- the usual work flow: set the positions, generate the course, start the job.
SET_POSITIONS_TO_VEHICLE = 3,
GENERATE_COURSE = 4,
START_JOB = 5,
STOP_JOB = 6,
DELETE_CUSTOM_FIELD = 7,
RENAME_CUSTOM_FIELD = 8,
EDIT_CUSTOM_FIELD = 9,
DRAW_CUSTOM_FIELD = 10,
HOTSPOT_SELECT_ALL = 11
},
AI_MODE_OVERVIEW = 1,
AI_MODE_CREATE = 2,
Expand DownExpand Up@@ -945,6 +948,63 @@ function CpCourseGeneratorFrame:getIsPicking()
return self.isPickingRotation or self.isPickingLocation
end

--- Sets the target position (the position the helper drives to first, with the vehicle's direction)
--- and the field/silo position of the job currently being created to the vehicle's position, so
--- these don't have to be picked on the map when standing on the field already.
function CpCourseGeneratorFrame:setJobPositionsToVehiclePosition()
local vehicle = self.currentJobVehicle
if self.currentJob == nil or vehicle == nil or vehicle.rootNode == nil or self:getIsPicking() then
return
end
local x, _, z = getWorldTranslation(vehicle.rootNode)
local dirX, _, dirZ = localDirectionToWorld(vehicle.rootNode, 0, 0, 1)
local angle = MathUtil.getYRotationFromDirection(dirX, dirZ)
local changed = false
for _, element in ipairs(self.currentJobElements) do
local parameter = element.aiParameter
if parameter and parameter.is_a and parameter:is_a(CpAIParameterPosition) and parameter:getCanBeChanged() then
local positionType = parameter:getPositionType()
if positionType == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO then
parameter:setPosition(x, z)
if parameter.setAngle then
--- the target of the drive to task also has a direction, use the one the vehicle is facing
parameter:setAngle(angle)
end
changed = true
elseif positionType == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
parameter:setPosition(x, z)
changed = true
end
end
end
if changed then
--- this also restarts the field boundary detection for the new field position
self:validateParameters()
self:updateParameterValueTexts()
end
end

--- Adds a button to the job parameter list, which sets the target and the field position
--- to the vehicle's current position. It gets a group of its own so it is separated from
--- the position rows above and isn't clicked by accident.
function CpCourseGeneratorFrame:addSetPositionsToVehicleButton()
local titleElement = self.createTitleTemplate:clone(self.jobMenuLayout)
titleElement:setText(g_i18n:getText("CP_ai_page_positions_to_vehicle_title"))
--- Using the position parameter template, so the button looks and behaves exactly
--- like the position rows above it.
local element = self.createPositionTemplate:clone(self.jobMenuLayout)
FocusManager:loadElementFromCustomValues(element)
element:setText(g_i18n:getText("CP_ai_page_positions_to_vehicle"))
local invalidElement = element:getDescendantByName("invalid")
if invalidElement then
invalidElement:setVisible(false)
end
element.onClickCallback = function()
self:setJobPositionsToVehiclePosition()
end
return element
end

function CpCourseGeneratorFrame:validateParameters()
local isValid = true
local errorText = ""
Expand DownExpand Up@@ -1153,7 +1213,7 @@ function CpCourseGeneratorFrame:getNumberOfItemsInSection(list, section)
end
if list == self.contextButtonList then
self.contextActionMapping = {}
for index, action in pairs(self.contextActions) do
for index, action in ipairs(self.contextActions) do
if action.isActive and not action.actionOnly then
table.insert(self.contextActionMapping, index)
end
Expand All@@ -1165,7 +1225,7 @@ function CpCourseGeneratorFrame:getNumberOfItemsInSection(list, section)
end
if list == self.contextButtonCustomFieldList then
self.contextActionMapping = {}
for index, action in pairs(self.contextActions) do
for index, action in ipairs(self.contextActions) do
if action.isActive and not action.actionOnly then
table.insert(self.contextActionMapping, index)
end
Expand DownExpand Up@@ -1455,6 +1515,12 @@ function CpCourseGeneratorFrame:initializeContextActions()
callback = self.onCreateJob,
isActive = false
},
[self.CONTEXT_ACTIONS.SET_POSITIONS_TO_VEHICLE] = {
text = g_i18n:getText("CP_ai_page_positions_to_vehicle"),
action = InputAction.CP_SET_POSITIONS_TO_VEHICLE,
callback = self.setJobPositionsToVehiclePosition,
isActive = false
},
[self.CONTEXT_ACTIONS.START_JOB] = {
text = g_i18n:getText("button_startJob"),
action = InputAction.MENU_EXTRA_1,
Expand DownExpand Up@@ -1547,6 +1613,9 @@ function CpCourseGeneratorFrame:updateContextActions()
end
end
self.contextActions[self.CONTEXT_ACTIONS.CREATE_JOB].isActive = self.canCreateJob and self.mode ~= self.AI_MODE_CREATE
self.contextActions[self.CONTEXT_ACTIONS.SET_POSITIONS_TO_VEHICLE].isActive =
self.mode == self.AI_MODE_CREATE and self.currentJob ~= nil and
self.currentJobVehicle ~= nil and not self:getIsPicking()
self.contextActions[self.CONTEXT_ACTIONS.START_JOB].isActive = self:getCanStartJob()
self.contextActions[self.CONTEXT_ACTIONS.STOP_JOB].isActive = self:getCanCancelJob() and self.mode ~= self.AI_MODE_CREATE
self.contextActions[self.CONTEXT_ACTIONS.GENERATE_COURSE].isActive = self:getCanGenerateFieldWorkCourse()
Expand DownExpand Up@@ -1765,11 +1834,27 @@ function CpCourseGeneratorFrame:setActiveJobTypeSelection(jobTypeIndex)
end
self.currentJob:applyCurrentState(self.currentJobVehicle, g_currentMission, farmId, false)
self.currentJobElements = {}
--- The button setting the positions to the vehicle position goes right below the field/silo
--- position, or below the target position for jobs without a field position (silo loader).
local buttonAnchorPositionType = nil
for _, group in ipairs(self.currentJob:getGroupedParameters()) do
for _, item in ipairs(group:getParameters()) do
local positionType = item.getPositionType and item:getPositionType()
if positionType == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
buttonAnchorPositionType = positionType
elseif positionType == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO and
buttonAnchorPositionType == nil then
buttonAnchorPositionType = positionType
end
end
end
local isButtonAdded = false
for _, group in ipairs(self.currentJob:getGroupedParameters()) do
local titleElement = self.createTitleTemplate:clone(self.jobMenuLayout)

titleElement:setText(group:getTitle())

local isButtonAnchorGroup = false
for _, item in ipairs(group:getParameters()) do
local element = nil
local parameterType = item:getType()
Expand DownExpand Up@@ -1797,8 +1882,16 @@ function CpCourseGeneratorFrame:setActiveJobTypeSelection(jobTypeIndex)
end
element:setDisabled(not item:getCanBeChanged())
table.insert(self.currentJobElements, element)
if buttonAnchorPositionType ~= nil and item.getPositionType and
item:getPositionType() == buttonAnchorPositionType then
isButtonAnchorGroup = true
end
end
end
if isButtonAnchorGroup and not isButtonAdded then
self:addSetPositionsToVehicleButton()
isButtonAdded = true
end
end
self:validateParameters()
self:updateParameterValueTexts()
Expand Down
3 changes: 3 additions & 0 deletions translations/translation_de.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,6 +108,8 @@
<text name="CP_job_bunkerSilo" text="CP: Siloarbeit"/>
<text name="CP_job_siloLoader" text="CP: Silo laden"/>
<text name="CP_ai_page_generate_course" text="CP: Feldkurs generieren"/>
<text name="CP_ai_page_positions_to_vehicle" text="Ziel &amp; Feld auf Fahrzeug"/>
<text name="CP_ai_page_positions_to_vehicle_title" text="Positionen setzen"/>
<text name="CP_ai_page_open_course_generator" text="CP: Kursgenerator öffnen/schließen"/>
<!---->
<!--AI error messages-->
Expand DownExpand Up@@ -1076,6 +1078,7 @@ Das Kreuz sollte jetzt, wie im Bild dargestellt, gelb sein.
<text name="input_CP_START_STOP_AT_NEAREST_WAYPOINT" text="CP: CP-Helfer starten/stoppen (am nächsten Wegpunkt)"/>
<text name="input_CP_START_STOP_AT_LAST_WAYPOINT" text="CP: CP-Helfer starten/stoppen (am letzten Wegpunkt)"/>
<text name="input_CP_GENERATE_COURSE" text="CP: Kurs generieren"/>
<text name="input_CP_SET_POSITIONS_TO_VEHICLE" text="CP: Ziel &amp; Feld auf Fahrzeugposition setzen"/>
<text name="input_CP_CHANGE_SELECTED_JOB" text="CP: Aktuell ausgewählten Job ändern"/>
<text name="input_CP_CHANGE_STARTING_POINT" text="CP: Startpunkt ändern"/>
<text name="input_CP_CLEAR_COURSE" text="CP: Aktuell geladenen Kurs löschen"/>
Expand Down
3 changes: 3 additions & 0 deletions translations/translation_en.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,6 +108,8 @@
<text name="CP_job_bunkerSilo" text="CP: Silo work"/>
<text name="CP_job_siloLoader" text="CP: Silo loading"/>
<text name="CP_ai_page_generate_course" text="CP: Generate fieldwork course"/>
<text name="CP_ai_page_positions_to_vehicle" text="Target &amp; field to vehicle"/>
<text name="CP_ai_page_positions_to_vehicle_title" text="Set positions"/>
<text name="CP_ai_page_open_course_generator" text="CP: Open/close course generator"/>
<!---->
<!--AI error messages-->
Expand DownExpand Up@@ -1092,6 +1094,7 @@ Now your selection should look similar to the image.
<text name="input_CP_START_STOP_AT_NEAREST_WAYPOINT" text="CP: Start/stop driver (at nearest waypoint)"/>
<text name="input_CP_START_STOP_AT_LAST_WAYPOINT" text="CP: Start/stop driver (at last waypoint)"/>
<text name="input_CP_GENERATE_COURSE" text="CP: Generate course"/>
<text name="input_CP_SET_POSITIONS_TO_VEHICLE" text="CP: Set target &amp; field to vehicle position"/>
<text name="input_CP_CHANGE_SELECTED_JOB" text="CP: Change current selected job"/>
<text name="input_CP_CHANGE_STARTING_POINT" text="CP: Change starting point"/>
<text name="input_CP_CLEAR_COURSE" text="CP: Clear currently loaded course"/>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add a button to set the job positions to the vehicle position by helgehelge123 · Pull Request #1314 · Courseplay/Courseplay_FS25 · GitHub
Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions modDesc.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -404,6 +404,10 @@ Changelog 8.1.0.3
<actionBinding action="CP_GENERATE_COURSE">
<binding device="KB_MOUSE_DEFAULT" input="KEY_lctrl KEY_g" />
</actionBinding>
<!--- Only used in the course generator menu while creating a job, where KEY_v is free. -->
<actionBinding action="CP_SET_POSITIONS_TO_VEHICLE">
<binding device="KB_MOUSE_DEFAULT" input="KEY_v" />
</actionBinding>

<actionBinding action="CP_CHANGE_SELECTED_JOB">
<binding device="" input="" />
Expand DownExpand Up@@ -451,6 +455,7 @@ Changelog 8.1.0.3
<action name="CP_START_STOP_AT_NEAREST_WAYPOINT"/>
<action name="CP_START_STOP_AT_LAST_WAYPOINT"/>
<action name="CP_GENERATE_COURSE" />
<action name="CP_SET_POSITIONS_TO_VEHICLE" />

<action name="CP_CHANGE_SELECTED_JOB"/>
<action name="CP_CHANGE_STARTING_POINT"/>
Expand Down
113 changes: 103 additions & 10 deletions scripts/gui/pages/CpCourseGeneratorFrame.lua
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,14 +35,17 @@ CpCourseGeneratorFrame = {
CONTEXT_ACTIONS = {
ENTER_VEHICLE = 1,
CREATE_JOB = 2,
START_JOB = 3,
STOP_JOB = 4,
GENERATE_COURSE = 5,
DELETE_CUSTOM_FIELD = 6,
RENAME_CUSTOM_FIELD = 7,
EDIT_CUSTOM_FIELD = 8,
DRAW_CUSTOM_FIELD = 9,
HOTSPOT_SELECT_ALL = 10
--- These three show up in the create job button list in this order, which is also
--- the usual work flow: set the positions, generate the course, start the job.
SET_POSITIONS_TO_VEHICLE = 3,
GENERATE_COURSE = 4,
START_JOB = 5,
STOP_JOB = 6,
DELETE_CUSTOM_FIELD = 7,
RENAME_CUSTOM_FIELD = 8,
EDIT_CUSTOM_FIELD = 9,
DRAW_CUSTOM_FIELD = 10,
HOTSPOT_SELECT_ALL = 11
},
AI_MODE_OVERVIEW = 1,
AI_MODE_CREATE = 2,
Expand DownExpand Up@@ -945,6 +948,63 @@ function CpCourseGeneratorFrame:getIsPicking()
return self.isPickingRotation or self.isPickingLocation
end

--- Sets the target position (the position the helper drives to first, with the vehicle's direction)
--- and the field/silo position of the job currently being created to the vehicle's position, so
--- these don't have to be picked on the map when standing on the field already.
function CpCourseGeneratorFrame:setJobPositionsToVehiclePosition()
local vehicle = self.currentJobVehicle
if self.currentJob == nil or vehicle == nil or vehicle.rootNode == nil or self:getIsPicking() then
return
end
local x, _, z = getWorldTranslation(vehicle.rootNode)
local dirX, _, dirZ = localDirectionToWorld(vehicle.rootNode, 0, 0, 1)
local angle = MathUtil.getYRotationFromDirection(dirX, dirZ)
local changed = false
for _, element in ipairs(self.currentJobElements) do
local parameter = element.aiParameter
if parameter and parameter.is_a and parameter:is_a(CpAIParameterPosition) and parameter:getCanBeChanged() then
local positionType = parameter:getPositionType()
if positionType == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO then
parameter:setPosition(x, z)
if parameter.setAngle then
--- the target of the drive to task also has a direction, use the one the vehicle is facing
parameter:setAngle(angle)
end
changed = true
elseif positionType == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
parameter:setPosition(x, z)
changed = true
end
end
end
if changed then
--- this also restarts the field boundary detection for the new field position
self:validateParameters()
self:updateParameterValueTexts()
end
end

--- Adds a button to the job parameter list, which sets the target and the field position
--- to the vehicle's current position. It gets a group of its own so it is separated from
--- the position rows above and isn't clicked by accident.
function CpCourseGeneratorFrame:addSetPositionsToVehicleButton()
local titleElement = self.createTitleTemplate:clone(self.jobMenuLayout)
titleElement:setText(g_i18n:getText("CP_ai_page_positions_to_vehicle_title"))
--- Using the position parameter template, so the button looks and behaves exactly
--- like the position rows above it.
local element = self.createPositionTemplate:clone(self.jobMenuLayout)
FocusManager:loadElementFromCustomValues(element)
element:setText(g_i18n:getText("CP_ai_page_positions_to_vehicle"))
local invalidElement = element:getDescendantByName("invalid")
if invalidElement then
invalidElement:setVisible(false)
end
element.onClickCallback = function()
self:setJobPositionsToVehiclePosition()
end
return element
end

function CpCourseGeneratorFrame:validateParameters()
local isValid = true
local errorText = ""
Expand DownExpand Up@@ -1153,7 +1213,7 @@ function CpCourseGeneratorFrame:getNumberOfItemsInSection(list, section)
end
if list == self.contextButtonList then
self.contextActionMapping = {}
for index, action in pairs(self.contextActions) do
for index, action in ipairs(self.contextActions) do
if action.isActive and not action.actionOnly then
table.insert(self.contextActionMapping, index)
end
Expand All@@ -1165,7 +1225,7 @@ function CpCourseGeneratorFrame:getNumberOfItemsInSection(list, section)
end
if list == self.contextButtonCustomFieldList then
self.contextActionMapping = {}
for index, action in pairs(self.contextActions) do
for index, action in ipairs(self.contextActions) do
if action.isActive and not action.actionOnly then
table.insert(self.contextActionMapping, index)
end
Expand DownExpand Up@@ -1455,6 +1515,12 @@ function CpCourseGeneratorFrame:initializeContextActions()
callback = self.onCreateJob,
isActive = false
},
[self.CONTEXT_ACTIONS.SET_POSITIONS_TO_VEHICLE] = {
text = g_i18n:getText("CP_ai_page_positions_to_vehicle"),
action = InputAction.CP_SET_POSITIONS_TO_VEHICLE,
callback = self.setJobPositionsToVehiclePosition,
isActive = false
},
[self.CONTEXT_ACTIONS.START_JOB] = {
text = g_i18n:getText("button_startJob"),
action = InputAction.MENU_EXTRA_1,
Expand DownExpand Up@@ -1547,6 +1613,9 @@ function CpCourseGeneratorFrame:updateContextActions()
end
end
self.contextActions[self.CONTEXT_ACTIONS.CREATE_JOB].isActive = self.canCreateJob and self.mode ~= self.AI_MODE_CREATE
self.contextActions[self.CONTEXT_ACTIONS.SET_POSITIONS_TO_VEHICLE].isActive =
self.mode == self.AI_MODE_CREATE and self.currentJob ~= nil and
self.currentJobVehicle ~= nil and not self:getIsPicking()
self.contextActions[self.CONTEXT_ACTIONS.START_JOB].isActive = self:getCanStartJob()
self.contextActions[self.CONTEXT_ACTIONS.STOP_JOB].isActive = self:getCanCancelJob() and self.mode ~= self.AI_MODE_CREATE
self.contextActions[self.CONTEXT_ACTIONS.GENERATE_COURSE].isActive = self:getCanGenerateFieldWorkCourse()
Expand DownExpand Up@@ -1765,11 +1834,27 @@ function CpCourseGeneratorFrame:setActiveJobTypeSelection(jobTypeIndex)
end
self.currentJob:applyCurrentState(self.currentJobVehicle, g_currentMission, farmId, false)
self.currentJobElements = {}
--- The button setting the positions to the vehicle position goes right below the field/silo
--- position, or below the target position for jobs without a field position (silo loader).
local buttonAnchorPositionType = nil
for _, group in ipairs(self.currentJob:getGroupedParameters()) do
for _, item in ipairs(group:getParameters()) do
local positionType = item.getPositionType and item:getPositionType()
if positionType == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
buttonAnchorPositionType = positionType
elseif positionType == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO and
buttonAnchorPositionType == nil then
buttonAnchorPositionType = positionType
end
end
end
local isButtonAdded = false
for _, group in ipairs(self.currentJob:getGroupedParameters()) do
local titleElement = self.createTitleTemplate:clone(self.jobMenuLayout)

titleElement:setText(group:getTitle())

local isButtonAnchorGroup = false
for _, item in ipairs(group:getParameters()) do
local element = nil
local parameterType = item:getType()
Expand DownExpand Up@@ -1797,8 +1882,16 @@ function CpCourseGeneratorFrame:setActiveJobTypeSelection(jobTypeIndex)
end
element:setDisabled(not item:getCanBeChanged())
table.insert(self.currentJobElements, element)
if buttonAnchorPositionType ~= nil and item.getPositionType and
item:getPositionType() == buttonAnchorPositionType then
isButtonAnchorGroup = true
end
end
end
if isButtonAnchorGroup and not isButtonAdded then
self:addSetPositionsToVehicleButton()
isButtonAdded = true
end
end
self:validateParameters()
self:updateParameterValueTexts()
Expand Down
3 changes: 3 additions & 0 deletions translations/translation_de.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,6 +108,8 @@
<text name="CP_job_bunkerSilo" text="CP: Siloarbeit"/>
<text name="CP_job_siloLoader" text="CP: Silo laden"/>
<text name="CP_ai_page_generate_course" text="CP: Feldkurs generieren"/>
<text name="CP_ai_page_positions_to_vehicle" text="Ziel &amp; Feld auf Fahrzeug"/>
<text name="CP_ai_page_positions_to_vehicle_title" text="Positionen setzen"/>
<text name="CP_ai_page_open_course_generator" text="CP: Kursgenerator öffnen/schließen"/>
<!---->
<!--AI error messages-->
Expand DownExpand Up@@ -1076,6 +1078,7 @@ Das Kreuz sollte jetzt, wie im Bild dargestellt, gelb sein.
<text name="input_CP_START_STOP_AT_NEAREST_WAYPOINT" text="CP: CP-Helfer starten/stoppen (am nächsten Wegpunkt)"/>
<text name="input_CP_START_STOP_AT_LAST_WAYPOINT" text="CP: CP-Helfer starten/stoppen (am letzten Wegpunkt)"/>
<text name="input_CP_GENERATE_COURSE" text="CP: Kurs generieren"/>
<text name="input_CP_SET_POSITIONS_TO_VEHICLE" text="CP: Ziel &amp; Feld auf Fahrzeugposition setzen"/>
<text name="input_CP_CHANGE_SELECTED_JOB" text="CP: Aktuell ausgewählten Job ändern"/>
<text name="input_CP_CHANGE_STARTING_POINT" text="CP: Startpunkt ändern"/>
<text name="input_CP_CLEAR_COURSE" text="CP: Aktuell geladenen Kurs löschen"/>
Expand Down
3 changes: 3 additions & 0 deletions translations/translation_en.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,6 +108,8 @@
<text name="CP_job_bunkerSilo" text="CP: Silo work"/>
<text name="CP_job_siloLoader" text="CP: Silo loading"/>
<text name="CP_ai_page_generate_course" text="CP: Generate fieldwork course"/>
<text name="CP_ai_page_positions_to_vehicle" text="Target &amp; field to vehicle"/>
<text name="CP_ai_page_positions_to_vehicle_title" text="Set positions"/>
<text name="CP_ai_page_open_course_generator" text="CP: Open/close course generator"/>
<!---->
<!--AI error messages-->
Expand DownExpand Up@@ -1092,6 +1094,7 @@ Now your selection should look similar to the image.
<text name="input_CP_START_STOP_AT_NEAREST_WAYPOINT" text="CP: Start/stop driver (at nearest waypoint)"/>
<text name="input_CP_START_STOP_AT_LAST_WAYPOINT" text="CP: Start/stop driver (at last waypoint)"/>
<text name="input_CP_GENERATE_COURSE" text="CP: Generate course"/>
<text name="input_CP_SET_POSITIONS_TO_VEHICLE" text="CP: Set target &amp; field to vehicle position"/>
<text name="input_CP_CHANGE_SELECTED_JOB" text="CP: Change current selected job"/>
<text name="input_CP_CHANGE_STARTING_POINT" text="CP: Change starting point"/>
<text name="input_CP_CLEAR_COURSE" text="CP: Clear currently loaded course"/>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add a button to set the job positions to the vehicle position by helgehelge123 · Pull Request #1314 · Courseplay/Courseplay_FS25 · GitHub
Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions modDesc.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -404,6 +404,10 @@ Changelog 8.1.0.3
<actionBinding action="CP_GENERATE_COURSE">
<binding device="KB_MOUSE_DEFAULT" input="KEY_lctrl KEY_g" />
</actionBinding>
<!--- Only used in the course generator menu while creating a job, where KEY_v is free. -->
<actionBinding action="CP_SET_POSITIONS_TO_VEHICLE">
<binding device="KB_MOUSE_DEFAULT" input="KEY_v" />
</actionBinding>

<actionBinding action="CP_CHANGE_SELECTED_JOB">
<binding device="" input="" />
Expand DownExpand Up@@ -451,6 +455,7 @@ Changelog 8.1.0.3
<action name="CP_START_STOP_AT_NEAREST_WAYPOINT"/>
<action name="CP_START_STOP_AT_LAST_WAYPOINT"/>
<action name="CP_GENERATE_COURSE" />
<action name="CP_SET_POSITIONS_TO_VEHICLE" />

<action name="CP_CHANGE_SELECTED_JOB"/>
<action name="CP_CHANGE_STARTING_POINT"/>
Expand Down
113 changes: 103 additions & 10 deletions scripts/gui/pages/CpCourseGeneratorFrame.lua
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,14 +35,17 @@ CpCourseGeneratorFrame = {
CONTEXT_ACTIONS = {
ENTER_VEHICLE = 1,
CREATE_JOB = 2,
START_JOB = 3,
STOP_JOB = 4,
GENERATE_COURSE = 5,
DELETE_CUSTOM_FIELD = 6,
RENAME_CUSTOM_FIELD = 7,
EDIT_CUSTOM_FIELD = 8,
DRAW_CUSTOM_FIELD = 9,
HOTSPOT_SELECT_ALL = 10
--- These three show up in the create job button list in this order, which is also
--- the usual work flow: set the positions, generate the course, start the job.
SET_POSITIONS_TO_VEHICLE = 3,
GENERATE_COURSE = 4,
START_JOB = 5,
STOP_JOB = 6,
DELETE_CUSTOM_FIELD = 7,
RENAME_CUSTOM_FIELD = 8,
EDIT_CUSTOM_FIELD = 9,
DRAW_CUSTOM_FIELD = 10,
HOTSPOT_SELECT_ALL = 11
},
AI_MODE_OVERVIEW = 1,
AI_MODE_CREATE = 2,
Expand DownExpand Up@@ -945,6 +948,63 @@ function CpCourseGeneratorFrame:getIsPicking()
return self.isPickingRotation or self.isPickingLocation
end

--- Sets the target position (the position the helper drives to first, with the vehicle's direction)
--- and the field/silo position of the job currently being created to the vehicle's position, so
--- these don't have to be picked on the map when standing on the field already.
function CpCourseGeneratorFrame:setJobPositionsToVehiclePosition()
local vehicle = self.currentJobVehicle
if self.currentJob == nil or vehicle == nil or vehicle.rootNode == nil or self:getIsPicking() then
return
end
local x, _, z = getWorldTranslation(vehicle.rootNode)
local dirX, _, dirZ = localDirectionToWorld(vehicle.rootNode, 0, 0, 1)
local angle = MathUtil.getYRotationFromDirection(dirX, dirZ)
local changed = false
for _, element in ipairs(self.currentJobElements) do
local parameter = element.aiParameter
if parameter and parameter.is_a and parameter:is_a(CpAIParameterPosition) and parameter:getCanBeChanged() then
local positionType = parameter:getPositionType()
if positionType == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO then
parameter:setPosition(x, z)
if parameter.setAngle then
--- the target of the drive to task also has a direction, use the one the vehicle is facing
parameter:setAngle(angle)
end
changed = true
elseif positionType == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
parameter:setPosition(x, z)
changed = true
end
end
end
if changed then
--- this also restarts the field boundary detection for the new field position
self:validateParameters()
self:updateParameterValueTexts()
end
end

--- Adds a button to the job parameter list, which sets the target and the field position
--- to the vehicle's current position. It gets a group of its own so it is separated from
--- the position rows above and isn't clicked by accident.
function CpCourseGeneratorFrame:addSetPositionsToVehicleButton()
local titleElement = self.createTitleTemplate:clone(self.jobMenuLayout)
titleElement:setText(g_i18n:getText("CP_ai_page_positions_to_vehicle_title"))
--- Using the position parameter template, so the button looks and behaves exactly
--- like the position rows above it.
local element = self.createPositionTemplate:clone(self.jobMenuLayout)
FocusManager:loadElementFromCustomValues(element)
element:setText(g_i18n:getText("CP_ai_page_positions_to_vehicle"))
local invalidElement = element:getDescendantByName("invalid")
if invalidElement then
invalidElement:setVisible(false)
end
element.onClickCallback = function()
self:setJobPositionsToVehiclePosition()
end
return element
end

function CpCourseGeneratorFrame:validateParameters()
local isValid = true
local errorText = ""
Expand DownExpand Up@@ -1153,7 +1213,7 @@ function CpCourseGeneratorFrame:getNumberOfItemsInSection(list, section)
end
if list == self.contextButtonList then
self.contextActionMapping = {}
for index, action in pairs(self.contextActions) do
for index, action in ipairs(self.contextActions) do
if action.isActive and not action.actionOnly then
table.insert(self.contextActionMapping, index)
end
Expand All@@ -1165,7 +1225,7 @@ function CpCourseGeneratorFrame:getNumberOfItemsInSection(list, section)
end
if list == self.contextButtonCustomFieldList then
self.contextActionMapping = {}
for index, action in pairs(self.contextActions) do
for index, action in ipairs(self.contextActions) do
if action.isActive and not action.actionOnly then
table.insert(self.contextActionMapping, index)
end
Expand DownExpand Up@@ -1455,6 +1515,12 @@ function CpCourseGeneratorFrame:initializeContextActions()
callback = self.onCreateJob,
isActive = false
},
[self.CONTEXT_ACTIONS.SET_POSITIONS_TO_VEHICLE] = {
text = g_i18n:getText("CP_ai_page_positions_to_vehicle"),
action = InputAction.CP_SET_POSITIONS_TO_VEHICLE,
callback = self.setJobPositionsToVehiclePosition,
isActive = false
},
[self.CONTEXT_ACTIONS.START_JOB] = {
text = g_i18n:getText("button_startJob"),
action = InputAction.MENU_EXTRA_1,
Expand DownExpand Up@@ -1547,6 +1613,9 @@ function CpCourseGeneratorFrame:updateContextActions()
end
end
self.contextActions[self.CONTEXT_ACTIONS.CREATE_JOB].isActive = self.canCreateJob and self.mode ~= self.AI_MODE_CREATE
self.contextActions[self.CONTEXT_ACTIONS.SET_POSITIONS_TO_VEHICLE].isActive =
self.mode == self.AI_MODE_CREATE and self.currentJob ~= nil and
self.currentJobVehicle ~= nil and not self:getIsPicking()
self.contextActions[self.CONTEXT_ACTIONS.START_JOB].isActive = self:getCanStartJob()
self.contextActions[self.CONTEXT_ACTIONS.STOP_JOB].isActive = self:getCanCancelJob() and self.mode ~= self.AI_MODE_CREATE
self.contextActions[self.CONTEXT_ACTIONS.GENERATE_COURSE].isActive = self:getCanGenerateFieldWorkCourse()
Expand DownExpand Up@@ -1765,11 +1834,27 @@ function CpCourseGeneratorFrame:setActiveJobTypeSelection(jobTypeIndex)
end
self.currentJob:applyCurrentState(self.currentJobVehicle, g_currentMission, farmId, false)
self.currentJobElements = {}
--- The button setting the positions to the vehicle position goes right below the field/silo
--- position, or below the target position for jobs without a field position (silo loader).
local buttonAnchorPositionType = nil
for _, group in ipairs(self.currentJob:getGroupedParameters()) do
for _, item in ipairs(group:getParameters()) do
local positionType = item.getPositionType and item:getPositionType()
if positionType == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
buttonAnchorPositionType = positionType
elseif positionType == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO and
buttonAnchorPositionType == nil then
buttonAnchorPositionType = positionType
end
end
end
local isButtonAdded = false
for _, group in ipairs(self.currentJob:getGroupedParameters()) do
local titleElement = self.createTitleTemplate:clone(self.jobMenuLayout)

titleElement:setText(group:getTitle())

local isButtonAnchorGroup = false
for _, item in ipairs(group:getParameters()) do
local element = nil
local parameterType = item:getType()
Expand DownExpand Up@@ -1797,8 +1882,16 @@ function CpCourseGeneratorFrame:setActiveJobTypeSelection(jobTypeIndex)
end
element:setDisabled(not item:getCanBeChanged())
table.insert(self.currentJobElements, element)
if buttonAnchorPositionType ~= nil and item.getPositionType and
item:getPositionType() == buttonAnchorPositionType then
isButtonAnchorGroup = true
end
end
end
if isButtonAnchorGroup and not isButtonAdded then
self:addSetPositionsToVehicleButton()
isButtonAdded = true
end
end
self:validateParameters()
self:updateParameterValueTexts()
Expand Down
3 changes: 3 additions & 0 deletions translations/translation_de.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,6 +108,8 @@
<text name="CP_job_bunkerSilo" text="CP: Siloarbeit"/>
<text name="CP_job_siloLoader" text="CP: Silo laden"/>
<text name="CP_ai_page_generate_course" text="CP: Feldkurs generieren"/>
<text name="CP_ai_page_positions_to_vehicle" text="Ziel &amp; Feld auf Fahrzeug"/>
<text name="CP_ai_page_positions_to_vehicle_title" text="Positionen setzen"/>
<text name="CP_ai_page_open_course_generator" text="CP: Kursgenerator öffnen/schließen"/>
<!---->
<!--AI error messages-->
Expand DownExpand Up@@ -1076,6 +1078,7 @@ Das Kreuz sollte jetzt, wie im Bild dargestellt, gelb sein.
<text name="input_CP_START_STOP_AT_NEAREST_WAYPOINT" text="CP: CP-Helfer starten/stoppen (am nächsten Wegpunkt)"/>
<text name="input_CP_START_STOP_AT_LAST_WAYPOINT" text="CP: CP-Helfer starten/stoppen (am letzten Wegpunkt)"/>
<text name="input_CP_GENERATE_COURSE" text="CP: Kurs generieren"/>
<text name="input_CP_SET_POSITIONS_TO_VEHICLE" text="CP: Ziel &amp; Feld auf Fahrzeugposition setzen"/>
<text name="input_CP_CHANGE_SELECTED_JOB" text="CP: Aktuell ausgewählten Job ändern"/>
<text name="input_CP_CHANGE_STARTING_POINT" text="CP: Startpunkt ändern"/>
<text name="input_CP_CLEAR_COURSE" text="CP: Aktuell geladenen Kurs löschen"/>
Expand Down
3 changes: 3 additions & 0 deletions translations/translation_en.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,6 +108,8 @@
<text name="CP_job_bunkerSilo" text="CP: Silo work"/>
<text name="CP_job_siloLoader" text="CP: Silo loading"/>
<text name="CP_ai_page_generate_course" text="CP: Generate fieldwork course"/>
<text name="CP_ai_page_positions_to_vehicle" text="Target &amp; field to vehicle"/>
<text name="CP_ai_page_positions_to_vehicle_title" text="Set positions"/>
<text name="CP_ai_page_open_course_generator" text="CP: Open/close course generator"/>
<!---->
<!--AI error messages-->
Expand DownExpand Up@@ -1092,6 +1094,7 @@ Now your selection should look similar to the image.
<text name="input_CP_START_STOP_AT_NEAREST_WAYPOINT" text="CP: Start/stop driver (at nearest waypoint)"/>
<text name="input_CP_START_STOP_AT_LAST_WAYPOINT" text="CP: Start/stop driver (at last waypoint)"/>
<text name="input_CP_GENERATE_COURSE" text="CP: Generate course"/>
<text name="input_CP_SET_POSITIONS_TO_VEHICLE" text="CP: Set target &amp; field to vehicle position"/>
<text name="input_CP_CHANGE_SELECTED_JOB" text="CP: Change current selected job"/>
<text name="input_CP_CHANGE_STARTING_POINT" text="CP: Change starting point"/>
<text name="input_CP_CLEAR_COURSE" text="CP: Clear currently loaded course"/>
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Add a button to set the job positions to the vehicle position by helgehelge123 · Pull Request #1314 · Courseplay/Courseplay_FS25 · GitHub
Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions modDesc.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -404,6 +404,10 @@ Changelog 8.1.0.3
<actionBinding action="CP_GENERATE_COURSE">
<binding device="KB_MOUSE_DEFAULT" input="KEY_lctrl KEY_g" />
</actionBinding>
<!--- Only used in the course generator menu while creating a job, where KEY_v is free. -->
<actionBinding action="CP_SET_POSITIONS_TO_VEHICLE">
<binding device="KB_MOUSE_DEFAULT" input="KEY_v" />
</actionBinding>

<actionBinding action="CP_CHANGE_SELECTED_JOB">
<binding device="" input="" />
Expand DownExpand Up@@ -451,6 +455,7 @@ Changelog 8.1.0.3
<action name="CP_START_STOP_AT_NEAREST_WAYPOINT"/>
<action name="CP_START_STOP_AT_LAST_WAYPOINT"/>
<action name="CP_GENERATE_COURSE" />
<action name="CP_SET_POSITIONS_TO_VEHICLE" />

<action name="CP_CHANGE_SELECTED_JOB"/>
<action name="CP_CHANGE_STARTING_POINT"/>
Expand Down
113 changes: 103 additions & 10 deletions scripts/gui/pages/CpCourseGeneratorFrame.lua
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,14 +35,17 @@ CpCourseGeneratorFrame = {
CONTEXT_ACTIONS = {
ENTER_VEHICLE = 1,
CREATE_JOB = 2,
START_JOB = 3,
STOP_JOB = 4,
GENERATE_COURSE = 5,
DELETE_CUSTOM_FIELD = 6,
RENAME_CUSTOM_FIELD = 7,
EDIT_CUSTOM_FIELD = 8,
DRAW_CUSTOM_FIELD = 9,
HOTSPOT_SELECT_ALL = 10
--- These three show up in the create job button list in this order, which is also
--- the usual work flow: set the positions, generate the course, start the job.
SET_POSITIONS_TO_VEHICLE = 3,
GENERATE_COURSE = 4,
START_JOB = 5,
STOP_JOB = 6,
DELETE_CUSTOM_FIELD = 7,
RENAME_CUSTOM_FIELD = 8,
EDIT_CUSTOM_FIELD = 9,
DRAW_CUSTOM_FIELD = 10,
HOTSPOT_SELECT_ALL = 11
},
AI_MODE_OVERVIEW = 1,
AI_MODE_CREATE = 2,
Expand DownExpand Up@@ -945,6 +948,63 @@ function CpCourseGeneratorFrame:getIsPicking()
return self.isPickingRotation or self.isPickingLocation
end

--- Sets the target position (the position the helper drives to first, with the vehicle's direction)
--- and the field/silo position of the job currently being created to the vehicle's position, so
--- these don't have to be picked on the map when standing on the field already.
function CpCourseGeneratorFrame:setJobPositionsToVehiclePosition()
local vehicle = self.currentJobVehicle
if self.currentJob == nil or vehicle == nil or vehicle.rootNode == nil or self:getIsPicking() then
return
end
local x, _, z = getWorldTranslation(vehicle.rootNode)
local dirX, _, dirZ = localDirectionToWorld(vehicle.rootNode, 0, 0, 1)
local angle = MathUtil.getYRotationFromDirection(dirX, dirZ)
local changed = false
for _, element in ipairs(self.currentJobElements) do
local parameter = element.aiParameter
if parameter and parameter.is_a and parameter:is_a(CpAIParameterPosition) and parameter:getCanBeChanged() then
local positionType = parameter:getPositionType()
if positionType == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO then
parameter:setPosition(x, z)
if parameter.setAngle then
--- the target of the drive to task also has a direction, use the one the vehicle is facing
parameter:setAngle(angle)
end
changed = true
elseif positionType == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
parameter:setPosition(x, z)
changed = true
end
end
end
if changed then
--- this also restarts the field boundary detection for the new field position
self:validateParameters()
self:updateParameterValueTexts()
end
end

--- Adds a button to the job parameter list, which sets the target and the field position
--- to the vehicle's current position. It gets a group of its own so it is separated from
--- the position rows above and isn't clicked by accident.
function CpCourseGeneratorFrame:addSetPositionsToVehicleButton()
local titleElement = self.createTitleTemplate:clone(self.jobMenuLayout)
titleElement:setText(g_i18n:getText("CP_ai_page_positions_to_vehicle_title"))
--- Using the position parameter template, so the button looks and behaves exactly
--- like the position rows above it.
local element = self.createPositionTemplate:clone(self.jobMenuLayout)
FocusManager:loadElementFromCustomValues(element)
element:setText(g_i18n:getText("CP_ai_page_positions_to_vehicle"))
local invalidElement = element:getDescendantByName("invalid")
if invalidElement then
invalidElement:setVisible(false)
end
element.onClickCallback = function()
self:setJobPositionsToVehiclePosition()
end
return element
end

function CpCourseGeneratorFrame:validateParameters()
local isValid = true
local errorText = ""
Expand DownExpand Up@@ -1153,7 +1213,7 @@ function CpCourseGeneratorFrame:getNumberOfItemsInSection(list, section)
end
if list == self.contextButtonList then
self.contextActionMapping = {}
for index, action in pairs(self.contextActions) do
for index, action in ipairs(self.contextActions) do
if action.isActive and not action.actionOnly then
table.insert(self.contextActionMapping, index)
end
Expand All@@ -1165,7 +1225,7 @@ function CpCourseGeneratorFrame:getNumberOfItemsInSection(list, section)
end
if list == self.contextButtonCustomFieldList then
self.contextActionMapping = {}
for index, action in pairs(self.contextActions) do
for index, action in ipairs(self.contextActions) do
if action.isActive and not action.actionOnly then
table.insert(self.contextActionMapping, index)
end
Expand DownExpand Up@@ -1455,6 +1515,12 @@ function CpCourseGeneratorFrame:initializeContextActions()
callback = self.onCreateJob,
isActive = false
},
[self.CONTEXT_ACTIONS.SET_POSITIONS_TO_VEHICLE] = {
text = g_i18n:getText("CP_ai_page_positions_to_vehicle"),
action = InputAction.CP_SET_POSITIONS_TO_VEHICLE,
callback = self.setJobPositionsToVehiclePosition,
isActive = false
},
[self.CONTEXT_ACTIONS.START_JOB] = {
text = g_i18n:getText("button_startJob"),
action = InputAction.MENU_EXTRA_1,
Expand DownExpand Up@@ -1547,6 +1613,9 @@ function CpCourseGeneratorFrame:updateContextActions()
end
end
self.contextActions[self.CONTEXT_ACTIONS.CREATE_JOB].isActive = self.canCreateJob and self.mode ~= self.AI_MODE_CREATE
self.contextActions[self.CONTEXT_ACTIONS.SET_POSITIONS_TO_VEHICLE].isActive =
self.mode == self.AI_MODE_CREATE and self.currentJob ~= nil and
self.currentJobVehicle ~= nil and not self:getIsPicking()
self.contextActions[self.CONTEXT_ACTIONS.START_JOB].isActive = self:getCanStartJob()
self.contextActions[self.CONTEXT_ACTIONS.STOP_JOB].isActive = self:getCanCancelJob() and self.mode ~= self.AI_MODE_CREATE
self.contextActions[self.CONTEXT_ACTIONS.GENERATE_COURSE].isActive = self:getCanGenerateFieldWorkCourse()
Expand DownExpand Up@@ -1765,11 +1834,27 @@ function CpCourseGeneratorFrame:setActiveJobTypeSelection(jobTypeIndex)
end
self.currentJob:applyCurrentState(self.currentJobVehicle, g_currentMission, farmId, false)
self.currentJobElements = {}
--- The button setting the positions to the vehicle position goes right below the field/silo
--- position, or below the target position for jobs without a field position (silo loader).
local buttonAnchorPositionType = nil
for _, group in ipairs(self.currentJob:getGroupedParameters()) do
for _, item in ipairs(group:getParameters()) do
local positionType = item.getPositionType and item:getPositionType()
if positionType == CpAIParameterPositionAngle.POSITION_TYPES.FIELD_OR_SILO then
buttonAnchorPositionType = positionType
elseif positionType == CpAIParameterPositionAngle.POSITION_TYPES.DRIVE_TO and
buttonAnchorPositionType == nil then
buttonAnchorPositionType = positionType
end
end
end
local isButtonAdded = false
for _, group in ipairs(self.currentJob:getGroupedParameters()) do
local titleElement = self.createTitleTemplate:clone(self.jobMenuLayout)

titleElement:setText(group:getTitle())

local isButtonAnchorGroup = false
for _, item in ipairs(group:getParameters()) do
local element = nil
local parameterType = item:getType()
Expand DownExpand Up@@ -1797,8 +1882,16 @@ function CpCourseGeneratorFrame:setActiveJobTypeSelection(jobTypeIndex)
end
element:setDisabled(not item:getCanBeChanged())
table.insert(self.currentJobElements, element)
if buttonAnchorPositionType ~= nil and item.getPositionType and
item:getPositionType() == buttonAnchorPositionType then
isButtonAnchorGroup = true
end
end
end
if isButtonAnchorGroup and not isButtonAdded then
self:addSetPositionsToVehicleButton()
isButtonAdded = true
end
end
self:validateParameters()
self:updateParameterValueTexts()
Expand Down
3 changes: 3 additions & 0 deletions translations/translation_de.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,6 +108,8 @@
<text name="CP_job_bunkerSilo" text="CP: Siloarbeit"/>
<text name="CP_job_siloLoader" text="CP: Silo laden"/>
<text name="CP_ai_page_generate_course" text="CP: Feldkurs generieren"/>
<text name="CP_ai_page_positions_to_vehicle" text="Ziel &amp; Feld auf Fahrzeug"/>
<text name="CP_ai_page_positions_to_vehicle_title" text="Positionen setzen"/>
<text name="CP_ai_page_open_course_generator" text="CP: Kursgenerator öffnen/schließen"/>
<!---->
<!--AI error messages-->
Expand DownExpand Up@@ -1076,6 +1078,7 @@ Das Kreuz sollte jetzt, wie im Bild dargestellt, gelb sein.
<text name="input_CP_START_STOP_AT_NEAREST_WAYPOINT" text="CP: CP-Helfer starten/stoppen (am nächsten Wegpunkt)"/>
<text name="input_CP_START_STOP_AT_LAST_WAYPOINT" text="CP: CP-Helfer starten/stoppen (am letzten Wegpunkt)"/>
<text name="input_CP_GENERATE_COURSE" text="CP: Kurs generieren"/>
<text name="input_CP_SET_POSITIONS_TO_VEHICLE" text="CP: Ziel &amp; Feld auf Fahrzeugposition setzen"/>
<text name="input_CP_CHANGE_SELECTED_JOB" text="CP: Aktuell ausgewählten Job ändern"/>
<text name="input_CP_CHANGE_STARTING_POINT" text="CP: Startpunkt ändern"/>
<text name="input_CP_CLEAR_COURSE" text="CP: Aktuell geladenen Kurs löschen"/>
Expand Down
3 changes: 3 additions & 0 deletions translations/translation_en.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -108,6 +108,8 @@
<text name="CP_job_bunkerSilo" text="CP: Silo work"/>
<text name="CP_job_siloLoader" text="CP: Silo loading"/>
<text name="CP_ai_page_generate_course" text="CP: Generate fieldwork course"/>
<text name="CP_ai_page_positions_to_vehicle" text="Target &amp; field to vehicle"/>
<text name="CP_ai_page_positions_to_vehicle_title" text="Set positions"/>
<text name="CP_ai_page_open_course_generator" text="CP: Open/close course generator"/>
<!---->
<!--AI error messages-->
Expand DownExpand Up@@ -1092,6 +1094,7 @@ Now your selection should look similar to the image.
<text name="input_CP_START_STOP_AT_NEAREST_WAYPOINT" text="CP: Start/stop driver (at nearest waypoint)"/>
<text name="input_CP_START_STOP_AT_LAST_WAYPOINT" text="CP: Start/stop driver (at last waypoint)"/>
<text name="input_CP_GENERATE_COURSE" text="CP: Generate course"/>
<text name="input_CP_SET_POSITIONS_TO_VEHICLE" text="CP: Set target &amp; field to vehicle position"/>
<text name="input_CP_CHANGE_SELECTED_JOB" text="CP: Change current selected job"/>
<text name="input_CP_CHANGE_STARTING_POINT" text="CP: Change starting point"/>
<text name="input_CP_CLEAR_COURSE" text="CP: Clear currently loaded course"/>
Expand Down
Loading