From fa36fbe74fcefa96a2bf944e3d9a3f59ed38dc2e Mon Sep 17 00:00:00 2001 From: vetal l Date: Tue, 26 Dec 2023 17:33:55 +0300 Subject: [PATCH] [Tools] slicers wrapper (#2249) * Update updtset.cmd - fixed Python version to be compatible with NumPy - added Update PIP if necessary - added Install NumPy module for slicing * Update .gitignore - Add Ignore source folder for multitiles * Create slicemt.ps1 slicer wrapper * Create slicemt.py * Update slicemt.py Rewritten on Python and this time it automatically updates tileset. * Delete slicemt.ps1 --- .gitignore | 3 + tools/slicemt.py | 235 ++++++++++++++++++++++++++++++++++++++++++++++ tools/updtset.cmd | 19 +++- 3 files changed, 255 insertions(+), 2 deletions(-) create mode 100644 tools/slicemt.py diff --git a/.gitignore b/.gitignore index c59d20f186..c8a7976012 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ book .direnv result .local + +# Source multitile files +source diff --git a/tools/slicemt.py b/tools/slicemt.py new file mode 100644 index 0000000000..9109d90d81 --- /dev/null +++ b/tools/slicemt.py @@ -0,0 +1,235 @@ +""" +Slice a multitile source image into individual images and put them in the parent folder +Uses path to detect tile name, dimentions, tileset name etc +Intended to run in a cloned tileset repository + +I think it can be run only on Windows. +""" + +import sys +import os +import fnmatch +import time +import subprocess +from pathlib import Path +from slice_multitile import main as mt_slicer +from slice_variants import main as var_slicer + +class bcolors: + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKCYAN = '\033[96m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + +class sliceargs: + def __init__(self, image, width , height, tile, out): + self.image = image + self.width = width + self.height = height + self.tile = tile + self.out = out + self.no_json = False + self.append = True + self.iso = False + self.rearrange_top = None + self.rearrange_bottom = None + self.background = None + + +def show_exception_and_exit(exc_type, exc_value, tb): + import traceback + traceback.print_exception(exc_type, exc_value, tb) + input("Press Enter to exit.") + sys.exit(-1) + + +def CheckAffectedFiles(ArgPath,ArgTime): + NumberOfFiles = 0 + for root, dirs, files in os.walk(ArgPath): + for name in files: + filename = os.path.join(root, name) + if os.stat(filename).st_mtime > ArgTime: + NumberOfFiles += 1 + print('Number of affected files : ' + str(NumberOfFiles)) + print() + + +sys.excepthook = show_exception_and_exit + +# Set working path +if len(sys.argv) < 2: + FullPath = os.getcwd() +else: + FullPath = sys.argv[1] + +PathHead, PathTail = os.path.split(FullPath) +if PathTail != 'source': + FullPath += '\\source' +print(f'Will work on : {bcolors.OKCYAN}' + FullPath + f'{bcolors.ENDC}') + +# Set tile name +PathDetails = FullPath.split('\\') +CurrentTileName = PathDetails[-2] +print(f'Tile name is : {bcolors.OKCYAN}' + CurrentTileName + f'{bcolors.ENDC}') +# TODO: Probably should check it it looks like a tile name + +# Check if working path contains tile dimentions, set them +PathLevel = fnmatch.filter(PathDetails,'*pngs*x*') +if len(PathLevel) > 0: + LevelParts = PathLevel[0].split('_') + Dimensions = LevelParts[-1] + DimX = Dimensions.split('x')[0] + DimY = Dimensions.split('x')[1] +else: + print(f'{bcolors.FAIL}Check folder. It has to be cloned repository.{bcolors.ENDC}') + quit() +print(f'Dimentions : {bcolors.OKCYAN}' + DimX + ' x ' + DimY + f'{bcolors.ENDC}') + +# Set current tileset name +TilesetName = PathDetails[PathDetails.index('gfx')+1] +print(f'Tileset name : {bcolors.OKCYAN}' + TilesetName + f'{bcolors.ENDC}') +print('') + +# Set updtset.cmd path +UpdateCmd = '\\'.join(PathDetails[:PathDetails.index('gfx')]) + '\\tools\\updtset.cmd ' + TilesetName +UpdatePath = '\\'.join(PathDetails[:PathDetails.index('gfx')]) + '\\tools\\' + +OutPath = FullPath + '\\..\\' + +# Detect source files for variants +StartTime = time.time() +Patterns = [ '*_var*.png' ] +print('1) Searching for variants :') +for Pattern in Patterns: + print(f' {bcolors.OKBLUE}' + Pattern + f'{bcolors.ENDC}') + for File in Path(FullPath).glob(Pattern): + PathHead, PathTail = os.path.split(File) + print(f' found : {bcolors.OKGREEN}' + PathTail + f'{bcolors.ENDC}') + ResultName = PathTail.split('.')[0].split('_var')[0]+'_var' + print(' result : ' + ResultName) + Args = sliceargs( + File, # image name + int(DimX), # width + int(DimY), # height + ResultName, # resulting filenames + OutPath # out path + ) + var_slicer(Args) +CheckAffectedFiles( FullPath+'\\..\\', StartTime ) + +# Detect source files for simple multitile +StartTime = time.time() +Patterns = [ CurrentTileName +'.png' ] +print('2) Searching for simple multitile :') +for Pattern in Patterns: + print(f' {bcolors.OKBLUE}' + Pattern + f'{bcolors.ENDC}') + for File in Path(FullPath).glob(Pattern): + PathHead, PathTail = os.path.split(File) + print(f' found : {bcolors.OKGREEN}' + PathTail + f'{bcolors.ENDC}') + ResultName = CurrentTileName + print(' result : ' + ResultName) + Args = sliceargs( + File, # image name + int(DimX), # width + int(DimY), # height + ResultName, # resulting filenames + OutPath # out path + ) + JsonCheck = OutPath + ResultName + '.json' + if (os.path.exists(JsonCheck)) : + print(f'{bcolors.WARNING} ignoring : ' + ResultName + '.json' + f'{bcolors.ENDC}') + Args.no_json = True + mt_slicer(Args) +CheckAffectedFiles( FullPath+'\\..\\', StartTime ) + +# Detect source files for transparent multitile +StartTime = time.time() +Patterns = [ CurrentTileName +'_t*.png' ] +print('3) Searching for transparent multitile :') +for Pattern in Patterns: + print(f' {bcolors.OKBLUE}' + Pattern + f'{bcolors.ENDC}') + for File in Path(FullPath).glob(Pattern): + PathHead, PathTail = os.path.split(File) + print(f' found : {bcolors.OKGREEN}' + PathTail + f'{bcolors.ENDC}') + ResultName = CurrentTileName + '_transparent' + print(' result : ' + ResultName) + Args = sliceargs( + File, # image name + int(DimX), # width + int(DimY), # height + ResultName, # resulting filenames + OutPath # out path + ) + JsonCheck = OutPath + ResultName + '.json' + if (os.path.exists(JsonCheck)) : + print(f'{bcolors.WARNING} ignoring : ' + ResultName + '.json' + f'{bcolors.ENDC}') + Args.no_json = True + mt_slicer(Args) +CheckAffectedFiles( FullPath+'\\..\\', StartTime ) + +# Detect source files for seasonal multitiles +StartTime = time.time() +Patterns = [ CurrentTileName + '*_winter.png', + CurrentTileName + '*_spring.png', + CurrentTileName + '*_summer.png', + CurrentTileName + '*_autumn.png' ] +print('4) Searching for simple multitiles :') +for Pattern in Patterns: + print(f' {bcolors.OKBLUE}' + Pattern + f'{bcolors.ENDC}') + for File in Path(FullPath).glob(Pattern): + PathHead, PathTail = os.path.split(File) + Season = str(PathTail).split('.')[0].split('_')[-1] + print(' '+Season+f' : {bcolors.OKGREEN}' + PathTail + f'{bcolors.ENDC}') + ResultName = CurrentTileName + '_season_' + Season + print(' result : ' + ResultName) + Args = sliceargs( + File, # image name + int(DimX), # width + int(DimY), # height + ResultName, # resulting filenames + OutPath # out path + ) + JsonCheck = OutPath + ResultName + '.json' + if (os.path.exists(JsonCheck)) : + print(f'{bcolors.WARNING} ignoring : ' + ResultName + '.json' + f'{bcolors.ENDC}') + Args.no_json = True + mt_slicer(Args) +CheckAffectedFiles( FullPath+'\\..\\', StartTime ) + +# Detect source files for seasonal transparent multitiles +StartTime = time.time() +Patterns = [ CurrentTileName + '*_winter_t*.png', + CurrentTileName + '*_spring_t*.png', + CurrentTileName + '*_summer_t*.png', + CurrentTileName + '*_autumn_t*.png' ] +print('5) Searching for seasonal transparent multitiles :') +for Pattern in Patterns: + print(f' {bcolors.OKBLUE}' + Pattern + f'{bcolors.ENDC}') + for File in Path(FullPath).glob(Pattern): + PathHead, PathTail = os.path.split(File) + Season = str(PathTail).split('.')[0].split('_')[-2] + print(' '+Season+f' : {bcolors.OKGREEN}' + PathTail + f'{bcolors.ENDC}') + ResultName = CurrentTileName + '_season_' + Season + '_transparent' + print(' result : ' + ResultName) + Args = sliceargs( + File, # image name + int(DimX), # width + int(DimY), # height + ResultName, # resulting filenames + OutPath # out path + ) + JsonCheck = OutPath + ResultName + '.json' + if (os.path.exists(JsonCheck)) : + print(f'{bcolors.WARNING} ignoring : ' + ResultName + '.json' + f'{bcolors.ENDC}') + Args.no_json = True + mt_slicer(Args) +CheckAffectedFiles( FullPath+'\\..\\', StartTime ) + +input('Press Enter to update tileset...') + +subprocess.Popen(UpdateCmd, shell = True, cwd = UpdatePath) diff --git a/tools/updtset.cmd b/tools/updtset.cmd index cabea13094..7583f0b011 100644 --- a/tools/updtset.cmd +++ b/tools/updtset.cmd @@ -179,9 +179,9 @@ if errorlevel 1 ( if errorlevel 1 ( echo ERROR: No Python found! echo If you are sure that Python is installed - please check 'path' environment variable. - echo Script will try to install Python 3.12, try to run this script again after this. + echo Script will try to install Python 3.10, try to run this script again after this. echo. - winget install Python.Python.3.12 --disable-interactivity + winget install Python.Python.3.10 --disable-interactivity goto stop ) else ( set APP=python @@ -196,6 +196,8 @@ if errorlevel 1 ( if /i [!verbose!] EQU [YES] (echo - %APP% found.) %APP% --version +pip install --upgrade pip --no-color 1>nul + pip show pyvips --no-color 1>nul if errorlevel 1 ( if /i [!verbose!] EQU [YES] (echo - NO python 'pyvips' module found. Will try to install it.) @@ -207,6 +209,19 @@ if errorlevel 1 ( ) else ( if /i [!verbose!] EQU [YES] (echo - Python 'pyvips' module found.) ) + +pip show numpy --no-color 1>nul +if errorlevel 1 ( + if /i [!verbose!] EQU [YES] (echo - NO python 'numpy' module found. Will try to install it.) + %APP% -m pip install numpy --no-color >nul + if errorlevel 1 ( + echo - Python 'numpy' failed to install. && goto stop + ) + if /i [!verbose!] EQU [YES] (echo - Python 'numpy' installed.) +) else ( + if /i [!verbose!] EQU [YES] (echo - Python 'numpy' module found.) +) + where /q %LIBVIPS_PATH%\bin:vips.exe if errorlevel 1 ( echo ERROR^^^! No 'libvips' library found. Please refer installation manual: