/// <summary> /// Process the data in a <see cref="MAPBrush"/> into the passed <see cref="StringBuilder"/>. /// </summary> /// <param name="brush">The <see cref="MAPBrush"/> to process.</param> /// <param name="index">The index of <see cref="MAPBrush"/> entity in the <see cref="Entity"/>.</param> /// <param name="sb">A <see cref="StringBuilder"/> object to append processed data from <paramref name="brush"/> to.</param> private void ParseBrush(MAPBrush brush, int index, StringBuilder sb) { // Unsupported features. Ignore these completely. if (brush.ef2Terrain != null) { return; } if (brush.sides.Count < 4 && brush.patch == null && brush.mohTerrain == null) { // Can't create a brush with less than 4 sides _master.Print("WARNING: Tried to create brush from " + brush.sides.Count + " sides!"); return; } sb.Append("// Brush ") .Append(index.ToString()) .Append("\r\n"); if (brush.patch != null) { ParsePatch(brush.patch, sb); } else if (brush.mohTerrain != null) { ParseTerrain(brush.mohTerrain, sb); } else { sb.Append("{\r\n"); foreach (MAPBrushSide brushSide in brush.sides) { ParseBrushSide(brushSide, brush.isDetail, sb); } sb.Append("}\r\n"); } }
/// <summary> /// Process the data in a <see cref="MAPBrush"/> into the passed <see cref="StringBuilder"/>. /// </summary> /// <param name="brush">The <see cref="MAPBrush"/> to process.</param> /// <param name="index">The index of <see cref="MAPBrush"/> entity in the <see cref="Entity"/>.</param> /// <param name="sb">A <see cref="StringBuilder"/> object to append processed data from <paramref name="brush"/> to.</param> private void ParseBrush(MAPBrush brush, int index, StringBuilder sb) { // Unsupported features. Ignore these completely. if (brush.patch != null || brush.ef2Terrain != null || brush.mohTerrain != null) { return; } if (brush.sides.Count < 4) { // Can't create a brush with less than 4 sides _master.Print("WARNING: Tried to create brush from " + brush.sides.Count + " sides!"); return; } sb.Append("{ // Brush ") .Append(index.ToString()) .Append("\r\n"); if (brush.isDetail) { sb.Append("\"BRUSHFLAGS\" \"DETAIL\"\r\n"); } foreach (MAPBrushSide brushSide in brush.sides) { ParseBrushSide(brushSide, sb); } sb.Append("}\r\n"); }
/// <summary> /// Process the data in a <see cref="MAPBrush"/> into the passed <see cref="StringBuilder"/>. /// </summary> /// <param name="brush">The <see cref="MAPBrush"/> to process.</param> /// <param name="sb">A <see cref="StringBuilder"/> object to append processed data from <paramref name="brush"/> to.</param> private void ParseBrush(MAPBrush brush, StringBuilder sb) { // Unsupported features. Ignore these completely. if (brush.patch != null || brush.ef2Terrain != null || brush.mohTerrain != null) { return; } if (brush.sides.Count < 4) { // Can't create a brush with less than 4 sides _master.Print("WARNING: Tried to create brush from " + brush.sides.Count + " sides!"); return; } sb.Append("\tsolid\r\n\t{\r\n\t\t\"id\" \"") .Append(_nextID) .Append("\"\r\n"); foreach (MAPBrushSide brushSide in brush.sides) { ++_nextID; ParseBrushSide(brushSide, sb); } sb.Append("\t}\r\n"); }
/// <summary> /// Processes an <see cref="Entity"/> into a state where it can be output into a file that map editors can read. /// </summary> /// <param name="entity">The <see cref="Entity"/> to process.</param> /// <remarks>This method does not return anything, since the <see cref="Entity"/> object is modified by reference.</remarks> private void ProcessEntity(Entity entity) { int modelNumber = entity.modelNumber; // If this Entity has no modelNumber, then this is a no-op. No processing is needed. // A modelnumber of 0 indicates the world entity. if (modelNumber >= 0) { Model model = _bsp.models[modelNumber]; if (_bsp.brushes != null) { List <Brush> brushes = _bsp.GetBrushesInModel(model); if (brushes != null) { foreach (Brush brush in brushes) { MAPBrush result = ProcessBrush(brush, entity.origin); result.isWater |= (entity.className == "func_water"); if (_master.settings.brushesToWorld) { _bsp.entities.GetWithAttribute("classname", "worldspawn").brushes.Add(result); } else { entity.brushes.Add(result); } ++_itemsProcessed; ReportProgress(); } } } if (model.numLeafPatches > 0 && _bsp.markSurfaces != null && _bsp.patches != null) { HashSet <Patch> patches = new HashSet <Patch>(); List <long> leafPatchesInModel = _bsp.GetReferencedObjects <long>(model, "markSurfaces"); foreach (long leafPatch in leafPatchesInModel) { if (leafPatch >= 0) { patches.Add(_bsp.patches[(int)leafPatch]); } } foreach (Patch patch in patches) { if (_bsp.version != MapType.CoD || patch.patchType == 0) { MAPPatch mappatch = ProcessPatch(patch); MAPBrush newBrush = new MAPBrush(); newBrush.patch = mappatch; entity.brushes.Add(newBrush); } } } if (_bsp.faces != null) { List <Face> surfaces = _bsp.GetFacesInModel(model); foreach (Face face in surfaces) { if (face.displacement >= 0) { if (modelNumber != 0) { _master.Print("WARNING: Displacement not part of world in " + _bsp.MapNameNoExtension); } MAPDisplacement displacement = ProcessDisplacement(_bsp.dispInfos[face.displacement]); MAPBrush newBrush = face.CreateBrush(_bsp, 32); newBrush.sides[0].displacement = displacement; // If we are not decompiling to VMF, vis will need to skip this brush. newBrush.isDetail = true; entity.brushes.Add(newBrush); } else if (face.flags == 2) { MAPPatch patch = ProcessPatch(face); MAPBrush newBrush = new MAPBrush(); newBrush.patch = patch; entity.brushes.Add(newBrush); } else if ((_bsp.version == MapType.STEF2 || _bsp.version == MapType.STEF2Demo) && face.flags == 5) { if (modelNumber != 0) { _master.Print("WARNING: Terrain not part of world in " + _bsp.MapNameNoExtension); } MAPTerrainEF2 terrain = ProcessEF2Terrain(face); MAPBrush newBrush = new MAPBrush(); newBrush.ef2Terrain = terrain; entity.brushes.Add(newBrush); } } } // If this is model 0 (worldspawn) there are other things that need to be taken into account. if (modelNumber == 0) { if (_bsp.lodTerrains != null) { foreach (LODTerrain lodTerrain in _bsp.lodTerrains) { MAPTerrainMoHAA terrain = ProcessTerrainMoHAA(lodTerrain); MAPBrush newBrush = new MAPBrush(); newBrush.mohTerrain = terrain; entity.brushes.Add(newBrush); } } } entity.Remove("model"); } }
/// <summary> /// Writes a GearCraft map using the provided <see cref="Entities"/>. /// </summary> /// <param name="deepCopy">If <c>true</c>, the <see cref="Entities"/> will be deep copied to preserve the original ones, so postprocessing for this format won't interfere with others.</param> public void WriteGearcraft(bool deepCopy = false) { Entities myEntities = deepCopy ? (Entities)DeepCopy(_entities) : _entities; EntityToGearcraft entityPostProcessor = new EntityToGearcraft(myEntities, _version, _master); entityPostProcessor.PostProcessEntities(); GearcraftMapGenerator mapMaker = new GearcraftMapGenerator(myEntities, _master); string output = mapMaker.ParseMap(); string extension = deepCopy ? "_gc.map" : ".map"; if (string.IsNullOrEmpty(_master.settings.outputFolder)) { _master.Print("Writing file " + Path.Combine(_mapDirectory, _mapName + extension) + " for Gearcraft"); File.WriteAllText(Path.Combine(_mapDirectory, _mapName + extension), output); } else { _master.Print("Writing file " + Path.Combine(_master.settings.outputFolder, _mapName + extension) + " for Gearcraft"); File.WriteAllText(Path.Combine(_master.settings.outputFolder, _mapName + extension), output); } }