Skip to content

Instantly share code, notes, and snippets.

@asm256
Last active May 26, 2017 20:01
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save asm256/8f5472657c1675bdc77a to your computer and use it in GitHub Desktop.
Save asm256/8f5472657c1675bdc77a to your computer and use it in GitHub Desktop.
CM3D2.ArchiveReplacer

CM3D2.ArchiveReplacer

目的

非公式MODを再梱包も、展開もせずに使うためのツール

必要なもの

  • ReiPatcher
  • .NET Framework

インストール方法

https://gist.github.com/asm256/ed75d84a9e89802821f8

ReiPatcherからパッチを当てる

CM3D2_KAIZOU\_Dataフォルダに入れたいMODを展開する

_Data\なんとか衣装MOD\GameData\menu\menu\dress...
みたいに深いとこに置いてもおk

(細かい話をすると、CM3D2は大抵の場合ディレクトリ構造を認識していません)

更新履歴

  • 2015.9.5 初版
  • 2015.9.5.1 サブディレクトリ対応
  • 2015.9.6 バグ修正
    • _Data内に同名ファイルが存在すると起動に失敗するバグの修正
    • ついでに色々情報埋め込んでみた
  • 2015.9.9 簡易インストール対応
    • なぜインストーラにここまでベストを尽くしたのか自分でもわからん

既知の問題点

  • Deflarcとの併用は不可能
  • script(*.tjs,*.ks)とは置換不可能
  • 未確認だけどoggも無理?
  • ディレクトリ構造無視なのでMODのインストールが面倒くさい (ひとまず解決したつもり)
  • MOD削除はさらに面倒くさい (解決はしたが、一時無効化機能をつけるかも)
  • SS.jpgだの1.pngだのが同名重複の可能性がある
  • 一応readme.txtについては対策してるけど…gitみたいな.ignore実装する?
  • ネーミングセンス無さ過ぎて泣ける
  • _Dataフォルダとかいい名前思いついたら改名したい
  • ArchiveReplacerについては半日考えてこんな名前しか思いつかなかった自分に泣ける
