Editor/CreateModelWithScaleAndMirror.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Sandbox;
using Editor;

public static partial class CreateModelWithScaleAndMirror
{
	// Inches - Feet - Meters - Centimeters - Millimeters
	private static double[] scaleValues = new double[5]
	{
		1,
		12,
		39.37,
		0.3937,
		0.03937
	};

	// Keeping the whole string for future reference
	// "\n\t\t\t{\n\t\t\t\t_class = \"ModelModifierList\"\n\t\t\t\tchildren = \n\t\t\t\t[\n\t\t\t\t\t{\n\t\t\t\t\t\t_class = \"ModelModifier_ScaleAndMirror\"\n\t\t\t\t\t\tscale = 0.3937\n\t\t\t\t\t\tmirror_x = false\n\t\t\t\t\t\tmirror_y = false\n\t\t\t\t\t\tmirror_z = false\n\t\t\t\t\t\tflip_bone_forward = false\n\t\t\t\t\t\tswap_left_and_right_bones = false\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t},",

	private static string ScaleAndModifierStart =
		"\n\t\t\t{\n\t\t\t\t_class = \"ModelModifierList\"\n\t\t\t\tchildren = \n\t\t\t\t[\n\t\t\t\t\t{\n\t\t\t\t\t\t_class = \"ModelModifier_ScaleAndMirror\"\n\t\t\t\t\t\tscale = ";

	private static string ScaleAndModifierEnd =
		"\n\t\t\t\t\t\tmirror_x = false\n\t\t\t\t\t\tmirror_y = false\n\t\t\t\t\t\tmirror_z = false\n\t\t\t\t\t\tflip_bone_forward = false\n\t\t\t\t\t\tswap_left_and_right_bones = false\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t},";
	
	private static readonly HashSet<string> MeshExtensions = new HashSet<string>( StringComparer.OrdinalIgnoreCase )
	{
		"fbx",
		"obj",
		"dmx"
	};

	private static void AppendScaleAndMirror( Asset meshFile, int scaleUnitIndex )
	{
		string filename = meshFile.GetSourceFile(true);
		string txt = System.IO.File.ReadAllText( filename );
		if ( txt.First() == '<' )
		{
			// As we don't have access to EngineGlue.LoadKeyValues3( txt )
			// And EditorUtility.KeyValues3ToJson( txt ); returns null
			// we must manually insert the ScaleAndMirror modifier
			var lastChildIndex = txt.LastIndexOf( ',' );
			txt = txt.Insert( lastChildIndex + 1, ScaleAndModifierStart + scaleValues[scaleUnitIndex] + ScaleAndModifierEnd );
						
			System.IO.File.WriteAllText( filename, txt );
		}
	}
	
	static void RebuildCreateModelMenu( Menu model_menu, List<Asset> entries )
	{
		model_menu.AddOption( "ScaleAndMirror(Inches)", "open_in_new", () => entries.ForEach( asset => AppendScaleAndMirror( EditorUtility.CreateModelFromMeshFile( asset ), 0 ) ) );
		model_menu.AddOption( "ScaleAndMirror(Feet)", "open_in_new", () => entries.ForEach( asset => AppendScaleAndMirror( EditorUtility.CreateModelFromMeshFile( asset ), 1 ) ) );
		model_menu.AddOption( "ScaleAndMirror(Meters)", "open_in_new", () => entries.ForEach( asset => AppendScaleAndMirror( EditorUtility.CreateModelFromMeshFile( asset ), 2 ) ) );
		model_menu.AddOption( "ScaleAndMirror(Centimeters)", "open_in_new", () => entries.ForEach( asset => AppendScaleAndMirror( EditorUtility.CreateModelFromMeshFile( asset ), 3 ) ) );
		model_menu.AddOption( "ScaleAndMirror(Millimeters)", "open_in_new", () => entries.ForEach( asset => AppendScaleAndMirror( EditorUtility.CreateModelFromMeshFile( asset ), 4 ) ) );
	}

	[Event( "asset.contextmenu", Priority = 51 )]
	private static void OnMeshFileAssetContextExtension( AssetContextMenu e )
	{
		var meshes = e.SelectedList
			.Where( x => x.Asset is not null && MeshExtensions.Contains( x.AssetType.FileExtension ) )
			.Select( x => x.Asset )
			.ToList();

		if ( meshes.Count > 0 )
		{
			var model_menu = e.Menu.AddMenu( "Create model with..", "open_in_new" );
			RebuildCreateModelMenu( model_menu, meshes );
		}
	}
}