[Bug: UI/LUA] Research interdependency visualization issue. Proposed fix is included!

Ask here if you experience technical problems with X4: Foundations.

Moderator: Moderators for English X Forum

User avatar
ChemODun
Posts: 560
Joined: Mon, 12. Feb 07, 21:58
x4

[Bug: UI/LUA] Research interdependency visualization issue. Proposed fix is included!

Post by ChemODun »

Looks like applicable several versions as the problematic strings of code are not changed at least from version 7.60.

Description - if some research lines have several steps of research, and, another research line has dependency from, for example first step of "frits" lines, the result dependencies will show as a "full mesh", i.e. a mess.
It's simpler to show on example:

In vanilla game exists a several research lines related to ship mods. Will show them using their appropriate wares macros:

Code: Select all

research_mod_ship_mk1       -> research_mod_ship_mk2       -> research_mod_ship_mk3
research_mod_engine_mk1   -> research_mod_engine_mk2   -> research_mod_engine_mk3
research_mod_shield_mk1    -> research_mod_shield_mk2    -> research_mod_shield_mk3
research_mod_weapon_mk1 -> research_mod_weapon_mk2 -> research_mod_weapon_mk3
They have no interdependencies. And them visualized normally in game:

Image

But if we will add new research dependent of one, two, all or off them - we will have a real "full mesh", i.e. full mess with displayed dependencies.

There is a ware:

Code: Select all

<ware id="research_test_ware_for_display_fix" name="Test research" description="This is simple test research for the Research dependency display fix" transport="research" volume="1"
  tags="research" sortorder="800">
  <price min="1" average="1" max="1" />
  <research time="10">
    <research>
      <ware ware="research_mod_ship_mk1" />
      <ware ware="research_mod_engine_mk1" />
      <ware ware="research_mod_shield_mk1" />
      <ware ware="research_mod_weapon_mk1"/>
    </research>
  </research>
</ware>
I.e. it has dependency from 4 lines on a first step, and nothing more. I.e. original dependencies of next step Ships Mods are not changes, and not dependent on this new ware or each other. Only this new ware dependent on first steps of Ships Mods
And what we have in game in this case:
Image

As you can see - it is a real mess.

There in addition two examples with one and two dependencies:

Image

Image

It happens due to current logic collect "all" steps. Again, it simpler to provide a path, instead of long explanation.
There is patch(diff) as code:
Spoiler
Show

Code: Select all

--- ui.original/menu_research.lua	2025-08-18 16:40:24.000000000 +0300
+++ ui.modified/menu_research.lua	2025-11-15 21:37:59.832444800 +0200
@@ -116,7 +116,9 @@
 				if not GetWareData(temptechlist[i], "ismissiononly") then
 					-- print("found " .. temptechlist[i])
 					local state_completed = C.HasResearched(temptechlist[i])
-					table.insert(menu.techtree, { [1] = { [1] = { tech = temptechlist[i], sortorder = sortorder, completed = state_completed } } })
+					-- start fix: added empty precursor list
+					table.insert(menu.techtree,	{ [1] = { [1] = { tech = temptechlist[i], sortorder = sortorder, completed = state_completed, precursors = {} } } })
+					-- end fix: added empty precursor list
 				end
 				table.remove(temptechlist, i)
 			else
@@ -130,7 +132,9 @@
 				if hasonlymissionprecursors then
 					-- print("found with only mission precursors" .. temptechlist[i])
 					local state_completed = C.HasResearched(temptechlist[i])
-					table.insert(menu.techtree, { [1] = { [1] = { tech = temptechlist[i], sortorder = sortorder, completed = state_completed } } })
+					-- start fix: added empty precursor list
+					table.insert(menu.techtree, { [1] = { [1] = { tech = temptechlist[i], sortorder = sortorder, completed = state_completed, precursors = {} } } })
+					-- end fix: added empty precursor list
 					table.remove(temptechlist, i)
 				end
 			end
@@ -177,12 +181,26 @@

 				-- add this tech to the tree and remove it from the list
 				local state_completed = C.HasResearched(temptechlist[idx])
