Skip to content

Commit 0e3e165

Browse files
committed
Cleanup & description support
better handling of user input (might wana add error messages down the line) added support for remplacing place holder text in a folder containing readme&descriptions. Making it less and less painfull to propare a page for the public
1 parent a9391d0 commit 0e3e165

4 files changed

Lines changed: 174 additions & 43 deletions

File tree

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Here's a cool description for my face tracking add-on for /*AVATAR AUTHOR*/'s /*AVATAR NAME*/
2+
much swag, very bussin!
3+
4+
for this add-on to work you need to own /*AVATAR NAME*/ by /*AVATAR AUTHOR*/, avaliable @:
5+
/*StoreLink*/
6+
7+
this DLC will only work if you use the package /*PACKAGE NAME*/ and have the model that comes with it in your unity project
8+
9+
after buying you'll get a program stored in
10+
/*DIR PATCHER*/
11+
12+
after running it you should have a working prefab in:
13+
14+
/*DIR PREFAB*/
15+
16+
Import it into your scene, and voila!
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
thanks for buying my Add-on for /*AVATAR NAME*/. it means a lot to me
2+
3+
After importing the package in your unity project that has the model in it. please run the program in
4+
/*DIR PATCHER*/
5+
6+
after running it you should have a working prefab in:
7+
/*DIR PREFAB*/
8+
9+
10+
11+
Import it into your scene, and voila!
12+
13+
14+
15+
Enjoy!

FT_Builder.py

Lines changed: 113 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import os
2+
from pickle import TRUE
23
import sys
34
import shutil
45
import subprocess
56
import PyInstaller.__main__
67

