Advertisement
Guest User

Untitled

a guest
Sep 26th, 2018
403
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 10.60 KB | None | 0 0
  1. import java.io.File;
  2. import java.io.FileOutputStream;
  3. import java.io.IOException;
  4. import java.io.PrintStream;
  5. import java.nio.file.Files;
  6. import java.nio.file.Path;
  7. import java.nio.file.Paths;
  8. import java.nio.file.StandardCopyOption;
  9. import java.util.Arrays;
  10.  
  11. public class Main {
  12.  
  13.     public static void main(String[] args) throws IOException {
  14.        
  15.         //setting output
  16.         boolean to_file = false;
  17.         if (to_file) {
  18.             PrintStream printStream = new PrintStream(new FileOutputStream(new File("D:/SteamLibrary/steamapps/common/Left 4 Dead 2/left4dead2/maps/output.txt")));
  19.             System.setOut(printStream);
  20.         }
  21.        
  22.         String[] names = {
  23.             "c1m1_hotel",
  24.             "c1m2_streets",
  25.             "c1m3_mall",
  26.             "c1m4_atrium",
  27.             "c2m1_highway",
  28.             "c2m2_fairgrounds",
  29.             "c2m3_coaster",
  30.             "c2m4_barns",
  31.             "c2m5_concert",
  32.             "c3m1_plankcountry",
  33.             "c3m2_swamp",
  34.             "c3m3_shantytown",
  35.             "c3m4_plantation",
  36.             "c4m1_milltown_a",
  37.             "c4m2_sugarmill_a",
  38.             "c4m3_sugarmill_b",
  39.             "c4m4_milltown_b",
  40.             "c4m5_milltown_escape",
  41.             "c5m1_waterfront",
  42.             "c5m2_park",
  43.             "c5m3_cemetery",
  44.             "c5m4_quarter",
  45.             "c5m5_bridge",
  46.             "c6m1_riverbank",
  47.             "c6m2_bedlam",
  48.             "c6m3_port",
  49.             "c7m1_docks",
  50.             "c7m2_barge",
  51.             "c7m3_port",
  52.             "c8m1_apartment",
  53.             "c8m2_subway",
  54.             "c8m3_sewers",
  55.             "c8m4_interior",
  56.             "c8m5_rooftop",
  57.             "c9m1_alleys",
  58.             "c9m2_lots",
  59.             "c10m1_caves",
  60.             "c10m2_drainage",
  61.             "c10m3_ranchhouse",
  62.             "c10m4_mainstreet",
  63.             "c10m5_houseboat",
  64.             "c11m1_greenhouse",
  65.             "c11m2_offices",
  66.             "c11m3_garage",
  67.             "c11m4_terminal",
  68.             "c11m5_runway",
  69.             "C12m1_hilltop",
  70.             "C12m2_traintunnel",
  71.             "C12m3_bridge",
  72.             "C12m4_barn",
  73.             "C12m5_cornfield",
  74.             "c13m1_alpinecreek",
  75.             "c13m2_southpinestream",
  76.             "c13m3_memorialbridge",
  77.             "c13m4_cutthroatcreek"
  78.         };
  79.         for (String mapname: names) {
  80.             work(mapname);
  81.         }
  82.     }
  83.    
  84.     static void work(String mapname) throws IOException {
  85.         //reading file
  86.         String path_str = "D:/SteamLibrary/steamapps/common/Left 4 Dead 2/left4dead2/maps/" + mapname + ".bsp";
  87.         Path path = Paths.get(path_str);
  88.         byte[] b = Files.readAllBytes(path);
  89.         byte[] b_edited = subArray(b, 0, b.length);
  90.         System.out.println(path_str + " contains " + b.length + " bytes");
  91.         System.out.println("-----------------------------");
  92.        
  93.         //reading magic number and version
  94.         int magic_number = readInteger(b, 0);
  95.         int bsp_version = readInteger(b, 4);
  96.         if (magic_number == (('P'<<24)+('S'<<16)+('B'<<8)+'V')) {
  97.             System.out.println("VBSP version " + bsp_version);
  98.         } else {
  99.             System.out.println("Unknown magic number " + toHex(magic_number));
  100.         }
  101.         System.out.println("-----------------------------");
  102.        
  103.         //reading lump directory array
  104.         int[] lump_start = new int[64];
  105.         int[] lump_length = new int[64];
  106.         for (int i = 0; i < 64; i++) {
  107.             int offset = 12 + i*16;
  108.             byte[] lump = subArray(b, offset, 16);
  109.             lump_start[i] = readInteger(lump, 0);
  110.             lump_length[i] = readInteger(lump, 4);
  111.             String start_percent = 100 * lump_start[i] / b.length + "% of file";
  112.             String length_percent = 100 * lump_length[i] / b.length + "% of file";
  113.             System.out.println("lump " + i + " starts from " + toHex(lump_start[i]) + " (" + start_percent + ") and has length of " + toHex(lump_length[i]) + " (" + length_percent + ")");
  114.         }
  115.         System.out.println("-----------------------------");
  116.        
  117.         //reading TexdataStringTable (lump 44)
  118.         byte[] texdataStringTable = subArray(b, lump_start[44], lump_length[44]);
  119.         System.out.println("TexdataStringTable has length of " + texdataStringTable.length + " bytes");
  120.         int number_of_textures = texdataStringTable.length / 4;
  121.         System.out.println("Number of textures: " + number_of_textures);
  122.         if (number_of_textures * 4 != texdataStringTable.length) System.err.println("Error wrong TexdataStringTable");
  123.         int[] textureStringOffsets = new int[number_of_textures];
  124.         System.out.print("textureStringOffsets: ");
  125.         for (int i = 0; i < number_of_textures; i++) {
  126.             int offset = i * 4;
  127.             textureStringOffsets[i] = readInteger(texdataStringTable, offset);
  128.             System.out.print(textureStringOffsets[i]);
  129.             if (i != number_of_textures - 1) System.out.print(",");
  130.         }
  131.         System.out.println();
  132.         System.out.println("-----------------------------");
  133.        
  134.         //reading TexdataStringData (lump 43)
  135.         byte[] texdataStringData = subArray(b, lump_start[43], lump_length[43]);
  136.         System.out.println("TexdataStringData has length of " + texdataStringData.length + " bytes");
  137.         String[] texture_names = new String[number_of_textures];
  138.         for (int i = 0; i < number_of_textures; i++) {
  139.             int offset = textureStringOffsets[i];
  140.             int offset_next = (i == number_of_textures - 1) ? texdataStringData.length : textureStringOffsets[i + 1];
  141.             int length = offset_next - offset - 1;
  142.             byte[] str_bytes = subArray(texdataStringData, offset, length);
  143.             texture_names[i] = new String(str_bytes, "UTF-8");
  144.             System.out.print("[" + i + "]" + texture_names[i]);
  145.             if (i != number_of_textures - 1) System.out.print(",");
  146.         }
  147.         System.out.println();
  148.         System.out.println("-----------------------------");
  149.        
  150.         //reading Texdata (lump 2)
  151.         byte[] texdata = subArray(b, lump_start[2], lump_length[2]);
  152.         System.out.println("Texdata has length of " + texdata.length + " bytes");
  153.         int[] texData_indices = new int[number_of_textures];
  154.         for (int i = 0; i < number_of_textures; i++) {
  155.             int offset = i * 32 + 12;
  156.             texData_indices[i] = readInteger(texdata, offset);
  157.             System.out.print(texData_indices[i]);
  158.             if (i != number_of_textures - 1) System.out.print(",");
  159.         }
  160.         System.out.println();
  161.         System.out.println("-----------------------------");
  162.        
  163.         //reading Texinfo (lump 6)
  164.         byte[] texinfo = subArray(b, lump_start[6], lump_length[6]);
  165.         System.out.println("Texinfo has length of " + texinfo.length + " bytes");
  166.         int texinfo_entries = texinfo.length / 72;
  167.         if (texinfo_entries * 72 != texinfo.length) System.err.println("Error wrong Texinfo");
  168.         System.out.println("Texinfo has " + texinfo_entries + " entries");
  169.         int skybox_changed = 0;
  170.         int nodraw_changed = 0;
  171.         for (int i = 0; i < texinfo_entries; i++) {
  172.             int offset = i * 72 + 64;
  173.             int flags = readInteger(texinfo, offset);
  174.             System.out.print(toBin(flags));
  175.            
  176.             int texdata_index = readInteger(texinfo, offset + 4);
  177.             int texture_index = texData_indices[texdata_index];
  178.             String texture_name = texture_names[texture_index];
  179.            
  180.             System.out.print(" " + texture_index + " " + texture_name);
  181.             boolean is_skybox = (flags & (1 << 2)) != 0;
  182.             if (is_skybox) {
  183.                 System.out.print(" - SKYBOX");
  184.                 //editing
  185.                
  186.                 int address_of_byte = lump_start[6] + offset;
  187.                 byte _b = b[address_of_byte];
  188.                 _b &= Integer.reverse(1 << 2);
  189.                 b_edited[address_of_byte] = _b;
  190.                
  191.                 System.out.print(" - changing to " + toBin(readInteger(b_edited, address_of_byte)));
  192.                 skybox_changed++;
  193.             }
  194.            
  195.             boolean is_nodraw = (flags & (1 << 7)) != 0;
  196.             if (is_nodraw) {
  197.                 System.out.print(" - NODRAW");
  198.                 //editing
  199.                
  200.                 writeInteger(b_edited, lump_start[6] + offset, 0);
  201.                
  202.                 int new_texture_index = -1;
  203.                 for (int i2 = 0; i2 < texture_names.length; i2++) {
  204.                     if (texture_names[i2].equalsIgnoreCase("CONCRETE/CONCRETE_EXT_01")) {
  205.                         new_texture_index = i2;
  206.                         break;
  207.                     }
  208.                 }
  209.                 int new_texdata_index = -1;
  210.                 if (new_texture_index != -1) {
  211.                     for (int i2 = 0; i2 < texData_indices.length; i2++) {
  212.                         if (texData_indices[i2] == new_texture_index) {
  213.                             new_texdata_index = i2;
  214.                             break;
  215.                         }
  216.                     }
  217.                 }
  218.                 if (new_texdata_index != -1) {
  219.                     System.out.print(" - new textdata index " + new_texdata_index);
  220.                     writeInteger(b_edited, lump_start[6] + offset + 4, new_texdata_index);
  221.                     System.out.print(" - checking, result is " + readInteger(b_edited, lump_start[6] + offset + 4));
  222.                 }
  223.                
  224.                 System.out.print(" - changing to " + toBin(readInteger(b_edited, lump_start[6] + offset)));
  225.                 nodraw_changed++;
  226.             }
  227.            
  228.             System.out.println();
  229.         }
  230.         System.out.println("-----------------------------");
  231.        
  232.         //reading Brush (lump 18)
  233.         int clips_changed = 0;
  234.         byte[] brush = subArray(b, lump_start[18], lump_length[18]);
  235.         System.out.println("Brush has length of " + brush.length + " bytes");
  236.         int number_of_brushes = brush.length / 12;
  237.         System.out.println("Number of brushes: " + number_of_brushes);
  238.         if (number_of_brushes * 12 != brush.length) System.err.println("Error wrong Brush");
  239.         for (int i = 0; i < number_of_brushes; i++) {
  240.             int offset = i * 12 + 8;
  241.             int flags = readInteger(brush, offset);
  242.             System.out.print(toBin(flags));
  243.             boolean is_playerclip = (flags & 0x10000) != 0;
  244.             boolean is_monsterclip = (flags & 0x20000) != 0;
  245.             if (is_playerclip & !is_monsterclip) {
  246.                 System.out.print(" - PLAYERCLIP_ONLY");
  247.                 writeInteger(b_edited, lump_start[18] + offset, 0x8000000); //CONTENTS_DETAIL 0x8000000 - brushes to be added after vis leafs
  248.                 clips_changed++;
  249.             }
  250.             System.out.println();
  251.         }
  252.         System.out.println("-----------------------------");
  253.        
  254.         //writing to file
  255.         try (FileOutputStream fos = new FileOutputStream("D:/SteamLibrary/steamapps/common/Left 4 Dead 2/left4dead2/maps/" + mapname + "_skybox.bsp")) {
  256.            fos.write(b_edited);
  257.         }
  258.         System.out.println("success");
  259.         System.out.println("skybox changed: " + skybox_changed);
  260.         System.out.println("nodraw changed: " + nodraw_changed);
  261.         System.out.println("clips changed: " + clips_changed);
  262.        
  263.         Files.copy(new File("D:/SteamLibrary/steamapps/common/Left 4 Dead 2/left4dead2/maps/" + mapname + ".nav").toPath(),
  264.                 new File("D:/SteamLibrary/steamapps/common/Left 4 Dead 2/left4dead2/maps/" + mapname + "_skybox.nav").toPath(),
  265.                 StandardCopyOption.REPLACE_EXISTING);
  266.         System.out.println("navigation file created for " + mapname);
  267.     }
  268.    
  269.     static int readInteger(byte[] b, int offset) { //little-endian
  270.         return ((b[offset+3]&0xff)<<24)+((b[offset+2]&0xff)<<16)+((b[offset+1]&0xff)<<8)+(b[offset]&0xff);
  271.     }
  272.    
  273.     static void writeInteger(byte[] b, int offset, int val) { //little-endian
  274.         //((b[offset+3]&0xff)<<24)+((b[offset+2]&0xff)<<16)+((b[offset+1]&0xff)<<8)+(b[offset]&0xff);
  275.         b[offset+3] = (byte) (val / 0xffffff); //старший разряд
  276.         b[offset+2] = (byte) (val / 0xffff);
  277.         b[offset+1] = (byte) (val / 0xff);
  278.         b[offset] = (byte) (val); //младший разряд
  279.     }
  280.    
  281.     static String toHex(int val) {
  282.         return String.format("0x%08X", val);
  283.     }
  284.    
  285.     static String toBin(int val) {
  286.         //return "0b" + Integer.toBinaryString(val);
  287.         return "0b" + String.format("%32s", Integer.toBinaryString(val)).replace(' ', '0');
  288.     }
  289.    
  290.     static byte[] subArray(byte[] array, int start, int length) {
  291.         return Arrays.copyOfRange(array, start, start + length);
  292.     }
  293. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement