Skip to content

Commit

Permalink
Black Ops 1 Support, Static Models for Ghosts, AW, and MWR
Browse files Browse the repository at this point in the history
  • Loading branch information
Scobalula committed Nov 18, 2018
1 parent fd67938 commit cb421ae
Show file tree
Hide file tree
Showing 11 changed files with 995 additions and 63 deletions.
111 changes: 111 additions & 0 deletions src/Husky/Husky/FileFormats/IWMap.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace Husky
{
/// <summary>
/// A class to hold IWMap Info and Logic
/// </summary>
public class IWMap
{
/// <summary>
/// A class to hold a .MAP Entity
/// </summary>
public class Entity
{
/// <summary>
/// Entity KVPs
/// </summary>
public Dictionary<string, string> KeyValuePairs = new Dictionary<string, string>();

/// <summary>
/// Initializes an entity with a Classname
/// </summary>
public Entity(string className)
{
KeyValuePairs["classname"] = className;
}

/// <summary>
/// Creates a Misc/Prop Model
/// </summary>
/// <param name="modelName">Name of the Model Asset</param>
/// <param name="origin">XYZ Origin</param>
/// <param name="angles">XYZ Angles</param>
/// <param name="modelScale">Model Scale</param>
/// <returns>Resulting entity</returns>
public static Entity CreateMiscModel(string modelName, Vector3 origin, Vector3 angles, float modelScale)
{
// Create new entity
var result = new Entity("misc_model");
// Add properties
result.KeyValuePairs["model"] = modelName;
result.KeyValuePairs["origin"] = String.Format("{0} {1} {2}", origin.X, origin.Y, origin.Z);
result.KeyValuePairs["angles"] = String.Format("{1} {2} {0}", angles.X, angles.Y, angles.Z);
result.KeyValuePairs["modelscale"] = modelScale.ToString();
// Ship her back
return result;
}
}

/// <summary>
/// Map entities
/// </summary>
public List<Entity> Entities = new List<Entity>();

/// <summary>
/// Initializes an IW Map with a Basic Worldspawn Entity
/// </summary>
public IWMap()
{
// Create Worldspawn Entity
var worldspawn = new Entity("worldspawn");
// Set properties
worldspawn.KeyValuePairs["fsi"] = "default";
worldspawn.KeyValuePairs["gravity"] = "800";
worldspawn.KeyValuePairs["lodbias"] = "default";
worldspawn.KeyValuePairs["lutmaterial"] = "luts_t7_default";
worldspawn.KeyValuePairs["numOmniShadowSlices"] = "24";
worldspawn.KeyValuePairs["numSpotShadowSlices"] = "64";
worldspawn.KeyValuePairs["sky_intensity_factor0"] = "1";
worldspawn.KeyValuePairs["sky_intensity_factor1"] = "1";
worldspawn.KeyValuePairs["state_alias_1"] = "State 1";
worldspawn.KeyValuePairs["state_alias_2"] = "State 2";
worldspawn.KeyValuePairs["state_alias_3"] = "State 3";
worldspawn.KeyValuePairs["state_alias_4"] = "State 4";
// Add it
Entities.Add(worldspawn);
}

/// <summary>
/// Dumps whatever we can to a .MAP file
/// </summary>
/// <param name="fileName">File Name</param>
public void DumpToMap(string fileName)
{
// Create output stream
using (var writer = new StreamWriter(fileName))
{
// Write basic header
writer.WriteLine("iwmap 4");
writer.WriteLine("\"script_startingnumber\" 0");
writer.WriteLine("\"000_Global\" flags active");
writer.WriteLine("\"The Map\" flags expanded ");

// Write entitys
for (int i = 0; i < Entities.Count; i++)
{
// Write Index Comment
writer.WriteLine("// entity {0}", i);
// Write initial bracket
writer.WriteLine("{");
// Write KVPs
foreach (var kvp in Entities[i].KeyValuePairs)
writer.WriteLine("\"{0}\" \"{1}\"", kvp.Key, kvp.Value);
// Write end bvracket
writer.WriteLine("}");
}
}
}
}
}
47 changes: 0 additions & 47 deletions src/Husky/Husky/GameStructures/Shared.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,53 +123,6 @@ public struct PackedUnitVector
public byte Byte4;
}

/// <summary>
/// Gfx Static Model
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct GfxStaticModel
{
/// <summary>
/// X Origin
/// </summary>
public float X { get; set; }

/// <summary>
/// Y Origin
/// </summary>
public float Y { get; set; }

/// <summary>
/// Z Origin
/// </summary>
public float Z { get; set; }

/// <summary>
/// Rotation (TODO: Look into it)
/// </summary>
public fixed byte UnknownBytes1[36];

/// <summary>
/// Model Scale
/// </summary>
public float ModelScale { get; set; }

/// <summary>
/// Null Padding
/// </summary>
public int Padding { get; set; }

/// <summary>
/// Pointer to the XModel Asset
/// </summary>
public long ModelPointer { get; set; }

/// <summary>
/// Unknown Bytes
/// </summary>
public fixed byte UnknownBytes2[0x10];
}

/// <summary>
/// Material Image for: WaW
/// </summary>
Expand Down
116 changes: 115 additions & 1 deletion src/Husky/Husky/Games/AdvancedWarfare.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,32 @@ public unsafe struct GfxMap
/// <summary>
/// Points, etc.
/// </summary>
public fixed byte Padding3[0x830];
public fixed byte Padding3[0x5A0];