sal csc ((Get-ItemProperty 'HKLM:\SoftWare\Microsoft\NET Framework Setup\NDP\v3.5').InstallPath+"csc.exe")
$cm3d2= (Get-ItemProperty 'HKCU:\Software\KISS\カスタムメイド3D2').InstallPath
if(!$reip){
$reip = Read-Host "ReiPatcherの位置を入力/空行でスキップ"
}
if($reip){
csc /t:library /lib:$reip /r:ReiPatcher.exe /r:mono.cecil.dll /r:mono.cecil.rocks.dll CM3D2.ArchiveReplacer.Patcher.cs
}else{
echo "Patcherのビルドをしません"
}
csc /t:library /lib:$cm3d2 /r:CM3D2x64_Data\Managed\Assembly-CSharp-firstpass.dll CM3D2.ArchiveReplacer.Hook.cs
/*
* コンパイルしてManagedフォルダ内へ置いてください
* csc /t:library /r:Assembly-CSharp-firstpass.dll CM3D2.ArchiveReplacer.Hook.cs
* CM3D2_KAIZOU\_Data フォルダに追加・置換したいファイルを置いてください
*/
// @AB_addarg /r:Assembly-CSharp-firstpass.dll
// @AB_addarg /lib:%managed%
// @AB_install %managed%
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
[assembly: AssemblyTitle("CM3D2.ArchiveReplacer.Hook")]
[assembly: AssemblyDescription("FileSystemArchiveのProxyClass")]
[assembly: AssemblyProduct("CM3D2.ArchiveReplacer")]
[assembly: AssemblyCopyright("Copyright © asm__ 2015")]
[assembly: AssemblyVersion("2015.9.9.0")]
namespace CM3D2.ArchiveReplacer.Hook
{
public class AFile : AFileBase
{
FileStream fs;
protected override void Dispose(bool is_release_managed_code)
{
fs.Dispose();
fs = null;
}
public override int GetSize()
{
return (int)fs.Length;
}
public override bool IsValid()
{
return fs != null;
}
public override int Read(ref byte[] f_byBuf, int f_nReadSize)
{
return fs.Read(f_byBuf,0, f_nReadSize);
}
public override byte[] ReadAll()
{
int len = (int)fs.Length;
byte[] buf = new byte[len];
fs.Read(buf, 0, len);
return buf;
}
public override int Seek(int f_unPos, bool absolute_move)
{
return (int)fs.Seek(f_unPos, absolute_move ? SeekOrigin.Begin : SeekOrigin.Current);
}
public override int Tell()
{
return (int)fs.Position;
}
public override DLLFile.Data object_data
{
get { throw new NotImplementedException(); }
}
public AFile(string path)
{
fs = File.OpenRead(path);
}
}
public class HookArchive : FileSystemArchive
{
string path;
Dictionary<string, string> locations;
public HookArchive()
{
path = Path.Combine(System.Environment.CurrentDirectory, "_Data");
//ファイル収集
string[] list = Directory.GetFiles(path, "*", SearchOption.AllDirectories);
locations = new Dictionary<string, string>(list.Length);
foreach (string item in list)
{
string name = Path.GetFileName(item).ToLower();
if (!Regex.IsMatch(name, @"readme\.txt$", RegexOptions.IgnoreCase))
{
//LogPrint(name.ToLower());
if (locations.ContainsKey(name))
{
NDebug.Warning(string.Format("{0}と{1}が干渉しています\n{1}で上書きします", locations[name], item));
locations[name] = item;
}
else
{
locations.Add(name.ToLower(), item);
}
}
}
}
private void LogPrint(object s){
Console.Write(string.Format("AchiveReplacer : {0}\n",s));
}
public override bool IsExistentFile(string file_name)
{
#if DEBUG
LogPrint("IsExistentFile <- " + file_name);
#endif
return base.IsExistentFile(file_name);
}
public override AFileBase FileOpen(string file_name)
{
#if DEBUG
LogPrint("FileOpen <- " + file_name);
#endif
var name = file_name.ToLower();
string val;
locations.TryGetValue(name, out val);
if(!string.IsNullOrEmpty(val))
return new AFile(val);
return base.FileOpen(file_name);
}
public override string[] GetList(string f_str_path, ListType type)
{
#if DEBUG
LogPrint(string.Format("List <- {0} / {1}", f_str_path, type));
#endif
string[] list = base.GetList(f_str_path, type);
if (type == ListType.AllFile)
{
var ll = from p in locations
where Regex.IsMatch(p.Key,string.Format("\\.{0}$",f_str_path))
select p.Key;
return ll.Concat(list).ToArray();
}
return list;
}
}
}
/*
* コンパイルしてReiPatcher\Patchesに置いてください
* csc /t:library /r:..\ReiPatcher.exe /r:..\mono.cecil.dll /r:..\mono.cecil.rocks.dll CM3D2.ArchiveReplacer.Patcher.cs
*/
// @AB_addarg /r:mono.cecil.dll
// @AB_addarg /r:mono.cecil.rocks.dll
// @AB_addarg /r:ReiPatcher.exe
// @AB_addarg /lib:%reipatcher%
// @AB_install %reipatcher%\Patches
using Mono.Cecil;
using Mono.Cecil.Cil;
using System;
using System.IO;
using System.Linq;
namespace CM3D2.ArchiveReplacer.Patcher
{
public class ArchiveReplacerPatcher : ReiPatcher.Patch.PatchBase
{
const string patchTag = "CM3D2_ArchiveReplacer_PATCHED";
AssemblyDefinition hookdef;
public override bool CanPatch(ReiPatcher.Patch.PatcherArguments args)
{
return args.Assembly.Name.Name == "Assembly-CSharp" && !base.GetPatchedAttributes(args.Assembly).Any(a => a.Info == patchTag);
}
public override void PrePatch()
{
ReiPatcher.RPConfig.RequestAssembly("Assembly-CSharp.dll");
string path = Path.Combine(base.AssembliesDir, "CM3D2.ArchiveReplacer.Hook.dll");
using (Stream str = File.OpenRead(path))
{
hookdef = AssemblyDefinition.ReadAssembly(str);
}
}
public override void Patch(ReiPatcher.Patch.PatcherArguments args)
{
TypeDefinition gameuty = args.Assembly.MainModule.GetType("GameUty");
var initmethod = gameuty.Methods.First((MethodDefinition def) => def.Name == "Init");
foreach (var il in initmethod.Body.Instructions)
{
if (il.OpCode == OpCodes.Newobj)
{
MethodReference oprnd = (MethodReference)il.Operand;
if (oprnd.DeclaringType.ToString() == "FileSystemArchive")
{
var defHook_ctor = hookdef.MainModule.GetType("CM3D2.ArchiveReplacer.Hook.HookArchive")
.Methods.First((MethodDefinition def) => def.Name == ".ctor");
il.Operand = args.Assembly.MainModule.Import(defHook_ctor);
}
}
}
base.SetPatchedAttribute(args.Assembly, patchTag);
}
}
}
$web = new-object net.webclient
$gist = 'https://gist.githubusercontent.com/asm256/8f5472657c1675bdc77a/raw/'
$web.DownloadFile($gist+'CM3D2.ArchiveReplacer.Hook.cs' , 'CM3D2.ArchiveReplacer.Hook.cs')
$web.DownloadFile($gist+'CM3D2.ArchiveReplacer.Patcher.cs' , 'CM3D2.ArchiveReplacer.Patcher.cs')
iex($web.DownloadString($gist+'build.ps1'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment