ghorsington 4 years ago
commit
d718fd1dff

+ 425 - 0
.gitignore

@@ -0,0 +1,425 @@
+
+# Created by https://www.gitignore.io/api/csharp,rider
+# Edit at https://www.gitignore.io/?templates=csharp,rider
+
+### Csharp ###
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+### Rider ###
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn.  Uncomment if using
+# auto-import.
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+# End of https://www.gitignore.io/api/csharp,rider

+ 4 - 0
.idea/.idea.COM3D2.CacheEditMenu/.idea/encodings.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
+</project>

+ 8 - 0
.idea/.idea.COM3D2.CacheEditMenu/.idea/indexLayout.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ContentModelUserStore">
+    <attachedFolders />
+    <explicitIncludes />
+    <explicitExcludes />
+  </component>
+</project>

+ 8 - 0
.idea/.idea.COM3D2.CacheEditMenu/.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/.idea.COM3D2.CacheEditMenu/riderModule.iml" filepath="$PROJECT_DIR$/.idea/.idea.COM3D2.CacheEditMenu/riderModule.iml" />
+    </modules>
+  </component>
+</project>

+ 6 - 0
.idea/.idea.COM3D2.CacheEditMenu/.idea/projectSettingsUpdater.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RiderProjectSettingsUpdater">
+    <option name="vcsConfiguration" value="1" />
+  </component>
+</project>

+ 6 - 0
.idea/.idea.COM3D2.CacheEditMenu/.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 7 - 0
.idea/.idea.COM3D2.CacheEditMenu/riderModule.iml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="RIDER_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$/../.." />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 58 - 0
COM3D2.CacheEditMenu.Patcher/COM3D2.CacheEditMenu.Patcher.csproj

@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{ECFC9EDF-C56B-4749-9135-428282B67492}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>COM3D2.CacheEditMenu.Patcher</RootNamespace>
+    <AssemblyName>COM3D2.CacheEditMenu.Patcher</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Mono.Cecil, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756">
+      <HintPath>..\lib\Mono.Cecil.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Patcher.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="COM3D2.CacheEditMenu.dll" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+         Other similar extension points exist, see Microsoft.Common.targets.
+    <Target Name="BeforeBuild">
+    </Target>
+    <Target Name="AfterBuild">
+    </Target>
+    -->
+</Project>

BIN
COM3D2.CacheEditMenu.Patcher/COM3D2.CacheEditMenu.Patcher.dll


BIN
COM3D2.CacheEditMenu.Patcher/COM3D2.CacheEditMenu.dll


BIN
COM3D2.CacheEditMenu.Patcher/Mono.Cecil.dll


+ 71 - 0
COM3D2.CacheEditMenu.Patcher/Patcher.cs

@@ -0,0 +1,71 @@
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace COM3D2.CacheEditMenu.Patcher
+{
+    public static class Patcher
+    {
+        public static readonly string[] TargetAssemblyNames = { "Assembly-CSharp.dll" };
+
+        public static readonly string SybarisPath = Path.GetDirectoryName(typeof(Patcher).Assembly.Location);
+        
+        public static void Patch(AssemblyDefinition ad)
+        {
+            var hookAd = AssemblyDefinition.ReadAssembly(
+                typeof(Patcher).Assembly.GetManifestResourceStream(
+                    "COM3D2.CacheEditMenu.Patcher.COM3D2.CacheEditMenu.dll"));
+
+            var sceneEdit = ad.MainModule.GetType("SceneEdit");
+            var getMenuItemSetUp = sceneEdit.Methods.FirstOrDefault(m => m.Name == "GetMenuItemSetUP");
+
+            var hookType = hookAd.MainModule.GetType("COM3D2.CacheEditMenu.Hooks");
+            var getMenuItemSetUpPrefix = hookType.Methods.FirstOrDefault(m => m.Name == "Prefix");
+            var getMenuItemSetUpPostfix = hookType.Methods.FirstOrDefault(m => m.Name == "Postfix");
+
+            var il = getMenuItemSetUp.Body.GetILProcessor();
+            var resultVar = new VariableDefinition(ad.MainModule.ImportReference(typeof(bool)));
+            getMenuItemSetUp.Body.Variables.Add(resultVar);
+            var ins = getMenuItemSetUp.Body.Instructions[0];
+            
+            il.InsertBefore(ins, il.Create(OpCodes.Ldloca, resultVar));
+            il.InsertBefore(ins, il.Create(OpCodes.Ldarg_0));
+            il.InsertBefore(ins, il.Create(OpCodes.Ldarg_1));
+            il.InsertBefore(ins, il.Create(OpCodes.Call, ad.MainModule.ImportReference(getMenuItemSetUpPrefix)));
+            il.InsertBefore(ins, il.Create(OpCodes.Brtrue, ins));
+            il.InsertBefore(ins, il.Create(OpCodes.Ldloc, resultVar));
+            il.InsertBefore(ins, il.Create(OpCodes.Ret));
+            
+            ins = il.Create(OpCodes.Nop);
+            
+            foreach (var bodyInstruction in getMenuItemSetUp.Body.Instructions.Where(bodyInstruction => bodyInstruction.OpCode == OpCodes.Ret).Skip(1))
+            {
+                bodyInstruction.OpCode = OpCodes.Br;
+                bodyInstruction.Operand = ins;
+            }
+            
+            il.Append(ins);
+            ins = il.Create(OpCodes.Ret);
+            il.Append(ins);
+            
+            il.InsertBefore(ins, il.Create(OpCodes.Ldarg_0));
+            il.InsertBefore(ins, il.Create(OpCodes.Ldarg_1));
+            il.InsertBefore(ins, il.Create(OpCodes.Call, ad.MainModule.ImportReference(getMenuItemSetUpPostfix)));
+            
+
+            var buffer = new byte[4096];
+            using(var s = typeof(Patcher).Assembly.GetManifestResourceStream(
+                "COM3D2.CacheEditMenu.Patcher.COM3D2.CacheEditMenu.dll"))
+            using (var ms = new MemoryStream())
+            {
+                int read;
+                while ((read = s.Read(buffer, 0, buffer.Length)) > 0)
+                    ms.Write(buffer, 0, read);
+
+                Assembly.Load(ms.ToArray());
+            }
+        }
+    }
+}

