diff --git a/.gitignore b/.gitignore index dd0d916..fb7b9b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ *.zip +*.pyc +*.log /plugin/Data/Scripts/ /plugin/Data/Meshes/ +/plugin/Data/Textures/ /build/ node_modules/ -*.blend[0-9]* \ No newline at end of file +*.blend[0-9]* diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 76ae18b..6f8b74b 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -11,7 +11,20 @@ "kind": "build" }, "command": "${workspaceFolder}/build.ps1", - "args": ["-Reload"], + "args": ["-KickVortex"], + "problemMatcher": [ + "$PapyrusCompiler" + ] + }, + { + "label": "Build and Reload", + "type": "shell", + "group": { + "isDefault": true, + "kind": "build" + }, + "command": "${workspaceFolder}/build.ps1", + "args": ["-KickVortex", "-Reload"], "problemMatcher": [ "$PapyrusCompiler" ] diff --git a/README.md b/README.md index 9432c3d..c06400b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,17 @@ # skyrim-item-roulette -Roulettes items \ No newline at end of file +Roulettes items + +## Notes + +* NIF export from Blender is perfectly fine if you're working from scratch. +Skyrim doesn't seem to care that the models are an old format. +* It should go without saying that if you change a model texture or any +resource other than the main plugin file, make sure you redeploy from Vortex +or you won't see the changes. +* Likewise, if you change the texture in GIMP, you must rebuild the textures +or you won't see them anywhere. +* If you include a texture it must be connected to the Color node of the Material +in the Shader node view, and the **node name** must be `Base`. The image path must +be the DDS in the /plugin folder. The NIF plugin is intelligent enough to relativize +the path when exporting. \ No newline at end of file diff --git a/Source/Meshes/_EQ_ItemRoulette/roulette_container.blend b/Source/Meshes/_EQ_ItemRoulette/roulette_container.blend index 38bca27..109ae16 100644 Binary files a/Source/Meshes/_EQ_ItemRoulette/roulette_container.blend and b/Source/Meshes/_EQ_ItemRoulette/roulette_container.blend differ diff --git a/Source/Textures/_EQ_ItemRoulette/roulette_container.xcf b/Source/Textures/_EQ_ItemRoulette/roulette_container.xcf new file mode 100644 index 0000000..4cb3ce4 Binary files /dev/null and b/Source/Textures/_EQ_ItemRoulette/roulette_container.xcf differ diff --git a/build.ps1 b/build.ps1 index a1e0951..10ef345 100644 --- a/build.ps1 +++ b/build.ps1 @@ -2,18 +2,57 @@ .SYNOPSIS Builds the plugin and optionally reloads it in Vortex. + .PARAMETER Scripts + Build Papyrus scripts + + .PARAMETER Models + Build Blender models + + .PARAMETER Textures + Build GIMP textures + + .PARAMETER Zip + Build the ZIP AND NOTHING ELSE. You probably don't want this option + + .PARAMETER KickVortex + Syncs the plugin with Vortex. If there are file conflicts, take changes + from the game directory! This will have changes from the ESP that were + made in Creation Kit! You need to symlink the /plugin directory into + the staging area, preferably using setup-dev.ps1 script. + .PARAMETER Reload - Reloads Skyrim after building. Reloading assumes you have symlinked the mod - into Vortex's staging area using the method in setup-dev.ps1. It completely - kills and restarts the game as I had trouble getting hlp and reloadscript - commands to work. + Reloads Skyrim after building. It completely kills and restarts the game + as I had trouble getting hlp and reloadscript commands to work. #> param ( + [Parameter(Mandatory = $False)] + [Switch] + $Scripts, + [Parameter(Mandatory = $False)] + [Switch] + $Models, + [Parameter(Mandatory = $False)] + [Switch] + $Textures, + [Parameter(Mandatory = $False)] + [Switch] + $Zip, + + [Parameter(Mandatory = $False)] + [Switch] + $KickVortex, [Parameter(Mandatory = $False)] [Switch] $Reload ) +if(-not $Scripts -and -not $Models -and -not $Textures -and -not $Zip) { + $Scripts = $true + $Textures = $true + $Models = $true + $Zip = $true +} + New-Item -ItemType Directory "$PSScriptRoot/build" -ErrorAction SilentlyContinue Add-Type -Path "$PSScriptRoot/Gameloop.Vdf.dll" -ErrorAction SilentlyContinue @@ -71,36 +110,49 @@ if(-not $SkyrimBase) { )).FullName } -# Compile the scripts -& "$SkyrimBase/Papyrus Compiler/PapyrusCompiler.exe" ` - "$PsScriptRoot/Source/Scripts" ` - "-f=$SkyrimBase/Data/Source/Scripts/TESV_Papyrus_Flags.flg" ` - "-i=$SkyrimBase/Data/Source/Scripts;$PsScriptRoot/Source/Scripts" ` - "-o=$PsScriptRoot/plugin/Data/Scripts" ` - "-all" +if($Scripts) { + # Compile the scripts + & "$SkyrimBase/Papyrus Compiler/PapyrusCompiler.exe" ` + "$PsScriptRoot/Source/Scripts" ` + "-f=$SkyrimBase/Data/Source/Scripts/TESV_Papyrus_Flags.flg" ` + "-i=$SkyrimBase/Data/Source/Scripts;$PsScriptRoot/Source/Scripts" ` + "-o=$PsScriptRoot/plugin/Data/Scripts" ` + "-all" -if($LastExitCode -ne 0) { - return $LastExitCode + if($LastExitCode -ne 0) { + return $LastExitCode + } } -# Build the models -blender.exe --background --python "$PSScriptRoot/export-blender-models.py" +if($Textures) { + Push-Location "$PSScriptRoot" -if($LastExitCode -ne 0) { - return $LastExitCode -} + gimp-console -n -i --batch-interpreter python-fu-eval -b "import export_gimp_textures" -# ZIP up the deployment package -$ZipPath = "$PSScriptRoot/build/Item Roulette for VRIK.zip" - -Remove-Item $ZipPath -ErrorAction SilentlyContinue -Compress-Archive -Path $PSScriptRoot/plugin/* -DestinationPath $ZipPath - -if($Reload) { - if($Proc) { - Stop-Process $Proc + if($LastExitCode -ne 0) { + return $LastExitCode } + Pop-Location +} + +if($Models) { + blender --background --python "$PSScriptRoot/export_blender_models.py" + + if($LastExitCode -ne 0) { + return $LastExitCode + } +} + +if($Zip) { + # ZIP up the deployment package + $ZipPath = "$PSScriptRoot/build/Item Roulette for VRIK.zip" + + Remove-Item $ZipPath -ErrorAction SilentlyContinue + Compress-Archive -Path $PSScriptRoot/plugin/* -DestinationPath $ZipPath +} + +if($KickVortex) { # Restart Vortex and kick off deploy-mods event via Chrome Debug Protocol. Stop-Process -Name Vortex $env:KICK_PORT=6969 @@ -110,8 +162,14 @@ if($Reload) { pnpm install -C "$PSScriptRoot" - node.exe "$PSScriptRoot/kick-vortex.js" + node "$PSScriptRoot/kick-vortex.js" Stop-Process -Name Vortex -ErrorAction SilentlyContinue +} + +if($Reload) { + if($Proc) { + Stop-Process $Proc + } # Prefer SKSE loader if we have it installed $SkyrimExe = Get-Item -Path @( @@ -134,4 +192,6 @@ if($Reload) { { "command": "load \"autosave1\" " } "@ } while ($wrFail) -} \ No newline at end of file +} + +return 0 \ No newline at end of file diff --git a/export-blender-models.py b/export_blender_models.py similarity index 97% rename from export-blender-models.py rename to export_blender_models.py index a0b9d7b..a081931 100644 --- a/export-blender-models.py +++ b/export_blender_models.py @@ -1,7 +1,7 @@ import bpy import os - from pathlib import Path + curdir = Path(__file__).parent print("Current directory: " + str(curdir)) plugin_data_dir = curdir.joinpath("plugin/Data") @@ -16,9 +16,9 @@ for blend_path in blend_paths: nif_parent = dest_blend_path.parent nif_path = nif_parent.joinpath(dest_blend_path.stem + '.nif') print(str(blend_path) + " -> " + str(nif_path)) - bpy.ops.wm.open_mainfile(filepath=str(blend_path)) try: nif_parent.mkdir(parents=True) except FileExistsError: pass + bpy.ops.wm.open_mainfile(filepath=str(blend_path)) bpy.ops.export_scene.nif(filepath=str(nif_path)) \ No newline at end of file diff --git a/export_gimp_textures.py b/export_gimp_textures.py new file mode 100644 index 0000000..db1e93a --- /dev/null +++ b/export_gimp_textures.py @@ -0,0 +1,75 @@ +from gimpfu import pdb +import platform +import sys + +pdb.gimp_message("Started exporting textures.") +pdb.gimp_message(platform.python_version()) + +try: + import glob + import os + import pydoc + + curdir = os.path.dirname(os.path.abspath(__file__)) + pdb.gimp_message("Current directory: " + curdir) + plugin_data_dir = os.path.join(curdir, "plugin/Data") + pdb.gimp_message("Plugin directory: " + plugin_data_dir) + texture_src_dir = os.path.join(curdir, "Source/Textures/_EQ_ItemRoulette") + pdb.gimp_message("Texture Source directory: " + texture_src_dir) + texture_dest_dir = os.path.join(plugin_data_dir, "Textures/_EQ_ItemRoulette") + pdb.gimp_message("Texture Dest directory: " + texture_dest_dir) + + # FIXME This won't recurse + xcf_paths = glob.glob(texture_src_dir + "/*.xcf") + for xcf_path in xcf_paths: + dest_xcf_path = os.path.join(texture_dest_dir, os.path.relpath(path=xcf_path, start=texture_src_dir)) + dds_parent = os.path.dirname(dest_xcf_path) + dds_path = os.path.join(os.path.splitext(dest_xcf_path)[0] + '.dds') + pdb.gimp_message(xcf_path + " -> " + dds_path) + try: + os.makedirs(dds_parent) + except: + pass + image = pdb.gimp_xcf_load(1, xcf_path, xcf_path) + #pdb.gimp_message(str(pdb.file_dds_save.params)) + pdb.file_dds_save( + image, + # (13, 'image', 'Input image'), + image.flatten(), + # (16, 'drawable', 'Drawable to save'), + dds_path, + # (4, 'filename', 'The name of the file to save the image as'), + dds_path, + # (4, 'raw-filename', 'The name entered'), + 0, + # (0, 'compression-format', 'Compression format # (0 = None, 1 = BC1/DXT1, 2 = BC2/DXT3, 3 = BC3/DXT5, 4 = BC3n/DXT5nm, 5 = BC4/ATI1N, 6 = BC5/ATI2N, 7 = RXGB # (DXT5), 8 = Alpha Exponent # (DXT5), 9 = YCoCg # (DXT5), 10 = YCoCg scaled # (DXT5))'), + 1, + # (0, 'mipmaps', 'How to handle mipmaps # (0 = No mipmaps, 1 = Generate mipmaps, 2 = Use existing mipmaps # (layers)'), + 0, + # (0, 'savetype', 'How to save the image # (0 = selected layer, 1 = cube map, 2 = volume map, 3 = texture array'), + 0, + # (0, 'format', 'Custom pixel format # (0 = default, 1 = R5G6B5, 2 = RGBA4, 3 = RGB5A1, 4 = RGB10A2)'), + -1, + # (0, 'transparent-index', 'Index of transparent color or -1 to disable # (for indexed images only).'), + 0, + # (0, 'mipmap-filter', 'Filtering to use when generating mipmaps # (0 = default, 1 = nearest, 2 = box, 3 = triangle, 4 = quadratic, 5 = bspline, 6 = mitchell, 7 = lanczos, 8 = kaiser)'), + 0, + # (0, 'mipmap-wrap', 'Wrap mode to use when generating mipmaps # (0 = default, 1 = mirror, 2 = repeat, 3 = clamp)'), + 0, + # (0, 'gamma-correct', 'Use gamma correct mipmap filtering'), + 0, + # (0, 'srgb', 'Use sRGB colorspace for gamma correction'), + 0, + # (3, 'gamma', 'Gamma value to use for gamma correction # (i.e. 2.2)'), + 2.2, + # (0, 'perceptual-metric', 'Use a perceptual error metric during compression'), + 0, + # (0, 'preserve-alpha-coverage', 'Preserve alpha test converage for alpha channel maps'), + 0 + # (3, 'alpha-test-threshold', 'Alpha test threshold value for which alpha test converage should be preserved') + ) + pdb.gimp_image_delete(image) +except: + pdb.gimp_message("An unhandled error occurred: " + str(sys.exc_info()[0]) + ": " + str(sys.exc_info()[1])) + +pdb.gimp_quit(0) \ No newline at end of file diff --git a/plugin/Data/_EQ_ItemRoulette.esp b/plugin/Data/_EQ_ItemRoulette.esp index 04f10b0..638cc6a 100644 Binary files a/plugin/Data/_EQ_ItemRoulette.esp and b/plugin/Data/_EQ_ItemRoulette.esp differ