public bool Execute(string[] args) { if (args.Length < 1) { Console.WriteLine("Expected at least 1 argument."); return(false); } var inputPath = args[0]; if (!File.Exists(inputPath)) { Console.WriteLine("Input file doesn't exist."); return(false); } var outputPath = Path.ChangeExtension(inputPath, null); if (args.Length > 1) { outputPath = args[1]; } Directory.CreateDirectory(outputPath); var fs = new LBFileSystem(); try { fs.Load(inputPath); } catch (Exception) { Console.WriteLine("Invalid LB file."); return(false); } using ( fs ) { foreach (int file in fs.EnumerateFiles(SearchOption.AllDirectories)) { var info = fs.GetInfo(file); using (var stream = FileUtils.Create($"{outputPath}{Path.DirectorySeparatorChar}{file:D2}{'_'}{info.UserId:D2}.{info.Extension}")) using (var inputStream = fs.OpenFile(file)) { Console.WriteLine($"Extracting: {file}"); inputStream.CopyTo(stream); } } } return(true); }
private static void ReplaceF1Test() { var modelPack = new ModelPack(); var model = new Model(); model.Nodes.Add(new Node { Name = "model" }); modelPack.Models.Add(model); modelPack.Replace("f1test.fbx"); var lb = new LBFileSystem(); lb.Load(@"D:\Modding\DDS3\Nocturne\_HostRoot\dds3data\fld\f\f037\_f037_027.LB"); var f1Handle = lb.GetHandle("F1"); FieldScene f1; using (var stream = lb.OpenFile(f1Handle)) f1 = new FieldScene(stream, true); f1.Objects.RemoveAll(x => x.ResourceType == FieldObjectResourceType.Model); f1.Objects.Clear(); f1.Objects.Add(new FieldObject() { Id = 0, Name = "model", Transform = new FieldObjectTransform(), Resource = modelPack.Models[0] }); ExportObj(f1); lb.AddFile(f1Handle, f1.Save(), true, ConflictPolicy.Replace); if (modelPack.TexturePack != null) { var tbHandle = lb.GetHandle("TBN"); lb.AddFile(tbHandle, modelPack.TexturePack.Save(), true, ConflictPolicy.Replace); } lb.Save(@"D:\Modding\DDS3\Nocturne\_HostRoot\dds3data\fld\f\f037\f037_027.LB"); }
private static void Main(string[] args) { { File.Delete("test.fbx"); var modelPack = new ModelPack(@"D:\dumps\smt3_ntsc\DDS3\model\field\player_a.PB"); //var modelPack = new ModelPack( @"D:\dumps\smt3_ntsc\DDS3\model\devil\on\0x126_on.PB"); FbxModelExporter.Instance.Export(modelPack.Models[0], "test.fbx", modelPack.TexturePack); return; //AssimpModelExporter.Instance.Export( modelPack.Models[ 0 ], "player_a.dae", modelPack.TexturePack ); //for ( var i = 0; i < modelPack.MotionPacks[ 0 ].Motions.Count; i++ ) //{ // var motion = modelPack.MotionPacks[ 0 ].Motions[ i ]; // if ( motion == null ) // continue; // AssimpMotionExporter.Instance.Export( modelPack.Models[ 0 ], motion, $"player_a_motion_{i:D2}.dae" ); //} var newMotion = AssimpMotionImporter.Instance.Import(@"D:\Users\smart\Desktop\nocturne_player_a_fortnite.fbx", new AssimpMotionImporter.Config { NodeIndexResolver = n => modelPack.Models[0].Nodes.FindIndex(x => x.Name == n) }); for (int i = 0; i < modelPack.MotionPacks[0].Motions.Count; i++) { modelPack.MotionPacks[0].Motions[i] = newMotion; } modelPack.Save(@"D:\Modding\DDS3\Nocturne\_HostRoot\dds3data\model\field\player_a.PB"); } { var lb = new LBFileSystem(); lb.Load(@"D:\Modding\DDS3\Nocturne\_HostRoot\dds3data\fld\f\f037\_f037_027.LB"); var f1Handle = lb.GetHandle("F1"); FieldScene f1; using (var stream = lb.OpenFile(f1Handle)) f1 = new FieldScene(stream, true); foreach (var obj in f1.Objects) { switch (obj.ResourceType) { case FieldObjectResourceType.Model: { var model = ( Model )obj.Resource; foreach (var material in model.Materials) { if (material.TextureId.HasValue) { material.TextureId = 0; } material.Color1 = material.Color2 = material.Color3 = material.Color4 = material.Color5 = null; material.Float1 = null; material.FloatArray1 = material.FloatArray2 = material.FloatArray3 = null; } foreach (var node in model.Nodes) { if (node.Geometry == null) { continue; } foreach (var _mesh in node.Geometry.Meshes) { if (_mesh is MeshType1 mesh) { foreach (var batch in mesh.Batches) { batch.Flags &= ~MeshFlags.Normal; batch.Flags &= ~MeshFlags.Color; } } } } } break; case FieldObjectResourceType.Type3: break; case FieldObjectResourceType.TextureListFileName: break; case FieldObjectResourceType.Effect: break; case FieldObjectResourceType.Light: break; } } ExportObj(f1); lb.AddFile(f1Handle, f1.Save(), true, ConflictPolicy.Replace); var tbHandle = lb.GetHandle("TBN"); var texturePack = new TexturePack(); texturePack.Textures.Add(new Texture(new Bitmap(@"D:\Modding\Tools\magenta.png"))); lb.AddFile(tbHandle, texturePack.Save(), true, ConflictPolicy.Replace); lb.Save(@"D:\Modding\DDS3\Nocturne\_HostRoot\dds3data\fld\f\f037\f037_027.LB"); } //OpenAndSaveModelPackTest(); //ReplaceF1Test(); //ReplaceModelTest(); //OpenAndSaveModelPackBatchTest(); //return; //ExportObj( new ModelPack( @"D:\Modding\DDS3\Nocturne\_HostRoot\dds3data\model\field\player_b.PB" ) ); //return; //OpenAndSaveModelPackBatchTest();return; //OpenAndSaveFieldSceneBatchTest();return; //ReplaceModelTest();return; //var modelPack = new ModelPack( @"..\..\..\..\Resources\player_a.PB" ); //var modelPack = new ModelPack( @"D:\Modding\DDS3\Nocturne\_HostRoot\dds3data\model\field\player_a.PB" ); //using ( var writer = File.CreateText( "test.obj" ) ) //{ // var vertexBaseIndex = 0; // foreach ( var model in modelPack.Models ) // { // foreach ( var node in model.Nodes ) // { // if ( node.Geometry == null ) // continue; // for ( var meshIndex = 0; meshIndex < node.Geometry.Meshes.Count; meshIndex++ ) // { // var _mesh = node.Geometry.Meshes[ meshIndex ]; // if ( _mesh.Type != MeshType.Type7 ) // continue; // var mesh = ( MeshType7 ) _mesh; // var positions = new Vector3[mesh.VertexCount]; // var normals = new Vector3[positions.Length]; // var weights = new List<(short NodeIndex, float Weight)>[positions.Length]; // var texCoords = new Vector2[positions.Length]; // var batchVertexBaseIndex = 0; // foreach ( var batch in mesh.Batches ) // { // for ( var nodeBatchIndex = 0; nodeBatchIndex < batch.NodeBatches.Count; nodeBatchIndex++ ) // { // var nodeBatch = batch.NodeBatches[ nodeBatchIndex ]; // var nodeWorldTransform = model.Nodes[ nodeBatch.NodeIndex ].WorldTransform; // for ( int i = 0; i < nodeBatch.Positions.Length; i++ ) // { // var position = new Vector3( nodeBatch.Positions[i].X, nodeBatch.Positions[i].Y, // nodeBatch.Positions[i].Z ); // var weight = nodeBatch.Positions[i].W; // var weightedNodeWorldTransform = nodeWorldTransform * weight; // var weightedWorldPosition = Vector3.Transform( position, weightedNodeWorldTransform ); // positions[batchVertexBaseIndex + i] += weightedWorldPosition; // if ( weights[batchVertexBaseIndex + i] == null ) // weights[batchVertexBaseIndex + i] = new List<(short NodeIndex, float Weight)>(); // weights[batchVertexBaseIndex + i].Add( (nodeBatch.NodeIndex, weight) ); // normals[batchVertexBaseIndex + i] += Vector3.TransformNormal( nodeBatch.Normals[i], weightedNodeWorldTransform ); // } // } // Array.Copy( batch.TexCoords, 0, texCoords, batchVertexBaseIndex, batch.TexCoords.Length ); // //foreach ( var position in positions ) // //{ // // writer.WriteLine( $"v {position.X} {position.Y} {position.Z}" ); // //} // //foreach ( var normal in normals ) // //{ // // writer.WriteLine( $"vn {normal.X} {normal.Y} {normal.Z}" ); // //} // //foreach ( var texCoord in batch.TexCoords ) // //{ // // writer.WriteLine( $"vt {texCoord.X} {texCoord.Y}" ); // //} // batchVertexBaseIndex += batch.VertexCount; // } // foreach ( var position in positions ) // { // writer.WriteLine( $"v {position.X} {position.Y} {position.Z}" ); // } // foreach ( var normal in normals ) // { // writer.WriteLine( $"vn {normal.X} {normal.Y} {normal.Z}" ); // } // foreach ( var texCoord in texCoords ) // { // writer.WriteLine( $"vt {texCoord.X} {texCoord.Y}" ); // } // //// Find unique node indices used by the mesh (max 4 per mesh!) // //var usedNodeIndices = weights.SelectMany( x => x.Select( y => y.NodeIndex ) ).Distinct().ToList(); // //// Calculate node index usage frequency // //var usedNodeIndicesFrequency = new Dictionary<int, int>(); // //for ( int i = 0; i < usedNodeIndices.Count; i++ ) // // usedNodeIndicesFrequency[usedNodeIndices[i]] = 0; // //for ( int j = 0; j < positions.Length; j++ ) // //{ // // foreach ( var (nodeIndex, _) in weights[j] ) // // ++usedNodeIndicesFrequency[nodeIndex]; // //} // //// Sort used node indices by frequency // //usedNodeIndices = usedNodeIndices.OrderBy( x => usedNodeIndicesFrequency[ x ] ).ToList(); // //// Start building batches // //var vertexIndexRemap = new Dictionary<int, int>(); // //var batches = new List<MeshType7Batch>(); // //batchVertexBaseIndex = 0; // //while ( vertexIndexRemap.Count < positions.Length ) // //{ // // var batchVertexCount = Math.Min( 24, positions.Length - vertexIndexRemap.Count ); // // var batch = new MeshType7Batch(); // // var batchVertexIndexRemap = new Dictionary<int, int>(); // // var batchTexCoords = new List<Vector2>(); // // // req. all vertices to use the same set of node indices // // for ( var i = 0; i < usedNodeIndices.Count; i++ ) // // { // // var nodeIndex = usedNodeIndices[i]; // // var nodeWorldTransform = model.Nodes[nodeIndex].WorldTransform; // // var nodeWorldTransformInv = nodeWorldTransform.Inverted(); // // // get all verts with this index // // var nodePositions = new List<Vector4>(); // // var nodeNormals = new List<Vector3>(); // // for ( int j = 0; j < positions.Length; j++ ) // // { // // // Skip this vertex if it has already been processed before // // if ( vertexIndexRemap.ContainsKey( j ) ) // // continue; // // foreach ( (short NodeIndex, float Weight) in weights[j] ) // // { // // if ( NodeIndex != nodeIndex ) // // continue; // // // Transform position and normal to model space // // var position = Vector3.Transform( positions[j], nodeWorldTransformInv ); // // var normal = Vector3.TransformNormal( normals[j], nodeWorldTransformInv ); // // // Add entry to vertex remap, and add the model space positions and normals to our lists // // batchVertexIndexRemap[j] = batchVertexBaseIndex + nodePositions.Count; // // nodePositions.Add( new Vector4( position, Weight ) ); // // nodeNormals.Add( normal ); // // if ( i == 0 ) // // { // // // Only add this once, of course // // batchTexCoords.Add( texCoords[ j ] ); // // } // // // Stop looking if we've reached our vertex count // // if ( nodePositions.Count == batchVertexCount ) // // goto end; // // } // // } // // end: // // batch.NodeBatches.Add( new MeshType7NodeBatch() // // { // // NodeIndex = nodeIndex, // // Positions = nodePositions.ToArray(), // // Normals = nodeNormals.ToArray() // // }); // // } // // batch.TexCoords = batchTexCoords.ToArray(); // // foreach ( var i in batchVertexIndexRemap ) // // vertexIndexRemap.Add( i.Key, i.Value ); // // Debug.Assert( batch.NodeBatches.Count > 0 ); // // Debug.Assert( batch.NodeBatches.TrueForAll( x => x.VertexCount == batch.NodeBatches[ 0 ].VertexCount ) ); // // batches.Add( batch ); // // batchVertexBaseIndex += batchVertexCount; // //} // //var materialIndex = mesh.MaterialIndex; // //var triangles = new Triangle[mesh.TriangleCount]; // //for ( var i = 0; i < mesh.Triangles.Length; i++ ) // //{ // // ref var triangle = ref triangles[i]; // // triangle.A = ( ushort )vertexIndexRemap[mesh.Triangles[i].A]; // // triangle.B = ( ushort )vertexIndexRemap[mesh.Triangles[i].B]; // // triangle.C = ( ushort )vertexIndexRemap[mesh.Triangles[i].C]; // //} // //mesh = new MeshType7(); // //mesh.Batches.AddRange( batches ); // //mesh.Triangles = triangles; // //mesh.MaterialIndex = materialIndex; // //node.Geometry.Meshes[meshIndex] = mesh; // writer.WriteLine( $"o node_{node.Name}_mesh_{meshIndex}" ); // foreach ( var triangle in mesh.Triangles ) // { // writer.WriteLine( "f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}", vertexBaseIndex + triangle.A + 1, vertexBaseIndex + triangle.B + 1, vertexBaseIndex + triangle.C + 1 ); // } // vertexBaseIndex += mesh.VertexCount; // } // } // } //} //modelPack.Save( @"D:\Modding\DDS3\Nocturne\_HostRoot\dds3data\model\field\player_a.PB" ); //ReplaceModelTest(); //return; //GenerateMaterialPresets(); //return; //var modelPack = new ModelPack( @"..\..\..\..\Resources\player_a.PB" ); //foreach ( var material in modelPack.Models[0].Materials ) //{ // Console.WriteLine( MaterialPresetStore.GetPresetId( material ) ); //} //return; ////for ( var i = 0; i < modelPack.TexturePack.Count; i++ ) ////{ //// var texture = modelPack.TexturePack[ i ]; //// texture.GetBitmap().Save( $"player_a_{i}.png" ); ////} //modelPack.Save( @"D:\Modding\DDS3\Nocturne\_HostRoot\dds3data\model\field\player_a.PB" ); ////ReplaceModelTest(); //OpenAndSaveModelPackBatchTest(); }
public bool Execute(string[] args) { if (args.Length < 2) { Console.WriteLine("Expected at least 2 arguments."); return(false); } var inputPath = args[0]; if (!File.Exists(inputPath)) { Console.WriteLine("Input file doesn't exist."); return(false); } var fs = new LBFileSystem(); try { fs.Load(inputPath); } catch (Exception) { Console.WriteLine("Invalid LB file"); return(false); } string outputPath = inputPath; if (Directory.Exists(args[1])) { var directoryPath = args[1]; if (args.Length > 2) { outputPath = args[2]; } using ( fs ) { foreach (string file in Directory.EnumerateFiles(directoryPath, "*.*", SearchOption.AllDirectories)) { Console.WriteLine($"Adding/Replacing file: {file}"); var name = Path.GetFileNameWithoutExtension(file); if (name == null) { continue; } var nameParts = name.Split(new[] { '_' }, StringSplitOptions.RemoveEmptyEntries); if (int.TryParse(nameParts[0], out var handle)) { if (nameParts.Length > 1 && short.TryParse(nameParts[1], out var userId)) { fs.AddFile(handle, userId, file, ConflictPolicy.Replace); } else { fs.AddFile(handle, file, ConflictPolicy.Replace); } } else { fs.AddFile(file); } } Console.WriteLine("Saving..."); fs.Save(outputPath); } } else { if (args.Length > 3) { outputPath = args[3]; } using ( fs ) { var entryName = args[1]; var entryNameParts = entryName.Split(new[] { '_' }, StringSplitOptions.RemoveEmptyEntries); if (int.TryParse(entryNameParts[0], out var handle)) { if (!fs.Exists(handle)) { Console.WriteLine("Specified entry doesn't exist."); return(false); } var filePath = args[2]; if (!File.Exists(filePath)) { Console.WriteLine("Specified replacement file doesn't exist."); return(false); } Console.WriteLine($"Replacing file: {filePath}"); fs.AddFile(handle, filePath, ConflictPolicy.Replace); Console.WriteLine("Saving..."); fs.Save(outputPath); } } } return(true); }
private static void ConvertAssimpModel() { switch (Options.OutputFormat) { case OutputFormat.PB: { if (Options.PackedModel.ReplaceInput == null) { throw new Exception("You must specify a PB replacement input for conversion to PB"); } var modelPack = new ModelPack(); if (Options.PackedModel.ReplaceInput != null) { modelPack.Load(Options.PackedModel.ReplaceInput); } if (!Options.Assimp.TreatInputAsAnimation) { modelPack.Replace(Options.Input, Options.TmxScale, Options.Model.EnableMaterialOverlays, Options.Model.WeightedMeshType, Options.Model.UnweightedMeshType, Options.Model.MeshWeightLimit, Options.Model.BatchVertexLimit); } else { var newMotion = AssimpMotionImporter.Instance.Import(Options.Input, new AssimpMotionImporter.Config { NodeIndexResolver = n => modelPack.Models[Options.PackedModel.ReplaceMotionModelIndex].Nodes.FindIndex(x => x.Name == n) }); if (Options.PackedModel.ReplaceMotionIndex < 0 || (Options.PackedModel.ReplaceMotionIndex + 1) > modelPack.MotionPacks[Options.PackedModel.ReplaceMotionPackIndex].Motions.Count) { modelPack.MotionPacks[Options.PackedModel.ReplaceMotionPackIndex].Motions[Options.PackedModel.ReplaceMotionIndex] = newMotion; } } modelPack.Save(Options.Output); } break; case OutputFormat.F1: { var modelPack = new ModelPack(); var model = new Model(); model.Nodes.Add(new Node { Name = "model" }); modelPack.Models.Add(model); modelPack.Replace(Options.Input, Options.TmxScale, Options.Model.EnableMaterialOverlays, Options.Model.WeightedMeshType, Options.Model.UnweightedMeshType, Options.Model.MeshWeightLimit, Options.Model.BatchVertexLimit); var lb = new LBFileSystem(); lb.Load(Options.Field.LbReplaceInput); var f1Handle = lb.GetHandle("F1"); FieldScene f1; using (var stream = lb.OpenFile(f1Handle)) f1 = new FieldScene(stream, true); f1.Objects.RemoveAll(x => x.ResourceType == FieldObjectResourceType.Model); f1.Objects.Clear(); f1.Objects.Add(new FieldObject() { Id = 0, Name = "model", Transform = new FieldObjectTransform(), Resource = modelPack.Models[0] }); lb.AddFile(f1Handle, f1.Save(), true, ConflictPolicy.Replace); if (modelPack.TexturePack != null) { var tbHandle = lb.GetHandle("TBN"); lb.AddFile(tbHandle, modelPack.TexturePack.Save(), true, ConflictPolicy.Replace); } lb.Save(Options.Output); } break; default: throw new Exception("Unsupported output format"); } }