private static void LoadEntities(NTROValue lump, Renderer.Renderer renderer, string path, Package package) { var reference = ((NTROValue <ResourceExtRefList.ResourceReferenceInfo>)lump).Value; if (reference == null) { return; } var newResource = FileExtensions.LoadFileByAnyMeansNecessary(reference.Name + "_c", path, package); if (newResource == null) { Console.WriteLine("unable to load entity lump " + reference.Name + "_c"); return; } var entityLump = newResource.Blocks[BlockType.DATA] as EntityLump; var childLumps = (NTROArray)entityLump.Output["m_childLumps"]; foreach (var lump2 in childLumps) { var lol = ((NTROValue <ResourceExtRefList.ResourceReferenceInfo>)lump).Value; // TODO: Should be controlled in UI with world layers if (lol.Name.Contains("_destruction")) { continue; } LoadEntities(lump2, renderer, path, package); } foreach (var entity in entityLump.Datas) { var scale = string.Empty; var position = string.Empty; var angles = string.Empty; var model = string.Empty; var skin = string.Empty; var colour = new byte[0]; var classname = string.Empty; var name = string.Empty; foreach (var property in entity) { //metadata switch (property.Item2) { case 3368008710: //World Model model = property.Item3 as string; break; case 3827302934: //Position position = property.Item3 as string; break; case 3130579663: //Angles angles = property.Item3 as string; break; case 432137260: //Scale scale = property.Item3 as string; break; case 2020856412: //Skin skin = property.Item3 as string; break; case 588463423: //Colour colour = property.Item3 as byte[]; break; case 3323665506: //Classname classname = property.Item3 as string; break; case 1094168427: name = property.Item3 as string; break; } } if (scale == string.Empty || position == string.Empty || angles == string.Empty) { continue; } var isCamera = classname == "info_player_start" || classname == "worldspawn" || classname == "sky_camera" || classname == "point_devshot_camera" || classname == "point_camera"; if (!isCamera && model == string.Empty) { continue; } var scaleMatrix = Matrix4.CreateScale(ParseCoordinates(scale)); var positionVector = ParseCoordinates(position); var positionMatrix = Matrix4.CreateTranslation(positionVector); var pitchYawRoll = ParseCoordinates(angles); var rollMatrix = Matrix4.CreateRotationX(MathHelper.DegreesToRadians(pitchYawRoll.Z)); // Roll var pitchMatrix = Matrix4.CreateRotationY(MathHelper.DegreesToRadians(pitchYawRoll.X)); // Pitch var yawMatrix = Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(pitchYawRoll.Y)); // Yaw var rotationMatrix = rollMatrix * pitchMatrix * yawMatrix; var transformationMatrix = scaleMatrix * rotationMatrix * positionMatrix; if (isCamera) { if (classname == "worldspawn") { renderer.SetDefaultWorldCamera(positionVector); } else { renderer.AddCamera(name == string.Empty ? $"{classname} #{anonymousCameraCount++}" : name, transformationMatrix); } continue; } var objColor = Vector4.One; // Parse colour if present if (colour.Length == 4) { for (var i = 0; i < 4; i++) { objColor[i] = colour[i] / 255.0f; } } var newEntity = FileExtensions.LoadFileByAnyMeansNecessary(model + "_c", path, package); if (newEntity == null) { Console.WriteLine($"unable to load entity {model}_c"); continue; } var entityModel = new Model(newEntity); entityModel.LoadMeshes(renderer, path, transformationMatrix, objColor, package, skin); } }
private void ReadFieldIntrospection(ResourceIntrospectionManifest.ResourceDiskStruct.Field field, ref NTROStruct structEntry) { var count = (uint)field.Count; var pointer = false; // TODO: get rid of this if (count == 0) { count = 1; } long prevOffset = 0; if (field.Indirections.Count > 0) { // TODO if (field.Indirections.Count > 1) { throw new NotImplementedException("More than one indirection, not yet handled."); } // TODO if (field.Count > 0) { throw new NotImplementedException("Indirection.Count > 0 && field.Count > 0"); } var indirection = field.Indirections[0]; // TODO: depth needs fixing? var offset = Reader.ReadUInt32(); if (indirection == 0x03) { pointer = true; if (offset == 0) { structEntry.Add(field.FieldName, new NTROValue <byte?>(field.Type, null, true)); //being byte shouldn't matter return; } prevOffset = Reader.BaseStream.Position; Reader.BaseStream.Position += offset - 4; } else if (indirection == 0x04) { count = Reader.ReadUInt32(); prevOffset = Reader.BaseStream.Position; if (count > 0) { Reader.BaseStream.Position += offset - 8; } } else { throw new NotImplementedException(string.Format("Unknown indirection. ({0})", indirection)); } } //if (pointer) //{ // Writer.Write("{0} {1}* = (ptr) ->", ValveDataType(field.Type), field.FieldName); //} if (field.Count > 0 || field.Indirections.Count > 0) { if (field.Type == DataType.Byte) { //special case for byte arrays for faster access var ntroValues = new NTROValue <byte[]>(field.Type, Reader.ReadBytes((int)count), pointer); structEntry.Add(field.FieldName, ntroValues); } else { var ntroValues = new NTROArray(field.Type, (int)count, pointer, field.Indirections.Count > 0); for (var i = 0; i < count; i++) { ntroValues[i] = ReadField(field, pointer); } structEntry.Add(field.FieldName, ntroValues); } } else { for (var i = 0; i < count; i++) { structEntry.Add(field.FieldName, ReadField(field, pointer)); } } if (prevOffset > 0) { Reader.BaseStream.Position = prevOffset; } }
private static void LoadEntities(NTROValue lump, Renderer.Renderer renderer, string path, Package package) { var reference = ((NTROValue <ResourceExtRefList.ResourceReferenceInfo>)lump).Value; if (reference == null) { return; } var newResource = FileExtensions.LoadFileByAnyMeansNecessary(reference.Name + "_c", path, package); if (newResource == null) { Console.WriteLine("unable to load entity lump " + reference.Name + "_c"); return; } var entityLump = newResource.Blocks[BlockType.DATA] as EntityLump; var childLumps = (NTROArray)entityLump.Output["m_childLumps"]; foreach (var lump2 in childLumps) { var lol = ((NTROValue <ResourceExtRefList.ResourceReferenceInfo>)lump).Value; // TODO: Should be controlled in UI with world layers if (lol.Name.Contains("_destruction")) { continue; } LoadEntities(lump2, renderer, path, package); } foreach (var entity in entityLump.Datas) { var scale = string.Empty; var position = string.Empty; var angles = string.Empty; var model = string.Empty; var skin = string.Empty; var colour = new byte[0]; var classname = string.Empty; var name = string.Empty; foreach (var property in entity) { //metadata switch (property.Item2) { case 3368008710: //World Model model = property.Item3 as string; break; case 3827302934: //Position position = property.Item3 as string; break; case 3130579663: //Angles angles = property.Item3 as string; break; case 432137260: //Scale scale = property.Item3 as string; break; case 2020856412: //Skin skin = property.Item3 as string; break; case 588463423: //Colour colour = property.Item3 as byte[]; break; case 3323665506: //Classname classname = property.Item3 as string; break; case 1094168427: name = property.Item3 as string; break; } } if (scale == string.Empty || position == string.Empty || angles == string.Empty) { continue; } if (classname == "point_camera" || classname == "vr_teleport_marker" || model != string.Empty) { var scaleMatrix = Matrix4.CreateScale(ParseCoordinates(scale)); var positionMatrix = Matrix4.CreateTranslation(ParseCoordinates(position)); var rotationVector = ParseCoordinates(angles); var rotationMatrix = Matrix4.CreateRotationX(MathHelper.DegreesToRadians(rotationVector.Z)); rotationMatrix *= Matrix4.CreateRotationY(MathHelper.DegreesToRadians(rotationVector.X)); rotationMatrix *= Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(rotationVector.Y)); var megaMatrix = scaleMatrix * rotationMatrix * positionMatrix; var objColor = Vector4.One; // Parse colour if present if (colour.Length == 4) { for (var i = 0; i < 4; i++) { objColor[i] = colour[i] / 255.0f; } } //This model is hardcoded into the FGD if (classname == "vr_teleport_marker") { model = "models/effects/teleport/teleport_marker.vmdl"; } if (classname == "point_camera") { renderer.AddCamera(name == string.Empty ? $"Camera {anonymousCameraCount++}" : name, megaMatrix); } else { var newEntity = FileExtensions.LoadFileByAnyMeansNecessary(model + "_c", path, package); if (newEntity == null) { Console.WriteLine("unable to load entity " + model + "_c"); continue; } var entityModel = new Model(newEntity); entityModel.LoadMeshes(renderer, path, megaMatrix, objColor, package, skin); } } } }