ParadoxLive Scripting Metro cs 1 Roslyn Microsoft MVP

  • Slides: 34
Download presentation
ParadoxのLive. Scripting事情 Metro. cs #1 -メタプログラミング & Roslyn 事例集Microsoft MVP for Windows Platform Development[Jan,

ParadoxのLive. Scripting事情 Metro. cs #1 -メタプログラミング & Roslyn 事例集Microsoft MVP for Windows Platform Development[Jan, 2015 -Dec, 2015] @hr_sao 遥佐保(はるかさお)

自己紹介 @hr_sao Silicon. Studio - Software Engineer and Evangelist Microsoft MVP for Windows Platform

自己紹介 @hr_sao Silicon. Studio - Software Engineer and Evangelist Microsoft MVP for Windows Platform Development • めとべや東京&大阪 →東京の次回は 11月予定

Live Scripting

Live Scripting

Demo

Demo

Live Scripting: synchronization with code and exe Paradox Game Studio Roslyn利用 Visual Studio Running

Live Scripting: synchronization with code and exe Paradox Game Studio Roslyn利用 Visual Studio Running EXE

1. Start Game

1. Start Game

1. Start Game - Initialize WCF pipe Roslyn/MSBuild Project Part 0 -csproj Player. cs

1. Start Game - Initialize WCF pipe Roslyn/MSBuild Project Part 0 -csproj Player. cs Part 1 -csproj ↑こんなsln構成 だと思いますが Enemy. cs Player. dll Player. pdb Enemy. dll Enemy. pdb 後々DLLの差分更新をしたい!

1. Start Game - compile Game用のプロジェクトを新規作成 using Microsoft. Code. Analysis MSBuild. Workspaceを作成 private async

1. Start Game - compile Game用のプロジェクトを新規作成 using Microsoft. Code. Analysis MSBuild. Workspaceを作成 private async Task<Project> Open. Project(string project. Path) { var csharp. Workspace. Assemblies = new[]{ System. Reflection. Assembly. Load("Microsoft. Code. Analysis. Workspaces"), System. Reflection. Assembly. Load("Microsoft. Code. Analysis. CSharp. Workspaces"), System. Reflection. Assembly. Load("Microsoft. Code. Analysis. Workspaces. Desktop") }; var ms. Workspace = MSBuild. Workspace. Create( Immutable. Dictionary<string, string>. Empty, Mef. Host. Services. Create(csharp. Workspace. Assemblies)); return await ms. Workspace. Open. Project. Async(project. Path); }

1. Start Game – Roslyn compile Game用プロジェクトを新規に作成する 元Projectと”同じ様な”構造、だが1ファイルづつ Solution. Add. Project, Add. DocumentでCSファイルなど追加 var

1. Start Game – Roslyn compile Game用プロジェクトを新規に作成する 元Projectと”同じ様な”構造、だが1ファイルづつ Solution. Add. Project, Add. DocumentでCSファイルなど追加 var newproject = solution. Add. Project(assembly. Name, Language. Names. CSharp). With. Metadata. References(moto. Project. Metadata. References). With. Project. References(moto. Project. All. Project. References). With. Compilation. Options( new CSharp. Compilation. Options(Output. Kind. Dynamically. Linked. Library)); // ソースコードの追加 Newproject = newproject. Add. Document(syntax. Tree. File. Path, syntax. Tree. Get. Text()). Project; // 他のソースコードの参照があれば追加(※しれっと……? ? ? ) project = newproject. Add. Project. Reference( new Project. Reference(dependency. Source. Group. Target. Project. Id));

他のソースコードの参照があれば? Quick. Graph. Adjacency. Graph Quick. Graph, Graph Data Structures And Algorithms for. NET

他のソースコードの参照があれば? Quick. Graph. Adjacency. Graph Quick. Graph, Graph Data Structures And Algorithms for. NET http: //quickgraph. codeplex. com/ グラフライブラリを利用して、ファイルの依存関係を取得している Quick. Graph. Adjacency. Graph<Syntax. Tree, SEdge<Syntax. Tree>>

1. Start Game – Roslyn compile Roslynでコンパイル、1ファイルづつ Get. Compilation. Async でコンパイル(オンメモリ) ファイルの数の分だけ、コンパイル var compilation

1. Start Game – Roslyn compile Roslynでコンパイル、1ファイルづつ Get. Compilation. Async でコンパイル(オンメモリ) ファイルの数の分だけ、コンパイル var compilation = await newproject. Get. Compilation. Async();

1. Start Game – MSBuild compile MSBuildで改めて実際にコンパイル 実際のDLLが1個づつ作成される (Roslyn for Scriting があれば良いんだけど、まだない) Task<Build. Result>

