-
-
Save gsw945/f2c03286bf498397e4b008575607b234 to your computer and use it in GitHub Desktop.
Converts old UNET code into modern Mirror Networking code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Mirror Network Migration Tool | |
// Written by M. Coburn (@coburn64 on Twitter/SoftwareGuy on Github) | |
// This file is part of Mirror Networking by Coburn64, Lymdun, vis2k and Paul (goldbug). | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Text; | |
using System.Text.RegularExpressions; | |
using UnityEditor; | |
using UnityEngine; | |
// This is an editor script and should not be referenced in Runtime binaries. | |
namespace Mirror.MigrationUtilities | |
{ | |
/// <summary> | |
/// A migration tool that will help migrate stock UNET code to Mirror code. | |
/// </summary> | |
public static class MirrorNetworkMigrator | |
{ | |
// Private variables that don't need to be modified. | |
static string scriptExtension = "*.cs"; | |
static string[] knownIncompatibleRegexes = { | |
"SyncListStruct", // this probably needs improvement but i didn't want to duplicate lines of code | |
@"\[Command([^\],]*)\]", // Commands over non-reliable channels | |
@"\[ClientRpc([^\],]*)\]", // ClientRPCs over non-reliable channels | |
@"\[TargetRpc([^\],]*)\]", // TargetRPCs over non-reliable channels | |
@"\[SyncEvent([^\],]*)\]" // SyncEvents (over non-reliable channels) - seriously? | |
}; | |
static string[] knownCompatibleReplacements = { | |
"SyncListSTRUCT", // because mirror's version is moar bettah. | |
"[Command]", | |
"[ClientRpc]", | |
"[TargetRpc]", | |
"[SyncEvent]" | |
}; | |
static int filesModified = 0; | |
static string scriptBuffer = string.Empty; | |
static MatchCollection matches; | |
// Logic portion begins below. | |
[MenuItem("Tools/Mirror/Migrate from UNET")] | |
public static void Mirror_Migration_Tool() | |
{ | |
// Safeguard in case a developer goofs up | |
if (knownIncompatibleRegexes.Length != knownCompatibleReplacements.Length) | |
{ | |
Debug.Log("[Mirror Migration Tool] BUG DETECTED: Regexes to search for DO NOT match the Regex Replacements. Cannot continue."); | |
return; | |
} | |
// Display a welcome dialog. | |
if (EditorUtility.DisplayDialog("Mirror Network Migration Tool", "Welcome to the Migration Tool for Mirror Networking. " + | |
"This tool will convert your existing UNET code into the Mirror equivalent code.\n\nBefore we begin, we STRONGLY " + | |
"recommend you take a full backup of your project as this tool is not perfect.\n\nWhile it does not attempt to " + | |
"purposefully trash your network scripts, it could break your project. Be smart and BACKUP NOW.", | |
"I'm good.", "I'll backup first.")) { | |
// User accepted the risks - go ahead! | |
MigrationTool_DoActualMigration(); | |
// Cleanup after yourself. | |
MigrationTool_Cleanup(); | |
// Refresh the asset database, because sometimes Unity will be lazy about it. | |
AssetDatabase.Refresh(); | |
} else { | |
EditorUtility.DisplayDialog("Aborted", "You opted to abort the migration process. Please come back once you've taken a backup.", "Got it"); | |
return; | |
} | |
} | |
private static void MigrationTool_DoActualMigration() | |
{ | |
// Place holder for the assets folder location. | |
string assetsFolder = Application.dataPath; | |
// List structure for the CSharp files. | |
List<string> filesToScanAndModify = new List<string>(); | |
// Be verbose and say what's happening. | |
Debug.Log("[Mirror Migration Tool] Determined your asset folder is at: " + assetsFolder); | |
Debug.Log("[Mirror Migration Tool] Scanning your C# scripts... This might take a moment."); | |
// Now we scan the directory... | |
try | |
{ | |
DirectoryInfo dirInfo = new DirectoryInfo(assetsFolder); | |
// For every entry in this structure add it to the list. | |
// SearchOption.AllDirectories will traverse the directory stack | |
foreach (FileInfo potentialFile in dirInfo.GetFiles(scriptExtension, SearchOption.AllDirectories)) | |
{ | |
// DEBUG ONLY. This will cause massive Unity Console Spammage! | |
// Debug.Log("[Mirror Migration Tool] DEBUG: Scanned " + potentialFile.FullName); | |
filesToScanAndModify.Add(potentialFile.FullName); | |
} | |
// Final chance to abort. | |
if (!EditorUtility.DisplayDialog("Continue?", string.Format("We've found {0} file(s) that may need updating. Depending on your hardware and storage, " + | |
"this might take a while. Do you wish to continue the process?", filesToScanAndModify.Count), "Go ahead!", "Abort")) | |
{ | |
EditorUtility.DisplayDialog("Aborted", "You opted to abort the migration process. Please come back once you're ready to migrate.", "Got it"); | |
return; | |
} | |
// Okay, let's do this! | |
MigrationTool_FileProcessor(filesToScanAndModify); | |
Debug.Log("[Mirror Migration Tool] Processed (and patched, if required) " + filesModified + " files"); | |
EditorUtility.DisplayDialog("Migration complete.", "Congratulations, you should now be Mirror Network ready.\n\n" + | |
"Thank you for using Mirror and Telepathy Networking Stack for Unity!\n\nPlease don't forget to drop by the GitHub " + | |
"repository to keep up to date and the Discord server if you have any problems. Have fun!", "Awesome"); | |
return; | |
} catch (System.Exception ex) | |
{ | |
EditorUtility.DisplayDialog("Oh no!", "An exception occurred. If you think this is a Mirror Networking bug, please file a bug report on the GitHub repository." + | |
"It could also be a logic bug in the Migration Tool itself. I encountered the following exception:\n\n" + ex.ToString(), "Okay"); | |
MigrationTool_Cleanup(); | |
return; | |
} | |
} | |
private static void MigrationTool_FileProcessor(List<string> filesToProcess) | |
{ | |
StreamReader sr; | |
StreamWriter sw; | |
foreach(string file in filesToProcess) | |
{ | |
try | |
{ | |
// Open and load it into the script buffer. | |
using(sr = new StreamReader(file)) | |
{ | |
scriptBuffer = sr.ReadToEnd(); | |
sr.Close(); | |
} | |
// Get outta here, UnityEngine.Networking ! | |
scriptBuffer = scriptBuffer.Replace("using UnityEngine.Networking;", "using Mirror;"); | |
// Work our magic. | |
for (int i = 0; i < knownIncompatibleRegexes.Length; i++) | |
{ | |
matches = Regex.Matches(scriptBuffer, knownIncompatibleRegexes[i]); | |
if (matches.Count > 0) | |
{ | |
// It was successful - replace it. | |
scriptBuffer = Regex.Replace(scriptBuffer, knownIncompatibleRegexes[i], knownCompatibleReplacements[i]); | |
} | |
} | |
// Be extra gentle with some like NetworkSettings directives. | |
matches = Regex.Matches(scriptBuffer, @"NetworkSettings\(([^\)]*)\)"); | |
// A file could have more than one NetworkSettings... better to just do the whole lot. | |
// We don't know what the developer might be doing. | |
if (matches.Count > 0) { | |
for (int i = 0; i < matches.Count; i++) | |
{ | |
Match nsm = Regex.Match(matches[i].ToString(), @"(?<=\().+?(?=\))"); | |
if (nsm.Success) | |
{ | |
string[] netSettingArguments = nsm.ToString().Split(','); | |
if (netSettingArguments.Length > 1) | |
{ | |
string patchedNetSettings = string.Empty; | |
int a = 0; | |
foreach (string argument in netSettingArguments) | |
{ | |
// Increment a, because that's how many elements we've looked at. | |
a++; | |
// If it contains the offender, just continue, don't do anything. | |
if (argument.Contains("channel")) continue; | |
// If it doesn't then add it to our new string. | |
patchedNetSettings += argument.Trim(); | |
if (a < netSettingArguments.Length) patchedNetSettings += ", "; | |
} | |
// a = netSettingArguments.Length; patch it up and there we go. | |
scriptBuffer = Regex.Replace(scriptBuffer, nsm.Value, patchedNetSettings); | |
} else { | |
// Replace it. | |
if (netSettingArguments[0].Contains("channel")) | |
{ | |
// Don't touch this. | |
scriptBuffer = scriptBuffer.Replace(string.Format("[{0}]", matches[i].Value), string.Empty); | |
} | |
// DONE! | |
} | |
} | |
} | |
} | |
// Backup the old files for safety. | |
// The user can delete them later. | |
if(!File.Exists(file + ".bak")) File.Copy(file, file + ".bak"); | |
// Now the job is done, we want to write the data out to disk... | |
using(sw = new StreamWriter(file, false, Encoding.UTF8)) | |
{ | |
sw.WriteLine(scriptBuffer); | |
sw.Close(); | |
} | |
// Increment the modified counter for statistics. | |
filesModified++; | |
} catch (System.Exception e) { | |
// Kaboom, this tool ate something it shouldn't have. | |
Debug.LogError(string.Format("[Mirror Migration Tool] Encountered an exception processing {0}:\n{1}", file, e.ToString())); | |
} | |
} | |
} | |
/// <summary> | |
/// Cleans up after the migration tool is completed or has failed. | |
/// </summary> | |
private static void MigrationTool_Cleanup() { | |
scriptBuffer = string.Empty; | |
matches = null; | |
filesModified = 0; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment