{"id":379,"date":"2010-03-31T11:53:28","date_gmt":"2010-03-31T19:53:28","guid":{"rendered":"http:\/\/technofovea.com\/blog\/?p=379"},"modified":"2010-04-21T18:41:05","modified_gmt":"2010-04-22T02:41:05","slug":"packbsp-progress-when-collisions-occur","status":"publish","type":"post","link":"http:\/\/technofovea.com\/blog\/archives\/379","title":{"rendered":"PackBSP progress: When collisions occur"},"content":{"rendered":"<p>As mentioned in my <a href=\"http:\/\/technofovea.com\/blog\/archives\/332\">last post<\/a>, one of the interesting things about the files in a Source game is that they use multiple search paths. While this makes it easy to do things like override content, it also makes for a bit of a headache. This post is an attempt to sketch out how I want to handle things in my rewrite of PackBSP to avoid errors.<\/p>\n<div id=\"attachment_386\" style=\"width: 248px\" class=\"wp-caption alignnone\"><a href=\"http:\/\/technofovea.com\/blog\/wp-content\/uploads\/2010\/03\/decision_tree.png\"><img aria-describedby=\"caption-attachment-386\" loading=\"lazy\" class=\"size-medium wp-image-386\" title=\"Packbsp decision tree for file collisions\" src=\"http:\/\/technofovea.com\/blog\/wp-content\/uploads\/2010\/03\/decision_tree-238x300.png\" alt=\"\" width=\"238\" height=\"300\" srcset=\"http:\/\/technofovea.com\/blog\/wp-content\/uploads\/2010\/03\/decision_tree-238x300.png 238w, http:\/\/technofovea.com\/blog\/wp-content\/uploads\/2010\/03\/decision_tree.png 665w\" sizes=\"(max-width: 238px) 100vw, 238px\" \/><\/a><p id=\"caption-attachment-386\" class=\"wp-caption-text\">How PackBSP will check file locations<\/p><\/div>\n<p><!--more--> Basically, there are three types of places you can find a file. In the map, in a normal folder on the disk, or inside an archive file, like a GCF. Technically there&#8217;s another variation (pak\/vpk files) but for sanity&#8217;s sake I&#8217;m going to ignore them until I need to some form of add L4D support.  So given a relative path (like &#8220;materials\/floor\/tile.vmt&#8221;) which version should I parse (for its direct dependencies) and what should get embedded into the map? In answering this question I got the above diagram.  Essentially, certain conditions are sufficiently creepy that the program cannot progress: The user has a sloppy work environment and needs to put things in order. These correspond to the red &#8220;halt&#8221; boxes.<\/p>\n<ol>\n<li>If you have file in the map and on the drive that has the same name \tbut different contents, something is wrong. Since Bspzip doesn&#8217;t \thave consistent support for removing or replacing already-packed \tfiles, PackBSP probably can&#8217;t fix the problem. The user should start \twith a &#8220;fresh&#8221; copy of their map.<\/li>\n<li>If the map contains a file that conflicts with another in the standard \tarchives, that&#8217;s a bad idea, because it can cause non-map-related graphical glitches for clients that persist even when the server switches to another map.<\/li>\n<li>If a disk conflicts with an archive file, the developer&#8217;s intention \tis unclear: We can&#8217;t pack the disk-version, because then eventually \twe&#8217;ll end up with the case we just looked at in the last paragraph. \tBut if we ignore it, we run the risk of creating a final-product \tthat is unexpectedly different from what the mapper is seeing during \ttheir pre-release testing.<\/li>\n<\/ol>\n<p>Fortunately, these ambiguous cases should be few and far between, and arguably PackBSP would just be &#8220;being a good citizen&#8221; of the SDK tools when refusing to work without them being resolved.<\/p>\n<h3>&#8220;I override skins and things all the time as a player, why can&#8217;t I do it as a mapper?&#8221;<\/h3>\n<p>Suppose in Counter-Strike or TF2 someone creates a Halloween map with custom &#8220;zombie&#8221; player-skins, anyone who starts the game and joins that map will see the effect. Sounds cool, right? Unfortunately, these materials generally don&#8217;t get cleared out afterwards, so players are stuck seeing the zombie skins even though the Halloween map is long-over.<\/p>\n<h3>&#8220;Why check the map&#8217;s contents against the disk?&#8221;<\/h3>\n<p>Two reasons. Firstly, I want to be able to detect and avoid cases where PackBSP <em>thinks<\/em> it is injecting a new file but is actually failing because an incompatible version is already present. In a sense, we want to make sure the map file being modified is &#8220;clean&#8221; to start with.  Secondly, a patched WVT materials.<\/p>\n<h3>&#8220;WVT-patch materials?&#8221;<\/h3>\n<p>There&#8217;s probably a better name for them, but when someone uses a &#8220;blend&#8221; material in Hammer on a <em>non<\/em>-displacement surface, it causes a sort of incompatibility. Hammer automatically works around this by spontaneously generating a custom material, copying over the relevant settings, and inserting the new material into the map when it is first compiled.<\/p>\n<pre>Patching WVT material: maps\/ctf_examplemap\/nature\/blendsandgrass008a_wvt_patch<\/pre>\n<p>The real problem occurs when you are using a <em>custom<\/em> blend material which depends one or more <em>custom<\/em> textures. Hammer has\u00c2\u00a0 inserted the material, but the texture(s) are still missing and won&#8217;t look good when you distribute your map. So when we encounter a WVT-patch, we need to read it (even if it&#8217;s already inside the map) to make sure we catch any custom textures as well.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>As mentioned in my last post, one of the interesting things about the files in a Source game is that they use multiple search paths. While this makes it easy to do things like override content, it also makes for a bit of a headache. This post is an attempt to sketch out how I [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[4],"tags":[8],"_links":{"self":[{"href":"http:\/\/technofovea.com\/blog\/wp-json\/wp\/v2\/posts\/379"}],"collection":[{"href":"http:\/\/technofovea.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/technofovea.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/technofovea.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/technofovea.com\/blog\/wp-json\/wp\/v2\/comments?post=379"}],"version-history":[{"count":14,"href":"http:\/\/technofovea.com\/blog\/wp-json\/wp\/v2\/posts\/379\/revisions"}],"predecessor-version":[{"id":392,"href":"http:\/\/technofovea.com\/blog\/wp-json\/wp\/v2\/posts\/379\/revisions\/392"}],"wp:attachment":[{"href":"http:\/\/technofovea.com\/blog\/wp-json\/wp\/v2\/media?parent=379"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/technofovea.com\/blog\/wp-json\/wp\/v2\/categories?post=379"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/technofovea.com\/blog\/wp-json\/wp\/v2\/tags?post=379"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}