+				-- start fix: build new entry with precursor links
+				local newentry = { tech = temptechlist[idx], sortorder = sortorder, completed = state_completed, precursors = {} }
+				for _, precursor in ipairs(techprecursors) do
+					local precursorMainIdx, precursorCol, precursorTechIdx = menu.findTech(menu.techtree, precursor)
+					if precursorMainIdx and precursorCol and precursorTechIdx then
+						newentry.precursors[#newentry.precursors + 1] = menu.techtree[precursorMainIdx][precursorCol]
+						[precursorTechIdx]
+					end
+				end
+				-- end fix: build new entry with precursor links
 				if menu.techtree[smallestMainIdx][foundPrecusorCol + 1] then
 					-- print("    adding")
-					table.insert(menu.techtree[smallestMainIdx][foundPrecusorCol + 1], { tech = temptechlist[idx], sortorder = sortorder, completed = state_completed })
+					-- start fix: adding the data with precursor links
+					table.insert(menu.techtree[smallestMainIdx][foundPrecusorCol + 1], newentry)
+					-- end fix: adding the data with precursor links
 				else
 					-- print("    new entry")
-					menu.techtree[smallestMainIdx][foundPrecusorCol + 1] = { [1] = { tech = temptechlist[idx], sortorder = sortorder, completed = state_completed } }
+					-- start fix: replacing the data with precursor links
+					menu.techtree[smallestMainIdx][foundPrecusorCol + 1] = { [1] = newentry }
+					-- end fix: replacing the data with precursor links
 				end
 				-- print("    removed")
 				table.remove(temptechlist, idx)
@@ -365,10 +383,18 @@
 					menu.restoreNode = techentry.node
 					menu.restoreNodeTech = nil
 				end
-
-				if col > 1 then
-					for k, previousentry in ipairs(mainentry[col - 1]) do
-						-- print("adding edge from node " .. previousentry.tech .. " to " .. techentry.tech)
+				-- start fix: added predecessors handling to apply dependency fix
+				local predecessors = techentry.precursors or {}
+				if (#predecessors == 0) and (col > 1) then
+					local fallbackColumn = mainentry[col - 1]
+					if fallbackColumn then
+						predecessors = fallbackColumn
+					end
+				end
+				for k = 1, #predecessors do
+					local previousentry = predecessors[k]
+					if previousentry.node then
+						--end fix: added predecessors handling to apply dependency fix
 						local edge = previousentry.node:addEdgeTo(techentry.node)
 						if not previousentry.completed then
 							edge.properties.sourceSlotColor = Color["research_incomplete"]
@@ -913,12 +939,23 @@
 function menu.isResearchAvailable(tech, mainIdx, col)
 	if menu.availableresearchmodule then
 		if col > 1 then
-			for _, techentry in ipairs(menu.techtree[mainIdx][col - 1]) do
-				if not techentry.completed then
-					return false
+			-- start fix: finding current tech and checking its predecessors
+      		local currentColumn = menu.techtree[mainIdx][col]
+			for i = 1, #currentColumn do
+				local techentry = currentColumn[i]
+				if techentry and techentry.tech == tech then
+					if techentry.precursors and #techentry.precursors > 0 then
+						for i = 1, #techentry.precursors do
+							local precursor = techentry.precursors[i]
+							if not precursor.completed then
+								return false
+							end
+						end
+					end
 				end
 			end
+			-- end fix: finding current tech and checking its predecessors
 		end
 		return true
 	end
There is patch(diff) as file.

And there an image how it has to be (after patch is applied):
Image
Last edited by ChemODun on Sat, 15. Nov 25, 20:45, edited 2 times in total.
Multiply entropy by absolute zero

Freedom in space
User avatar
ChemODun
Posts: 560
Joined: Mon, 12. Feb 07, 21:58
x4

Re: [Bug: UI/LUA] Research interdependency visualization issue

Post by ChemODun »

Temporary fix

You can download the latest version via Steam client - Research dependency display fix
Or you can do it via the Nexus Mods - Research dependency display fix

Till bug will be fixed in better way :-) in game.
Multiply entropy by absolute zero

Freedom in space
User avatar
ChemODun
Posts: 560
Joined: Mon, 12. Feb 07, 21:58
x4

Re: [Bug: UI/LUA] Research interdependency visualization issue. Proposed fix is included!

Post by ChemODun »

Slightly refactored and simplified the fix code, as result - patch is simplified too :-)
Multiply entropy by absolute zero

Freedom in space
florianlt
EGOSOFT
EGOSOFT
Posts: 1360
Joined: Mon, 22. Aug 11, 14:05
x4

Re: [Bug: UI/LUA] Research interdependency visualization issue. Proposed fix is included!

Post by florianlt »

Thanks for pointing this out. Will be fixed on our side in an upcoming version.
User avatar
ChemODun
Posts: 560
Joined: Mon, 12. Feb 07, 21:58
x4

Re: [Bug: UI/LUA] Research interdependency visualization issue. Proposed fix is included!

Post by ChemODun »

You always welcome.

And thanks for this impressive game!
Multiply entropy by absolute zero

Freedom in space

Return to “X4: Foundations - Technical Support”