8+
9+
#prints my cool ascii art
710
def print_ascii_art():
811
ascii_art = r"""
912
____ ____ ____ _ _ __ __ ____ ____ ____
@@ -19,14 +22,51 @@ def print_ascii_art():
1922
print(ascii_art)
2023
print(credits)
2124

25+
26+
#remplaces the sick descriptions you've made for your product with what you input if you so please
27+
def replace_placeholders_in_files_in_directory(directory, AvatarName, AvatarCreatorName, BoothLink, PackageName, DirPatcher, DirPrefab):
28+
replacements = {
29+
'/*AVATAR NAME*/': AvatarName,
30+
'/*AVATAR AUTHOR*/': AvatarCreatorName,
31+
'/*StoreLink*/': BoothLink,
32+
'/*PACKAGE NAME*/': PackageName,
33+
'/*DIR PATCHER*/': DirPatcher,
34+
'/*DIR PREFAB*/': DirPrefab
35+
}
36+
37+
current_directory = os.getcwd()
38+
retail_folder = os.path.join(current_directory, 'Retail Descriptions ' + AvatarName)
39+
os.makedirs(retail_folder, exist_ok=True)
40+
41+
for root, _, files in os.walk(directory):
42+
for file_name in files:
43+
file_path = os.path.join(root, file_name)
44+
with open(file_path, 'r', encoding='utf-8') as file:
45+
file_content = file.read()
46+
47+
for placeholder, value in replacements.items():
48+
file_content = file_content.replace(placeholder, value)
49+
50+
relative_path = os.path.relpath(file_path, directory)
51+
new_file_path = os.path.join(retail_folder, relative_path)
52+
os.makedirs(os.path.dirname(new_file_path), exist_ok=True)
53+
with open(new_file_path, 'w', encoding='utf-8') as file:
54+
file.write(file_content)
55+
56+
print(f"Modified files saved in '{retail_folder}' folder.")
57+
58+
59+
60+
#fonction that gives the relative path from the Assets folder
2261
def get_assets_relative_path(file_path):
2362
asset_folder = "Assets"
2463
index = file_path.rfind(asset_folder)
2564
if index != -1:
2665
return file_path[index + len(asset_folder) + 1:]
2766
else:
2867
return None
29-
68+
69+
#fonction that will take care of modifying the right lines of code in the patcher
3070
def modify_python_patcher_script(original_model_path, original_meta_file_path, diff_file_name, meta_diff_file_name, output_name, NameCustomScript):
3171
with open('PythonPatcher.py', 'r') as file:
3272
script_content = file.read()
@@ -63,27 +103,47 @@ def main():
63103

64104
print_ascii_art()
65105

66-
# Get the dropped file path as input
67-
OriginalFBX = input("Drag and drop the original FBX here (make sure it's in between quotation marks): ")
68-
OriginalFBX = OriginalFBX.strip('"')
69-
FaceTrackedFBX = input("Drag and drop the face tracked FBX here (make sure it's in between quotation marks): ")
70-
FaceTrackedFBX = FaceTrackedFBX.strip('"')
106+
# Get the required info to proceed
107+
108+
OriginalFBX = input("Drag and drop the original FBX here: ")
109+
if OriginalFBX.startswith('"') and OriginalFBX.endswith('"'):
110+
OriginalFBX = OriginalFBX.strip('"')
111+
112+
113+
FaceTrackedFBX = input("Drag and drop the face tracked FBX here: ")
114+
if FaceTrackedFBX.startswith('"') and FaceTrackedFBX.endswith('"'):
115+
FaceTrackedFBX = FaceTrackedFBX.strip('"')
116+
117+
71118
NameCustomDir = input("Please input the name of your custom directory: ")
72119
NameCustomAvatarDir = input("Please input the name of the avatar's custom directory: ")
73-
NameFBXDiffFile = input("Please input the name of your FBX Diff file: ")
74-
NameMetaDiffFile = input("Please input the name of your import settings Diff file: ")
120+
NameFBXDiffFile = NameCustomAvatarDir + 'Diff'
121+
NameMetaDiffFile = NameCustomAvatarDir + 'Meta' + 'Diff'
122+
DescriptionDir = input("Please input the directory of your descriptions and readme files (will skip if left empty): ")
123+
124+
125+
if DescriptionDir.startswith('"') and DescriptionDir.endswith('"'):
126+
DescriptionDir = DescriptionDir.strip('"')
127+
if DescriptionDir != '':
128+
CreatorName = input("Please input the name of the creator: ")
129+
BoothPage = input("Please input the page of the avatar: ")
130+
PackageName = input("Please input the name of the package that users will have: ")
131+
75132

76133

77134

78135

136+
137+
#creates the funky subfolders
79138
target_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), NameCustomDir, NameCustomAvatarDir, 'patcher', 'data', 'DiffFiles'))
80139
os.makedirs(target_dir, exist_ok=True)
81140

82141

142+
#location of the hdiff builds
143+
hdiffz = os.path.join(os.path.dirname(__file__), 'hdiff', 'hdiffz.exe')
144+
hpatchz = os.path.join(os.path.dirname(__file__), 'hdiff', 'hpatchz.exe')
83145

84-
hdiffz = os.path.join(os.path.dirname(__file__), 'hdiff', 'hdiffz.exe')
85-
hpatchz = os.path.join(os.path.dirname(__file__), 'hdiff', 'hpatchz.exe')
86-
146+
#location of the diff files
87147
FBXDiffFile = os.path.abspath(os.path.join(os.path.dirname(__file__), NameCustomDir, NameCustomAvatarDir, 'patcher', 'data', 'DiffFiles', NameFBXDiffFile+".hdiff"))
88148
MetaDiffFile = os.path.abspath(os.path.join(os.path.dirname(__file__), NameCustomDir, NameCustomAvatarDir, 'patcher', 'data', 'DiffFiles', NameMetaDiffFile+".hdiff"))
89149

@@ -97,6 +157,7 @@ def main():
97157
print("Error occurred during creation of the meta diff file.")
98158
input("Press Enter to continue...")
99159

160+
#location of the og script and the destination script
100161
OriginalScript = os.path.abspath(os.path.join(__file__, '..', 'PythonPatcher.py'))
101162
destination_path = os.path.abspath(os.path.join(os.path.dirname(__file__),"! "+ NameCustomAvatarDir + "Patcher.py"))
102163

@@ -116,7 +177,7 @@ def main():
116177
)
117178

118179

119-
#build
180+
#build the patcher
120181
buildDestination = os.path.abspath(os.path.join(os.path.dirname(__file__), NameCustomDir, NameCustomAvatarDir, 'patcher'))
121182
PyInstaller.__main__.run([
122183
"! "+NameCustomAvatarDir+"Patcher.py",
@@ -127,27 +188,55 @@ def main():
127188
])
128189

129190

130-
#moving files over
191+
#moving patcher files over
131192
source_dir = os.path.join(buildDestination, "! "+NameCustomAvatarDir+"Patcher")
132193
file_names = os.listdir(source_dir)
133194

134195
for file_name in file_names:
135196
shutil.move(os.path.join(source_dir, file_name), buildDestination)
136197

137-
#moving evrything under the data folder
138-
shutil.move(os.path.join(buildDestination, '_bz2.pyd'), os.path.join(buildDestination, 'data', '_bz2.pyd'))
139-
shutil.move(os.path.join(buildDestination, '_hashlib.pyd'), os.path.join(buildDestination, 'data', '_hashlib.pyd'))
140-
shutil.move(os.path.join(buildDestination, '_lzma.pyd'), os.path.join(buildDestination, 'data', '_lzma.pyd'))
141-
shutil.move(os.path.join(buildDestination, '_socket.pyd'), os.path.join(buildDestination, 'data', '_socket.pyd'))
142-
shutil.move(os.path.join(buildDestination, '_ssl.pyd'), os.path.join(buildDestination, 'data', '_ssl.pyd'))
143-
shutil.move(os.path.join(buildDestination, 'libcrypto-1_1-x64.dll'), os.path.join(buildDestination, 'data', 'libcrypto-1_1-x64.dll'))
144-
shutil.move(os.path.join(buildDestination, 'libssl-1_1-x64.dll'), os.path.join(buildDestination, 'data', 'libssl-1_1-x64.dll'))
145-
shutil.move(os.path.join(buildDestination, 'select.pyd'), os.path.join(buildDestination, 'data', 'select.pyd'))
146-
shutil.move(os.path.join(buildDestination, 'unicodedata.pyd'), os.path.join(buildDestination, 'data', 'unicodedata.pyd'))
147-
shutil.move(os.path.join(buildDestination, 'VCRUNTIME140.dll'), os.path.join(buildDestination, 'data', 'VCRUNTIME140.dll'))
198+
#moving evrything that can be under the data folder
199+
200+
files_to_exclude = [
201+
"! "+NameCustomAvatarDir+"Patcher.exe",
202+
"base_library.zip",
203+
NameFBXDiffFile+".hdiff",
204+
NameMetaDiffFile+".hdiff"
205+
]
206+
207+
dll_names_to_exclude = ["python"]
208+
209+
for root, _, files in os.walk(buildDestination):
210+
for file_name in files:
211+
source_path = os.path.join(root, file_name)
212+
destination_path = ""
213+
214+
if file_name in files_to_exclude:
215+
continue
216+
217+
is_dll_with_python = any(name in file_name.lower() for name in dll_names_to_exclude)
218+
if is_dll_with_python:
219+
continue
220+
else:
221+
destination_path = os.path.join(buildDestination, 'data', file_name)
222+
223+
shutil.move(source_path, destination_path)
224+
148225
shutil.copy(hpatchz, os.path.join(buildDestination, 'data', 'hpatchz.exe'))
149226
shutil.copy(os.path.join(hpatchz, '..', 'License.txt'), os.path.join(buildDestination, 'data', 'License.txt'))
150227
os.rmdir(source_dir)
228+
print("Files moved to the 'data' folder.")
229+
230+
#remplacing descriptions and readme placeholders
231+
replace_placeholders_in_files_in_directory(
232+
DescriptionDir,
233+
NameCustomAvatarDir,
234+
CreatorName,
235+
BoothPage,
236+
PackageName,
237+
'Assets' + NameCustomDir + NameCustomAvatarDir + 'patcher',
238+
'Assets' + NameCustomDir + NameCustomAvatarDir + 'prefab',
239+
)
151240

152241

153242
if __name__ == "__main__":

README.md

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,49 +11,63 @@ Due to how curent 3D model files are set up there isn't a way to share shape-key
1111
After being involved in the scene it was clear that the previous mainstream methods were sub optimal: overwriting the original model and requiering the user to navigate to a subfolder unknown in advanced.
1212

1313
My piece of software let's you build a patcher with ease, saving you time and letting your customers have a reliable path to navigate to. Building a reliable way for them to interact with your products.
14+
It also now supports adding a directory with your different localized descriptions and readme to make the process of putting the avatar on the storefront much less painfull
1415

1516
I am going to be using my tool from now on to build my Face Tracking Add-ons avaliable on my [Booth](https://hashedits.booth.pm/) and [Ko-Fi](https://ko-fi.com/hashedits/shop) shops
1617

1718
If used please credit my socials and this GitHub Page
1819

19-
# Pre-requisites 🤓
20+
## Pre-requisites 🤓
2021

2122
[Python](https://www.python.org/downloads/)
2223

24+
> pip install auto-py-to-exe
25+
2326
[Py Intsaller](https://pypi.org/project/auto-py-to-exe/)
2427

2528

2629

2730
>pip install pyinstaller
2831
29-
# How to use 😎
32+
## How to use 😎
33+
34+
- Make sure both your model and your face tracked model are set up in a unity project
35+
- (optional) put all of your descriptions and readme in a folder to ease the creation of pages
3036

3137
- Open your python IDLE
3238

3339
- Click File -> Open
3440

35-
- Navigate to where you have downloaded the latest release -> FT_Builder
41+
- Navigate to where you have downloaded the repo -> FT_Builder
3642

3743
- Press F5
3844

3945
- Follow the instructions
4046

41-
# Exemple 📑
42-
There is an extra theorical directory to show you what to expect from the builder if you input
47+
## Exemple 📑
48+
There is an extra theorical directory to show you what to expect from the builder if you input:
49+
50+
- WhereverOnYourProjectIsLocatedOnYourDrive\ProjectName\Assets\CreatorName\AvatarName\fbx\MyCoolAvatar.fbx
51+
52+
- WhereverOnYourProjectIsLocatedOnYourDrive\ProjectName\Assets\YourCustomDir\NameOfTheModel\fbx\MyCoolAvatar_FT.fbx
53+
54+
- YourCustomDir
55+
56+
- NameOfTheModel
4357

44-
"WhereverOnYourProjectIsLocatedOnYourDrive\ProjectName\Assets\CreatorName\AvatarName\fbx\MyCoolAvatar.fbx"
58+
- Path\To\My\Cool\Descriptions&ReadMe
4559

46-
"WhereverOnYourProjectIsLocatedOnYourDrive\ProjectName\Assets\YourCustomDir\NameOfTheModel\fbx\MyCoolAvatar_FT.fbx"
60+
- AvatarCreatorName
4761

48-
YourCustomDir
62+
- Creator.CoolStoreFront.com/item/MyCoolAvatar
4963

50-
NameOfTheModel
64+
- NameOfThePackageCustomersOwn
5165

52-
MyModelDiff
66+
you'll find an exemple readme in **Description&ReadMeExemples** that you can bundle with your avatar's package to let the customer know what to do with it.
67+
There's also an exemple description there.
5368

54-
MyModelMetaDiff
5569

56-
# Distribute a face tracked avatar 👨‍🏫
70+
## Distribute a face tracked avatar 👨‍🏫
5771
- Copy your custom generated directory earlier and drag and drop it in the Assets folder of your unity project
5872

5973
- Make sure that your avatar has the required parameters, FX and additive controllers set up for VRCFaceTracking.
@@ -82,21 +96,18 @@ MyModelMetaDiff
8296

8397
- You're ready to sell your custom face tracked avatar!
8498
(make sure to always check the creator's licence agreement on attachements)
99+
85100

86101

87-
# Build FT_Builder
102+
## Build FT_Builder
88103

89104
Somehow running into issues with that, it ends up restarting the script uppon wanting to run pyinstaller from the script (line 121), if any of you have an idea how to build the daim thing I'd be glad to merge it to the main branch 🤗
90105

91106

92107

93108

94-
# Credits 📕
109+
## Credits 📕
95110

96111
**[HDiffPatch](https://github.com/sisong/HDiffPatch)**
97-
98-
99112
**[Nimble Design System Icons](https://iconduck.com/sets/nimble-design-system-icons)**
100-
101-
102-
**[Auto py to exe](https://pypi.org/project/auto-py-to-exe/)**
113+
**[Auto py to exe](https://pypi.org/project/auto-py-to-exe/)**

0 commit comments

Comments
 (0)