Jump to content

TOGETHER BnB: Modding Guide


Recommended Posts

TOGETHER BnB

https://store.steampowered.com/app/1239020

 

0001.jpg

 

TOGETHER BnB includes official nude model for s*x scenes, but it can't be used in story mode.

This guide will tell you how to apply (and edit) nude model for story mode!

 

Please note that this guide is only for mod creators. I won't upload any modded files.

 

Requirements


- Visual Studio Community 2019 (to build custom UE Viewer)

- Blender 2.9 and PSK addon https://github.com/Befzz/blender3d_import_psk_psa
- Asset Editor https://github.com/kaiheilos/Utilities

- Unreal Engine 4.26
- u4pak and Python 3 https://github.com/panzi/u4pak

 

Modding Guide

 

(1) We need a custom build of UE Viewer, to support morphs and normals.

Apply the following diff to the source code of UE Viewer and build it in Visual Studio.

 

Spoiler
diff --git a/Exporters/ExportPsk.cpp b/Exporters/ExportPsk.cpp
index 6db8e51..93b8aec 100644
--- a/Exporters/ExportPsk.cpp
+++ b/Exporters/ExportPsk.cpp
@@ -80,7 +80,7 @@ static void ExportCommonMeshData
 	guard(ExportCommonMeshData);
 
 	// using 'static' here to avoid zero-filling unused fields
-	static VChunkHeader MainHdr, PtsHdr, WedgHdr, FacesHdr, MatrHdr;
+	static VChunkHeader MainHdr, PtsHdr, WedgHdr, FacesHdr, MatrHdr, NormHdr;
 	int i;
 
 #define SECT(n)		(Sections + n)
@@ -247,6 +247,22 @@ static void ExportCommonMeshData
 	}
 	unguard;
 
+	guard(Normals);
+	NormHdr.DataCount = Share.Normals.Num();
+	NormHdr.DataSize = sizeof(CVec3);
+	SAVE_CHUNK(NormHdr, "VTXNORMS");
+	for (i = 0; i < Share.Normals.Num(); i++)
+	{
+		CVec3 Normal;
+		Unpack(Normal, Share.Normals[i]);
+		Normal.Normalize();
+#if MIRROR_MESH
+		Normal.Y = -Normal.Y;
+#endif
+		Ar << Normal.X << Normal.Y << Normal.Z;
+	}
+	unguard;
+
 	unguard;
 }
 
@@ -323,7 +339,7 @@ static void CopyBoneName(char* Dst, int DstLen, const char* Src)
 	}
 }
 
