MMD4Mecanim ships an editor routine that deletes files belonging to the VRChat SDK from any Unity project that contains both packages. It runs automatically, it does not ask, it does not check whether you are actually using MMD content with VRChat, and it reports what it did only after the files are already gone.
This repository contains a technical writeup and a script that disables that routine on your own local copy of the assembly.
No part of MMD4Mecanim is redistributed here. The script edits an assembly you already have.
The routine lives in Assets/MMD4Mecanim/Editor/MMD4MecanimEditor.dll, in a class named
MMD4MecanimEditorValidator. Decompiled:
[InitializeOnLoad]
public class MMD4MecanimEditorValidator
{
static MMD4MecanimEditorValidator()
{
bool flag = false;
List<string> list = new List<string>();
string[] allAssetPaths = AssetDatabase.GetAllAssetPaths();
foreach (string text in allAssetPaths)
{
if (text.Contains("/VRChat/") || text.Contains("\\VRChat\\"))
{
flag = true;
if (text.Contains("/Editor/") || text.Contains("\\Editor\\"))
{
list.Add(text);
}
}
}
if (_WeakFix(list))
{
AssetDatabase.Refresh();
}
if (flag)
{
// ... four Debug.LogError calls, shown below
}
}
private static bool _WeakFix(List<string> targetList)
{
foreach (string target in targetList)
{
try
{
File.Delete(target);
}
catch (Exception)
{
}
}
return targetList.Count > 0;
}
}The messages it prints afterwards:
Use to VRChat is prohibited. Please refer to the Readme for details.
A part of VRChat extensions was deleted. If you need to restore it, please reimport package in other project.
Most models are prohibited to redistribution (or uploading).
If you've uploaded some models, please delete some models.
The trigger is a substring match on file paths, nothing more. There is no check for whether an MMD model exists in the project, whether one has been assigned to an avatar, or whether anything is being uploaded anywhere. Having both packages installed in one Unity project is the entire condition. Using the same project for VTubing and for VRChat avatars is enough to trigger it.
It is broader than "the VRChat SDK". Any asset path containing a VRChat directory
segment and an Editor directory segment is deleted. A folder of your own at
Assets/MyStuff/VRChat/Editor/ is caught by the same sweep. The code never looks at what
the files are, who authored them, or whether they relate to MMD at all.
It re-runs constantly. [InitializeOnLoad] static constructors execute on editor
startup and after every script recompilation. This is not a one-shot check at import
time. Reinstalling the SDK gets you a working SDK until the next domain reload, which
deletes it again. Without knowing the cause, this presents as an SDK that mysteriously
refuses to stay installed.
It fails silently and destroys data. _WeakFix wraps File.Delete in a catch that
swallows every exception, so partial failures are invisible. Deletion happens before the
console messages are emitted, so by the time you read "a part of VRChat extensions was
deleted", it has already happened. There is no prompt, no dry run, and no undo.
The damage is not confined to what it deleted. Deleting a subset of an SDK's editor scripts leaves the remainder uncompilable. A typical first symptom is a wall of unrelated compile errors:
Packages\com.vrchat.base\Editor\VRCSDK\PerceptualPostProcessor.cs(47,14):
error CS0103: The name 'VRCPackageSettings' does not exist in the current context
Because the project no longer compiles, other editor tooling stops working too, which makes the root cause harder to find.
A license term prohibiting a combination of software is one thing. Enforcing it by deleting another vendor's files off a user's disk, without consent or warning, is a different thing.
The script edits the two string literals the path matcher compares against, in the assembly's user-string heap:
"/VRChat/" -> "/VRCh*t/"
"\VRChat\" -> "\VRCh*t\"
* is not a legal character in a Windows filename, so the comparison can never match a
real asset path again. flag is never set and the deletion list is always empty, so:
- nothing is deleted,
_WeakFixreturnsfalse, so no spuriousAssetDatabase.Refresh()is triggered,- the four console errors stop as well, since they are gated on the same match.
Nothing else changes. MMD4Mecanim's model import, material handling, physics and morph functionality are untouched.
The edit is length-preserving and touches only string content — no IL, no method bodies, no metadata tables, no offsets. The assembly stays structurally valid by construction.
It is also located by content search rather than by hardcoded file offset, so it is not tied to one specific build. The script refuses to modify anything it does not recognise rather than writing to a guessed offset.
On the build verified here it changes exactly two bytes:
0x023323: 61 -> 2a ('a' -> '*')
0x023335: 61 -> 2a ('a' -> '*')
Alternative: neutralising the static constructor instead
The static constructor can also be disabled directly by writing ret (0x2A) as the
first byte of its IL body. On the build verified here that is file offset 0x44c8,
changing 0x16 (ldc.i4.0) to 0x2A. Its method body uses a fat header with no
exception-handling clauses, so a leading ret is valid IL.
This works and is a single byte, but it depends on a hardcoded offset into one specific build, which makes it a poor thing to hand to other people. The string edit above is preferred for that reason.
Close the Unity Editor first. Unity locks loaded editor assemblies, and it will re-run the deletion routine on its next domain reload.
Check whether your copy is affected:
.\Patch-MMD4Mecanim.ps1 -VerifyApply the patch:
.\Patch-MMD4Mecanim.ps1Run from anywhere inside your Unity project and the assembly is located automatically, or
pass -Path to point at it explicitly:
.\Patch-MMD4Mecanim.ps1 -Path "C:\MyProject\Assets\MMD4Mecanim\Editor\MMD4MecanimEditor.dll"Preview the edits without writing anything:
.\Patch-MMD4Mecanim.ps1 -WhatIfUndo it:
.\Patch-MMD4Mecanim.ps1 -RestoreThe script backs the original assembly up before its first write, to
<ProjectRoot>/MMD4MecanimEditor.dll.prepatch-backup — outside Assets/, so Unity does
not import it as a stray asset. It is idempotent, verifies the result by re-reading from
disk, and rolls back automatically if verification fails.
If PowerShell blocks the script, either unblock the downloaded file or run it for the current process only:
Unblock-File .\Patch-MMD4Mecanim.ps1powershell -ExecutionPolicy Bypass -File .\Patch-MMD4Mecanim.ps1Do not take any of the above on faith. The claims are checkable with a decompiler:
dotnet tool install --global ilspycmd --version 8.2.0.7535ilspycmd -t MMD4MecanimEditorValidator MMD4MecanimEditor.dllAn unpatched assembly shows the matcher comparing against "/VRChat/" and "\VRChat\".
A patched one shows "/VRCh*t/" and "\VRCh*t\". Decompiling before and after the patch
and diffing the output is a good way to confirm that nothing else was altered.
The patch stops further deletions; it does not restore what was already removed.
Deleted files are unrecoverable from within Unity, so reinstall the affected packages. For VCC/VPM installs, remove and re-add the package, or delete the package directory and let the resolver restore it. Patch the assembly first — otherwise the next domain reload deletes the freshly restored files again.
To find the damage, look for emptied directories under the SDK:
Get-ChildItem -Path .\Packages -Recurse -Directory | Where-Object { -not (Get-ChildItem $_.FullName -File) }- Verified against
MMD4MecanimEditor.dll, SHA-25639e1196a95bb6ac933079c0ff3fcd22cfb67d18f528ec685cac88ec3b204f1ee, 183,296 bytes. - Other builds are handled by content search, but if a build searches for paths some other
way the script will report
UNKNOWNand refuse to modify it rather than guessing. Please report those so the script can be updated. - The runtime assemblies (
Scripts/MMD4Mecanim.dll,Scripts/Internal/MMD4Mecanim.dll) were checked and contain no equivalent routine. Only the editor assembly needs patching. - The other three
File.Deletecall sites in the editor assembly are legitimate (.metarewriting, a compile lock file, import dependency cleanup) and are left alone. - The patch is applied to a file inside
Assets/, which is typically not tracked in version control. Updating or reimporting MMD4Mecanim silently reverts it. Re-run-Verifyafter any update.
This does not bypass any copy protection, license check, or activation mechanism, and it does not enable any prohibited use. The routine it disables does not protect MMD4Mecanim from anything — it only deletes third-party files from the user's disk. The patch stops that and changes nothing else.
Whatever license terms apply to MMD4Mecanim and to any MMD models you use continue to apply, and this patch has no bearing on them. If you do not intend to comply with those terms, the fix is to not use the software — not to patch it.