1. Start Game – MSBuild compile MSBuildで改めて実際にコンパイル 実際のDLLが1個づつ作成される (Roslyn for Scriting があれば良いんだけど、まだない) Task<Build. Result> Build. Task { get; private set; } Microsoft. Build. Evaluation. Project project; var project. Instance = new Project. Instance( project. Xml, project. Project. Collection. Global. Properties, null, project. Project. Collection); Build. Task = Task. Run(() =>{ … new Build. Parameters(project. Project. Collection) … }

1. Start Game – MSBuild compile できたDLLをメモリに保存 差分更新をするために、DLLをバイナリで保持する // source. Groupとは独自で作ったクラス // - PE(dllファイル)

1. Start Game – MSBuild compile できたDLLをメモリに保存 差分更新をするために、DLLをバイナリで保持する // source. Groupとは独自で作ったクラス // - PE(dllファイル) // - PDB // - Microsoft. Code. Analysis. Project // - Mono. Cecil. Assembly. Definition (ParadoxではScriptのシリアライズに利用している) source. Group. PE = File. Read. All. Bytes(pe. File. Name); source. Group. PDB = File. Read. All. Bytes(pdb. File. Name);

1. Start Game–WCF pipe // game. Debugger. Hostとは独自で作ったクラス // 今から起動させるアプリケーションのこと Service. Host = new

1. Start Game–WCF pipe // game. Debugger. Hostとは独自で作ったクラス // 今から起動させるアプリケーションのこと Service. Host = new System. Service. Model. Service. Host(game. Debugger. Host); Service. Host. Add. Service. Endpoint( typeof(IGame. Debugger. Host), new Net. Named. Pipe. Binding(Net. Named. Pipe. Security. Mode. None) { Max. Received. Message. Size = int. Max. Value }, address); Service. Host. Open(); var start. Info = new Process. Start. Info{ File. Name = game. Host. Assembly, Arguments = "—-host=net. pipe: //localhost/xxx", Working. Directory = working. Directory, Create. No. Window = true, Use. Shell. Execute = false, Redirect. Standard. Output = true, Redirect. Standard. Error = true, }; var process = new System. Diabnostics. Process { Start. Info = start. Info }; process. Start(); WCF pipe通信

2. Watch Project 3. Change Project

2. Watch Project 3. Change Project

2. / 3. Watch Directory File. System. Watcher public Watcher(string path) { watcher =

2. / 3. Watch Directory File. System. Watcher public Watcher(string path) { watcher = new File. System. Watcher(){ Path = path, Notify. Filter = ( Notify. Filters. Last. Write | Notify. Filters. File. Name | Notify. Filters. Directory. Name), Include. Subdirectories = true, Filter = "" }; watcher. Begin. Init(); watcher. Changed += On. Modified; watcher. Created += On. Modified; watcher. Deleted += On. Modified; watcher. Renamed += On. Modified; watcher. End. Init(); }

4. Recompile

4. Recompile

4. Recompile – 差分コードの確認 Roslyn/MSBuild Project Part 0 -csproj Player. cs Part 1 -csproj

4. Recompile – 差分コードの確認 Roslyn/MSBuild Project Part 0 -csproj Player. cs Part 1 -csproj Enemy. cs Player. dll Player. pdb Enemy. dll Enemy. pdb 初回ビルド時のソースコードと 2回目にビルドしたソースコードの差分をチェックする

5. Send Assembly

5. Send Assembly

5. Send Assembly– 差分DLLの送信 DLL Hot Swap. NETだから可能な技術 Paradox Game Studio // Target(Running EXE)に送って実行させる(DLLのSwap)

5. Send Assembly– 差分DLLの送信 DLL Hot Swap. NETだから可能な技術 Paradox Game Studio // Target(Running EXE)に送って実行させる(DLLのSwap) // Game Studioは何もしていない debug. Target. Assembly. Load. Raw( loaded. Project. PE, loaded. Project. PDB); // 実際にSwapを実行しているのは、Running EXE側 public Assembly. Load. Raw(byte[] pe. Data, byte[] pdb. Data) { return Assembly. Load(pe. Data, pdb. Data); } Running EXE https: //github. com/Silicon. Studio/paradox/blob/master/sources/engine/Silico n. Studio. Paradox. Debugger/Game. Debugger. Target. cs

6. Swap Script Compornent from Game Studio

6. Swap Script Compornent from Game Studio

6. Swap Script Component DLLを読み込んだだけでは更新されない →その処理は通っていない 単に初期化処理を行う(通常のC#の話) Running EXE 既に読み込んであるAssetデータには何もしない ParadoxのScript. Compornentのみリロードする ※ Script細かいルールを独自に決めている

6. Swap Script Component DLLを読み込んだだけでは更新されない →その処理は通っていない 単に初期化処理を行う(通常のC#の話) Running EXE 既に読み込んであるAssetデータには何もしない ParadoxのScript. Compornentのみリロードする ※ Script細かいルールを独自に決めている • BMGなどはリロードしたくない →ユーザがAttributeで指定 • シリアライズ対象はpublicのみ…などなど https: //github. com/Silicon. Studio/paradox/blob/master/sources/engine/Silicon. Studio. Paradox. Debugger/D ebugger/Live. Assembly. Reloader. cs

Live Scripting Paradox Game Studio Roslyn利用 Visual Studio Running EXE

Live Scripting Paradox Game Studio Roslyn利用 Visual Studio Running EXE

Paradox オンラインアンケート実施 中 https: //www. surveymonkey. com/r/YGD 8 VYH

Paradox オンラインアンケート実施 中 https: //www. surveymonkey. com/r/YGD 8 VYH