This commit is contained in:
Даниил Заикин
2026-06-17 20:44:53 +03:00
parent 9d153773c2
commit b133e7c656
1880 changed files with 244545 additions and 0 deletions
@@ -0,0 +1,16 @@
#if !QC_DISABLED && !QC_DISABLE_BUILTIN_ALL && !QC_DISABLE_BUILTIN_EXTRA
using UnityEngine;
namespace QFSW.QC.Extras
{
public static class ApplicationCommands
{
[Command("quit", "Quits the player application")]
[CommandPlatform(Platform.AllPlatforms ^ (Platform.EditorPlatforms | Platform.WebGLPlayer))]
private static void Quit()
{
Application.Quit();
}
}
}
#endif
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e9da7f85fdcb033409727f504fdda906
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,26 @@
#if !QC_DISABLED && !QC_DISABLE_BUILTIN_ALL && !QC_DISABLE_BUILTIN_EXTRA
using System;
using System.Collections;
using UnityEngine;
namespace QFSW.QC.Extras
{
[AddComponentMenu("")]
public class CoroutineCommands : MonoBehaviour
{
[Command("start-coroutine", "starts the supplied command as a coroutine", MonoTargetType.Singleton)]
private void StartCoroutineCommand(string coroutineCommand)
{
object coroutineReturn = QuantumConsoleProcessor.InvokeCommand(coroutineCommand);
if (coroutineReturn is IEnumerator)
{
StartCoroutine(coroutineReturn as IEnumerator);
}
else
{
throw new ArgumentException($"{coroutineCommand} is not a coroutine");
}
}
}
}
#endif
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1a0d171dbb1da05489c852d95745226f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,115 @@
#if UNITY_EDITOR && !QC_DISABLED && !QC_DISABLE_BUILTIN_ALL && !QC_DISABLE_BUILTIN_EXTRA
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace QFSW.QC.Extras
{
internal static class EditorCommands
{
private static IEnumerable<GameObject> LoadPrefabs(string prefabName, params PrefabAssetType[] prefabTypes)
{
string filter = $"{prefabName} t:GameObject";
string[] guids = AssetDatabase.FindAssets(filter);
foreach (string guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
GameObject obj = AssetDatabase.LoadAssetAtPath<GameObject>(path);
if (obj.name == prefabName)
{
if (prefabTypes.Contains(PrefabUtility.GetPrefabAssetType(obj)))
{
yield return obj;
}
}
}
}
private static T ForceSingle<T>(IEnumerable<T> stream, string errorMessage, string warningMessage)
{
bool singleFound = false;
T single = default;
foreach (T item in stream)
{
if (singleFound)
{
Debug.LogWarning(warningMessage);
break;
}
single = item;
singleFound = true;
}
if (singleFound)
{
return single;
}
else
{
throw new ArgumentException(errorMessage);
}
}
private static GameObject LoadPrefab(string prefabName)
{
IEnumerable<GameObject> prefabs = LoadPrefabs(prefabName, PrefabAssetType.Regular, PrefabAssetType.Variant);
return ForceSingle(prefabs, $"No prefab with the name {prefabName} could be found.", $"Multiple prefabs with the name {prefabName} were found");
}
private static GameObject LoadModel(string modelName)
{
IEnumerable<GameObject> models = LoadPrefabs(modelName, PrefabAssetType.Model);
return ForceSingle(models, $"No model with the name {modelName} could be found.", $"Multiple models with the name {modelName} were found");
}
[Command("instantiate-prefab", "Instantiates a GameObject from the specified prefab", Platform.EditorPlatforms)]
private static void InstantiateGOFromPrefab(
[CommandParameterDescription("The name of the prefab to instantiate a copy of.")]string prefabName,
[CommandParameterDescription("The position of the instantiated GameObject.")]Vector3 position,
[CommandParameterDescription("The rotation of the instantiated GameObject.")]Quaternion rotation)
{
GameObject.Instantiate(LoadPrefab(prefabName), position, rotation);
}
[Command("instantiate-prefab", "Instantiates a GameObject from the specified prefab", Platform.EditorPlatforms)]
private static void InstantiateGOFromPrefab(string prefabName, Vector3 position)
{
GameObject prefab = LoadPrefab(prefabName);
GameObject.Instantiate(prefab, position, prefab.transform.rotation);
}
[Command("instantiate-prefab", "Instantiates a GameObject from the specified prefab", Platform.EditorPlatforms)]
private static void InstantiateGOFromPrefab(string prefabName)
{
GameObject.Instantiate(LoadPrefab(prefabName));
}
[Command("instantiate-model", "Instantiates a GameObject from the specified model prefab", Platform.EditorPlatforms)]
private static void InstantiateGOFromModelPrefab(
[CommandParameterDescription("The name of the model to instantiate a copy of.")]string modelName,
[CommandParameterDescription("The position of the instantiated GameObject.")]Vector3 position,
[CommandParameterDescription("The rotation of the instantiated GameObject.")]Quaternion rotation)
{
GameObject.Instantiate(LoadModel(modelName), position, rotation);
}
[Command("instantiate-model", "Instantiates a GameObject from the specified model prefab", Platform.EditorPlatforms)]
private static void InstantiateGOFromModelPrefab(string modelName, Vector3 position)
{
GameObject prefab = LoadModel(modelName);
GameObject.Instantiate(prefab, position, prefab.transform.rotation);
}
[Command("instantiate-model", "Instantiates a GameObject from the specified model prefab", Platform.EditorPlatforms)]
private static void InstantiateGOFromModelPrefab(string modelName)
{
GameObject.Instantiate(LoadModel(modelName));
}
}
}
#endif
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 15cc172f9ab7e744ebb12f0ac6965c79
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,33 @@
#if !QC_DISABLED && !QC_DISABLE_BUILTIN_ALL && !QC_DISABLE_BUILTIN_EXTRA
using System.IO;
using System.Threading.Tasks;
namespace QFSW.QC.Extras
{
public static class FileCommands
{
[Command("write-file", Platform.AllPlatforms ^ Platform.WebGLPlayer)]
[CommandDescription("Writes the provided data to a file at the provided path")]
private static async Task WriteFile(string path, string data)
{
FileInfo file = new FileInfo(path);
file.Directory?.Create();
using (StreamWriter writer = new StreamWriter(path))
{
await writer.WriteAsync(data);
}
}
[Command("read-file", Platform.AllPlatforms ^ Platform.WebGLPlayer)]
[CommandDescription("Reads the contents of the file at the provided path")]
private static string ReadFile(string path)
{
using (StreamReader reader = new StreamReader(path))
{
return reader.ReadToEnd();
}
}
}
}
#endif
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4e0016aee4d4b3348a733339a47a9bab
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,30 @@
#if !QC_DISABLED && !QC_DISABLE_BUILTIN_ALL && !QC_DISABLE_BUILTIN_EXTRA
using UnityEngine;
namespace QFSW.QC.Extras
{
public static class GraphicsCommands
{
[Command("max-fps", "the maximum FPS imposed on the application. Set to -1 for unlimited.")]
private static int MaxFPS
{
get => Application.targetFrameRate;
set => Application.targetFrameRate = value;
}
[Command("vsync", "enables or disables vsync for the application.")]
private static bool VSync
{
get => QualitySettings.vSyncCount > 0;
set => QualitySettings.vSyncCount = value ? 1 : 0;
}
[Command("msaa", "Gets or sets the number of msaa samples in use. Valid values are 0, 2, 4 and 8.")]
private static int MSAA
{
get => QualitySettings.antiAliasing;
set => QualitySettings.antiAliasing = value;
}
}
}
#endif
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7f64c9104d262446583f03a81c2947fe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,50 @@
#if !QC_DISABLED && !QC_DISABLE_BUILTIN_ALL && !QC_DISABLE_BUILTIN_EXTRA
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace QFSW.QC.Extras
{
[CommandPrefix("http.")]
public static class HttpCommands
{
private static readonly HttpClient _client = new HttpClient();
[Command("get", "Sends a GET request to the specified URL.")]
private static async Task<string> Get(string url)
{
HttpResponseMessage response = await _client.GetAsync(url);
return await response.Content.ReadAsStringAsync();
}
[Command("delete", "Sends a DELETE request to the specified URL.")]
private static async Task<string> Delete(string url)
{
HttpResponseMessage response = await _client.DeleteAsync(url);
return await response.Content.ReadAsStringAsync();
}
[Command("post", "Sends a POST request to the specified URL. " +
"A body may be sent with the request, with a default mediaType of text/plain.")]
private static async Task<string> Post(string url, string content = "", string mediaType = "text/plain")
{
HttpContent body = new StringContent(content, Encoding.Default, mediaType);
HttpResponseMessage response = await _client.PostAsync(url, body);
return await response.Content.ReadAsStringAsync();
}
[Command("put", "Sends a PUT request to the specified URL. " +
"A body may be sent with the request, with a default mediaType of text/plain.")]
private static async Task<string> Put(string url, string content = "", string mediaType = "text/plain")
{
HttpContent body = new StringContent(content, Encoding.Default, mediaType);
HttpResponseMessage response = await _client.PutAsync(url, body);
return await response.Content.ReadAsStringAsync();
}
}
}
#endif
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bc59abfc03e45b542947d9dc45bd1e72
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,100 @@
#if !QC_DISABLED && !QC_DISABLE_BUILTIN_ALL && !QC_DISABLE_BUILTIN_EXTRA
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace QFSW.QC.Extras
{
public class KeyBinderModule : MonoBehaviour
{
private readonly struct Binding
{
public readonly KeyCode Key;
public readonly string Command;
public Binding(KeyCode key, string command)
{
Key = key;
Command = command;
}
}
private readonly List<Binding> _bindings = new List<Binding>();
private QuantumConsole _consoleInstance;
private bool _blocked = false;
private void BlockInput() { _blocked = true; }
private void UnblockInput() { _blocked = false; }
private void BindToConsoleInstance()
{
if (!_consoleInstance) { _consoleInstance = FindObjectOfType<QuantumConsole>(); }
if (_consoleInstance)
{
_consoleInstance.OnActivate += BlockInput;
_consoleInstance.OnDeactivate += UnblockInput;
_blocked = _consoleInstance.IsActive;
}
else
{
UnblockInput();
}
}
private void Awake()
{
BindToConsoleInstance();
}
private void Update()
{
if (!_blocked)
{
foreach (Binding binding in _bindings)
{
if (InputHelper.GetKeyDown(binding.Key))
{
try
{
QuantumConsoleProcessor.InvokeCommand(binding.Command);
}
catch (System.Exception e) { Debug.LogException(e); }
}
}
}
}
[Command("bind", MonoTargetType.Singleton)]
[CommandDescription("Binds a given command to a given key, so that every time the key is pressed, the command is invoked.")]
private void AddBinding(KeyCode key, string command)
{
_bindings.Add(new Binding(key, command));
}
[Command("unbind", MonoTargetType.Singleton)]
[CommandDescription("Removes every binding for the given key")]
private void RemoveBindings(KeyCode key)
{
_bindings.RemoveAll(x => x.Key == key);
}
[Command("unbind-all", MonoTargetType.Singleton)]
[CommandDescription("Unbinds every existing key binding")]
private void RemoveAllBindings()
{
_bindings.Clear();
}
[Command("display-bindings", MonoTargetType.Singleton)]
[CommandDescription("Displays all existing bindings on the key binder")]
private IEnumerable<object> DisplayAllBindings()
{
foreach (Binding binding in _bindings.OrderBy(x => x.Key))
{
yield return new KeyValuePair<KeyCode, string>(binding.Key, binding.Command);
}
}
}
}
#endif
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fb5d29f1db8b3ac41bea9c4355331a1f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,251 @@
#if !QC_DISABLED && !QC_DISABLE_BUILTIN_ALL && !QC_DISABLE_BUILTIN_EXTRA
using QFSW.QC.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace QFSW.QC.Extras
{
public static class MegaCommands
{
private static readonly QuantumSerializer Serializer = new QuantumSerializer();
private static readonly QuantumParser Parser = new QuantumParser();
private static MethodInfo[] ExtractMethods(Type type, string name)
{
const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod |
BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
MethodInfo[] methods = type.GetMethods(flags).Where(x => x.Name == name).ToArray();
if (!methods.Any())
{
PropertyInfo property = type.GetProperty(name, flags);
if (property != null)
{
methods = new[] {property.GetMethod, property.SetMethod}.Where(x => x != null).ToArray();
if (methods.Length > 0)
{
return methods;
}
}
throw new ArgumentException($"No method or property named {name} could be found in class {Serializer.SerializeFormatted(type)}");
}
return methods;
}
private static string GenerateSignature(MethodInfo method)
{
IEnumerable<string> paramParts = method.GetParameters()
.Select(x => (x.Name, x.ParameterType))
.Select(x => $"{x.ParameterType.GetDisplayName()} {x.Name}");
string paramSignature = string.Join(", ", paramParts);
return $"{method.Name}({paramSignature})";
}
private static MethodInfo GetIdealOverload(MethodInfo[] methods, bool isStatic, int argc)
{
methods = methods.Where(x => x.IsStatic == isStatic).ToArray();
if (methods.Length == 0)
{
throw new ArgumentException($"No {(isStatic ? "static" : "non-static")} overloads could be found.");
}
if (methods.Length == 1)
{
return methods[0];
}
methods = methods.Where(x => !x.IsGenericMethod).ToArray();
if (methods.Length == 0)
{
throw new ArgumentException("Generic methods are not supported.");
}
MethodInfo[] argcMatches = methods.Where(x => x.GetParameters().Length == argc).ToArray();
if (argcMatches.Length == 1)
{
return argcMatches[0];
}
else if (argcMatches.Length == 0)
{
IEnumerable<string> signatures = methods.Select(GenerateSignature);
string combinedSignatures = string.Join("\n", signatures);
throw new ArgumentException($"No overloads with {argc} arguments were found. the following overloads are available:\n{combinedSignatures}");
}
else
{
IEnumerable<string> signatures = argcMatches.Select(GenerateSignature);
string combinedSignatures = string.Join("\n", signatures);
throw new ArgumentException($"Multiple overloads with the same argument count were found: please specify the types explicitly.\n{combinedSignatures}");
}
}
private static MethodInfo GetIdealOverload(MethodInfo[] methods, bool isStatic, Type[] argTypes)
{
// Exact matching
foreach (MethodInfo method in methods)
{
if (method.IsStatic == isStatic)
{
IEnumerable<Type> methodParamTypes = method.GetParameters().Select(x => x.ParameterType);
if (methodParamTypes.SequenceEqual(argTypes))
{
return method;
}
}
}
// Polymorphic matching
foreach (MethodInfo method in methods)
{
if (method.IsStatic == isStatic)
{
ParameterInfo[] methodParams = method.GetParameters();
if (methodParams.Length == argTypes.Length)
{
bool isMatch = methodParams
.Select(x => x.ParameterType)
.Zip(argTypes, (x, y) => (x, y))
.All(pair => pair.x.IsAssignableFrom(pair.y));
if (isMatch)
{
return method;
}
}
}
}
throw new ArgumentException("No overload with the supplied argument types could be found.");
}
private static object[] CreateArgs(MethodInfo method, string[] rawArgs)
{
ParameterInfo[] methodParams = method.GetParameters();
Type[] argTypes = methodParams.Select(x => x.ParameterType).ToArray();
return CreateArgs(method, argTypes, rawArgs);
}
private static object[] CreateArgs(MethodInfo method, Type[] argTypes, string[] rawArgs)
{
ParameterInfo[] methodParams = method.GetParameters();
int defaultArgs = methodParams.Count(x => x.HasDefaultValue);
if (rawArgs.Length < argTypes.Length - defaultArgs || rawArgs.Length > argTypes.Length)
{
throw new ArgumentException($"Incorrect number ({rawArgs.Length}) of arguments supplied for {Serializer.SerializeFormatted(method.DeclaringType)}.{method.Name}" +
$", expected {argTypes.Length}");
}
object[] parsedArgs = new object[argTypes.Length];
for (int i = 0; i < parsedArgs.Length; i++)
{
if (i < rawArgs.Length)
{
parsedArgs[i] = Parser.Parse(rawArgs[i], argTypes[i]);
}
else
{
parsedArgs[i] = methodParams[i].DefaultValue;
}
}
return parsedArgs;
}
private static object InvokeAndUnwrapException(this MethodInfo method, object[] args)
{
try
{
return method.Invoke(null, args);
}
catch (TargetInvocationException e)
{
throw e.InnerException;
}
}
private static object InvokeAndUnwrapException(this MethodInfo method, IEnumerable<object> targets, object[] args)
{
try
{
return InvocationTargetFactory.InvokeOnTargets(method, targets, args);
}
catch (TargetInvocationException e)
{
throw e.InnerException;
}
}
[Command("call-static")]
private static object CallStatic(Type classType, string funcName)
{
return CallStatic(classType, funcName, Array.Empty<string>());
}
[Command("call-static")]
private static object CallStatic(Type classType, string funcName, string[] args)
{
MethodInfo[] methods = ExtractMethods(classType, funcName);
MethodInfo method = GetIdealOverload(methods, true, args.Length);
object[] parsedArgs = CreateArgs(method, args);
return method.InvokeAndUnwrapException(parsedArgs);
}
[Command("call-static")]
[CommandDescription("Invokes the specified static method or property with the provided arguments. Provide [argTypes] if there are ambiguous overloads")]
private static object CallStatic(
[CommandParameterDescription("Namespace qualified typename of the class.")] Type classType,
[CommandParameterDescription("Name of the method or property.")] string funcName,
[CommandParameterDescription("The arguments for the function call.")] string[] args,
[CommandParameterDescription("The types of the arguments to resolve ambiguous overloads.")] Type[] argTypes)
{
MethodInfo[] methods = ExtractMethods(classType, funcName);
MethodInfo method = GetIdealOverload(methods, true, argTypes);
object[] parsedArgs = CreateArgs(method, argTypes, args);
return method.InvokeAndUnwrapException(parsedArgs);
}
[Command("call-instance")]
private static object CallInstance(Type classType, string funcName, MonoTargetType targetType)
{
return CallInstance(classType, funcName, targetType, Array.Empty<string>());
}
[Command("call-instance")]
private static object CallInstance(Type classType, string funcName, MonoTargetType targetType, string[] args)
{
MethodInfo[] methods = ExtractMethods(classType, funcName);
MethodInfo method = GetIdealOverload(methods, false, args.Length);
object[] parsedArgs = CreateArgs(method, args);
IEnumerable<object> targets = InvocationTargetFactory.FindTargets(classType, targetType);
return method.InvokeAndUnwrapException(targets, parsedArgs);
}
[Command("call-instance")]
[CommandDescription("Invokes the specified non-static method or property with the provided arguments. Provide [argTypes] if there are ambiguous overloads")]
private static object CallInstance(
[CommandParameterDescription("Namespace qualified typename of the class.")] Type classType,
[CommandParameterDescription("Name of the method or property.")] string funcName,
[CommandParameterDescription("The MonoTargetType used to find the target instances.")] MonoTargetType targetType,
[CommandParameterDescription("The arguments for the function call.")] string[] args,
[CommandParameterDescription("The types of the arguments to resolve ambiguous overloads.")] Type[] argTypes)
{
MethodInfo[] methods = ExtractMethods(classType, funcName);
MethodInfo method = GetIdealOverload(methods, false, argTypes);
object[] parsedArgs = CreateArgs(method, argTypes, args);
IEnumerable<object> targets = InvocationTargetFactory.FindTargets(classType, targetType);
return method.InvokeAndUnwrapException(targets, parsedArgs);
}
}
}
#endif
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0ed09ce9eedb9c04fb9915469f53d71a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
{
"name": "QFSW.QC.Extras",
"references": [
"QFSW.QC"
],
"includePlatforms": [],
"excludePlatforms": []
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: dbe7cf6698bd54a63bc00412d71f8b48
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,95 @@
#if !QC_DISABLED && !QC_DISABLE_BUILTIN_ALL && !QC_DISABLE_BUILTIN_EXTRA
using QFSW.QC.Suggestors.Tags;
using QFSW.QC.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace QFSW.QC.Extras
{
public static class SceneCommands
{
private static async Task PollUntilAsync(int pollInterval, Func<bool> predicate)
{
while (!predicate())
{
await Task.Delay(pollInterval);
}
}
[Command("load-scene", "loads a scene by name into the game")]
private static async Task LoadScene(
[SceneName]
string sceneName,
[CommandParameterDescription("'Single' mode replaces the current scene with the new scene, whereas 'Additive' merges them")]
LoadSceneMode loadMode = LoadSceneMode.Single)
{
AsyncOperation asyncOperation = SceneUtilities.LoadSceneAsync(sceneName, loadMode);
await PollUntilAsync(16, () => asyncOperation.isDone);
}
[Command("load-scene-index", "loads a scene by index into the game")]
private static async Task LoadScene(int sceneIndex,
[CommandParameterDescription("'Single' mode replaces the current scene with the new scene, whereas 'Additive' merges them")]LoadSceneMode loadMode = LoadSceneMode.Single)
{
AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(sceneIndex, loadMode);
await PollUntilAsync(16, () => asyncOperation.isDone);
}
[Command("unload-scene", "unloads a scene by name")]
private static async Task UnloadScene([SceneName(LoadedOnly = true)] string sceneName)
{
AsyncOperation asyncOperation = SceneManager.UnloadSceneAsync(sceneName);
await PollUntilAsync(16, () => asyncOperation.isDone);
}
[Command("unload-scene-index", "unloads a scene by index")]
private static async Task UnloadScene(int sceneIndex)
{
AsyncOperation asyncOperation = SceneManager.UnloadSceneAsync(sceneIndex);
await PollUntilAsync(16, () => asyncOperation.isDone);
}
[Command("all-scenes", "gets the name and index of every scene included in the build")]
private static IEnumerable<KeyValuePair<int, string>> GetAllScenes()
{
int sceneIndex = 0;
foreach (string sceneName in SceneUtilities.GetAllSceneNames())
{
yield return new KeyValuePair<int, string>(sceneIndex++, sceneName);
}
}
[Command("loaded-scenes", "gets the name and index of every scene currently loaded")]
private static IEnumerable<KeyValuePair<int, string>> GetLoadedScenes()
{
return SceneUtilities.GetLoadedScenes()
.OrderBy(x => x.buildIndex)
.Select(x => new KeyValuePair<int, string>(x.buildIndex, x.name));
}
[Command("active-scene", "gets the name of the active primary scene")]
private static string GetCurrentScene()
{
Scene scene = SceneManager.GetActiveScene();
return scene.name;
}
[Command("set-active-scene", "sets the active scene to the scene with name 'sceneName'")]
private static void SetActiveScene([SceneName(LoadedOnly = true)] string sceneName)
{
Scene scene = SceneManager.GetSceneByName(sceneName);
if (!scene.isLoaded)
{
throw new ArgumentException($"Scene {sceneName} must be loaded before it can be set active");
}
SceneManager.SetActiveScene(scene);
}
}
}
#endif
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dc7a6d8b121ac49c8a37e3d393a51518
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,74 @@
#if !QC_DISABLED && !QC_DISABLE_BUILTIN_ALL && !QC_DISABLE_BUILTIN_EXTRA
using System.Collections.Generic;
using UnityEngine;
namespace QFSW.QC.Extras
{
public static class ScreenCommands
{
[Command("fullscreen", "fullscreen state of the application.")]
private static bool Fullscreen
{
get => Screen.fullScreen;
set => Screen.fullScreen = value;
}
[Command("screen-dpi", "dpi of the current device's screen.")]
private static float DPI => Screen.dpi;
[Command("screen-orientation", "the orientation of the screen.")]
[CommandPlatform(Platform.MobilePlatforms)]
private static ScreenOrientation Orientation
{
get => Screen.orientation;
set => Screen.orientation = value;
}
[Command("current-resolution", "current resolution of the application or window.")]
private static Resolution GetCurrentResolution()
{
Resolution resolution = new Resolution
{
width = Screen.width,
height = Screen.height,
refreshRate = Screen.currentResolution.refreshRate
};
return resolution;
}
[Command("supported-resolutions", "all resolutions supported by this device in fullscreen mode.")]
[CommandPlatform(Platform.AllPlatforms ^ Platform.WebGLPlayer)]
private static IEnumerable<Resolution> GetSupportedResolutions()
{
foreach (Resolution resolution in Screen.resolutions)
{
yield return resolution;
}
}
[Command("set-resolution")]
private static void SetResolution(int x, int y)
{
SetResolution(x, y, Screen.fullScreen);
}
[Command("set-resolution", "sets the resolution of the current application, optionally setting the fullscreen state too.")]
private static void SetResolution(int x, int y, bool fullscreen)
{
Screen.SetResolution(x, y, fullscreen);
}
[Command("capture-screenshot")]
[CommandDescription("Captures a screenshot and saves it to the supplied file path as a PNG.\n" +
"If superSize is supplied the screenshot will be captured at a higher than native resolution.")]
private static void CaptureScreenshot(
[CommandParameterDescription("The name of the file to save the screenshot in")] string filename,
[CommandParameterDescription("Factor by which to increase resolution")] int superSize = 1
)
{
ScreenCapture.CaptureScreenshot(filename, superSize);
}
}
}
#endif
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 937752cbc170542b8ae4a31a025b7cf2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,16 @@
#if !QC_DISABLED && !QC_DISABLE_BUILTIN_ALL && !QC_DISABLE_BUILTIN_EXTRA
using UnityEngine;
namespace QFSW.QC.Extras
{
public static class TimeCommands
{
[Command("time-scale", "the scale at which time is passing by.")]
private static float TimeScale
{
get => Time.timeScale;
set => Time.timeScale = value;
}
}
}
#endif
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 816d2412b2b594778a0e42b669424332
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,27 @@
#if !QC_DISABLED && !QC_DISABLE_BUILTIN_ALL && !QC_DISABLE_BUILTIN_EXTRA
using System;
using System.Collections.Generic;
namespace QFSW.QC.Extras
{
public static class TypeCommands
{
[Command("enum-info", "gets all of the numeric values and value names for the specified enum type.")]
private static IEnumerable<object> GetEnumInfo(Type enumType)
{
if (!enumType.IsEnum) { throw new ArgumentException($"Supplied type '{enumType}' must be an enum type"); }
Type enumInnerType = enumType.GetEnumUnderlyingType();
Array vals = enumType.GetEnumValues();
for (int i = 0; i < vals.Length; i++)
{
object name = vals.GetValue(i);
object val = Convert.ChangeType(name, enumInnerType);
KeyValuePair<object, object> pair = new KeyValuePair<object, object>(val, name);
yield return pair;
}
}
}
}
#endif
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fa2f2993809854c998bd8a5842582d5c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,163 @@
#if !QC_DISABLED && !QC_DISABLE_BUILTIN_ALL && !QC_DISABLE_BUILTIN_EXTRA
using QFSW.QC.Pooling;
using QFSW.QC.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace QFSW.QC.Extras
{
public static class UtilCommands
{
private static readonly ConcurrentStringBuilderPool _builderPool = new ConcurrentStringBuilderPool();
[Command("get-object-info", "Finds the specified GameObject and displays its transform and component data")]
private static string ExtractObjectInfo(GameObject target)
{
StringBuilder builder = _builderPool.GetStringBuilder();
builder.AppendLine($"Extracted info for object '{target.name}'");
builder.AppendLine("Transform data:");
builder.AppendLine($" - position: {target.transform.position}");
builder.AppendLine($" - rotation: {target.transform.localRotation}");
builder.AppendLine($" - scale: {target.transform.localScale}");
if (target.transform.childCount > 0) { builder.AppendLine($" - child count: {target.transform.childCount}"); }
if (target.transform.parent) { builder.AppendLine($" - parent: {target.transform.parent.name}"); }
Component[] components = target.GetComponents<Component>().OrderBy(x => x.GetType().Name).ToArray();
if (components.Length > 0)
{
builder.AppendLine("Component data:");
for (int i = 0; i < components.Length; i++)
{
int componentCount = 1;
Type componentType = components[i].GetType();
builder.AppendLine($" - {componentType.Name}");
while (i + 1 < components.Length && components[i + 1].GetType() == componentType)
{
componentCount++;
i++;
}
if (componentCount > 1) { builder.Append($" ({componentCount})"); }
}
}
if (target.transform.childCount > 0)
{
builder.AppendLine("Children:");
int childCount = target.transform.childCount;
for (int i = 0; i < childCount; i++)
{
builder.AppendLine($" - {target.transform.GetChild(i).name}");
}
}
return _builderPool.ReleaseAndToString(builder);
}
[Command("get-scene-hierarchy", "Renders the GameObject hierarchy of the currently open scenes")]
private static string GetSceneHierarchy()
{
List<GameObject> objects = new List<GameObject>();
StringBuilder buffer = _builderPool.GetStringBuilder();
foreach (Scene scene in SceneUtilities.GetLoadedScenes())
{
objects.Clear();
scene.GetRootGameObjects(objects);
buffer.AppendLine(scene.name);
GetSceneHierarchy(objects.Select(x => x.transform).ToArray(), 0, buffer, new List<bool>());
}
return _builderPool.ReleaseAndToString(buffer);
}
private static IEnumerable<Transform> GetChildren(this Transform transform)
{
for (int i = 0; i < transform.childCount; i++)
{
yield return transform.GetChild(i);
}
}
private static void GetSceneHierarchy(IList<Transform> roots, int depth, StringBuilder buffer, IList<bool> drawVertical)
{
const char terminalSymbol = '|';
const char verticalSplitSymbol = '|';
const char verticalSymbol = '|';
const char horizontalSymbol = '-';
const int indentation = 3;
for (int i = 0; i < roots.Count; i++)
{
Transform root = roots[i];
for (int j = 0; j < depth; j++)
{
buffer.Append(drawVertical[j] ? verticalSymbol : ' ');
buffer.Append(' ', indentation - 1);
}
bool terminal = i == roots.Count - 1;
drawVertical.Add(!terminal);
buffer.Append(terminal ? terminalSymbol : verticalSplitSymbol);
buffer.Append(horizontalSymbol, indentation - 1);
buffer.AppendLine(root.name);
GetSceneHierarchy(root.GetChildren().ToList(), depth + 1, buffer, drawVertical);
drawVertical.RemoveAt(drawVertical.Count - 1);
}
}
[Command("add-component", "Adds a component of type T to the specified GameObject")]
private static void AddComponent<T>(GameObject target) where T : Component { target.AddComponent<T>(); }
[Command("destroy-component", "Destroys the component of type T on the specified GameObject")]
private static void DestroyComponent<T>(T target) where T : Component { GameObject.Destroy(target); }
[Command("destroy", "Destroys a GameObject")]
private static void DestroyGO(GameObject target) { GameObject.Destroy(target); }
[Command("instantiate", "Instantiates a GameObject")]
private static void InstantiateGO(
[CommandParameterDescription("The original GameObject to instantiate a copy of.")] GameObject original,
[CommandParameterDescription("The position of the instantiated GameObject.")] Vector3 position,
[CommandParameterDescription("The rotation of the instantiated GameObject.")] Quaternion rotation)
{
GameObject.Instantiate(original, position, rotation);
}
[Command("instantiate", "Instantiates a GameObject")]
private static void InstantiateGO(GameObject original, Vector3 position) { GameObject.Instantiate(original).transform.position = position; }
[Command("instantiate", "Instantiates a GameObject")]
private static void InstantiateGO(GameObject original) { GameObject.Instantiate(original); }
[Command("teleport", "Teleports a GameObject")]
private static void TeleportGO(GameObject target, Vector3 position) { target.transform.position = position; }
[Command("teleport-relative", "Teleports a GameObject by a relative offset to its current position")]
private static void TeleportRelativeGO(GameObject target, Vector3 offset) { target.transform.Translate(offset); }
[Command("rotate", "Rotates a GameObject")]
private static void RotateGO(GameObject target, Quaternion rotation) { target.transform.Rotate(rotation.eulerAngles); }
[Command("set-active", "Activates/deactivates a GameObject")]
private static void SetGOActive(GameObject target, bool active) { target.SetActive(active); }
[Command("set-parent", "Sets the parent of the targert transform.")]
private static void SetGOParent(Transform target, Transform parentTarget) { target.SetParent(parentTarget); }
[Command("send-message", "Calls the method named 'methodName' on every MonoBehaviour in the target GameObject")]
private static void SendGOMessage(GameObject target, string methodName) { target.SendMessage(methodName); }
}
}
#endif
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 75e1e5918b90b4de5907e9e5bdf0d9b4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 496cffde696095c439db4ee329062978
folderAsset: yes
timeCreated: 1553955817
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 015e5afa17239334c8f085479673d346
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,153 @@
#if NET_4_6 && !NET_STANDARD_2_0
#define QC_SUPPORTED
#endif
using Mono.CSharp;
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using System.Reflection.Emit;
using System.Text;
#if QC_SUPPORTED
namespace CSharpCompiler
{
public class CodeCompiler : ICodeCompiler
{
static long assemblyCounter = 0;
public CompilerResults CompileAssemblyFromDom(CompilerParameters options, CodeCompileUnit compilationUnit)
{
return CompileAssemblyFromDomBatch(options, new[] { compilationUnit });
}
public CompilerResults CompileAssemblyFromDomBatch(CompilerParameters options, CodeCompileUnit[] ea)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
try
{
return CompileFromDomBatch(options, ea);
}
finally
{
options.TempFiles.Delete();
}
}
private CompilerResults CompileFromDomBatch(CompilerParameters options, CodeCompileUnit[] ea)
{
throw new NotImplementedException("sorry ICodeGenerator is not implemented, feel free to fix it and request merge");
}
public CompilerResults CompileAssemblyFromFile(CompilerParameters options, string fileName)
{
return CompileAssemblyFromFileBatch(options, new[] { fileName });
}
public CompilerResults CompileAssemblyFromFileBatch(CompilerParameters options, string[] fileNames)
{
var settings = ParamsToSettings(options);
foreach (var fileName in fileNames)
{
string path = Path.GetFullPath(fileName);
var unit = new SourceFile(fileName, path, settings.SourceFiles.Count + 1);
settings.SourceFiles.Add(unit);
}
return CompileFromCompilerSettings(settings, options.GenerateInMemory);
}
public CompilerResults CompileAssemblyFromSource(CompilerParameters options, string source)
{
return CompileAssemblyFromSourceBatch(options, new[] { source });
}
public CompilerResults CompileAssemblyFromSourceBatch(CompilerParameters options, string[] sources)
{
var settings = ParamsToSettings(options);
int i = 0;
foreach (var _source in sources)
{
var source = _source;
Func<Stream> getStream = () => { return new MemoryStream(Encoding.UTF8.GetBytes(source ?? "")); };
var fileName = i.ToString();
var unit = new SourceFile(fileName, fileName, settings.SourceFiles.Count + 1, getStream);
settings.SourceFiles.Add(unit);
i++;
}
return CompileFromCompilerSettings(settings, options.GenerateInMemory);
}
CompilerResults CompileFromCompilerSettings(CompilerSettings settings, bool generateInMemory)
{
var compilerResults = new CompilerResults(new TempFileCollection(Path.GetTempPath()));
var driver = new CustomDynamicDriver(new CompilerContext(settings, new CustomReportPrinter(compilerResults)));
AssemblyBuilder outAssembly = null;
try
{
driver.Compile(out outAssembly, AppDomain.CurrentDomain, generateInMemory);
}
catch (Exception e)
{
compilerResults.Errors.Add(new CompilerError()
{
IsWarning = false,
ErrorText = e.Message,
});
}
compilerResults.CompiledAssembly = outAssembly;
return compilerResults;
}
CompilerSettings ParamsToSettings(CompilerParameters parameters)
{
var settings = new CompilerSettings();
foreach (var assembly in parameters.ReferencedAssemblies) settings.AssemblyReferences.Add(assembly);
settings.Encoding = System.Text.Encoding.UTF8;
settings.GenerateDebugInfo = parameters.IncludeDebugInformation;
settings.MainClass = parameters.MainClass;
settings.Platform = Platform.AnyCPU;
settings.StdLibRuntimeVersion = RuntimeVersion.v4;
if (parameters.GenerateExecutable)
{
settings.Target = Target.Exe;
settings.TargetExt = ".exe";
}
else
{
settings.Target = Target.Library;
settings.TargetExt = ".dll";
}
if (parameters.GenerateInMemory) settings.Target = Target.Library;
if (string.IsNullOrEmpty(parameters.OutputAssembly))
{
parameters.OutputAssembly = settings.OutputFile = "DynamicAssembly_" + assemblyCounter + settings.TargetExt;
assemblyCounter++;
}
settings.OutputFile = parameters.OutputAssembly; // if it is not being outputted, we use this to set name of the dynamic assembly
settings.Version = LanguageVersion.Default;
settings.WarningLevel = parameters.WarningLevel;
settings.WarningsAreErrors = parameters.TreatWarningsAsErrors;
return settings;
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f3f2a9227250eeb43a8e3c138ce1a6a1
timeCreated: 1438909233
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,317 @@
// modified version of Mono.CSharp.Driver
// driver.cs: The compiler command line driver.
//
// Authors:
// Miguel de Icaza (miguel@gnu.org)
// Marek Safar (marek.safar@gmail.com)
//
// Dual licensed under the terms of the MIT X11 or GNU GPL
//
// Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
// Copyright 2004, 2005, 2006, 2007, 2008 Novell, Inc
// Copyright 2011 Xamarin Inc
//
#if NET_4_6 && !NET_STANDARD_2_0
#define QC_SUPPORTED
#endif
#if QC_SUPPORTED
using Mono.CSharp;
using System;
using System.IO;
using System.Reflection.Emit;
namespace CSharpCompiler
{
/// <summary>
/// The compiler driver.
/// </summary>
public class CustomDynamicDriver
{
readonly CompilerContext ctx;
public CustomDynamicDriver(CompilerContext ctx)
{
this.ctx = ctx;
}
public Report Report
{
get
{
return ctx.Report;
}
}
void tokenize_file(SourceFile sourceFile, ModuleContainer module, ParserSession session)
{
Stream input;
try
{
input = sourceFile.GetDataStream();
}
catch
{
Report.Error(2001, "Source file `" + sourceFile.Name + "' could not be found");
return;
}
using (input)
{
SeekableStreamReader reader = new SeekableStreamReader(input, ctx.Settings.Encoding);
var file = new CompilationSourceFile(module, sourceFile);
Tokenizer lexer = new Tokenizer(reader, file, session, ctx.Report);
int token, tokens = 0, errors = 0;
while ((token = lexer.token()) != Token.EOF)
{
tokens++;
if (token == Token.ERROR)
errors++;
}
Console.WriteLine("Tokenized: " + tokens + " found " + errors + " errors");
}
return;
}
public void Parse(ModuleContainer module)
{
bool tokenize_only = module.Compiler.Settings.TokenizeOnly;
var sources = module.Compiler.SourceFiles;
Location.Initialize(sources);
var session = new ParserSession
{
UseJayGlobalArrays = true,
LocatedTokens = new LocatedToken[15000]
};
for (int i = 0; i < sources.Count; ++i)
{
if (tokenize_only)
{
tokenize_file(sources[i], module, session);
}
else
{
Parse(sources[i], module, session, Report);
}
}
}
public void Parse(SourceFile file, ModuleContainer module, ParserSession session, Report report)
{
Stream input;
try
{
input = file.GetDataStream();
}
catch
{
report.Error(2001, "Source file `{0}' could not be found", file.Name);
return;
}
// Check 'MZ' header
if (input.ReadByte() == 77 && input.ReadByte() == 90)
{
report.Error(2015, "Source file `{0}' is a binary file and not a text file", file.Name);
input.Close();
return;
}
input.Position = 0;
SeekableStreamReader reader = new SeekableStreamReader(input, ctx.Settings.Encoding, session.StreamReaderBuffer);
Parse(reader, file, module, session, report);
if (ctx.Settings.GenerateDebugInfo && report.Errors == 0 && !file.HasChecksum)
{
input.Position = 0;
var checksum = session.GetChecksumAlgorithm();
file.SetChecksum(checksum.ComputeHash(input));
}
reader.Dispose();
input.Close();
}
public static void Parse(SeekableStreamReader reader, SourceFile sourceFile, ModuleContainer module, ParserSession session, Report report)
{
var file = new CompilationSourceFile(module, sourceFile);
module.AddTypeContainer(file);
CSharpParser parser = new CSharpParser(reader, file, report, session);
parser.parse();
}
//
// Main compilation method
//
public bool Compile(out AssemblyBuilder outAssembly, AppDomain domain, bool generateInMemory)
{
var settings = ctx.Settings;
outAssembly = null;
//
// If we are an exe, require a source file for the entry point or
// if there is nothing to put in the assembly, and we are not a library
//
if (settings.FirstSourceFile == null &&
((settings.Target == Target.Exe || settings.Target == Target.WinExe || settings.Target == Target.Module) ||
settings.Resources == null))
{
Report.Error(2008, "No files to compile were specified");
return false;
}
if (settings.Platform == Platform.AnyCPU32Preferred && (settings.Target == Target.Library || settings.Target == Target.Module))
{
Report.Error(4023, "Platform option `anycpu32bitpreferred' is valid only for executables");
return false;
}
TimeReporter tr = new TimeReporter(settings.Timestamps);
ctx.TimeReporter = tr;
tr.StartTotal();
var module = new ModuleContainer(ctx);
RootContext.ToplevelTypes = module;
tr.Start(TimeReporter.TimerType.ParseTotal);
Parse(module);
tr.Stop(TimeReporter.TimerType.ParseTotal);
if (Report.Errors > 0)
return false;
if (settings.TokenizeOnly || settings.ParseOnly)
{
tr.StopTotal();
tr.ShowStats();
return true;
}
var output_file = settings.OutputFile;
string output_file_name;
/* if (output_file == null)
{
var source_file = settings.FirstSourceFile;
if (source_file == null)
{
Report.Error(1562, "If no source files are specified you must specify the output file with -out:");
return false;
}
output_file_name = source_file.Name;
int pos = output_file_name.LastIndexOf('.');
if (pos > 0)
output_file_name = output_file_name.Substring(0, pos);
output_file_name += settings.TargetExt;
output_file = output_file_name;
}
else
{*/
output_file_name = Path.GetFileName(output_file);
/* if (string.IsNullOrEmpty(Path.GetFileNameWithoutExtension(output_file_name)) ||
output_file_name.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
{
Report.Error(2021, "Output file name is not valid");
return false;
}
}*/
var assembly = new AssemblyDefinitionDynamic(module, output_file_name, output_file);
module.SetDeclaringAssembly(assembly);
var importer = new ReflectionImporter(module, ctx.BuiltinTypes);
assembly.Importer = importer;
var loader = new DynamicLoader(importer, ctx);
loader.LoadReferences(module);
if (!ctx.BuiltinTypes.CheckDefinitions(module))
return false;
if (!assembly.Create(domain, AssemblyBuilderAccess.RunAndSave))
return false;
module.CreateContainer();
loader.LoadModules(assembly, module.GlobalRootNamespace);
module.InitializePredefinedTypes();
if (settings.GetResourceStrings != null)
module.LoadGetResourceStrings(settings.GetResourceStrings);
tr.Start(TimeReporter.TimerType.ModuleDefinitionTotal);
module.Define();
tr.Stop(TimeReporter.TimerType.ModuleDefinitionTotal);
if (Report.Errors > 0)
return false;
if (settings.DocumentationFile != null)
{
var doc = new DocumentationBuilder(module);
doc.OutputDocComment(output_file, settings.DocumentationFile);
}
assembly.Resolve();
if (Report.Errors > 0)
return false;
tr.Start(TimeReporter.TimerType.EmitTotal);
assembly.Emit();
tr.Stop(TimeReporter.TimerType.EmitTotal);
if (Report.Errors > 0)
{
return false;
}
tr.Start(TimeReporter.TimerType.CloseTypes);
module.CloseContainer();
tr.Stop(TimeReporter.TimerType.CloseTypes);
tr.Start(TimeReporter.TimerType.Resouces);
if (!settings.WriteMetadataOnly)
assembly.EmbedResources();
tr.Stop(TimeReporter.TimerType.Resouces);
if (Report.Errors > 0)
return false;
if (!generateInMemory) assembly.Save();
outAssembly = assembly.Builder;
tr.StopTotal();
tr.ShowStats();
return Report.Errors == 0;
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e389d8a5b0e25ae44a841060cecca276
timeCreated: 1435446720
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,53 @@
#if NET_4_6 && !NET_STANDARD_2_0
#define QC_SUPPORTED
#endif
using Mono.CSharp;
using System.CodeDom.Compiler;
#if QC_SUPPORTED
namespace CSharpCompiler
{
public class CustomReportPrinter : ReportPrinter
{
readonly CompilerResults compilerResults;
#region Properties
public new int ErrorsCount { get; protected set; }
public new int WarningsCount { get; private set; }
#endregion
public CustomReportPrinter(CompilerResults compilerResults)
{
this.compilerResults = compilerResults;
}
public override void Print(AbstractMessage msg, bool showFullPath)
{
if (msg.IsWarning)
{
++WarningsCount;
}
else
{
++ErrorsCount;
}
compilerResults.Errors.Add(new CompilerError()
{
IsWarning = msg.IsWarning,
Column = msg.Location.Column,
Line = msg.Location.Row,
ErrorNumber = msg.Code.ToString(),
ErrorText = msg.Text,
FileName = showFullPath ? msg.Location.SourceFile.FullPathName : msg.Location.SourceFile.Name,
// msg.RelatedSymbols // extra info
});
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 39ec208e78505e342a2829289445b934
timeCreated: 1438909233
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,99 @@
/*
Implementation of ISynchronizeInvoke for Unity3D game engine.
Can be used to invoke anything on main Unity thread.
ISynchronizeInvoke is used extensively in .NET forms it's is elegant and quite useful in Unity as well.
I implemented it so i can use it with System.IO.FileSystemWatcher.SynchronizingObject.
help from: http://www.codeproject.com/Articles/12082/A-DelegateQueue-Class
example usage: https://gist.github.com/aeroson/90bf21be3fdc4829e631
license: WTFPL (http://www.wtfpl.net/)
contact: aeroson (theaeroson @gmail.com)
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Threading;
public class DeferredSynchronizeInvoke : ISynchronizeInvoke
{
Queue<UnityAsyncResult> fifoToExecute = new Queue<UnityAsyncResult>();
Thread mainThread;
public bool InvokeRequired { get { return mainThread.ManagedThreadId != Thread.CurrentThread.ManagedThreadId; } }
public DeferredSynchronizeInvoke()
{
mainThread = Thread.CurrentThread;
}
public IAsyncResult BeginInvoke(Delegate method, object[] args)
{
var asyncResult = new UnityAsyncResult()
{
method = method,
args = args,
IsCompleted = false,
AsyncWaitHandle = new ManualResetEvent(false),
};
lock (fifoToExecute)
{
fifoToExecute.Enqueue(asyncResult);
}
return asyncResult;
}
public object EndInvoke(IAsyncResult result)
{
if (!result.IsCompleted)
{
result.AsyncWaitHandle.WaitOne();
}
return result.AsyncState;
}
public object Invoke(Delegate method, object[] args)
{
if (InvokeRequired)
{
var asyncResult = BeginInvoke(method, args);
return EndInvoke(asyncResult);
}
else
{
return method.DynamicInvoke(args);
}
}
public void ProcessQueue()
{
if (Thread.CurrentThread != mainThread)
{
throw new TargetException(
this.GetType() + "." + MethodBase.GetCurrentMethod().Name + "() " +
"must be called from the same thread it was created on " +
"(created on thread id: " + mainThread.ManagedThreadId + ", called from thread id: " + Thread.CurrentThread.ManagedThreadId
);
}
bool loop = true;
UnityAsyncResult data = null;
while (loop)
{
lock (fifoToExecute)
{
loop = fifoToExecute.Count > 0;
if (!loop) break;
data = fifoToExecute.Dequeue();
}
data.AsyncState = Invoke(data.method, data.args);
data.IsCompleted = true;
}
}
class UnityAsyncResult : IAsyncResult
{
public Delegate method;
public object[] args;
public bool IsCompleted { get; set; }
public WaitHandle AsyncWaitHandle { get; internal set; }
public object AsyncState { get; set; }
public bool CompletedSynchronously { get { return IsCompleted; } }
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f6228134abfaad746965d9639b73908a
timeCreated: 1435576341
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,21 @@
Copyright (c) 2001, 2002, 2003 Ximian, Inc and the individuals listed
on the ChangeLog entries.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 09298e73731a3b64fbedf483cf7d4e42
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 2ce9bfedd125d1c49adb5c65c9e8ce53
folderAsset: yes
timeCreated: 1435432572
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,30 @@
fileFormatVersion: 2
guid: 0447405aaa6f3bd4c96d4c64631542fd
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
isPreloaded: 0
isOverridable: 0
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,172 @@
#if NET_4_6 && !NET_STANDARD_2_0
#define QC_SUPPORTED
#endif
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
#if QC_SUPPORTED
namespace CSharpCompiler
{
public class ScriptBundleLoader
{
public Func<Type, object> createInstance = (Type type) => { return Activator.CreateInstance(type); };
public Action<object> destroyInstance = delegate { };
public TextWriter logWriter = Console.Out;
ISynchronizeInvoke synchronizedInvoke;
List<ScriptBundle> allFilesBundle = new List<ScriptBundle>();
public ScriptBundleLoader(ISynchronizeInvoke synchronizedInvoke)
{
this.synchronizedInvoke = synchronizedInvoke;
}
/// <summary>
///
/// </summary>
/// <param name="fileSources"></param>
/// <returns>true on success, false on failure</returns>
public ScriptBundle LoadAndWatchScriptsBundle(IEnumerable<string> fileSources)
{
var bundle = new ScriptBundle(this, fileSources);
allFilesBundle.Add(bundle);
return bundle;
}
/// <summary>
/// Manages a bundle of files which form one assembly, if one file changes entire assembly is recompiled.
/// </summary>
public class ScriptBundle
{
Assembly assembly;
IEnumerable<string> filePaths;
List<FileSystemWatcher> fileSystemWatchers = new List<FileSystemWatcher>();
List<object> instances = new List<object>();
ScriptBundleLoader manager;
string[] assemblyReferences;
public ScriptBundle(ScriptBundleLoader manager, IEnumerable<string> filePaths)
{
this.filePaths = filePaths.Select(x => Path.GetFullPath(x));
this.manager = manager;
var domain = System.AppDomain.CurrentDomain;
this.assemblyReferences = domain
.GetAssemblies()
.Where(a => !(a is System.Reflection.Emit.AssemblyBuilder) && !string.IsNullOrEmpty(a.Location))
.Select(a => a.Location)
.ToArray();
manager.logWriter.WriteLine("loading " + string.Join(", ", filePaths.ToArray()));
CompileFiles();
CreateFileWatchers();
CreateNewInstances();
}
void CompileFiles()
{
filePaths = filePaths.Where(x => File.Exists(x)).ToArray();
var options = new CompilerParameters();
options.GenerateExecutable = false;
options.GenerateInMemory = true;
options.ReferencedAssemblies.AddRange(assemblyReferences);
var compiler = new CodeCompiler();
var result = compiler.CompileAssemblyFromFileBatch(options, filePaths.ToArray());
foreach (var err in result.Errors)
{
manager.logWriter.WriteLine(err);
}
this.assembly = result.CompiledAssembly;
}
void CreateFileWatchers()
{
foreach (var filePath in filePaths)
{
FileSystemWatcher watcher = new FileSystemWatcher();
fileSystemWatchers.Add(watcher);
watcher.Path = Path.GetDirectoryName(filePath);
/* Watch for changes in LastAccess and LastWrite times, and
the renaming of files or directories. */
watcher.NotifyFilter = NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
watcher.Filter = Path.GetFileName(filePath);
// Add event handlers.
watcher.Changed += new FileSystemEventHandler((object o, FileSystemEventArgs a) => { Reload(recreateWatchers: false); });
//watcher.Created += new FileSystemEventHandler((object o, FileSystemEventArgs a) => { });
watcher.Deleted += new FileSystemEventHandler((object o, FileSystemEventArgs a) => { Reload(recreateWatchers: false); });
watcher.Renamed += new RenamedEventHandler((object o, RenamedEventArgs a) =>
{
filePaths = filePaths.Select(x =>
{
if (x == a.OldFullPath) return a.FullPath;
else return x;
});
Reload(recreateWatchers: true);
});
watcher.SynchronizingObject = manager.synchronizedInvoke;
// Begin watching.
watcher.EnableRaisingEvents = true;
}
}
void StopFileWatchers()
{
foreach (var w in fileSystemWatchers)
{
w.EnableRaisingEvents = false;
w.Dispose();
}
fileSystemWatchers.Clear();
}
void Reload(bool recreateWatchers = false)
{
manager.logWriter.WriteLine("reloading " + string.Join(", ", filePaths.ToArray()));
StopInstances();
CompileFiles();
CreateNewInstances();
if (recreateWatchers)
{
StopFileWatchers();
CreateFileWatchers();
}
}
void CreateNewInstances()
{
if (assembly == null) return;
foreach (var type in assembly.GetTypes())
{
manager.synchronizedInvoke.Invoke((System.Action)(() =>
{
instances.Add(manager.createInstance(type));
}), null);
}
}
void StopInstances()
{
foreach (var instance in instances)
{
manager.synchronizedInvoke.Invoke((System.Action)(() =>
{
manager.destroyInstance(instance);
}), null);
}
instances.Clear();
}
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3dfc88ca39a87dc46bc7fd337be863bb
timeCreated: 1440503653
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,110 @@
#if NET_4_6 && !NET_STANDARD_2_0
#define QC_SUPPORTED
#endif
#if QC_SUPPORTED && !QC_DISABLED && !QC_DISABLE_BUILTIN_ALL && !QC_DISABLE_BUILTIN_EXTRA
using System;
using System.CodeDom.Compiler;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
namespace QFSW.QC
{
public static class DynamicCodeCommands
{
private const Platform execAvailability = Platform.AllPlatforms ^ (Platform.WebGLPlayer | Platform.IPhonePlayer | Platform.XboxOne | Platform.PS4 | Platform.Switch);
[CommandDescription("Loads the code at the specified file and compiles it to C# which will then be executed. Use with caution as no safety checks will be performed. Not supported in AOT (IL2CPP) builds." +
"\n\nBy default, boiler plate code will NOT be inserted around the code you provide. Please see 'exec' for more information about boilerplate insertion")]
[Command("exec-extern", execAvailability)]
private static async Task ExecuteExternalArbitaryCodeAsync(string filePath, bool insertBoilerplate = false)
{
if (!File.Exists(filePath)) { throw new ArgumentException($"file at the specified path '{filePath}' did not exist."); }
string code = File.ReadAllText(filePath);
await ExecuteArbitaryCodeAsync(code.Replace("”", "\"").Replace("“", "\""), insertBoilerplate);
}
[CommandDescription("Compiles the given code to C# which will then be executed. Use with caution as no safety checks will be performed. Not supported in AOT (IL2CPP) builds." +
"\n\nBy default, boiler plate code will be inserted around the code you provide. This means various namespaces will be included, and the main class and main function entry point will " +
"provided. In this case, the code you provide should be code that would exist within the body of the main function, and thus cannot contain things such as class definition. If you " +
"disable boiler plate insertion, you can write whatever code you want, however you must provide a static entry point called Main in a static class called Program")]
[Command("exec", execAvailability)]
private static async Task ExecuteArbitaryCodeAsync(string code, bool insertBoilerplate = true)
{
#if !UNITY_EDITOR && ENABLE_IL2CPP
await Task.FromException(new Exception("exec is not supported on AOT platforms such as IL2CPP and requires JIT (Mono)."));
#else
MethodInfo entryPoint = await Task.Run(() =>
{
string fullCode = string.Empty;
if (insertBoilerplate)
{
string[] includedNamespaces = new string[] { "System", "System.Collections", "System.Collections.Generic",
"System.Reflection", "System.Linq", "System.Text", "System.Globalization",
"UnityEngine", "UnityEngine.Events", "UnityEngine.EventSystems", "UnityEngine.UI" };
for (int i = 0; i < includedNamespaces.Length; i++) { fullCode += $"using {includedNamespaces[i]};\n"; }
fullCode += @"
public class Program
{
public static void Main()
{"
+ code +
@"}
}";
}
else { fullCode = code; }
Assembly assembly = CompileCode(fullCode);
BindingFlags searchFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
Type program = assembly.GetType("Program");
if (program == null) { throw new ArgumentException("Code Execution Failure - required static class Program could not be found"); }
entryPoint = program.GetMethod("Main", searchFlags);
if (entryPoint == null) { throw new ArgumentException("Code Execution Failure - required static entry point Main could not be found"); }
return entryPoint;
});
entryPoint.Invoke(null, null);
#endif
}
private static Assembly CompileCode(string code)
{
#if !UNITY_EDITOR && ENABLE_IL2CPP
throw new Exception("Code compilation is not supported on AOT platforms such as IL2CPP and requires JIT (Mono).");
#else
CSharpCompiler.CodeCompiler compiler = new CSharpCompiler.CodeCompiler();
CompilerParameters compilerParams = new CompilerParameters();
Assembly[] allLoadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
compilerParams.GenerateExecutable = false;
compilerParams.GenerateInMemory = true;
for (int i = 0; i < allLoadedAssemblies.Length; i++)
{
if (!allLoadedAssemblies[i].IsDynamic)
{
string dllName = allLoadedAssemblies[i].Location;
compilerParams.ReferencedAssemblies.Add(dllName);
}
}
CompilerResults compiledCode = compiler.CompileAssemblyFromSource(compilerParams, code);
if (compiledCode.Errors.HasErrors)
{
string errorMessage = "Code Compilation Failure";
for (int i = 0; i < compiledCode.Errors.Count; i++)
{
errorMessage += $"\n{compiledCode.Errors[i].ErrorNumber} - {compiledCode.Errors[i].ErrorText}";
}
throw new ArgumentException(errorMessage);
}
return compiledCode.CompiledAssembly;
#endif
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e32a67fb03a2f6548b653203ff9fedf3
timeCreated: 1553955853
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: