Here's how to do something you never ever wanted to do: Convert an unreal engine model from a game you like to a source model you can use in your silly VScript Portal 2 Mod. I tested this with models from "Ghostrunner" and ported them over to "Portal 2". I'm now writing this guide after the first ever success in hope to never forget this in the future!
First we need to extract the model from Unreal Engine. That's a pretty simple task... just kidding.
Most Unreal Engine files are encrypted with a key that is located in the Game-Shipping.exe. In order to obtain those keys we need to first get rid of DRM (applied by Steam) and then search for the keys.
Download and open Steamless. In the fairly simple UI select the Game-Win64-Shipping.exe file, which should be located in <Game name>/Binaries/Win64/<Game name>-Win64-Shipping.exe. Then run the tool and copy the newly created <Game name>-Win64-Shipping.unpacked.exe.
Now download the AES Key Finder tool. Paste the exe into the folder and drag the exe onto the .bat file. After a few minutes there will be a new folder with many oddly named subfolders. Inside of those folders, are files, those files are your keys. Copy all of the filenames into a txt and call it keys.txt, move that to your working folder. You can delete the exe and it's folder now.
Download FModel and click "ADD UNDETECTED GAME". Follow the dialog (and make sure you click the "+"" first, not "OK" like I did). If the archive is encrypted then it will be greyed out. Click "AES" in the title bar and try every AES keys until one works. After a bit of loading you'll see the entire games archives. In here you'll have to find the models, they will hopefully have a nice name. Export all materials, textures, models and whatever you need for your model to run into a new directory.
If you exported the right files you'll now have a PSK file (which is the model) alongside some jsons for materials and tga/pngs for textures. Create a nice folder structure, trust me, you'll need it.
We're gonna need to download a few Blender addons for this to work. Download and install io_scene_psk_psa for importing unreal engine models and animations. Download and install Blender Source Tools for exporting the models to source. Finally, get the Source VertexLitGeneric Shader Blender reimplementation and put it in the working directory
You'd probably expect this to be the most annoying process, but it definitely is not! Create a new Blender project, follow the instructions on the BlenderVertexLitGeneric repository to add the shader to your Blender project. Then import the valve PSK file into Blender and adjust the model to your needs.
Head to the Shading tab in Blender and select your objects materials in the right pane. Delete the "Principled BSDF" node and replace it with a VertexLitGeneric node that you imported before. Then create an image node for your normal map and diffuse map (your plain old texture) and connect them to the VertexLitGeneric node. Then connect that node to the "Material Output" node. Adjust the shader settings until it looks good. The more changes you do, the more you'll have to manually edit text files later. I also recommend renaming the entities and materials in Blender now.
Now you should have the model perfectly working in Blender. Now comes the painful part, porting all of this to an outdated engine predating literally any sort of workflow optimization. Get ready for a lot of open windows.
This part is simple. Head to the Scene tab with your Model selected and open "Source Engine Export". In here you'll want to change the export path to wherever you like it and the export format to SMD. You don't need to specify anything else, just click export and select your model in the popup.
Get ready for pain! Valve uses their own .VTF texture format, which is pretty cool because it has mipmaps and more metadata. They also have a .VMT file, that's a Valve Material (not to be confused with "VMware virtual machine configuration" which is also .VMT). We're gonna need those. Let's start with the VTF file. Download and install VTFEdit-Reloaded and select Tools -> Convert Folder. I hope you kept a clean folder structure! Select the folder containing your textures and adjust the first wildcard if necessary. Uncheck "Create VMT Files" because the ones made by this tool really suck. Click "Options" and change "Alpha Format" to "DXT1". No idea why, just do it. Then go to "Advanced" and change the "Version" to 7.4. This might not be necessary depending on the age of your game. Finally click convert. Those are now your texture files, treat them like your PNGs (but please don't put an NFT on them)!
In the same folder as the VTFs, create VMT files with the same name as the material you specified in Blender. Open them using a text editor (even VTFEdit if you like) and just paste this base here:
"VertexLitGeneric"
{
"$basetexture" "<yourmodname>/color"
"$bumpmap" "<yourmodname>/normals"
"$model" "1"
}
Before you adjust anything here's quick intro into the file structure of source games. Most of the assets are within .vpk files, which are just like .pak files, however source will accept folders and files floating around in the same directory as the vpks as well. You're going to want to your assets (the VTFs and VMTs) into a folder called materials/<your mod id>/. The model file you get later will go into models/<your mod id>/. Now, adjust basetexture and bumpmap in the VMT to the paths of your textures, without the materials/ prefix or .VTF suffix. Then, look into the shader graph in blender and copy all the other properties you messed with into this file. The documentation for VertexLitGeneric is here.
Download Crowbar and open it. Don't get overwhelmed by the UI, just adjust the game you'll be exporting this for in the tabs "Set Up Games" and "Compile". Now we'll need a .qc file for your model. It contains basic metadata for your model. Put it in the same folder as your SMD file from Blender. The structure is this:
$modelname "<yourmodname>\<modelname>.mdl"
$body vatbody "<smdfile>.smd"
$surfaceprop Default
$cdmaterials "<yourmodname>\"
$sequence idle "<smdfile>.smd"
Select the QC file in Crowbar and click "Compile" both naturally in the "Compile" tab. You might have to adjust the output path to some other folder but it depends on what's in that box already. Copy the 3 files it created into models/<yourmodname>/.
Open the Hammer Model Viewer... wherever that is located. For Portal 2 you can launch it via SDKLauncher.exe in Portal 2/bin. Load your model. If it displays properly then you did everything correctly. If not, start guessing what could be wrong. If you click on the Model tab it will show you if it successfully loaded the VMTs.
models/ghostrunner/Enemy.dx90.vtx
models/ghostrunner/enemy.mdl
models/ghostrunner/enemy.vdd
materials/ghostrunner/T_Enemy_Pistol_UpperBody_01_Normal.vtf
materials/ghostrunner/T_Enemy_Pistol_UpperBody_01_Color.vtf
materials/ghostrunner/T_Enemy_Pistol_LowerBody_01_Normal.vtf
materials/ghostrunner/T_Enemy_Pistol_LowerBody_01_Color.vtf
materials/ghostrunner/M_Enemy_Pistol_UpperBody_01.vmt
materials/ghostrunner/M_Enemy_Pistol_LowerBody_01.vmt
Adding animations and a physics model to this is fairly simple. For the physics model, simple create one or multiple new primitive objects that mark your models hitbox. When exporting export the entire scene instead of just one object. Now you just have to add it to the .qc file.
$collisionmodel "filename_phys" {
}
Inside of the block you can specify other options that you might need if your hitbox is not just a cube. Look them up here.
Animations are also really simple, simply create your armature in Blender, make animations and export them as well. Each animation is a simple .smd file and you can simply add them below your idle sequence:
$sequence idle "base.smd"
$sequence coolanimation "anims/coolanimation.smd"
You can preview both animations and physics models in the hammer model viewer. Note, that you should not change the scale of an object in Blender as the information will most likely get lost... or not applied to all vertices. If you want to scale the object, instead use $scale and apply it right after you set the model name.