+ 35 - 0
COM3D2.CacheEditMenu.Patcher/Properties/AssemblyInfo.cs

@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("COM3D2.CacheEditMenu.Patcher")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("COM3D2.CacheEditMenu.Patcher")]
+[assembly: AssemblyCopyright("Copyright ©  2020")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("ECFC9EDF-C56B-4749-9135-428282B67492")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 22 - 0
COM3D2.CacheEditMenu.sln

@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "COM3D2.CacheEditMenu", "COM3D2.CacheEditMenu\COM3D2.CacheEditMenu.csproj", "{56425A3D-B27E-49D7-B248-1BE6ED67EF2B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "COM3D2.CacheEditMenu.Patcher", "COM3D2.CacheEditMenu.Patcher\COM3D2.CacheEditMenu.Patcher.csproj", "{ECFC9EDF-C56B-4749-9135-428282B67492}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{56425A3D-B27E-49D7-B248-1BE6ED67EF2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{56425A3D-B27E-49D7-B248-1BE6ED67EF2B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{56425A3D-B27E-49D7-B248-1BE6ED67EF2B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{56425A3D-B27E-49D7-B248-1BE6ED67EF2B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{ECFC9EDF-C56B-4749-9135-428282B67492}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{ECFC9EDF-C56B-4749-9135-428282B67492}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{ECFC9EDF-C56B-4749-9135-428282B67492}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{ECFC9EDF-C56B-4749-9135-428282B67492}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal

+ 66 - 0
COM3D2.CacheEditMenu/COM3D2.CacheEditMenu.csproj

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{56425A3D-B27E-49D7-B248-1BE6ED67EF2B}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>COM3D2.CacheEditMenu</RootNamespace>
+    <AssemblyName>COM3D2.CacheEditMenu</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>none</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\COM3D2.CacheEditMenu.Patcher</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+      <HintPath>..\lib\Assembly-CSharp.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+    <Reference Include="UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+      <HintPath>..\lib\UnityEngine.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Hooks.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\COM3D2.CacheEditMenu.Patcher\COM3D2.CacheEditMenu.Patcher.csproj">
+      <Project>{ecfc9edf-c56b-4749-9135-428282b67492}</Project>
+      <Name>COM3D2.CacheEditMenu.Patcher</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+         Other similar extension points exist, see Microsoft.Common.targets.
+    <Target Name="BeforeBuild">
+    </Target>
+    <Target Name="AfterBuild">
+    </Target>
+    -->
+</Project>

+ 248 - 0
COM3D2.CacheEditMenu/Hooks.cs

@@ -0,0 +1,248 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace COM3D2.CacheEditMenu
+{
+    internal static class BinaryExtensions
+    {
+        public static string ReadNullableString(this BinaryReader br)
+        {
+            return br.ReadBoolean() ? br.ReadString() : null;
+        }
+
+        public static void WriteNullableString(this BinaryWriter bw, string value)
+        {
+            bw.Write(value != null);
+            if (value != null)
+                bw.Write(value);
+        }
+    }
+
+    public static class Hooks
+    {
+        private static readonly Dictionary<string, MenuInfo> infoCache = new Dictionary<string, MenuInfo>();
+        private static BinaryWriter cacheWriter;
+
+        private static readonly Func<Dictionary<int, SceneEdit.SMenuItem>> getIdItemDic = () =>
+            new Dictionary<int, SceneEdit.SMenuItem>();
+
+        private static readonly Func<Dictionary<int, string>> getTexFileIDDic = () => new Dictionary<int, string>();
+        private static readonly Action<bool> setNowMenuFlg = b => { };
+        private static readonly Action<int> setNowStrMenuFileID = b => { };
+
+        static Hooks()
+        {
+            var quickEditAss =
+                TryLoadFrom(Path.Combine(Patcher.Patcher.SybarisPath, "COM3D2.QuickEditStart.Managed.dll"));
+
+            if (quickEditAss == null)
+                return;
+
+            var mainType = quickEditAss.GetType("COM3D2.QuickEditStart.Managed.QuickEditStartManaged");
+
+            MakeStaticGetter(mainType.GetField("texFileIDDic", BindingFlags.Public | BindingFlags.Static),
+                ref getTexFileIDDic);
+            MakeStaticGetter(mainType.GetField("idItemDic", BindingFlags.Public | BindingFlags.Static),
+                ref getIdItemDic);
+            MakeStaticSetter(mainType.GetField("nowMenuFlg", BindingFlags.NonPublic | BindingFlags.Static),
+                ref setNowMenuFlg);
+            MakeStaticSetter(mainType.GetField("nowStrMenuFileID", BindingFlags.NonPublic | BindingFlags.Static),
+                ref setNowStrMenuFileID);
+        }
+
+        private static void MakeStaticGetter<T>(FieldInfo field, ref T result) where T : Delegate
+        {
+            if (field == null)
+                return;
+
+            var dm = new DynamicMethod($"CacheEditMenu_Getter_{field.GetHashCode()}", field.FieldType, null,
+                typeof(Hooks), true);
+
+            var il = dm.GetILGenerator();
+
+            il.Emit(OpCodes.Ldsfld, field);
+            il.Emit(OpCodes.Ret);
+
+            result = dm.CreateDelegate(typeof(T)) as T;
+        }
+
+        private static void MakeStaticSetter<T>(FieldInfo field, ref T result) where T : Delegate
+        {
+            if (field == null)
+                return;
+
+            var dm = new DynamicMethod($"CacheEditMenu_Getter_{field.GetHashCode()}", typeof(void),
+                new[] {field.FieldType}, typeof(Hooks), true);
+
+            var il = dm.GetILGenerator();
+
+            il.Emit(OpCodes.Ldarg_0);
+            il.Emit(OpCodes.Stsfld, field);
+            il.Emit(OpCodes.Ret);
+
+            result = dm.CreateDelegate(typeof(T)) as T;
+        }
+
+        private static Assembly TryLoadFrom(string path)
+        {
+            try
+            {
+                return Assembly.LoadFrom(path);
+            }
+            catch (Exception)
+            {
+                return null;
+            }
+        }
+
+        public static bool Prefix(ref bool result, SceneEdit.SMenuItem mi, string menuFileName)
+        {
+            Init();
+
+            if (menuFileName.Contains("_zurashi"))
+            {
+                result = false;
+                return false;
+            }
+            if (menuFileName.Contains("_mekure"))
+            {
+                result = false;
+                return false;
+            }
+            menuFileName = Path.GetFileName(menuFileName);
+            mi.m_strMenuFileName = menuFileName;
+            mi.m_nMenuFileRID = menuFileName.ToLower().GetHashCode();
+
+            if (infoCache.TryGetValue(menuFileName, out var menuInfo))
+            {
+                menuInfo.CopyTo(mi);
+                result = true;
+                return false;
+            }
+
+            return true;
+        }
+
+
+        private static Stopwatch sw = null;
+        public static bool Postfix(bool result, SceneEdit.SMenuItem mi, string menuFileName)
+        {
+            if (!result)
+                return false;
+            
+            var menuInfo = new MenuInfo
+            {
+                mi = mi,
+                key = menuFileName
+            };
+            getTexFileIDDic().TryGetValue(mi.m_nMenuFileRID, out menuInfo.texName);
+            infoCache[menuFileName] = menuInfo;
+            
+            menuInfo.Serialize(cacheWriter);
+            
+            return true;
+        }
+
+        private static void Init()
+        {
+            if (cacheWriter != null)
+                return;
+            var cacheDir = Path.Combine(Patcher.Patcher.SybarisPath, "EditMenuCache");
+            var cachePath = Path.Combine(cacheDir, "EditMenuCache.dat");
+
+            Directory.CreateDirectory(cacheDir);
+
+            if (File.Exists(cachePath))
+                using (var br = new BinaryReader(File.Open(cachePath, FileMode.Open, FileAccess.Read)))
+                {
+                    try
+                    {
+                        while (true)
+                        {
+                            var menuInfo = new MenuInfo();
+                            menuInfo.Deserialize(br);
+                            infoCache[menuInfo.key] = menuInfo;
+                        }
+                    }
+                    catch (EndOfStreamException)
+                    {
+                        // End of file, no need to read more
+                    }
+                }
+
+            cacheWriter = new BinaryWriter(File.OpenWrite(cachePath));
+            cacheWriter.BaseStream.Seek(0, SeekOrigin.End);
+        }
+
+        private class MenuInfo
+        {
+            public string key;
+            public SceneEdit.SMenuItem mi;
+            public string texName;
+
+            public void Deserialize(BinaryReader br)
+            {
+                key = br.ReadString();
+                texName = br.ReadNullableString();
+                mi = new SceneEdit.SMenuItem
+                {
+                    m_strMenuName = br.ReadString(),
+                    m_strInfo = br.ReadNullableString(),
+                    m_mpn = (MPN) br.ReadInt32(),
+                    m_strCateName = br.ReadString(),
+                    m_eColorSetMPN = (MPN) br.ReadInt32(),
+                    m_strMenuNameInColorSet = br.ReadNullableString(),
+                    m_pcMultiColorID = (MaidParts.PARTS_COLOR) br.ReadInt32(),
+                    m_boDelOnly = br.ReadBoolean(),
+                    m_fPriority = br.ReadSingle(),
+                    m_bMan = br.ReadBoolean()
+                };
+            }
+
+            public void Serialize(BinaryWriter bw)
+            {
+                bw.Write(key);
+                bw.WriteNullableString(texName);
+                bw.Write(mi.m_strMenuName);
+                bw.WriteNullableString(mi.m_strInfo);
+                bw.Write((int) mi.m_mpn);
+                bw.Write(mi.m_strCateName);
+                bw.Write((int) mi.m_eColorSetMPN);
+                bw.WriteNullableString(mi.m_strMenuNameInColorSet);
+                bw.Write((int) mi.m_pcMultiColorID);
+                bw.Write(mi.m_boDelOnly);
+                bw.Write(mi.m_fPriority);
+                bw.Write(mi.m_bMan);
+            }
+
+            public void CopyTo(SceneEdit.SMenuItem other)
+            {
+                other.m_strMenuName = mi.m_strMenuName;
+                other.m_strInfo = mi.m_strInfo;
+                other.m_mpn = mi.m_mpn;
+                other.m_strCateName = mi.m_strCateName;
+                other.m_eColorSetMPN = mi.m_eColorSetMPN;
+                other.m_strMenuNameInColorSet = mi.m_strMenuNameInColorSet;
+                other.m_pcMultiColorID = mi.m_pcMultiColorID;
+                other.m_boDelOnly = mi.m_boDelOnly;
+                other.m_fPriority = mi.m_fPriority;
+                other.m_bMan = mi.m_bMan;
+
+                if (string.IsNullOrEmpty(texName))
+                    return;
+
+                setNowMenuFlg(true);
+
+                setNowStrMenuFileID(other.m_nMenuFileRID);
+                getIdItemDic()[other.m_nMenuFileRID] = other;
+                other.m_texIcon = ImportCM.CreateTexture(texName);
+
+                setNowMenuFlg(false);
+            }
+        }
+    }
+}

+ 35 - 0
COM3D2.CacheEditMenu/Properties/AssemblyInfo.cs

@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("COM3D2.CacheEditMenu")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("COM3D2.CacheEditMenu")]
+[assembly: AssemblyCopyright("Copyright ©  2020")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("56425A3D-B27E-49D7-B248-1BE6ED67EF2B")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

BIN
lib/Assembly-CSharp.dll


BIN
lib/Mono.Cecil.dll


BIN
lib/UnityEngine.dll