/// <summary> /// Parses regions into Halo Online collision 'Region' tagblocks. /// Names are not preserved. /// </summary> /// <param name="coll"></param> /// <param name="reader"></param> /// <param name="count"></param> /// <returns></returns> public long ParseRegions(CollisionModel coll, BinaryReader reader, int count) { var originalPos = reader.BaseStream.Position; //The number of permutations that have been parsed in total for all regions var n_parsed_permutations = 0; //Permutations for all regions follow sequentially after all regions var permutations_base_addr = reader.BaseStream.Position + count * REGION_TAGBLOCK_SIZE; coll.Regions = new List<CollisionModel.Region>(); for (uint i = 0; i < count; ++i) { //configure the current region CollisionModel.Region region = new CollisionModel.Region(); region.Name = new StringId(0x140 + i); //set up stream for reading number of permutations in current region reader.BaseStream.Position = originalPos + (long)(i * REGION_TAGBLOCK_SIZE) + REGION_PERMUTATION_OFFSET; uint n_permutations = (uint)BitConverter.ToInt32(reader.ReadBytes(4).Reverse().ToArray(), 0); region.Permutations = new List<CollisionModel.Region.Permutation>(); for (uint j = 0; j < n_permutations; ++j) { var permutation = new CollisionModel.Region.Permutation(); permutation.Name = new StringId(0x140 + j); permutation.Bsps = new List<BSP>(); region.Permutations.Add(permutation); } coll.Regions.Add(region); n_parsed_permutations += (int)n_permutations; } return permutations_base_addr + (n_parsed_permutations * PERMUTATION_SIZE); }
/// <summary> /// Parses all H1CE Collision Node tagblocks stored sequentially. /// The purpose of 'Node' is similar to 'Region' in Halo Online. /// </summary> /// <param name="coll"></param> /// <param name="reader"></param> /// <param name="count"></param> /// <returns></returns> public long ParseNodes(CollisionModel coll, BinaryReader reader, int count) { var originalPos = reader.BaseStream.Position; coll.Nodes = new List<CollisionModel.Node>(); //destroy the old list of regions, it may not be fine-grained enough coll.Regions = new List<CollisionModel.Region>(); var new_region_count = 0; var current_bsp_offset = originalPos + (count * NODE_SIZE); for (var i = 0; i < count; ++i) { var node = new CollisionModel.Node(); node.Name = new StringId(0x140 + (uint)i); //offset of the parent node in the h1 ce node tagblock reader.BaseStream.Position = originalPos + (i * NODE_SIZE) + 32; short region_idx = BitConverter.ToInt16(reader.ReadBytes(2).Reverse().ToArray(), 0); short parent_node_idx = BitConverter.ToInt16(reader.ReadBytes(2).Reverse().ToArray(), 0); short next_sibling_idx = BitConverter.ToInt16(reader.ReadBytes(2).Reverse().ToArray(), 0); short first_child_idx = BitConverter.ToInt16(reader.ReadBytes(2).Reverse().ToArray(), 0); node.ParentNode = parent_node_idx; node.NextSiblingNode = next_sibling_idx; node.FirstChildNode = first_child_idx; coll.Nodes.Add(node); //there exists a region when the region index of the h1 ce collision node tagblock is not null if (region_idx >= 0) { var region = new CollisionModel.Region(); coll.Regions.Add(region); region.Name = new StringId(0x140 + (uint)new_region_count); reader.BaseStream.Position = originalPos + (i * NODE_SIZE) + 52; //bsp tagblock count //each bsp is placed into a separate permutation. In h1 ce // a node referencing a region with n permutations has n bsps region.Permutations = new List<CollisionModel.Region.Permutation>(); CollisionModel.Region.Permutation permutation = new CollisionModel.Region.Permutation(); region.Permutations.Add(permutation); permutation.Bsps = new List<BSP>(); uint n_bsps = (uint)BitConverter.ToInt32(reader.ReadBytes(4).Reverse().ToArray(), 0); for (uint j = 0; j < n_bsps; ++j) { reader.BaseStream.Position = current_bsp_offset; current_bsp_offset = ParseBSP(permutation, reader); } new_region_count++; } } return current_bsp_offset; }