/// <summary>
/// Number of Static Models
/// </summary>
public int GfxStaticModelsCount { get; set; }

/// <summary>
/// Pointers, etc.
/// </summary>
public fixed byte Padding4[0x28C];

/// <summary>
/// Pointer to the Gfx Index Data
/// </summary>
public long GfxSurfacesPointer { get; set; }

/// <summary>
/// Pointer
/// </summary>
public long Padding5 { get; set; }

/// <summary>
/// Pointer to the Gfx Static Models
/// </summary>
public long GfxStaticModelsPointer { get; set; }
}

/// <summary>
Expand Down Expand Up @@ -200,6 +220,53 @@ public unsafe struct Material
public fixed byte UnknownBytes2[0xD0];
}

/// <summary>
/// Gfx Static Model
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct GfxStaticModel
{
/// <summary>
/// X Origin
/// </summary>
public float X { get; set; }

/// <summary>
/// Y Origin
/// </summary>
public float Y { get; set; }

/// <summary>
/// Z Origin
/// </summary>
public float Z { get; set; }

/// <summary>
/// 3x3 Rotation Matrix
/// </summary>
public fixed float Matrix[9];

/// <summary>
/// Model Scale
/// </summary>
public float ModelScale { get; set; }

/// <summary>
/// Null Padding
/// </summary>
public int Padding { get; set; }

/// <summary>
/// Pointer to the XModel Asset
/// </summary>
public long ModelPointer { get; set; }

/// <summary>
/// Unknown Bytes
/// </summary>
public fixed byte UnknownBytes2[0x10];
}

/// <summary>
/// Reads BSP Data
/// </summary>
Expand All @@ -225,12 +292,15 @@ public static void ExportBSPData(ProcessReader reader, long assetPoolsAddress, l
}
else
{
// New IW Map
var mapFile = new IWMap();
// Print Info
Printer.WriteLine("INFO", String.Format("Loaded Gfx Map - {0}", gfxMapName));
Printer.WriteLine("INFO", String.Format("Loaded Map - {0}", mapName));
Printer.WriteLine("INFO", String.Format("Vertex Count - {0}", gfxMapAsset.GfxVertexCount));
Printer.WriteLine("INFO", String.Format("Indices Count - {0}", gfxMapAsset.GfxIndicesCount));
Printer.WriteLine("INFO", String.Format("Surface Count - {0}", gfxMapAsset.SurfaceCount));
Printer.WriteLine("INFO", String.Format("Model Count - {0}", gfxMapAsset.GfxStaticModelsCount));

// Stop watch
var stopWatch = Stopwatch.StartNew();
Expand Down Expand Up @@ -323,6 +393,10 @@ public static void ExportBSPData(ProcessReader reader, long assetPoolsAddress, l
// Dump it
File.WriteAllText(Path.ChangeExtension(gfxMapName, ".txt"), searchString);

// Read entities and dump to map
mapFile.Entities.AddRange(ReadStaticModels(reader, gfxMapAsset.GfxStaticModelsPointer, gfxMapAsset.GfxStaticModelsCount));
mapFile.DumpToMap(Path.ChangeExtension(gfxMapName, ".map"));

// Done
Printer.WriteLine("INFO", String.Format("Converted to OBJ in {0:0.00} seconds.", stopWatch.ElapsedMilliseconds / 1000.0));
}
Expand Down Expand Up @@ -422,5 +496,45 @@ public static WavefrontOBJ.Material ReadMaterial(ProcessReader reader, long addr
// Done
return objMaterial;
}

/// <summary>
/// Reads Static Models
/// </summary>
public unsafe static List<IWMap.Entity> ReadStaticModels(ProcessReader reader, long address, int count)
{
// Resulting Entities
List<IWMap.Entity> entities = new List<IWMap.Entity>(count);
// Read buffer
var byteBuffer = reader.ReadBytes(address, count * Marshal.SizeOf<GfxStaticModel>());
// Loop number of models we have
for (int i = 0; i < count; i++)
{
// Read Struct
var staticModel = ByteUtil.BytesToStruct<GfxStaticModel>(byteBuffer, i * Marshal.SizeOf<GfxStaticModel>());
// Model Name
var modelName = reader.ReadNullTerminatedString(reader.ReadInt64(staticModel.ModelPointer));
// New Matrix
var matrix = new Rotation.Matrix();
// Copy X Values
matrix.Values[0] = staticModel.Matrix[0];
matrix.Values[1] = staticModel.Matrix[1];
matrix.Values[2] = staticModel.Matrix[2];
// Copy Y Values
matrix.Values[4] = staticModel.Matrix[3];
matrix.Values[5] = staticModel.Matrix[4];
matrix.Values[6] = staticModel.Matrix[5];
// Copy Z Values
matrix.Values[8] = staticModel.Matrix[6];
matrix.Values[9] = staticModel.Matrix[7];
matrix.Values[10] = staticModel.Matrix[8];
// Convert to Euler
var euler = matrix.ToEuler();
// Add it
entities.Add(IWMap.Entity.CreateMiscModel(modelName, new Vector3(staticModel.X, staticModel.Y, staticModel.Z), Rotation.ToDegrees(euler), staticModel.ModelScale));
}
// Done
return entities;
}

}
}
Loading

0 comments on commit cb421ae

Please sign in to comment.