-static void ExportSkeletalMeshLod(const CSkeletalMesh &Mesh, const CSkelMeshLod &Lod, FArchive &Ar)
+static void ExportSkeletalMeshLod(const CSkeletalMesh &Mesh, const CSkelMeshLod &Lod, FArchive &Ar, int MorphIndex)
 {
 	guard(ExportSkeletalMeshLod);
 
@@ -333,16 +349,48 @@ static void ExportSkeletalMeshLod(const CSkeletalMesh &Mesh, const CSkelMeshLod
 	int i, j;
 	CVertexShare Share;
 
+	// Copy unmodified vertices
+	struct CSkelMeshVertex* MeshVerts = (CSkelMeshVertex*)appMalloc(sizeof(CSkelMeshVertex) * Lod.NumVerts, 16);
+	memcpy(MeshVerts, Lod.Verts, Lod.NumVerts * sizeof(CSkelMeshVertex));
+
 	// weld vertices
 	// The code below differs from similar code for StaticMesh export: it relies on vertex weight
 	// information to not perform occasional welding of vertices which has the same position and
 	// normal, but belongs to different bones.
 //	appResetProfiler();
 	guard(WeldVerts);
-	Share.Prepare(Lod.Verts, Lod.NumVerts, sizeof(CSkelMeshVertex));
+	Share.Prepare(MeshVerts, Lod.NumVerts, sizeof(CSkelMeshVertex));
+	if (MorphIndex >= 0)
+	{
+		// Copied from CSkelMeshInstance::BuildMorphVerts()
+		const TArray<CMorphVertex>& Deltas = Mesh.Morphs[MorphIndex]->Lods[0].Vertices;
+
+		// Apply deltas
+		for (const CMorphVertex& Delta : Deltas)
+		{
+			CSkelMeshVertex& V = MeshVerts[Delta.VertexIndex];
+			// Morph position
+			VectorAdd(V.Position, Delta.PositionDelta, V.Position);
+			// Morph normal
+			CVec3 Normal;
+			int8 W = V.Normal.GetW();
+			Unpack(Normal, V.Normal);
+			VectorAdd(Normal, Delta.NormalDelta, Normal);
+			Pack(V.Normal, Normal);
+			V.Normal.SetW(W);
+			// Adjust tangent vector to make basis orthonormal
+			CVec3 Tangent;
+			Unpack(Tangent, V.Tangent);
+			float shift = dot(Normal, Tangent); // it will be zero if vertices are perpendicular
+			VectorMA(Tangent, -shift, Normal);  // shift alongside the normal to make vertices perpendicular again
+			Tangent.NormalizeFast();            // ensure result is normalized
+			Pack(V.Tangent, Tangent);
+		}
+	}
+
 	for (i = 0; i < Lod.NumVerts; i++)
 	{
-		const CSkelMeshVertex &S = Lod.Verts[i];
+		const CSkelMeshVertex &S = MeshVerts[i];
 		// Here we relies on high possibility that vertices which should be shared between
 		// triangles will have the same order of weights and bones (because most likely
 		// these vertices were duplicated by copying). Doing more complicated comparison
@@ -463,37 +511,44 @@ void ExportPsk(const CSkeletalMesh *Mesh)
 		appNotify("Mesh %s has 0 lods", OriginalMesh->Name);
 		return;
 	}
+	if (GExportLods && !Mesh->Morphs.Num())
+	{
+		appNotify("Mesh %s has 0 morphs", OriginalMesh->Name);
+		return;
+	}
 
-	int MaxLod = (GExportLods) ? Mesh->Lods.Num() : 1;
-	for (int Lod = 0; Lod < MaxLod; Lod++)
+	int MaxMorph = (GExportLods) ? Mesh->Morphs.Num() : 0;
+	for (int Morph = -1; Morph < MaxMorph; Morph++)
 	{
-		guard(Lod);
+		guard(Morph);
 
-		const CSkelMeshLod &MeshLod = Mesh->Lods[Lod];
+		const CSkelMeshLod& MeshLod = Mesh->Lods[0];
 		if (!MeshLod.Sections.Num()) continue;		// empty mesh
 
 		bool UsePskx = (MeshLod.NumVerts > 65536);
 
 		char filename[512];
-		const char *Ext = (UsePskx) ? "pskx" : "psk";
-		if (Lod == 0)
+		const char* Ext = (UsePskx) ? "pskx" : "psk";
+		if (Morph < 0)
 			appSprintf(ARRAY_ARG(filename), "%s.%s", OriginalMesh->Name, Ext);
 		else
-			appSprintf(ARRAY_ARG(filename), "%s_Lod%d.%s", OriginalMesh->Name, Lod, Ext);
+		{
+			appSprintf(ARRAY_ARG(filename), "%s_Morph%02d_%s.%s", OriginalMesh->Name, Morph, *Mesh->Morphs[Morph]->Name, Ext);
+		}
 
-		FArchive *Ar = CreateExportArchive(OriginalMesh, EFileArchiveOptions::Default, "%s", filename);
+		FArchive* Ar = CreateExportArchive(OriginalMesh, EFileArchiveOptions::Default, "%s", filename);
 		if (Ar)
 		{
-			ExportSkeletalMeshLod(*Mesh, MeshLod, *Ar);
+			ExportSkeletalMeshLod(*Mesh, MeshLod, *Ar, Morph);
 			delete Ar;
 		}
-		else if (Lod == 0)
+		else if (Morph == 0)
 		{
 			// First LOD was failed to be saved, most likely file already exists
 			return;
 		}
 
-		unguardf("%d", Lod);
+		unguardf("%d", Morph);
 	}
 
 	// export script file
diff --git a/UmodelTool/SettingsDialog.cpp b/UmodelTool/SettingsDialog.cpp
index fb1acf6..caac7fd 100644
--- a/UmodelTool/SettingsDialog.cpp
+++ b/UmodelTool/SettingsDialog.cpp
@@ -146,7 +146,7 @@ UIElement& UISettingsDialog::MakeExportOptions()
 					.AddItem("ActorX (pskx)", EExportMeshFormat::psk)
 					.AddItem("glTF 2.0", EExportMeshFormat::gltf)
 			]
-			+ NewControl(UICheckbox, "Export LODs", &Opt.Export.ExportMeshLods)
+			+ NewControl(UICheckbox, "Export Morphs", &Opt.Export.ExportMeshLods)
 		]
 		+ NewControl(UIGroup, "Texture Export")
 		[

 

 

(2) Open character models in UE Viewer, and export them as PSK files.

 

Nana Model Paths:

 - Plain Nude: "/TogetherBNB/Plugins/DLC_R/Content/CH/Clear/Nana/NanaClear.uasset" (recommended to use as modding base model)

 - Complete Nude: "/Game/CH/Nana/R18/NanaR18_F0524.uasset" (more detailed nude of s*x scene. Good for importing only body mesh for editing. Don't use this model as modding base model, because it uses incompatible skeleton.)

 - Default Costume: "/Game/CH/Nana/N_All/NanaF6_2.uasset" (with clothes and accessory)

 

Options (Export Morphs checkbox should be ON only with modding base model):

export-options.jpg

 

(3) Follow the modding tutorial on Trials of Mana.
https://www.loverslab.com/topic/143609-trials-of-mana-mod-creation-guide/

 

Please read above tutorial and create your new model.

 

You can replace the default costume's uasset, but instead, I recommend you to

create new uasset and specify the new path in NpcClothesTable.uasset (costume list file).

To do this, open "/Game/Character/" in UE Viewer and click "Save packages" from right-click menu.

Then open NpcClothesTable.uasset in Asset Editor, and edit/save it.

For example, to replace swimsuit model with new model, replace two strings.

 - "/Game/CH/Nana/N_All/NanaSwim" to "/Game/CH/Nana/N_All/YourModelName"

 - "NanaSwim" to "YourModelName"

Currently, Asset Editor doesn't show "4.26" in the top-right select box, but it will work without problem.

 

asset-editor.jpg

 

 

Modding Result

 

0002.jpg

 

0003.jpg

 

- Base Model: NanaClear.uasset

- Body Mesh: NanaR18_F0524.uasset (merged into base model, make breasts size smaller to fit Nana, transfered weights from base model)

- Accessory Mesh: NanaF6_2.uasset (merged into base model)

Link to comment
  • 1 month later...
  • 1 month later...

Tutorial above is good, but significant resource seems needed.  If anyone has actually run through tutorial, would love for someone to share an actual mod.  Sharing a typical how-to is one thing, but one that requires all those programs is different (but I do appreciate the share, and am debating possibly trying, but lots of things to track down to even begin). A story mode regular nude mod would be great, the models look fantastic (why it's not included is beyond me, perhaps eventually).  Or if anyone has actually tracked down a mod on a chinese forum (I only say that as the discussion forum for this game in steam is all chinese).  If I find anything, I'll share. 

Link to comment
  • 1 month later...
  • 2 weeks later...
  • 2 months later...
  • 2 months later...
  • 2 months later...

I tried everything, replaced all the lines with Nana suits with the version of the R18 model, nothing changes in the game. I tried just to put the archive in pak or in the ~ mod folder. Checked through umodel, the archive is read and the file appears where necessary. In general, nothing works. It may not work anymore in newer builds. Does anyone have a 100% working version of the mod?

Link to comment
On 4/3/2023 at 3:01 AM, MARK2580 said:

I tried everything, replaced all the lines with Nana suits with the version of the R18 model, nothing changes in the game. I tried just to put the archive in pak or in the ~ mod folder. Checked through umodel, the archive is read and the file appears where necessary. In general, nothing works. It may not work anymore in newer builds. Does anyone have a 100% working version of the mod?

Do you have any modified umodels? I don't know how to compile umodel source code, so I lost facial morphs when making mods. Can you upload it if you have oneimage.png.95425aff53e141f056bcc120bb36cd64.png

Link to comment
On 4/4/2023 at 5:21 PM, bqcai said:

Do you have any modified umodels? I don't know how to compile umodel source code, so I lost facial morphs when making mods. Can you upload it if you have one

no, I didn't touch the models at all, I just tried to change the default model to the R18 model via cloth data...

Link to comment
  • 2 months later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. For more information, see our Privacy Policy & Terms of Use