-
-
Notifications
You must be signed in to change notification settings - Fork 12
How to Create a new Modifier
James edited this page Sep 28, 2025
·
4 revisions
A Modifier is a step in the build process that is run after retrieving all sources. Modifiers will change the files in a cached directory - avoiding changing original files.
The Build Uploader uses reflection to find all classes inheriting AUploadModifer to display them in the dropdown. UploadModifierAttribute is used to define static data about the modifier such as the text shown in the dropdown.
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
[UploadModifierAttribute("Compress")]
public partial class CompressModifier : AUploadModifer
{
public enum CompressionType
{
Zip,
}
private CompressionType m_compressionType = CompressionType.Zip;
private string m_compressedFileName = "";
private string m_targetPathToCompress = "";
private bool m_removeContentAfterCompress = true;
public CompressModifier()
{
// Required for reflection
}
public CompressModifier(string fileName, string targetPath, CompressionType compressionType=CompressionType.Zip, bool removeContentAfterCompress=true)
{
m_compressedFileName = fileName;
m_targetPathToCompress = targetPath;
m_compressionType = compressionType;
m_removeContentAfterCompress = removeContentAfterCompress;
}
public override void TryGetErrors(UploadConfig config, List<string> errors)
{
base.TryGetErrors(config, errors);
if (string.IsNullOrEmpty(m_compressedFileName))
{
errors.Add("No compressed file name set");
}
}
public override async Task<bool> ModifyBuildAtPath(string cachedFolderPath, UploadConfig uploadConfig,
int configIndex, UploadTaskReport.StepResult stepResult, StringFormatter.Context ctx)
{
string pathToCompress = cachedFolderPath;
if (!string.IsNullOrEmpty(m_targetPathToCompress))
{
pathToCompress = Path.Combine(cachedFolderPath, StringFormatter.FormatString(m_targetPathToCompress, ctx));
}
string compressedFileName = StringFormatter.FormatString(m_compressedFileName, ctx);
if (!compressedFileName.EndsWith(".zip"))
{
compressedFileName += ".zip";
}
bool successful = false;
if (File.Exists(pathToCompress))
{
// It's a file!
string zipPath = Path.Combine(Path.GetDirectoryName(pathToCompress), compressedFileName);
successful = await ZipUtils.Zip(pathToCompress, zipPath, stepResult);
if (successful)
{
stepResult.AddLog("Compressed file: " + pathToCompress + " to " + zipPath);
if (m_removeContentAfterCompress)
{
stepResult.AddLog("Deleting original file: " + pathToCompress);
File.Delete(pathToCompress);
}
}
}
else if (Directory.Exists(pathToCompress))
{
// It's a directory!
string[] files = Directory.GetFiles(pathToCompress).Concat(Directory.GetDirectories(pathToCompress)).ToArray();
string zipResultDirectory = pathToCompress == cachedFolderPath ? cachedFolderPath : Path.GetDirectoryName(pathToCompress);
string zipPath = Path.Combine(zipResultDirectory, compressedFileName);
successful = await ZipUtils.Zip(pathToCompress, zipPath, stepResult);
if (successful)
{
stepResult.AddLog("Compressed directory: " + pathToCompress + " to " + zipPath);
if (m_removeContentAfterCompress)
{
string[] filesAfterZip = Directory.GetFiles(pathToCompress).Concat(Directory.GetDirectories(pathToCompress)).ToArray();
if (filesAfterZip.Length == files.Length)
{
stepResult.AddLog("Deleting original directory: " + pathToCompress);
Directory.Delete(pathToCompress, true);
}
else
{
foreach (string file in files)
{
if (File.Exists(file))
{
stepResult.AddLog("Deleting original file: " + file);
File.Delete(file);
}
else if (Directory.Exists(file))
{
stepResult.AddLog("Deleting original folder: " + file);
Directory.Delete(file, true);
}
}
}
}
}
}
else
{
stepResult.SetFailed("Path to compress does not exist: " + pathToCompress);
}
return successful;
}
public override Dictionary<string, object> Serialize()
{
return new Dictionary<string, object>()
{
{ "compressedFileName", m_compressedFileName },
{ "subPathToCompress", m_targetPathToCompress },
{ "compressionType", m_compressionType.ToString() },
{ "removeContentAfterCompress", m_removeContentAfterCompress },
};
}
public override void Deserialize(Dictionary<string, object> data)
{
if (data.ContainsKey("compressedFileName"))
{
m_compressedFileName = data["compressedFileName"].ToString();
}
if (data.ContainsKey("subPathToCompress"))
{
m_targetPathToCompress = data["subPathToCompress"].ToString();
}
if (data.ContainsKey("compressionType"))
{
m_compressionType = (CompressionType)System.Enum.Parse(typeof(CompressionType), data["compressionType"].ToString());
}
if (data.ContainsKey("removeContentAfterCompress"))
{
m_removeContentAfterCompress = (bool)data["removeContentAfterCompress"];
}
}
}using UnityEditor;
using UnityEngine;
public partial class CompressModifier
{
private bool m_showFormattedCompressedFileName = false;
private bool m_showFormattedTargetPathToCompress = false;
protected internal override void OnGUIExpanded(ref bool isDirty, StringFormatter.Context ctx)
{
using (new GUILayout.HorizontalScope())
{
GUILayout.Label("Compression Type", GUILayout.Width(120));
var newCompressionType = (CompressionType)EditorGUILayout.EnumPopup(m_compressionType);
if (m_compressionType != newCompressionType)
{
m_compressionType = newCompressionType;
isDirty = true;
}
}
using (new GUILayout.HorizontalScope())
{
GUILayout.Label("Compressed Name", GUILayout.Width(120));
if (EditorUtils.FormatStringTextField(ref m_compressedFileName, ref m_showFormattedCompressedFileName, ctx))
{
isDirty = true;
}
}
using (new GUILayout.HorizontalScope())
{
GUILayout.Label("Target Path", GUILayout.Width(120));
if (EditorUtils.FormatStringTextField(ref m_targetPathToCompress, ref m_showFormattedTargetPathToCompress, ctx))
{
isDirty = true;
}
}
using (new GUILayout.HorizontalScope())
{
GUILayout.Label("Remove old files", GUILayout.Width(120));
var newRemoveContent = EditorGUILayout.Toggle(m_removeContentAfterCompress, GUILayout.Width(20));
if (m_removeContentAfterCompress != newRemoveContent)
{
m_removeContentAfterCompress = newRemoveContent;
isDirty = true;
}
}
}
}