Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
80f8a48
Stage Alpha 2 source update
SimGamerJen Jul 29, 2026
aa00ece
Stage HelperProfiles Alpha 2 payload
SimGamerJen Jul 29, 2026
9230838
Stage HelperProfiles Alpha 2 payload
SimGamerJen Jul 29, 2026
ef38811
Stage HelperProfiles Alpha 2 payload
SimGamerJen Jul 29, 2026
51c9c7f
Stage HelperProfiles Alpha 2 payload
SimGamerJen Jul 29, 2026
29278b7
Stage HelperProfiles Alpha 2 payload
SimGamerJen Jul 29, 2026
1408a8b
Stage HelperProfiles Alpha 2 payload
SimGamerJen Jul 29, 2026
2e9fdf9
Add one-use HelperProfiles Alpha 2 verifier
SimGamerJen Jul 29, 2026
2665082
Add HelperProfiles payload segment verification
SimGamerJen Jul 29, 2026
4228394
Replace malformed HelperProfiles payload segment
SimGamerJen Jul 29, 2026
e44fdb9
Stage replacement HelperProfiles payload segment 003a
SimGamerJen Jul 29, 2026
814f8eb
Stage replacement HelperProfiles payload segment 003b
SimGamerJen Jul 29, 2026
4e54c35
Use split verified HelperProfiles payload segment
SimGamerJen Jul 29, 2026
22360f0
Split malformed HelperProfiles payload segment further
SimGamerJen Jul 29, 2026
b2aba24
Stage HelperProfiles payload segment 003a0
SimGamerJen Jul 29, 2026
020aa05
Stage HelperProfiles payload segment 003a1
SimGamerJen Jul 29, 2026
b007893
Stage HelperProfiles payload segment 003a2
SimGamerJen Jul 29, 2026
7ac6bae
Stage HelperProfiles payload segment 003a3
SimGamerJen Jul 29, 2026
a4c9c04
Verify smaller HelperProfiles payload segments
SimGamerJen Jul 29, 2026
d1809e8
Split final malformed HelperProfiles payload piece
SimGamerJen Jul 29, 2026
06ace5f
Stage HelperProfiles payload piece 003a1x
SimGamerJen Jul 29, 2026
55f7953
Stage HelperProfiles payload piece 003a1y
SimGamerJen Jul 29, 2026
8d7eb6b
Verify final split HelperProfiles payload pieces
SimGamerJen Jul 29, 2026
a0dfe5e
Split final HelperProfiles payload fragment
SimGamerJen Jul 29, 2026
6686aff
Stage HelperProfiles payload fragment 003a1y0
SimGamerJen Jul 29, 2026
69f2ef5
Stage HelperProfiles payload fragment 003a1y1
SimGamerJen Jul 29, 2026
a6fac45
Stage HelperProfiles payload fragment 003a1y2
SimGamerJen Jul 29, 2026
945f55e
Stage HelperProfiles payload fragment 003a1y3
SimGamerJen Jul 29, 2026
1d26522
Verify final HelperProfiles payload fragments
SimGamerJen Jul 29, 2026
914be4a
Correct HelperProfiles active-slot verifier assertion
SimGamerJen Jul 29, 2026
182ff61
Prepare HelperProfiles 2.1.0.0 Alpha 2
github-actions[bot] Jul 29, 2026
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
8 changes: 8 additions & 0 deletions l10n/l10n_de.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@
<text name="hp_overlay_mode_first_free" text="Erster verfügbarer"/>
<text name="hp_overlay_mode_prefer_selected" text="Ausgewählten bevorzugen"/>
<text name="hp_slot_label" text="Slot: %s"/>
<text name="hp_state_active_read_only" text="AKTIV / SCHREIBGESCHÜTZT"/>
<text name="hp_error_active_slot_read_only" text="Slot %s ist aktiv. Beende den Helfereinsatz, bevor du die Erscheinungsbindung änderst."/>
<text name="hp_detail_active_read_only" text="Slot %s ist aktiv und schreibgeschützt. Beende den Helfereinsatz vor einer neuen Bindung."/>
<text name="hp_status_draft_clear_all_skipped_active" text="%d verfügbare Bindung(en) gelöscht; %d aktive Slot(s) blieben unverändert. Zum Speichern Speichern drücken."/>
<text name="hp_status_clear_all_active_only" text="Keine verfügbaren Bindungen gelöscht; %d aktive Slot(s) bleiben schreibgeschützt."/>
<text name="hp_status_no_bindings_to_clear" text="Keine Bindungen zum Löschen vorhanden."/>
<text name="hp_status_active_changes_skipped" text="Erscheinungsänderungen für %d aktive Slot(s) wurden ignoriert. Beende diese Helfereinsätze vor einer neuen Bindung."/>
<text name="hp_incompatible_hired_helper_tool" text="HelperProfiles ist deaktiviert, weil Hired Helper Tool aktiv ist."/>
<text name="hp_state_active" text="AKTIV"/>
<text name="hp_state_available" text="VERFÜGBAR"/>
<text name="hp_state_bound" text="GEBUNDEN"/>
Expand Down
8 changes: 8 additions & 0 deletions l10n/l10n_en.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@
<text name="hp_overlay_mode_first_free" text="First available"/>
<text name="hp_overlay_mode_prefer_selected" text="Prefer selected"/>
<text name="hp_slot_label" text="slot: %s"/>
<text name="hp_state_active_read_only" text="ACTIVE / READ-ONLY"/>
<text name="hp_error_active_slot_read_only" text="Slot %s is active. Release the worker before changing its appearance binding."/>
<text name="hp_detail_active_read_only" text="Slot %s is active and read-only. Release the worker before rebinding it."/>
<text name="hp_status_draft_clear_all_skipped_active" text="Cleared %d available binding(s); %d active slot(s) were left unchanged. Press Save to persist."/>
<text name="hp_status_clear_all_active_only" text="No available bindings were cleared; %d active slot(s) remain read-only."/>
<text name="hp_status_no_bindings_to_clear" text="No bindings to clear."/>
<text name="hp_status_active_changes_skipped" text="Ignored appearance changes for %d active slot(s). Release those workers before rebinding them."/>
<text name="hp_incompatible_hired_helper_tool" text="HelperProfiles is disabled because Hired Helper Tool is active."/>
<text name="hp_state_active" text="ACTIVE"/>
<text name="hp_state_available" text="AVAILABLE"/>
<text name="hp_state_bound" text="BOUND"/>
Expand Down
8 changes: 8 additions & 0 deletions l10n/l10n_fr.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@
<text name="hp_overlay_mode_first_free" text="Premier disponible"/>
<text name="hp_overlay_mode_prefer_selected" text="Préférer la sélection"/>
<text name="hp_slot_label" text="emplacement : %s"/>
<text name="hp_state_active_read_only" text="ACTIF / LECTURE SEULE"/>
<text name="hp_error_active_slot_read_only" text="L’emplacement %s est actif. Libérez l’aide avant de modifier sa liaison d’apparence."/>
<text name="hp_detail_active_read_only" text="L’emplacement %s est actif et en lecture seule. Libérez l’aide avant de le relier à nouveau."/>
<text name="hp_status_draft_clear_all_skipped_active" text="%d liaison(s) disponible(s) effacée(s) ; %d emplacement(s) actif(s) sont restés inchangés. Appuyez sur Enregistrer."/>
<text name="hp_status_clear_all_active_only" text="Aucune liaison disponible n’a été effacée ; %d emplacement(s) actif(s) restent en lecture seule."/>
<text name="hp_status_no_bindings_to_clear" text="Aucune liaison à effacer."/>
<text name="hp_status_active_changes_skipped" text="Les modifications d’apparence de %d emplacement(s) actif(s) ont été ignorées. Libérez ces aides avant de les relier à nouveau."/>
<text name="hp_incompatible_hired_helper_tool" text="HelperProfiles est désactivé car Hired Helper Tool est actif."/>
<text name="hp_state_active" text="ACTIVE"/>
<text name="hp_state_available" text="DISPONIBLE"/>
<text name="hp_state_bound" text="LIÉ"/>
Expand Down
27 changes: 24 additions & 3 deletions modDesc.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@
<en><![CDATA[
Helper Profiles is a helper-management mod for Farming Simulator 25.

2.1.0.0 Alpha 2 expands the managed roster to A-T.

It adds an autosizing tabular helper overlay, configurable helper selection behaviour, helper hiring mode controls, console/debug tools, an optional AvatarSwitcher binding interface for assigning saved appearances, and optional read-only HelperPayroll role information in the roster overlay.

This version is designed for single-player use.

Known incompatibility: Do not use HelperProfiles with Hired Helper Tool. When that mod is detected, HelperProfiles disables itself for the current session to prevent conflicting helper rosters.

Core features work without AvatarSwitcher:
- Cycle through available helpers.
- Toggle the helper overlay.
Expand All @@ -27,6 +31,7 @@ Optional AvatarSwitcher integration:
- Bind appearances to helper slots through an FS25-style XML GUI.
- Store bindings per savegame under modSettings/FS25_HelperProfiles/saves/savegameX/appearanceLinks.xml.
- Bind, clear, clear all, and save appearance links from the in-game interface.
- Active helper slots are read-only until their workers are released.

Migration note:
Older workflows that edited maps_helpers.xml in the Farming Simulator basegame install path are deprecated. Restore the original basegame file and recreate custom appearances as AvatarSwitcher presets before binding them in Helper Profiles.
Expand All @@ -44,6 +49,8 @@ Der Mod ergänzt ein automatisch skalierendes tabellarisches Helfer-Overlay, kon

Diese Version ist für den Einzelspielermodus vorgesehen.

Bekannte Inkompatibilität: HelperProfiles darf nicht zusammen mit Hired Helper Tool verwendet werden. Bei Erkennung wird HelperProfiles für die aktuelle Sitzung deaktiviert.

Kernfunktionen funktionieren ohne AvatarSwitcher:
- Durch verfügbare Helfer wechseln.
- Das Helfer-Overlay ein- oder ausschalten.
Expand All @@ -56,6 +63,7 @@ Optionale AvatarSwitcher-Integration:
- Erscheinungsbilder über eine XML-GUI im FS25-Stil an Helfer-Slots binden.
- Bindungen pro Spielstand unter modSettings/FS25_HelperProfiles/saves/savegameX/appearanceLinks.xml speichern.
- Erscheinungsbild-Bindungen im Spiel binden, löschen, alle löschen und speichern.
- Aktive Helfer-Slots sind bis zum Beenden des Helfereinsatzes schreibgeschützt.

Migrationshinweis:
Ältere Arbeitsweisen, bei denen maps_helpers.xml im Farming-Simulator-Basisinstallationspfad bearbeitet wurde, sind veraltet. Stelle die originale Basisdatei wieder her und erstelle eigene Erscheinungsbilder als AvatarSwitcher-Presets neu, bevor du sie in Helferprofile bindest.
Expand All @@ -73,6 +81,8 @@ Il ajoute une superposition tabulaire à dimensionnement automatique, un comport

Cette version est conçue pour le mode solo.

Incompatibilité connue : n’utilisez pas HelperProfiles avec Hired Helper Tool. Lorsqu’il est détecté, HelperProfiles se désactive pour la session en cours.

Les fonctions principales fonctionnent sans AvatarSwitcher :
- Parcourir les aides disponibles.
- Activer ou désactiver la superposition des aides.
Expand All @@ -84,6 +94,7 @@ Intégration optionnelle avec AvatarSwitcher :
- Lier des apparences aux emplacements d'aides via une interface XML au style FS25.
- Enregistrer les liaisons par sauvegarde dans modSettings/FS25_HelperProfiles/saves/savegameX/appearanceLinks.xml.
- Lier, effacer, tout effacer et enregistrer les liaisons d'apparence depuis l'interface en jeu.
- Les emplacements d’aides actifs restent en lecture seule jusqu’à la libération de l’aide.

Note de migration :
Les anciennes méthodes qui modifiaient maps_helpers.xml dans le dossier d'installation de base de Farming Simulator sont obsolètes. Restaurez le fichier d'origine du jeu, puis recréez vos apparences personnalisées comme presets AvatarSwitcher avant de les lier dans Profils d'aides.
Expand All @@ -98,7 +109,10 @@ RALT + ; active ou désactive la superposition.

<changelog>
<en><![CDATA[
Version 2.1.0.0:
Version 2.1.0.0 Alpha 2:
- Active helper slots are now read-only in the appearance-binding screen; Bind, Clear, Clear All, and Save preserve active-worker bindings.
- HelperProfiles now disables itself when Hired Helper Tool is detected, preventing competing roster ownership.
- Replaced unsupported decorative action-registration symbols in log output with plain text.
- Added an experimental twenty-helper roster by extending the standard A-J helpers with slots K-T.
- Added stable helper01-helper20 canonical slot identities while retaining legacy A-J mapping compatibility.
- Updated the Profiles screen, overlay, HelperProfiles API, appearance bindings, and HelperPayroll integration for twenty slots.
Expand Down Expand Up @@ -126,7 +140,10 @@ Version 2.0.26.0:
- Set multiplayer support to false.
]]></en>
<de><![CDATA[
Version 2.1.0.0:
Version 2.1.0.0 Alpha 2:
- Aktive Helfer-Slots sind im Bindungsfenster jetzt schreibgeschützt; Binden, Löschen, Alle löschen und Speichern erhalten aktive Bindungen.
- HelperProfiles deaktiviert sich bei erkanntem Hired Helper Tool, um konkurrierende Helferlisten zu verhindern.
- Nicht unterstützte Symbole in den Registrierungsprotokollen wurden durch Klartext ersetzt.
- Eine experimentelle Liste mit zwanzig Helfern wurde hinzugefügt; die Standardhelfer A-J werden um K-T erweitert.
- Stabile kanonische Slot-Identitäten helper01-helper20 wurden ergänzt, wobei die Kompatibilität mit vorhandenen A-J-Zuordnungen erhalten bleibt.
- Profilfenster, Overlay, HelperProfiles-API, Erscheinungsbildbindungen und HelperPayroll-Integration unterstützen nun zwanzig Slots.
Expand Down Expand Up @@ -155,7 +172,10 @@ Version 2.0.26.0:
- Die Mehrspielerunterstützung wurde auf false gesetzt.
]]></de>
<fr><![CDATA[
Version 2.1.0.0 :
Version 2.1.0.0 Alpha 2 :
- Les emplacements actifs sont désormais en lecture seule dans l’écran de liaison ; les actions conservent les liaisons des aides actives.
- HelperProfiles se désactive lorsqu’il détecte Hired Helper Tool afin d’éviter deux systèmes de liste concurrents.
- Les symboles décoratifs non pris en charge dans le journal ont été remplacés par du texte simple.
- Ajout expérimental d’une liste de vingt aides en complétant les aides standard A-J avec les emplacements K-T.
- Ajout des identités canoniques stables helper01-helper20 tout en conservant la compatibilité avec les liaisons A-J existantes.
- Mise à jour de l’écran des profils, de la superposition, de l’API HelperProfiles, des liaisons d’apparence et de l’intégration HelperPayroll pour vingt emplacements.
Expand Down Expand Up @@ -220,6 +240,7 @@ Version 2.0.26.0 :

<extraSourceFiles>
<sourceFile filename="scripts/HP_SlotRegistry.lua"/>
<sourceFile filename="scripts/HP_Compatibility.lua"/>
<sourceFile filename="scripts/HP_Config.lua"/>
<sourceFile filename="scripts/HP_UI.lua"/>
<sourceFile filename="scripts/HP_Debug.lua"/>
Expand Down
4 changes: 4 additions & 0 deletions scripts/HP_AppearanceMenu.lua
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ function HP_AppearanceMenu:syncSelectionFromDraft()
end

function HP_AppearanceMenu:open()
if HP_Compatibility ~= nil and HP_Compatibility:isBlocked() then
hpamPrint("Appearance menu unavailable: Hired Helper Tool is active and HelperProfiles is disabled.")
return false
end
self:init()
if HP_ASBridge ~= nil and HP_ASBridge.reload ~= nil then HP_ASBridge:reload() end
self:buildDraftFromBridge()
Expand Down
76 changes: 76 additions & 0 deletions scripts/HP_Compatibility.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
-- HP_Compatibility.lua (FS25_HelperProfiles)
-- Central runtime guard for helper-roster mods that cannot safely coexist.

HP_Compatibility = HP_Compatibility or {
checked = false,
blocked = false,
conflictMod = nil,
warningLogged = false
}

local LOG = "[FS25_HelperProfiles/Compatibility] "
local CONFLICT_NAMES = {"FS25_HiredHelperTool", "HiredHelperTool"}

local function isLoadedByName(name)
local loaded = rawget(_G, "g_modIsLoaded")
if type(loaded) == "table" and loaded[name] == true then
return true
end

if g_modManager ~= nil and type(g_modManager.getModByName) == "function" then
local ok, mod = pcall(g_modManager.getModByName, g_modManager, name)
if ok and type(mod) == "table" then
return mod.isLoaded == true or mod.isActive == true or mod.isSelected == true
end
end

return false
end

function HP_Compatibility:detect()
self.checked = true
self.blocked = false
self.conflictMod = nil

for _, name in ipairs(CONFLICT_NAMES) do
if isLoadedByName(name) then
self.blocked = true
self.conflictMod = name
break
end
end

if self.blocked and not self.warningLogged then
self.warningLogged = true
print(LOG .. "HelperProfiles disabled for this session: incompatible mod detected (" .. tostring(self.conflictMod) .. "). Disable either HelperProfiles or Hired Helper Tool and reload the save.")
end

return self.blocked
end

function HP_Compatibility:isBlocked()
if not self.checked then
self:detect()
end
return self.blocked == true
end

function HP_Compatibility:getReason()
if not self:isBlocked() then return nil end
return "incompatible-helper-roster-mod:" .. tostring(self.conflictMod or "unknown")
end

function HP_Compatibility:loadMap()
self.checked = false
self.warningLogged = false
self:detect()
end

function HP_Compatibility:deleteMap()
self.checked = false
self.blocked = false
self.conflictMod = nil
self.warningLogged = false
end

addModEventListener(HP_Compatibility)
22 changes: 3 additions & 19 deletions scripts/HP_RosterExpansion.lua
Original file line number Diff line number Diff line change
Expand Up @@ -67,22 +67,6 @@ local function getByIndex(manager, index)
return manager.indexToHelper ~= nil and manager.indexToHelper[index] or nil
end

local function isKnownExternalExpansionLoaded()
local loaded = rawget(_G, "g_modIsLoaded")
if type(loaded) == "table" then
if loaded.FS25_HiredHelperTool == true or loaded.HiredHelperTool == true then return true end
end
if g_modManager ~= nil and type(g_modManager.getModByName) == "function" then
for _, name in ipairs({"FS25_HiredHelperTool", "HiredHelperTool"}) do
local ok, mod = pcall(g_modManager.getModByName, g_modManager, name)
if ok and type(mod) == "table" and (mod.isLoaded == true or mod.isActive == true or mod.isSelected == true) then
return true
end
end
end
return false
end

local function invalidateRosterCache()
if HelperProfiles ~= nil then
HelperProfiles._defaultOrderRefs = nil
Expand Down Expand Up @@ -110,11 +94,11 @@ function HP_RosterExpansion:tryExpand(reason)
local manager = g_helperManager
local before = getCount(manager)

if isKnownExternalExpansionLoaded() then
if HP_Compatibility ~= nil and HP_Compatibility:isBlocked() then
self.completed = true
self.result = "external-expansion-mod"
self.result = "blocked-incompatible-mod"
invalidateRosterCache()
log("Known external helper expansion detected; no helpers injected: reason=%s helpers=%d", tostring(reason), before)
log("HelperProfiles roster disabled because Hired Helper Tool is active: reason=%s helpers=%d", tostring(reason), before)
return true
end

Expand Down
8 changes: 7 additions & 1 deletion scripts/HP_UI.lua
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,13 @@ end
-- ===== Public configuration setters =========================================

function HP_UI:setVisible(value) self.visible = value and true or false end
function HP_UI:toggle() self.visible = not self.visible end
function HP_UI:toggle()
if HP_Compatibility ~= nil and HP_Compatibility:isBlocked() then
self.visible = false
return
end
self.visible = not self.visible
end

function HP_UI:setAnchor(anchor)
anchor = string.upper(anchor or "")
Expand Down
5 changes: 5 additions & 0 deletions scripts/HP_WorkerAppearance.lua
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ function HP_WorkerAppearance:installHooks()
end

function HP_WorkerAppearance:update(dt)
if HP_Compatibility ~= nil and HP_Compatibility:isBlocked() then return end
self.scanTimer = (self.scanTimer or 0) + (dt or 0)
if self.scanTimer >= 1000 then
self.scanTimer = 0
Expand All @@ -329,6 +330,10 @@ function HP_WorkerAppearance:update(dt)
end

function HP_WorkerAppearance:loadMap()
if HP_Compatibility ~= nil and HP_Compatibility:isBlocked() then
hpwaPrint("Disabled because Hired Helper Tool is active.")
return
end
self:installHooks()
self:patchLoadedVehicles()
end
Expand Down
6 changes: 6 additions & 0 deletions scripts/HelperProfiles.lua
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ end
-- Once the idle managed roster order has been cached, keep returning that complete roster
-- even while GIANTS removes active workers from availableHelpers.
function HelperProfiles:getProfiles()
if HP_Compatibility ~= nil and HP_Compatibility:isBlocked() then return {} end
local available = _getHelpersRaw()

-- Only establish the stable managed roster while every helper is idle.
Expand Down Expand Up @@ -429,6 +430,10 @@ end
-- Expecting FS25 style callback with key status (1 on press).
function HelperProfiles:onCycleAction(actionName, keyStatus)
if keyStatus ~= 1 then return end -- press only
if HP_Compatibility ~= nil and HP_Compatibility:isBlocked() then
self:_flash(hpI18n("hp_incompatible_hired_helper_tool", "HelperProfiles is disabled because Hired Helper Tool is active."), 2.5)
return
end
self:cycleSelectionDebounced(1)
end

Expand Down Expand Up @@ -511,6 +516,7 @@ end
-- FS lifecycle
----------------------------------------------------------------------
function HelperProfiles:update(dt)
if HP_Compatibility ~= nil and HP_Compatibility:isBlocked() then return end
if not HelperProfiles._hooksDone then
hookOnce()
end
Expand Down
Loading