Dylancyclone / VMF2OBJ

Convert source-engine VMF files into OBJ files with materials (including brushes, displacements, entities, and models)
MIT License
109 stars 6 forks source link

Comparison method violates its general contract (Side.completeSide) #14

Closed ghost closed 2 years ago

ghost commented 3 years ago

Command - java -jar .\VMF2OBJ.jar .\de_dust2.vmf .\output "F:\SteamLibrary\steamapps\common\Counter-Strike Source\cstrike\cstrike_pak_dir.vpk;F:\SteamLibrary\steamapps\common\Counter-Strike Source\hl2\hl2_misc_dir.vpk;F:\SteamLibrary\steamapps\common\Counter-Strike Source\hl2\hl2_sound_misc_dir.vpk;F:\SteamLibrary\steamapps\common\Counter-Strike Source\hl2\hl2_sound_vo_english_dir.vpk;F:\SteamLibrary\steamapps\common\Counter-Strike Source\hl2\hl2_textures_dir.vpk"

Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract! at java.util.TimSort.mergeHi(Unknown Source) at java.util.TimSort.mergeAt(Unknown Source) at java.util.TimSort.mergeForceCollapse(Unknown Source) at java.util.TimSort.sort(Unknown Source) at java.util.Arrays.sort(Unknown Source) at java.util.ArrayList.sort(Unknown Source) at java.util.Collections.sort(Unknown Source) at com.lathrum.VMF2OBJ.dataStructure.map.Side.completeSide(Side.java:71) at com.lathrum.VMF2OBJ.dataStructure.map.VMF.parseSolids(VMF.java:311) at com.lathrum.VMF2OBJ.App.main(App.java:502)

Dylancyclone commented 3 years ago

This error haunts me. Essentially what is happening is there is a crash when the application tries to form a side that has two colinear points that are exactly the same distance from the origin in opposite directions. This never came up in the maps I tested, but it now seems to be cropping up every once in awhile.

The puzzle is how to sort a list of points in 3D space around the origin in a clockwise direction. The way I approached the problem was to compare each point to each other and order them by their dot product. If two points are colinear, I order by distance to the origin. https://github.com/Dylancyclone/VMF2OBJ/blob/master/src/main/java/com/lathrum/VMF2OBJ/dataStructure/map/Side.java#L71

The issue arises when two points are both equidistant and colinear to the origin. Java seems to be picking one at random which isn't a valid thing to do when trying to sort data. I've spent a ton of time thinking of a solution and asking around to find ideas on how to fix this, but I'm still mostly stumped.

One potential solution is to convert all the points into polar coordinates, sort them, then convert them back to Cartesian coordinates. Theoretically this would work, but would result in a lot of extra calculations to swap back and forth between coordinate systems. I'm still thinking about another solution in the background, but if I still cannot find an answers I'll have to go ahead and try that when I get some time.

Thank you for reporting this

Dylancyclone commented 3 years ago

Huzzah this issue has finally been fixed! Take a look at the commit above for details.

This will be a part of the 2.0.0 release