diff --git a/Source/Game/Cabrito/Console/Console.cs b/Source/Game/Cabrito/Console/Console.cs index cf0fb64..19aecce 100644 --- a/Source/Game/Cabrito/Console/Console.cs +++ b/Source/Game/Cabrito/Console/Console.cs @@ -7,349 +7,363 @@ using FlaxEngine.Assertions; namespace Cabrito { - public class ConsoleLine - { - public string content; + public class ConsoleLine + { + public string content; - internal ConsoleLine(string line) - { - content = line; - } + internal ConsoleLine(string line) + { + content = line; + } - public static implicit operator string(ConsoleLine line) => line.content; - public static explicit operator ConsoleLine(string line) => new ConsoleLine(line); + public static implicit operator string(ConsoleLine line) => line.content; + public static explicit operator ConsoleLine(string line) => new ConsoleLine(line); - public override string ToString() => content.ToString(); - } + public override string ToString() => content.ToString(); + } - public static class Console - { - private static ConsoleInstance instance; - public static void Init() - { - Destroy(); - instance = new ConsoleInstance(); - } + public static class Console + { + private static ConsoleInstance instance; - private static void Destroy() - { - if (instance != null) - { - instance.Dispose(); - instance = null; - FlaxEngine.Debug.Log("Console.Destroy"); - } - } + public static void Init() + { + Destroy(); + instance = new ConsoleInstance(); + } - // Returns if Console window open right now. - public static bool IsOpen => instance.IsOpen; + private static void Destroy() + { + if (instance != null) + { + instance.Dispose(); + instance = null; + FlaxEngine.Debug.Log("Console.Destroy"); + } + } - // For debugging only: Returns true when Console was not closed during the same frame. - // Needed when Escape-key both closes the console and exits the game. - public static bool IsSafeToQuit => instance.IsSafeToQuit; + // Returns if Console window open right now. + public static bool IsOpen => instance.IsOpen; - // Called when Console is opened. - public static Action OnOpen - { - get { return instance.OnOpen; } - set { instance.OnOpen = value; } - } + // For debugging only: Returns true when Console was not closed during the same frame. + // Needed when Escape-key both closes the console and exits the game. + public static bool IsSafeToQuit => instance.IsSafeToQuit; - // Called when Console is closed. - public static Action OnClose - { - get { return instance.OnClose; } - set { instance.OnClose = value; } - } + // Called when Console is opened. + public static Action OnOpen + { + get { return instance.OnOpen; } + set { instance.OnOpen = value; } + } - // Called when a line of text was printed in Console. - public static Action OnPrint - { - get { return instance.OnPrint; } - set { instance.OnPrint = value; } - } + // Called when Console is closed. + public static Action OnClose + { + get { return instance.OnClose; } + set { instance.OnClose = value; } + } - public static bool ShowExecutedLines => instance.ShowExecutedLines; - public static string LinePrefix => instance.LinePrefix; + // Called when a line of text was printed in Console. + public static Action OnPrint + { + get { return instance.OnPrint; } + set { instance.OnPrint = value; } + } - public static IReadOnlyCollection Lines => instance.Lines; + public static bool ShowExecutedLines => instance.ShowExecutedLines; + public static string LinePrefix => instance.LinePrefix; - // Echoes text to Console - public static void Print(string text) => instance.Print(text); + public static IReadOnlyCollection Lines => instance.Lines; - // Echoes warning text to Console - public static void PrintWarning(string text) => instance.PrintWarning(text); + // Echoes text to Console + public static void Print(string text) => instance.Print(text); - // Echoes error text to Console - public static void PrintError(string text) => instance.PrintError(text); + // Echoes warning text to Console + public static void PrintWarning(string text) => instance.PrintWarning(text); - // Echoes developer/debug text to Console - public static void PrintDebug(string text) => instance.PrintDebug(text); + // Echoes error text to Console + public static void PrintError(string text) => instance.PrintError(text); - // Opens the Console - public static void Open() => instance.Open(); + // Echoes developer/debug text to Console + public static void PrintDebug(string text) => instance.PrintDebug(text); - // Closes the Console - public static void Close() => instance.Close(); + // Opens the Console + public static void Open() => instance.Open(); - // Clears the content of the Console - public static void Clear() => instance.Clear(); + // Closes the Console + public static void Close() => instance.Close(); - public static void Execute(string str) => instance.Execute(str); + // Clears the content of the Console + public static void Clear() => instance.Clear(); - public static string GetVariable(string variableName) => instance.GetVariable(variableName); - } + public static void Execute(string str) => instance.Execute(str); - public class ConsoleInstance : IDisposable - { - public bool IsOpen { get; internal set; } = true; + public static string GetVariable(string variableName) => instance.GetVariable(variableName); + } - public bool IsSafeToQuit { get { return stopwatch.Elapsed.TotalSeconds > 0.1; } } - private Stopwatch stopwatch = Stopwatch.StartNew(); + public class ConsoleInstance : IDisposable + { + public bool IsOpen { get; internal set; } = true; - public Action OnOpen; - public Action OnClose; - public Action OnPrint; - - public bool ShowExecutedLines = true; - public string LinePrefix { get; internal set; } = "]"; + public bool IsSafeToQuit + { + get { return stopwatch.Elapsed.TotalSeconds > 0.1; } + } - //private static List consoleLines = new List(); - private List consoleLines = new List(); - private Dictionary consoleCommands = new Dictionary(); - private Dictionary consoleVariables = new Dictionary(); + private Stopwatch stopwatch = Stopwatch.StartNew(); - // Initializes the Console system. - public ConsoleInstance() - { - AppDomain currentDomain = AppDomain.CurrentDomain; - Assembly[] assemblies = currentDomain.GetAssemblies(); + public Action OnOpen; + public Action OnClose; + public Action OnPrint; - foreach (var assembly in assemblies) - { - // Skip common assemblies - var assemblyName = assembly.GetName().Name; - if (assemblyName == "System" || - assemblyName.StartsWith("System.") || - assemblyName.StartsWith("Mono.") || - assemblyName == "mscorlib" || - assemblyName == "Newtonsoft.Json" || - assemblyName.StartsWith("FlaxEngine.")) - { - continue; - } + public bool ShowExecutedLines = true; + public string LinePrefix { get; internal set; } = "]"; - foreach (var type in assembly.GetTypes()) - { - Dictionary cmdParsed = new Dictionary(); - Dictionary> cmdMethods = new Dictionary>(); + //private static List consoleLines = new List(); + private List consoleLines = new List(); + private Dictionary consoleCommands = new Dictionary(); + private Dictionary consoleVariables = new Dictionary(); - foreach (MethodInfo method in type.GetMethods()) - { - if (!method.IsStatic) - continue; + // Initializes the Console system. + public ConsoleInstance() + { + AppDomain currentDomain = AppDomain.CurrentDomain; + Assembly[] assemblies = currentDomain.GetAssemblies(); - Attribute[] attributes = Attribute.GetCustomAttributes(method); + foreach (var assembly in assemblies) + { + // Skip common assemblies + var assemblyName = assembly.GetName().Name; + if (assemblyName == "System" || + assemblyName.StartsWith("System.") || + assemblyName.StartsWith("Mono.") || + assemblyName == "mscorlib" || + assemblyName == "Newtonsoft.Json" || + assemblyName.StartsWith("FlaxEngine.")) + { + continue; + } - foreach (Attribute attr in attributes) - { - if (attr is ConsoleCommandAttribute cmdAttribute) - { - //Console.Print("found cmd '" + cmdAttribute.name + "' bound to field '" + method.Name + "'"); + foreach (var type in assembly.GetTypes()) + { + Dictionary cmdParsed = new Dictionary(); + Dictionary> cmdMethods = new Dictionary>(); - // Defer constructing the command until we have parsed all the methods for it in this assembly. + foreach (MethodInfo method in type.GetMethods()) + { + if (!method.IsStatic) + continue; - List methods; - if (!cmdMethods.TryGetValue(cmdAttribute.name, out methods)) - { - methods = new List(); - cmdMethods.Add(cmdAttribute.name, methods); - } - methods.Add(method); + Attribute[] attributes = Attribute.GetCustomAttributes(method); - ConsoleCommand cmd = new ConsoleCommand(cmdAttribute.name, null); - if (!cmdParsed.ContainsKey(cmdAttribute.name)) - cmdParsed.Add(cmdAttribute.name, cmd); - foreach (var alias in cmdAttribute.aliases) - { - if (!cmdParsed.ContainsKey(alias)) - cmdParsed.Add(alias, cmd); + foreach (Attribute attr in attributes) + { + if (attr is ConsoleCommandAttribute cmdAttribute) + { + //Console.Print("found cmd '" + cmdAttribute.name + "' bound to field '" + method.Name + "'"); - List aliasMethods; - if (!cmdMethods.TryGetValue(alias, out aliasMethods)) - { - aliasMethods = new List(); - cmdMethods.Add(alias, aliasMethods); - } - aliasMethods.Add(method); - } - } - } - } + // Defer constructing the command until we have parsed all the methods for it in this assembly. - foreach (var kv in cmdParsed) - { - var methods = cmdMethods[kv.Key]; - var definition = kv.Value; + List methods; + if (!cmdMethods.TryGetValue(cmdAttribute.name, out methods)) + { + methods = new List(); + cmdMethods.Add(cmdAttribute.name, methods); + } - ConsoleCommand cmd = new ConsoleCommand(definition.name, methods.ToArray()); - consoleCommands.Add(kv.Key, cmd); - } + methods.Add(method); - foreach (FieldInfo field in type.GetFields()) - { - if (!field.IsStatic) - continue; + ConsoleCommand cmd = new ConsoleCommand(cmdAttribute.name, null); + if (!cmdParsed.ContainsKey(cmdAttribute.name)) + cmdParsed.Add(cmdAttribute.name, cmd); + foreach (var alias in cmdAttribute.aliases) + { + if (!cmdParsed.ContainsKey(alias)) + cmdParsed.Add(alias, cmd); - Attribute[] attributes = Attribute.GetCustomAttributes(field); + List aliasMethods; + if (!cmdMethods.TryGetValue(alias, out aliasMethods)) + { + aliasMethods = new List(); + cmdMethods.Add(alias, aliasMethods); + } - foreach (Attribute attr in attributes) - { - if (attr is ConsoleVariableAttribute cvarAttribute) - { - //Console.Print("found cvar '" + cvarAttribute.name + "' bound to field '" + field.Name + "'"); - consoleVariables.Add(cvarAttribute.name, new ConsoleVariable(cvarAttribute.name, cvarAttribute.flags, field)); - foreach (var alias in cvarAttribute.aliases) - consoleVariables.Add(alias, new ConsoleVariable(cvarAttribute.name, cvarAttribute.flags | ConsoleFlags.NoSerialize, field)); - } - } - } + aliasMethods.Add(method); + } + } + } + } - foreach (PropertyInfo prop in type.GetProperties()) - { - MethodInfo getter = prop.GetGetMethod(); - MethodInfo setter = prop.GetSetMethod(); - if (getter == null || setter == null || !getter.IsStatic || !setter.IsStatic) - continue; + foreach (var kv in cmdParsed) + { + var methods = cmdMethods[kv.Key]; + var definition = kv.Value; - Attribute[] attributes = Attribute.GetCustomAttributes(prop); + ConsoleCommand cmd = new ConsoleCommand(definition.name, methods.ToArray()); + consoleCommands.Add(kv.Key, cmd); + } - foreach (Attribute attr in attributes) - { - if (attr is ConsoleVariableAttribute cvarAttribute) - { - //Console.Print("found cvar '" + cvarAttribute.name + "' bound to field '" + field.Name + "'"); - consoleVariables.Add(cvarAttribute.name, new ConsoleVariable(cvarAttribute.name, cvarAttribute.flags, getter, setter)); - foreach (var alias in cvarAttribute.aliases) - consoleVariables.Add(alias, new ConsoleVariable(cvarAttribute.name, cvarAttribute.flags | ConsoleFlags.NoSerialize, getter, setter)); - } - } - } - } - } - } + foreach (FieldInfo field in type.GetFields()) + { + if (!field.IsStatic) + continue; - public void Dispose() - { - } + Attribute[] attributes = Attribute.GetCustomAttributes(field); - public IReadOnlyCollection Lines - { - get => consoleLines.AsReadOnly(); - } + foreach (Attribute attr in attributes) + { + if (attr is ConsoleVariableAttribute cvarAttribute) + { + //Console.Print("found cvar '" + cvarAttribute.name + "' bound to field '" + field.Name + "'"); + consoleVariables.Add(cvarAttribute.name, + new ConsoleVariable(cvarAttribute.name, cvarAttribute.flags, field)); + foreach (var alias in cvarAttribute.aliases) + consoleVariables.Add(alias, + new ConsoleVariable(cvarAttribute.name, + cvarAttribute.flags | ConsoleFlags.NoSerialize, field)); + } + } + } - // Echoes text to Console - public void Print(string text) - { - ConsoleLine line = new ConsoleLine(text); - consoleLines.Add(line); - OnPrint?.Invoke(text); - } + foreach (PropertyInfo prop in type.GetProperties()) + { + MethodInfo getter = prop.GetGetMethod(); + MethodInfo setter = prop.GetSetMethod(); + if (getter == null || setter == null || !getter.IsStatic || !setter.IsStatic) + continue; - // Echoes warning text to Console - public void PrintWarning(string text) - { - ConsoleLine line = new ConsoleLine(text); - consoleLines.Add(line); - OnPrint?.Invoke(text); - } + Attribute[] attributes = Attribute.GetCustomAttributes(prop); - // Echoes error text to Console - public void PrintError(string text) - { - ConsoleLine line = new ConsoleLine(text); - consoleLines.Add(line); - OnPrint?.Invoke(text); - } + foreach (Attribute attr in attributes) + { + if (attr is ConsoleVariableAttribute cvarAttribute) + { + //Console.Print("found cvar '" + cvarAttribute.name + "' bound to field '" + field.Name + "'"); + consoleVariables.Add(cvarAttribute.name, + new ConsoleVariable(cvarAttribute.name, cvarAttribute.flags, getter, setter)); + foreach (var alias in cvarAttribute.aliases) + consoleVariables.Add(alias, + new ConsoleVariable(cvarAttribute.name, + cvarAttribute.flags | ConsoleFlags.NoSerialize, getter, setter)); + } + } + } + } + } + } - // Echoes developer/debug text to Console - public void PrintDebug(string text) - { - ConsoleLine line = new ConsoleLine(text); - consoleLines.Add(line); - OnPrint?.Invoke(text); - } + public void Dispose() + { + } - // Opens the Console - public void Open() - { - if (IsOpen) - return; + public IReadOnlyCollection Lines + { + get => consoleLines.AsReadOnly(); + } - IsOpen = true; - OnOpen?.Invoke(); - } + // Echoes text to Console + public void Print(string text) + { + ConsoleLine line = new ConsoleLine(text); + consoleLines.Add(line); + OnPrint?.Invoke(text); + } - // Closes the Console - public void Close() - { - if (!IsOpen) - return; + // Echoes warning text to Console + public void PrintWarning(string text) + { + ConsoleLine line = new ConsoleLine(text); + consoleLines.Add(line); + OnPrint?.Invoke(text); + } - IsOpen = false; - OnClose?.Invoke(); + // Echoes error text to Console + public void PrintError(string text) + { + ConsoleLine line = new ConsoleLine(text); + consoleLines.Add(line); + OnPrint?.Invoke(text); + } - stopwatch.Restart(); - } + // Echoes developer/debug text to Console + public void PrintDebug(string text) + { + ConsoleLine line = new ConsoleLine(text); + consoleLines.Add(line); + OnPrint?.Invoke(text); + } - // Clears the content of the Console - public void Clear() - { - consoleLines.Clear(); - } + // Opens the Console + public void Open() + { + if (IsOpen) + return; - public void Execute(string str) - { - str = str.Trim(); + IsOpen = true; + OnOpen?.Invoke(); + } - if (ShowExecutedLines) - Console.Print(LinePrefix + str); + // Closes the Console + public void Close() + { + if (!IsOpen) + return; - string[] strs = str.Split(' '); - string execute = strs[0]; - string executeLower = execute.ToLowerInvariant(); - string value = strs.Length > 1 ? str.Substring(execute.Length + 1) : null; + IsOpen = false; + OnClose?.Invoke(); - //Console.PrintDebug("Executed '" + execute + "' with params: '" + value + "'"); + stopwatch.Restart(); + } - if (consoleCommands.TryGetValue(executeLower, out ConsoleCommand cmd)) - { - string[] values = strs.Skip(1).ToArray(); - if (values.Length > 0) - cmd.Invoke(values); - else - cmd.Invoke(); - //Console.Print("Command bound to '" + execute + "' is '" + cmd.method.Name + "'"); - } - else if (consoleVariables.TryGetValue(executeLower, out ConsoleVariable cvar)) - { - if (value != null) - cvar.SetValue(value); + // Clears the content of the Console + public void Clear() + { + consoleLines.Clear(); + } - Console.Print("'" + execute + "' is '" + cvar.GetValueString() + "'"); - } - else - Console.Print("Unknown command '" + execute + "'"); - } + public void Execute(string str) + { + str = str.Trim(); - public string GetVariable(string variableName) - { - if (consoleVariables.TryGetValue(variableName, out ConsoleVariable cvar)) - { - string value = cvar.GetValueString(); - return value; - } - return null; - } - } -} + if (ShowExecutedLines) + Console.Print(LinePrefix + str); + + string[] strs = str.Split(' '); + string execute = strs[0]; + string executeLower = execute.ToLowerInvariant(); + string value = strs.Length > 1 ? str.Substring(execute.Length + 1) : null; + + //Console.PrintDebug("Executed '" + execute + "' with params: '" + value + "'"); + + if (consoleCommands.TryGetValue(executeLower, out ConsoleCommand cmd)) + { + string[] values = strs.Skip(1).ToArray(); + if (values.Length > 0) + cmd.Invoke(values); + else + cmd.Invoke(); + //Console.Print("Command bound to '" + execute + "' is '" + cmd.method.Name + "'"); + } + else if (consoleVariables.TryGetValue(executeLower, out ConsoleVariable cvar)) + { + if (value != null) + cvar.SetValue(value); + + Console.Print("'" + execute + "' is '" + cvar.GetValueString() + "'"); + } + else + Console.Print("Unknown command '" + execute + "'"); + } + + public string GetVariable(string variableName) + { + if (consoleVariables.TryGetValue(variableName, out ConsoleVariable cvar)) + { + string value = cvar.GetValueString(); + return value; + } + + return null; + } + } +} \ No newline at end of file diff --git a/Source/Game/Cabrito/Console/ConsoleAttributes.cs b/Source/Game/Cabrito/Console/ConsoleAttributes.cs index bd7fee7..8b3fd01 100644 --- a/Source/Game/Cabrito/Console/ConsoleAttributes.cs +++ b/Source/Game/Cabrito/Console/ConsoleAttributes.cs @@ -6,54 +6,54 @@ using System.Threading.Tasks; namespace Cabrito { - [AttributeUsage(AttributeTargets.All)] - public abstract class ConsoleBaseAttribute : Attribute - { - internal string name; + [AttributeUsage(AttributeTargets.All)] + public abstract class ConsoleBaseAttribute : Attribute + { + internal string name; - // Additional aliases for this command, these should only be used with user interaction. - // Commands such as 'cvarlist' should not list these in order to avoid clutter. - internal string[] aliases = new string[0]; + // Additional aliases for this command, these should only be used with user interaction. + // Commands such as 'cvarlist' should not list these in order to avoid clutter. + internal string[] aliases = new string[0]; - public ConsoleFlags flags { get; private set; } + public ConsoleFlags flags { get; private set; } - public ConsoleBaseAttribute(string name) - { - this.name = name.ToLowerInvariant(); - } + public ConsoleBaseAttribute(string name) + { + this.name = name.ToLowerInvariant(); + } - public ConsoleBaseAttribute(params string[] names) - { - this.name = names[0].ToLowerInvariant(); - aliases = new List(names).Skip(1).Select(x => x.ToLowerInvariant()).ToArray(); - } - } + public ConsoleBaseAttribute(params string[] names) + { + this.name = names[0].ToLowerInvariant(); + aliases = new List(names).Skip(1).Select(x => x.ToLowerInvariant()).ToArray(); + } + } - [AttributeUsage(AttributeTargets.All)] - public class ConsoleVariableAttribute : ConsoleBaseAttribute - { - public ConsoleVariableAttribute(string name) : base(name) - { - } - } + [AttributeUsage(AttributeTargets.All)] + public class ConsoleVariableAttribute : ConsoleBaseAttribute + { + public ConsoleVariableAttribute(string name) : base(name) + { + } + } - [AttributeUsage(AttributeTargets.All)] - public class ConsoleCommandAttribute : ConsoleBaseAttribute - { - /// - /// Registers a command to Console system. - /// - /// Name used for calling this command. - public ConsoleCommandAttribute(string name) : base(name) - { - } + [AttributeUsage(AttributeTargets.All)] + public class ConsoleCommandAttribute : ConsoleBaseAttribute + { + /// + /// Registers a command to Console system. + /// + /// Name used for calling this command. + public ConsoleCommandAttribute(string name) : base(name) + { + } - /// - /// Registers a command to Console system. - /// - /// Names used for calling this command. First name is the main name for this command, rest of the names are aliases. - public ConsoleCommandAttribute(params string[] names) : base(names) - { - } - } -} + /// + /// Registers a command to Console system. + /// + /// Names used for calling this command. First name is the main name for this command, rest of the names are aliases. + public ConsoleCommandAttribute(params string[] names) : base(names) + { + } + } +} \ No newline at end of file diff --git a/Source/Game/Cabrito/Console/ConsoleCommand.cs b/Source/Game/Cabrito/Console/ConsoleCommand.cs index a2d899b..05adf60 100644 --- a/Source/Game/Cabrito/Console/ConsoleCommand.cs +++ b/Source/Game/Cabrito/Console/ConsoleCommand.cs @@ -7,74 +7,75 @@ using System.Threading.Tasks; namespace Cabrito { - internal struct ConsoleCommand - { - public string name { get; private set; } + internal struct ConsoleCommand + { + public string name { get; private set; } - private MethodInfo[] methods; + private MethodInfo[] methods; - public ConsoleCommand(string name, MethodInfo[] method) - { - this.name = name; - this.methods = method; - } + public ConsoleCommand(string name, MethodInfo[] method) + { + this.name = name; + this.methods = method; + } - public void Invoke() - { - foreach (var method in methods) - { - var methodParameters = method.GetParameters(); - if (methodParameters.Length != 0) - continue; + public void Invoke() + { + foreach (var method in methods) + { + var methodParameters = method.GetParameters(); + if (methodParameters.Length != 0) + continue; - method.Invoke(null, null); - return; - } + method.Invoke(null, null); + return; + } - throw new Exception("Unexpected number of parameters."); - } + throw new Exception("Unexpected number of parameters."); + } - public void Invoke(string[] parameters) - { - MethodInfo match = null; - foreach (var method in methods) - { - var methodParameters = method.GetParameters(); - if (methodParameters.Length == 1 && methodParameters[0].ParameterType == typeof(string[])) - { - match = method; - continue; - } - else if (methodParameters.Length != parameters.Length) - continue; + public void Invoke(string[] parameters) + { + MethodInfo match = null; + foreach (var method in methods) + { + var methodParameters = method.GetParameters(); + if (methodParameters.Length == 1 && methodParameters[0].ParameterType == typeof(string[])) + { + match = method; + continue; + } + else if (methodParameters.Length != parameters.Length) + continue; - // TODO: try to parse string parameters to needed types first, - // may require finding the exact match first instead of first matching one. - for (int i = 0; i < methodParameters.Length; i++) - //if (methodParameters[i].ParameterType != parameters[i].GetType()) - if (methodParameters[i].ParameterType != typeof(string)) - continue; + // TODO: try to parse string parameters to needed types first, + // may require finding the exact match first instead of first matching one. + for (int i = 0; i < methodParameters.Length; i++) + //if (methodParameters[i].ParameterType != parameters[i].GetType()) + if (methodParameters[i].ParameterType != typeof(string)) + continue; - if (match != null) - { - // Prefer exact number of parameters over string[] match - if (methodParameters.Length != parameters.Length) - continue; - } - match = method; - } + if (match != null) + { + // Prefer exact number of parameters over string[] match + if (methodParameters.Length != parameters.Length) + continue; + } - if (match != null) - { - if (match.GetParameters().Length == 1 && match.GetParameters()[0].ParameterType == typeof(string[])) - match.Invoke(null, new object[] { parameters }); - else - match.Invoke(null, parameters); + match = method; + } - return; - } + if (match != null) + { + if (match.GetParameters().Length == 1 && match.GetParameters()[0].ParameterType == typeof(string[])) + match.Invoke(null, new object[] {parameters}); + else + match.Invoke(null, parameters); - throw new Exception("Unexpected number of parameters."); - } - } -} + return; + } + + throw new Exception("Unexpected number of parameters."); + } + } +} \ No newline at end of file diff --git a/Source/Game/Cabrito/Console/ConsoleContainerControl.cs b/Source/Game/Cabrito/Console/ConsoleContainerControl.cs index 9589591..cb57607 100644 --- a/Source/Game/Cabrito/Console/ConsoleContainerControl.cs +++ b/Source/Game/Cabrito/Console/ConsoleContainerControl.cs @@ -7,35 +7,33 @@ using FlaxEngine.GUI; namespace Cabrito { - // Container that keeps the focus on the input box - public class ConsoleContainerControl : ContainerControl - { - [HideInEditor] - public ConsoleInputTextBox inputBox; + // Container that keeps the focus on the input box + public class ConsoleContainerControl : ContainerControl + { + [HideInEditor] public ConsoleInputTextBox inputBox; - public ConsoleContainerControl() : base() - { + public ConsoleContainerControl() : base() + { + } - } + public ConsoleContainerControl(float x, float y, float width, float height) : base(x, y, width, height) + { + } - public ConsoleContainerControl(float x, float y, float width, float height) : base(x, y, width, height) - { - } + public ConsoleContainerControl(Rectangle bounds) : base(bounds) + { + } - public ConsoleContainerControl(Rectangle bounds) : base(bounds) - { - } + public override void OnGotFocus() + { + base.OnGotFocus(); + if (inputBox != null) + Focus(inputBox); + } - public override void OnGotFocus() - { - base.OnGotFocus(); - if (inputBox != null) - Focus(inputBox); - } - - public override void OnLostFocus() - { - base.OnLostFocus(); - } - } -} + public override void OnLostFocus() + { + base.OnLostFocus(); + } + } +} \ No newline at end of file diff --git a/Source/Game/Cabrito/Console/ConsoleContentTextBox.cs b/Source/Game/Cabrito/Console/ConsoleContentTextBox.cs index 039cc86..bdab04e 100644 --- a/Source/Game/Cabrito/Console/ConsoleContentTextBox.cs +++ b/Source/Game/Cabrito/Console/ConsoleContentTextBox.cs @@ -9,608 +9,617 @@ using FlaxEngine.GUI; namespace Cabrito { - public class ConsoleContentTextBox : Control - { - struct LineInfo - { - public int lineIndex; - public int lineOffset; - public int lineLength; - } - - [HideInEditor] - public ConsoleInputTextBox inputBox; - - protected TextLayoutOptions _layout; - - public FontReference Font; - - public float LineSpacing = 1.0f; - - public TextWrapping Wrapping; - - public Color SelectionColor = new Color(0x00, 0x7A, 0xCC, 0xFF); - public Color BackgroundSelectedColor = Color.Transparent; - public float BackgroundSelectedFlashSpeed = 0; - public Color BorderSelectedColor = Color.Transparent; - public float CaretFlashSpeed = 0; - public Color BorderColor; - public Color TextColor = Color.White; - - public int DefaultMargin = 1; - public int ScrollOffset = 0; - public int ScrollMouseLines = 3; - - private float heightMultiplier = 1.0f; - public float HeightMultiplier - { - get => heightMultiplier; - set - { - heightMultiplier = value; - UpdateHeight(); - } - } - - private int selectionStartLine = 0; - private int selectionStartChar = 0; - private int selectionEndLine = 0; - private int selectionEndChar = 0; - - - - private bool selectionActive; - public bool HasSelection => !(selectionStartLine == selectionEndLine && selectionStartChar == selectionEndChar); - - public ConsoleContentTextBox() : base() - { - } - - public ConsoleContentTextBox(ConsoleInputTextBox inputBox, float x, float y, float width, float height) : base(x, y, width, height) - { - this.inputBox = inputBox; - Height = height; - - _layout = TextLayoutOptions.Default; - _layout.VerticalAlignment = TextAlignment.Near; - _layout.TextWrapping = TextWrapping.WrapChars; - _layout.Bounds = new Rectangle(DefaultMargin, 1, Width - 2 * DefaultMargin, Height - 2); - - - //IsMultiline = true; - //IsReadOnly = true; - //CaretColor = new Color(0f, 0f, 0f, 0f); - AutoFocus = false; - } - - private int GetFontCharacterWidth() - { - var font = Font.GetFont(); - if (!font) - return 0; - return (int)font.MeasureText("a").X; // hacky, but works for fixed-size fonts... - } - - public int GetFontHeight() - { - var font = Font.GetFont(); - if (font == null) - return (int)Height; - - return (int)Mathf.Round(LineSpacing * (font.Height / Platform.DpiScale) * Scale.Y); - } - - private int GetHeightInLines() - { - var font = Font.GetFont(); - if (!font) - return 0; - return (int)(Height / (font.Height / Platform.DpiScale)); // number of fully visible lines - } - - protected override void OnParentChangedInternal() - { - base.OnParentChangedInternal(); - - if (Parent != null) - OnParentResized(); - } - - public override void OnParentResized() - { - UpdateHeight(); - base.OnParentResized(); - } - - private void UpdateHeight() - { - if (Parent != null && Parent.Parent != null) - Height = (Parent.Parent.Size.Y * HeightMultiplier) - GetFontHeight(); - } - - - private void CalculateVisibleLines(IReadOnlyCollection lines, out int firstVisibleLine, out int lastVisibleLine, out LineInfo[] wrappedLines) - { - wrappedLines = null; - firstVisibleLine = 0; - lastVisibleLine = 0; - - var font = Font.GetFont(); - if (!font) - return; - - float fontWidth = GetFontCharacterWidth(); - int lineMaxChars = (int)(Width / fontWidth); - int lineMaxLines = GetHeightInLines(); - int numLines = 0; - int lineIndex = lines.Count; - List lineInfos = new List(lineMaxLines+1); - int linesSkipped = 0; - foreach (string line in lines.Reverse()) - { - lineIndex--; - if (linesSkipped < ScrollOffset) - { - linesSkipped++; - continue; - } - int numChars = 0; - int startIndex = lineInfos.Count; - while (numChars < line.Length) - { - LineInfo li = new LineInfo(); - li.lineIndex = lineIndex; - li.lineOffset = numChars; - li.lineLength = Math.Min(line.Length - numChars, lineMaxChars); - lineInfos.Add(li); - - numChars += lineMaxChars; - } - if (lineInfos.Count - startIndex > 1) - lineInfos.Reverse(startIndex, lineInfos.Count - startIndex); - numLines++; - - if (lineInfos.Count > lineMaxLines) - break; - } - - lineInfos.Reverse(); - wrappedLines = lineInfos.ToArray(); - - //return lines[lines.Count - numLines .. lines.Count]; // C# 8.0... - lastVisibleLine = lineIndex; - firstVisibleLine = lastVisibleLine - numLines; - } - - public static double accumDrawTime = 0.0; - public static long accumDrawTimes = 0; - public override void Draw() - { - // Cache data - var rect = new Rectangle(Vector2.Zero, Size); - var font = Font.GetFont(); - if (!font) - return; - - Profiler.BeginEvent("ConsoleContetTextBoxDraw"); - Stopwatch sw = Stopwatch.StartNew(); - - // Background - Color backColor = BackgroundColor; - if (IsMouseOver) - backColor = BackgroundSelectedColor; - if (backColor.A > 0.0f) - Render2D.FillRectangle(rect, backColor); - - Color borderColor = IsFocused ? BorderSelectedColor : BorderColor; - if (borderColor.A > 0.0f) - Render2D.DrawRectangle(rect, borderColor); - - var lines = Console.Lines; - - if (lines.Count > 0) - { - - // Apply view offset and clip mask - var textClipRectangle = new Rectangle(1, 1, Width - 2, Height - 2); - Render2D.PushClip(textClipRectangle); - - // Make sure lengthy lines are split - CalculateVisibleLines(lines, out int startLine, out int lastLine, out LineInfo[] wrappedLines); - - float lineHeight = font.Height / Platform.DpiScale; - float accumHeight = wrappedLines.Length * lineHeight; - - // selection in line-space, wrapping ignored - int selectionLeftLine = selectionStartLine; - int selectionLeftChar = selectionStartChar; - int selectionRightLine = selectionEndLine; - int selectionRightChar = selectionEndChar; - - if (selectionLeftLine > selectionRightLine || (selectionLeftLine == selectionRightLine && selectionLeftChar > selectionRightChar)) - { - selectionLeftLine = selectionEndLine; - selectionLeftChar = selectionEndChar; - selectionRightLine = selectionStartLine; - selectionRightChar = selectionStartChar; - } - - // render selection - if (selectionActive) - { - - //float alpha = Mathf.Min(1.0f, Mathf.Cos(_animateTime * BackgroundSelectedFlashSpeed) * 0.5f + 1.3f); - //alpha = alpha * alpha; - Color selectionColor = SelectionColor;// * alpha; - - TextLayoutOptions layout = _layout; - layout.Bounds = rect; - layout.Bounds.Y -= accumHeight - Height; - //for (int i = startLine; i < lastLine; i++) - foreach (LineInfo li in wrappedLines) - { - var lineIndex = li.lineIndex; - string fullLine = lines.ElementAt(lineIndex); - string line = fullLine.Substring(li.lineOffset, li.lineLength); - - int leftChar = selectionLeftChar; - int rightChar = selectionRightChar; - - Rectangle selectionRect = new Rectangle(layout.Bounds.X, layout.Bounds.Y, 0f, 0f); - - // apply selection - if (lineIndex >= selectionLeftLine && lineIndex <= selectionRightLine) - { - if (lineIndex > selectionLeftLine && lineIndex < selectionRightLine) - { - // whole line is selected - Vector2 lineSize = font.MeasureText(line); - selectionRect.Width = lineSize.X; - selectionRect.Height = lineSize.Y; - } - else if (lineIndex == selectionLeftLine) - { - if (lineIndex < selectionRightLine) - { - // right side of the line is selected - Vector2 leftSize = font.MeasureText(fullLine.Substring(0, leftChar)); - Vector2 rightSize = font.MeasureText(fullLine.Substring(leftChar)); - selectionRect.X += leftSize.X; - selectionRect.Width = rightSize.X; - selectionRect.Height = rightSize.Y; - - //int diff = line.Length - selectionLeftChar; - //line = line.Substring(0, selectionLeftChar) + (diff > 0 ? new string('X', diff) : ""); - } - else if (lineIndex == selectionRightLine && leftChar != rightChar) - { - // selecting middle of the one line - Vector2 lineSize = font.MeasureText(fullLine); - Vector2 leftSize = font.MeasureText(fullLine.Substring(0, leftChar)); - Vector2 midSize = font.MeasureText(fullLine.Substring(leftChar, rightChar-leftChar)); - - selectionRect.X += leftSize.X; - selectionRect.Width = midSize.X; - selectionRect.Height = lineSize.Y; - - //int diff = selectionRightChar - selectionLeftChar; - //line = line.Substring(0, selectionLeftChar) + (diff > 0 ? new string('X', diff) : "") + line.Substring(selectionRightChar); - } - } - else if (lineIndex == selectionRightLine) - { - // left side of the line is selected - Vector2 leftSize = font.MeasureText(fullLine.Substring(0, rightChar)); - selectionRect.Width = leftSize.X; - selectionRect.Height = leftSize.Y; - - //line = (selectionRightChar > 0 ? new string('X', selectionRightChar) : "") + line.Substring(selectionRightChar); - } - } - - - Render2D.FillRectangle(selectionRect, selectionColor); - - layout.Bounds.Y += lineHeight; - } - } - - // render lines - { - TextLayoutOptions layout = _layout; - layout.Bounds = rect; - layout.Bounds.Y -= accumHeight - Height; - foreach (LineInfo li in wrappedLines) - { - var lineIndex = li.lineIndex; - string line = lines.ElementAt(lineIndex).content.Substring(li.lineOffset, li.lineLength); - Render2D.DrawText(font, line, TextColor, ref layout); - layout.Bounds.Y += lineHeight; - } - } - - /*if (CaretPosition > -1) - { - var prefixSize = TextPrefix != "" ? font.MeasureText(TextPrefix) : new Vector2(); - var caretBounds = CaretBounds; - caretBounds.X += prefixSize.X; - - float alpha = Mathf.Saturate(Mathf.Cos(_animateTime * CaretFlashSpeed) * 0.5f + 0.7f); - alpha = alpha * alpha * alpha * alpha * alpha * alpha; - Render2D.FillRectangle(caretBounds, CaretColor * alpha); - }*/ - - Render2D.PopClip(); - } - sw.Stop(); - accumDrawTime += sw.Elapsed.TotalSeconds; - accumDrawTimes++; - Profiler.EndEvent(); - } - - - private void OnSelectingBegin() - { - if (selectionActive) - return; - - selectionActive = true; - StartMouseCapture(); - } - - private void OnSelectingEnd() - { - if (!selectionActive) - return; - - selectionActive = false; - EndMouseCapture(); - } - - public bool HitTestText(Vector2 location, out int hitLine, out int hitChar) - { - hitLine = 0; - hitChar = 0; - var font = Font.GetFont(); - if (font == null) - return false; - - var lines = Console.Lines; - CalculateVisibleLines(lines, out int startLine, out int lastLine, out LineInfo[] wrappedLines); - - TextLayoutOptions layout = _layout; - layout.Bounds = new Rectangle(0, 0, Size); - float lineHeightNormalized = font.Height; - float lineHeight = lineHeightNormalized / Platform.DpiScale; - float visibleHeight = wrappedLines.Length * lineHeight; - float top = (layout.Bounds.Bottom - visibleHeight) / Platform.DpiScale; // UI coordinate space remains normalized - int lineMaxLines = (int)(Height / lineHeight); - - int hiddenLines = 0; - if (wrappedLines.Length > lineMaxLines) - hiddenLines = wrappedLines.Length - lineMaxLines; - //if (top < layout.Bounds.Top) - // hiddenLines = (int)Math.Ceiling((layout.Bounds.Top - top) / (float)lineHeight); - - int hitWrappedLine = (int)((location.Y - top) / lineHeight); //+ hiddenLines; - if (hitWrappedLine < 0 || hitWrappedLine >= wrappedLines.Length) - return false; - - hitLine = wrappedLines[hitWrappedLine].lineIndex; - string line = lines.ElementAt(hitLine).content.Substring(wrappedLines[hitWrappedLine].lineOffset, wrappedLines[hitWrappedLine].lineLength); - - layout.Bounds.Y = top + ((hitWrappedLine) * lineHeight); - layout.Bounds.Height = top + 9999;//(visibleHeight / Platform.DpiScale); - /*if (layout.Bounds.Y < 0) - { - layout.Bounds.Y = 1; - }*/ - - hitChar = font.HitTestText(line, location, ref layout); - hitChar += wrappedLines[hitWrappedLine].lineOffset; - - //FlaxEngine.Debug.Log(string.Format("hit line {0}/{1}, char {2}", hitWrappedLine, wrappedLines.Length, hitChar)); - return true; - } - - /*public int CharIndexAtPoint(ref Vector2 location) - { - return HitTestText(location + _viewOffset); - }*/ - - public override bool OnKeyDown(KeyboardKeys key) - { - bool shiftDown = Root.GetKey(KeyboardKeys.Shift); - bool ctrlDown = Root.GetKey(KeyboardKeys.Control); - - if ((shiftDown && key == KeyboardKeys.Delete) || (ctrlDown && key == KeyboardKeys.Insert) || (ctrlDown && key == KeyboardKeys.C) || (ctrlDown && key == KeyboardKeys.X)) - { - Copy(); - return true; - } - else if (key == KeyboardKeys.PageUp) - { - ScrollOffset += GetHeightInLines() / 2; - var maxOffset = Console.Lines.Count - GetHeightInLines(); - if (ScrollOffset > maxOffset) - ScrollOffset = maxOffset; - } - else if (key == KeyboardKeys.PageDown) - { - ScrollOffset -= GetHeightInLines() / 2; - if (ScrollOffset < 0) - ScrollOffset = 0; - } - //else if (ctrlDown && key == KeyboardKeys.A) - // SelectAll(); - return base.OnKeyDown(key); - } - - public override bool OnMouseWheel(Vector2 location, float delta) - { - if (delta < 0) - { - ScrollOffset -= ScrollMouseLines; - if (ScrollOffset < 0) - ScrollOffset = 0; - - } - else if (delta > 0) - { - ScrollOffset += ScrollMouseLines; - var maxOffset = Console.Lines.Count - GetHeightInLines(); - if (ScrollOffset > maxOffset) - ScrollOffset = maxOffset; - } - return false; - } - - public override bool OnMouseDown(Vector2 location, MouseButton button) - { - bool ret = false; - if (button == MouseButton.Left && !IsFocused) - { - Focus(); - ret = true; - } - - if (button == MouseButton.Left && Console.Lines.Count > 0) - { - bool selectionStarted = !selectionActive; - Focus(); - OnSelectingBegin(); - - //FlaxEngine.Debug.Log("mousedown, started: " + selectionStarted.ToString()); - - if (HitTestText(location, out int hitLine, out int hitChar)) - { - selectionStartLine = hitLine; - selectionStartChar = hitChar; - selectionEndLine = hitLine; - selectionEndChar = hitChar; - //FlaxEngine.Debug.Log(string.Format("start line {0} char {1}", hitLine, hitChar)); - } - else - throw new Exception("no???"); - - - // Select range with shift - /*if (_selectionStart != -1 && RootWindow.GetKey(KeyboardKeys.Shift) && SelectionLength == 0) - { - if (hitPos < _selectionStart) - SetSelection(hitPos, _selectionStart); - else - SetSelection(_selectionStart, hitPos); - } - else - { - SetSelection(hitPos); - }*/ - - return true; - } - - return ret; - } - - public override void OnMouseMove(Vector2 location) - { - if (selectionActive) - { - if (HitTestText(location, out int hitLine, out int hitChar)) - { - selectionEndLine = hitLine; - selectionEndChar = hitChar; - //FlaxEngine.Debug.Log(string.Format("end line {0} char {1}", hitLine, hitChar)); - } - } - } - - /// - public override bool OnMouseUp(Vector2 location, MouseButton button) - { - if (button == MouseButton.Left) - { - OnSelectingEnd(); - Focus(inputBox); - return true; - } - - return false; - } - - protected void Copy() - { - if (!selectionActive) - return; - - // selection in line-space, wrapping ignored - int selectionLeftLine = selectionStartLine; - int selectionLeftChar = selectionStartChar; - int selectionRightLine = selectionEndLine; - int selectionRightChar = selectionEndChar; - - if (selectionLeftLine > selectionRightLine || (selectionLeftLine == selectionRightLine && selectionLeftChar > selectionRightChar)) - { - selectionLeftLine = selectionEndLine; - selectionLeftChar = selectionEndChar; - selectionRightLine = selectionStartLine; - selectionRightChar = selectionStartChar; - } - - var lines = Console.Lines; - CalculateVisibleLines(lines, out int startLine, out int lastLine, out LineInfo[] wrappedLines); - - StringBuilder selectedText = new StringBuilder(); - int lastLineIndex = -1; - - foreach (LineInfo li in wrappedLines) - { - var lineIndex = li.lineIndex; - if (lineIndex < selectionLeftLine || lineIndex > selectionRightLine) - continue; - - if (lastLineIndex != lineIndex && lastLineIndex != -1) - selectedText.AppendLine(); - lastLineIndex = lineIndex; - - string fullLine = lines.ElementAt(lineIndex); - string line = fullLine.Substring(li.lineOffset, li.lineLength); - - int leftChar = selectionLeftChar; - int rightChar = selectionRightChar; - - if (lineIndex >= selectionLeftLine && lineIndex <= selectionRightLine) - { - if (lineIndex > selectionLeftLine && lineIndex < selectionRightLine) - { - // whole line is selected - selectedText.Append(line); - } - else if (lineIndex == selectionLeftLine) - { - if (lineIndex < selectionRightLine) - { - // right side of the line is selected - selectedText.Append(fullLine.Substring(leftChar)); - } - else if (lineIndex == selectionRightLine && leftChar != rightChar) - { - // selecting middle of the one line - selectedText.Append(fullLine.Substring(leftChar, rightChar - leftChar)); - } - } - else if (lineIndex == selectionRightLine) - { - // left side of the line is selected - selectedText.Append(fullLine.Substring(0, rightChar)); - } - } - } - - if (selectedText.Length > 0) - Clipboard.Text = selectedText.ToString(); - } - - } -} + public class ConsoleContentTextBox : Control + { + struct LineInfo + { + public int lineIndex; + public int lineOffset; + public int lineLength; + } + + [HideInEditor] public ConsoleInputTextBox inputBox; + + protected TextLayoutOptions _layout; + + public FontReference Font; + + public float LineSpacing = 1.0f; + + public TextWrapping Wrapping; + + public Color SelectionColor = new Color(0x00, 0x7A, 0xCC, 0xFF); + public Color BackgroundSelectedColor = Color.Transparent; + public float BackgroundSelectedFlashSpeed = 0; + public Color BorderSelectedColor = Color.Transparent; + public float CaretFlashSpeed = 0; + public Color BorderColor; + public Color TextColor = Color.White; + + public int DefaultMargin = 1; + public int ScrollOffset = 0; + public int ScrollMouseLines = 3; + + private float heightMultiplier = 1.0f; + + public float HeightMultiplier + { + get => heightMultiplier; + set + { + heightMultiplier = value; + UpdateHeight(); + } + } + + private int selectionStartLine = 0; + private int selectionStartChar = 0; + private int selectionEndLine = 0; + private int selectionEndChar = 0; + + + private bool selectionActive; + public bool HasSelection => !(selectionStartLine == selectionEndLine && selectionStartChar == selectionEndChar); + + public ConsoleContentTextBox() : base() + { + } + + public ConsoleContentTextBox(ConsoleInputTextBox inputBox, float x, float y, float width, float height) : base( + x, y, width, height) + { + this.inputBox = inputBox; + Height = height; + + _layout = TextLayoutOptions.Default; + _layout.VerticalAlignment = TextAlignment.Near; + _layout.TextWrapping = TextWrapping.WrapChars; + _layout.Bounds = new Rectangle(DefaultMargin, 1, Width - 2 * DefaultMargin, Height - 2); + + + //IsMultiline = true; + //IsReadOnly = true; + //CaretColor = new Color(0f, 0f, 0f, 0f); + AutoFocus = false; + } + + private int GetFontCharacterWidth() + { + var font = Font.GetFont(); + if (!font) + return 0; + return (int) font.MeasureText("a").X; // hacky, but works for fixed-size fonts... + } + + public int GetFontHeight() + { + var font = Font.GetFont(); + if (font == null) + return (int) Height; + + return (int) Mathf.Round(LineSpacing * (font.Height / Platform.DpiScale) * Scale.Y); + } + + private int GetHeightInLines() + { + var font = Font.GetFont(); + if (!font) + return 0; + return (int) (Height / (font.Height / Platform.DpiScale)); // number of fully visible lines + } + + protected override void OnParentChangedInternal() + { + base.OnParentChangedInternal(); + + if (Parent != null) + OnParentResized(); + } + + public override void OnParentResized() + { + UpdateHeight(); + base.OnParentResized(); + } + + private void UpdateHeight() + { + if (Parent != null && Parent.Parent != null) + Height = (Parent.Parent.Size.Y * HeightMultiplier) - GetFontHeight(); + } + + + private void CalculateVisibleLines(IReadOnlyCollection lines, out int firstVisibleLine, + out int lastVisibleLine, out LineInfo[] wrappedLines) + { + wrappedLines = null; + firstVisibleLine = 0; + lastVisibleLine = 0; + + var font = Font.GetFont(); + if (!font) + return; + + float fontWidth = GetFontCharacterWidth(); + int lineMaxChars = (int) (Width / fontWidth); + int lineMaxLines = GetHeightInLines(); + int numLines = 0; + int lineIndex = lines.Count; + List lineInfos = new List(lineMaxLines + 1); + int linesSkipped = 0; + foreach (string line in lines.Reverse()) + { + lineIndex--; + if (linesSkipped < ScrollOffset) + { + linesSkipped++; + continue; + } + + int numChars = 0; + int startIndex = lineInfos.Count; + while (numChars < line.Length) + { + LineInfo li = new LineInfo(); + li.lineIndex = lineIndex; + li.lineOffset = numChars; + li.lineLength = Math.Min(line.Length - numChars, lineMaxChars); + lineInfos.Add(li); + + numChars += lineMaxChars; + } + + if (lineInfos.Count - startIndex > 1) + lineInfos.Reverse(startIndex, lineInfos.Count - startIndex); + numLines++; + + if (lineInfos.Count > lineMaxLines) + break; + } + + lineInfos.Reverse(); + wrappedLines = lineInfos.ToArray(); + + //return lines[lines.Count - numLines .. lines.Count]; // C# 8.0... + lastVisibleLine = lineIndex; + firstVisibleLine = lastVisibleLine - numLines; + } + + public static double accumDrawTime = 0.0; + public static long accumDrawTimes = 0; + + public override void Draw() + { + // Cache data + var rect = new Rectangle(Vector2.Zero, Size); + var font = Font.GetFont(); + if (!font) + return; + + Profiler.BeginEvent("ConsoleContetTextBoxDraw"); + Stopwatch sw = Stopwatch.StartNew(); + + // Background + Color backColor = BackgroundColor; + if (IsMouseOver) + backColor = BackgroundSelectedColor; + if (backColor.A > 0.0f) + Render2D.FillRectangle(rect, backColor); + + Color borderColor = IsFocused ? BorderSelectedColor : BorderColor; + if (borderColor.A > 0.0f) + Render2D.DrawRectangle(rect, borderColor); + + var lines = Console.Lines; + + if (lines.Count > 0) + { + // Apply view offset and clip mask + var textClipRectangle = new Rectangle(1, 1, Width - 2, Height - 2); + Render2D.PushClip(textClipRectangle); + + // Make sure lengthy lines are split + CalculateVisibleLines(lines, out int startLine, out int lastLine, out LineInfo[] wrappedLines); + + float lineHeight = font.Height / Platform.DpiScale; + float accumHeight = wrappedLines.Length * lineHeight; + + // selection in line-space, wrapping ignored + int selectionLeftLine = selectionStartLine; + int selectionLeftChar = selectionStartChar; + int selectionRightLine = selectionEndLine; + int selectionRightChar = selectionEndChar; + + if (selectionLeftLine > selectionRightLine || + (selectionLeftLine == selectionRightLine && selectionLeftChar > selectionRightChar)) + { + selectionLeftLine = selectionEndLine; + selectionLeftChar = selectionEndChar; + selectionRightLine = selectionStartLine; + selectionRightChar = selectionStartChar; + } + + // render selection + if (selectionActive) + { + //float alpha = Mathf.Min(1.0f, Mathf.Cos(_animateTime * BackgroundSelectedFlashSpeed) * 0.5f + 1.3f); + //alpha = alpha * alpha; + Color selectionColor = SelectionColor; // * alpha; + + TextLayoutOptions layout = _layout; + layout.Bounds = rect; + layout.Bounds.Y -= accumHeight - Height; + //for (int i = startLine; i < lastLine; i++) + foreach (LineInfo li in wrappedLines) + { + var lineIndex = li.lineIndex; + string fullLine = lines.ElementAt(lineIndex); + string line = fullLine.Substring(li.lineOffset, li.lineLength); + + int leftChar = selectionLeftChar; + int rightChar = selectionRightChar; + + Rectangle selectionRect = new Rectangle(layout.Bounds.X, layout.Bounds.Y, 0f, 0f); + + // apply selection + if (lineIndex >= selectionLeftLine && lineIndex <= selectionRightLine) + { + if (lineIndex > selectionLeftLine && lineIndex < selectionRightLine) + { + // whole line is selected + Vector2 lineSize = font.MeasureText(line); + selectionRect.Width = lineSize.X; + selectionRect.Height = lineSize.Y; + } + else if (lineIndex == selectionLeftLine) + { + if (lineIndex < selectionRightLine) + { + // right side of the line is selected + Vector2 leftSize = font.MeasureText(fullLine.Substring(0, leftChar)); + Vector2 rightSize = font.MeasureText(fullLine.Substring(leftChar)); + selectionRect.X += leftSize.X; + selectionRect.Width = rightSize.X; + selectionRect.Height = rightSize.Y; + + //int diff = line.Length - selectionLeftChar; + //line = line.Substring(0, selectionLeftChar) + (diff > 0 ? new string('X', diff) : ""); + } + else if (lineIndex == selectionRightLine && leftChar != rightChar) + { + // selecting middle of the one line + Vector2 lineSize = font.MeasureText(fullLine); + Vector2 leftSize = font.MeasureText(fullLine.Substring(0, leftChar)); + Vector2 midSize = + font.MeasureText(fullLine.Substring(leftChar, rightChar - leftChar)); + + selectionRect.X += leftSize.X; + selectionRect.Width = midSize.X; + selectionRect.Height = lineSize.Y; + + //int diff = selectionRightChar - selectionLeftChar; + //line = line.Substring(0, selectionLeftChar) + (diff > 0 ? new string('X', diff) : "") + line.Substring(selectionRightChar); + } + } + else if (lineIndex == selectionRightLine) + { + // left side of the line is selected + Vector2 leftSize = font.MeasureText(fullLine.Substring(0, rightChar)); + selectionRect.Width = leftSize.X; + selectionRect.Height = leftSize.Y; + + //line = (selectionRightChar > 0 ? new string('X', selectionRightChar) : "") + line.Substring(selectionRightChar); + } + } + + + Render2D.FillRectangle(selectionRect, selectionColor); + + layout.Bounds.Y += lineHeight; + } + } + + // render lines + { + TextLayoutOptions layout = _layout; + layout.Bounds = rect; + layout.Bounds.Y -= accumHeight - Height; + foreach (LineInfo li in wrappedLines) + { + var lineIndex = li.lineIndex; + string line = lines.ElementAt(lineIndex).content.Substring(li.lineOffset, li.lineLength); + Render2D.DrawText(font, line, TextColor, ref layout); + layout.Bounds.Y += lineHeight; + } + } + + /*if (CaretPosition > -1) + { + var prefixSize = TextPrefix != "" ? font.MeasureText(TextPrefix) : new Vector2(); + var caretBounds = CaretBounds; + caretBounds.X += prefixSize.X; + + float alpha = Mathf.Saturate(Mathf.Cos(_animateTime * CaretFlashSpeed) * 0.5f + 0.7f); + alpha = alpha * alpha * alpha * alpha * alpha * alpha; + Render2D.FillRectangle(caretBounds, CaretColor * alpha); + }*/ + + Render2D.PopClip(); + } + + sw.Stop(); + accumDrawTime += sw.Elapsed.TotalSeconds; + accumDrawTimes++; + Profiler.EndEvent(); + } + + + private void OnSelectingBegin() + { + if (selectionActive) + return; + + selectionActive = true; + StartMouseCapture(); + } + + private void OnSelectingEnd() + { + if (!selectionActive) + return; + + selectionActive = false; + EndMouseCapture(); + } + + public bool HitTestText(Vector2 location, out int hitLine, out int hitChar) + { + hitLine = 0; + hitChar = 0; + var font = Font.GetFont(); + if (font == null) + return false; + + var lines = Console.Lines; + CalculateVisibleLines(lines, out int startLine, out int lastLine, out LineInfo[] wrappedLines); + + TextLayoutOptions layout = _layout; + layout.Bounds = new Rectangle(0, 0, Size); + float lineHeightNormalized = font.Height; + float lineHeight = lineHeightNormalized / Platform.DpiScale; + float visibleHeight = wrappedLines.Length * lineHeight; + float top = (layout.Bounds.Bottom - visibleHeight) / + Platform.DpiScale; // UI coordinate space remains normalized + int lineMaxLines = (int) (Height / lineHeight); + + int hiddenLines = 0; + if (wrappedLines.Length > lineMaxLines) + hiddenLines = wrappedLines.Length - lineMaxLines; + //if (top < layout.Bounds.Top) + // hiddenLines = (int)Math.Ceiling((layout.Bounds.Top - top) / (float)lineHeight); + + int hitWrappedLine = (int) ((location.Y - top) / lineHeight); //+ hiddenLines; + if (hitWrappedLine < 0 || hitWrappedLine >= wrappedLines.Length) + return false; + + hitLine = wrappedLines[hitWrappedLine].lineIndex; + string line = lines.ElementAt(hitLine).content.Substring(wrappedLines[hitWrappedLine].lineOffset, + wrappedLines[hitWrappedLine].lineLength); + + layout.Bounds.Y = top + ((hitWrappedLine) * lineHeight); + layout.Bounds.Height = top + 9999; //(visibleHeight / Platform.DpiScale); + /*if (layout.Bounds.Y < 0) + { + layout.Bounds.Y = 1; + }*/ + + hitChar = font.HitTestText(line, location, ref layout); + hitChar += wrappedLines[hitWrappedLine].lineOffset; + + //FlaxEngine.Debug.Log(string.Format("hit line {0}/{1}, char {2}", hitWrappedLine, wrappedLines.Length, hitChar)); + return true; + } + + /*public int CharIndexAtPoint(ref Vector2 location) + { + return HitTestText(location + _viewOffset); + }*/ + + public override bool OnKeyDown(KeyboardKeys key) + { + bool shiftDown = Root.GetKey(KeyboardKeys.Shift); + bool ctrlDown = Root.GetKey(KeyboardKeys.Control); + + if ((shiftDown && key == KeyboardKeys.Delete) || (ctrlDown && key == KeyboardKeys.Insert) || + (ctrlDown && key == KeyboardKeys.C) || (ctrlDown && key == KeyboardKeys.X)) + { + Copy(); + return true; + } + else if (key == KeyboardKeys.PageUp) + { + ScrollOffset += GetHeightInLines() / 2; + var maxOffset = Console.Lines.Count - GetHeightInLines(); + if (ScrollOffset > maxOffset) + ScrollOffset = maxOffset; + } + else if (key == KeyboardKeys.PageDown) + { + ScrollOffset -= GetHeightInLines() / 2; + if (ScrollOffset < 0) + ScrollOffset = 0; + } + + //else if (ctrlDown && key == KeyboardKeys.A) + // SelectAll(); + return base.OnKeyDown(key); + } + + public override bool OnMouseWheel(Vector2 location, float delta) + { + if (delta < 0) + { + ScrollOffset -= ScrollMouseLines; + if (ScrollOffset < 0) + ScrollOffset = 0; + } + else if (delta > 0) + { + ScrollOffset += ScrollMouseLines; + var maxOffset = Console.Lines.Count - GetHeightInLines(); + if (ScrollOffset > maxOffset) + ScrollOffset = maxOffset; + } + + return false; + } + + public override bool OnMouseDown(Vector2 location, MouseButton button) + { + bool ret = false; + if (button == MouseButton.Left && !IsFocused) + { + Focus(); + ret = true; + } + + if (button == MouseButton.Left && Console.Lines.Count > 0) + { + bool selectionStarted = !selectionActive; + Focus(); + OnSelectingBegin(); + + //FlaxEngine.Debug.Log("mousedown, started: " + selectionStarted.ToString()); + + if (HitTestText(location, out int hitLine, out int hitChar)) + { + selectionStartLine = hitLine; + selectionStartChar = hitChar; + selectionEndLine = hitLine; + selectionEndChar = hitChar; + //FlaxEngine.Debug.Log(string.Format("start line {0} char {1}", hitLine, hitChar)); + } + else + throw new Exception("no???"); + + + // Select range with shift + /*if (_selectionStart != -1 && RootWindow.GetKey(KeyboardKeys.Shift) && SelectionLength == 0) + { + if (hitPos < _selectionStart) + SetSelection(hitPos, _selectionStart); + else + SetSelection(_selectionStart, hitPos); + } + else + { + SetSelection(hitPos); + }*/ + + return true; + } + + return ret; + } + + public override void OnMouseMove(Vector2 location) + { + if (selectionActive) + { + if (HitTestText(location, out int hitLine, out int hitChar)) + { + selectionEndLine = hitLine; + selectionEndChar = hitChar; + //FlaxEngine.Debug.Log(string.Format("end line {0} char {1}", hitLine, hitChar)); + } + } + } + + /// + public override bool OnMouseUp(Vector2 location, MouseButton button) + { + if (button == MouseButton.Left) + { + OnSelectingEnd(); + Focus(inputBox); + return true; + } + + return false; + } + + protected void Copy() + { + if (!selectionActive) + return; + + // selection in line-space, wrapping ignored + int selectionLeftLine = selectionStartLine; + int selectionLeftChar = selectionStartChar; + int selectionRightLine = selectionEndLine; + int selectionRightChar = selectionEndChar; + + if (selectionLeftLine > selectionRightLine || + (selectionLeftLine == selectionRightLine && selectionLeftChar > selectionRightChar)) + { + selectionLeftLine = selectionEndLine; + selectionLeftChar = selectionEndChar; + selectionRightLine = selectionStartLine; + selectionRightChar = selectionStartChar; + } + + var lines = Console.Lines; + CalculateVisibleLines(lines, out int startLine, out int lastLine, out LineInfo[] wrappedLines); + + StringBuilder selectedText = new StringBuilder(); + int lastLineIndex = -1; + + foreach (LineInfo li in wrappedLines) + { + var lineIndex = li.lineIndex; + if (lineIndex < selectionLeftLine || lineIndex > selectionRightLine) + continue; + + if (lastLineIndex != lineIndex && lastLineIndex != -1) + selectedText.AppendLine(); + lastLineIndex = lineIndex; + + string fullLine = lines.ElementAt(lineIndex); + string line = fullLine.Substring(li.lineOffset, li.lineLength); + + int leftChar = selectionLeftChar; + int rightChar = selectionRightChar; + + if (lineIndex >= selectionLeftLine && lineIndex <= selectionRightLine) + { + if (lineIndex > selectionLeftLine && lineIndex < selectionRightLine) + { + // whole line is selected + selectedText.Append(line); + } + else if (lineIndex == selectionLeftLine) + { + if (lineIndex < selectionRightLine) + { + // right side of the line is selected + selectedText.Append(fullLine.Substring(leftChar)); + } + else if (lineIndex == selectionRightLine && leftChar != rightChar) + { + // selecting middle of the one line + selectedText.Append(fullLine.Substring(leftChar, rightChar - leftChar)); + } + } + else if (lineIndex == selectionRightLine) + { + // left side of the line is selected + selectedText.Append(fullLine.Substring(0, rightChar)); + } + } + } + + if (selectedText.Length > 0) + Clipboard.Text = selectedText.ToString(); + } + } +} \ No newline at end of file diff --git a/Source/Game/Cabrito/Console/ConsoleInputTextBox.cs b/Source/Game/Cabrito/Console/ConsoleInputTextBox.cs index 8886c5e..dafdd29 100644 --- a/Source/Game/Cabrito/Console/ConsoleInputTextBox.cs +++ b/Source/Game/Cabrito/Console/ConsoleInputTextBox.cs @@ -7,138 +7,142 @@ using FlaxEngine.GUI; namespace Cabrito { - public class ConsoleInputTextBox : ConsoleTextBoxBase - { - public override string TextPrefix { get => Console.LinePrefix; } + public class ConsoleInputTextBox : ConsoleTextBoxBase + { + public override string TextPrefix + { + get => Console.LinePrefix; + } - private ConsoleContentTextBox contentBox; + private ConsoleContentTextBox contentBox; - protected override Rectangle TextRectangle => new Rectangle(0, 0, Width, Height); - protected override Rectangle TextClipRectangle => new Rectangle(0, 0, Width, Height); + protected override Rectangle TextRectangle => new Rectangle(0, 0, Width, Height); + protected override Rectangle TextClipRectangle => new Rectangle(0, 0, Width, Height); - public ConsoleInputTextBox() : base() - { + public ConsoleInputTextBox() : base() + { + } - } + public ConsoleInputTextBox(ConsoleContentTextBox contentBox, float x, float y, float width, float height) : + base(x, y, width, height) + { + this.contentBox = contentBox; + IsMultiline = true; // Not really but behaves better than single-line box + } - public ConsoleInputTextBox(ConsoleContentTextBox contentBox, float x, float y, float width, float height) : base(x, y, width, height) - { - this.contentBox = contentBox; - IsMultiline = true; // Not really but behaves better than single-line box - } + private bool IsConsoleKeyPressed(KeyboardKeys key = KeyboardKeys.None) + { + // Ignore any characters generated by the key which opens the console + string inputTextLower = Input.InputText.ToLowerInvariant(); - private bool IsConsoleKeyPressed(KeyboardKeys key = KeyboardKeys.None) - { - // Ignore any characters generated by the key which opens the console - string inputTextLower = Input.InputText.ToLowerInvariant(); + IEnumerable consoleKeyMappings; + if (key == KeyboardKeys.None) + consoleKeyMappings = Input.ActionMappings.Where(x => x.Name == "Console" && x.Key != KeyboardKeys.None); + else + consoleKeyMappings = Input.ActionMappings.Where(x => x.Name == "Console" && x.Key == key); + foreach (var mapping in consoleKeyMappings) + { + if (inputTextLower.Length > 0) + { + if ((mapping.Key == KeyboardKeys.Backslash || mapping.Key == KeyboardKeys.BackQuote) && + (inputTextLower.Contains('ö') || + inputTextLower.Contains('æ') || + inputTextLower.Contains('ø'))) + { + continue; // Scandinavian keyboard layouts + } + else if (mapping.Key == KeyboardKeys.BackQuote && inputTextLower.Contains('\'')) + continue; + else if (mapping.Key == KeyboardKeys.Backslash && + (inputTextLower.Contains('\\') || inputTextLower.Contains('|'))) + { + continue; + } + } - IEnumerable consoleKeyMappings; - if (key == KeyboardKeys.None) - consoleKeyMappings = Input.ActionMappings.Where(x => x.Name == "Console" && x.Key != KeyboardKeys.None); - else - consoleKeyMappings = Input.ActionMappings.Where(x => x.Name == "Console" && x.Key == key); - foreach (var mapping in consoleKeyMappings) - { - if (inputTextLower.Length > 0) - { - if ((mapping.Key == KeyboardKeys.Backslash || mapping.Key == KeyboardKeys.BackQuote) && - (inputTextLower.Contains('ö') || - inputTextLower.Contains('æ') || - inputTextLower.Contains('ø'))) - { - continue; // Scandinavian keyboard layouts - } - else if (mapping.Key == KeyboardKeys.BackQuote && inputTextLower.Contains('\'')) - continue; - else if (mapping.Key == KeyboardKeys.Backslash && - (inputTextLower.Contains('\\') || inputTextLower.Contains('|'))) - { - continue; - } - } + if (Input.GetKey(mapping.Key)) + return true; + } - if (Input.GetKey(mapping.Key)) - return true; - } + return false; + } - return false; - } + public override bool OnCharInput(char c) + { + if (IsConsoleKeyPressed()) + return true; - public override bool OnCharInput(char c) - { - if (IsConsoleKeyPressed()) - return true; + return base.OnCharInput(c); + } - return base.OnCharInput(c); - } + public override bool OnKeyDown(KeyboardKeys key) + { + bool shiftDown = Root.GetKey(KeyboardKeys.Shift); + bool ctrlDown = Root.GetKey(KeyboardKeys.Control); - public override bool OnKeyDown(KeyboardKeys key) - { - bool shiftDown = Root.GetKey(KeyboardKeys.Shift); - bool ctrlDown = Root.GetKey(KeyboardKeys.Control); + if (IsConsoleKeyPressed(key)) + { + Clear(); + return true; + } + else if (key == KeyboardKeys.Escape) + { + Console.Close(); + Clear(); + return true; + } + else if (key == KeyboardKeys.Return) + { + try + { + Console.Execute(Text); + } + finally + { + Clear(); + } - if (IsConsoleKeyPressed(key)) - { - Clear(); - return true; - } - else if (key == KeyboardKeys.Escape) - { - Console.Close(); - Clear(); - return true; - } - else if (key == KeyboardKeys.Return) - { - try - { - Console.Execute(Text); - } - finally - { - Clear(); - } - contentBox.ScrollOffset = 0; - return true; - } - else if (key == KeyboardKeys.ArrowUp || key == KeyboardKeys.ArrowDown) - { - // TODO: implement input history - return true; - } - else if (key == KeyboardKeys.PageUp || key == KeyboardKeys.PageDown) - { - return contentBox.OnKeyDown(key); - } + contentBox.ScrollOffset = 0; + return true; + } + else if (key == KeyboardKeys.ArrowUp || key == KeyboardKeys.ArrowDown) + { + // TODO: implement input history + return true; + } + else if (key == KeyboardKeys.PageUp || key == KeyboardKeys.PageDown) + { + return contentBox.OnKeyDown(key); + } - return base.OnKeyDown(key); - } + return base.OnKeyDown(key); + } - public override void OnLostFocus() - { - // Avoids reseting the caret location - var oldEditing = _isEditing; - _isEditing = false; - base.OnLostFocus(); - _isEditing = oldEditing; - } + public override void OnLostFocus() + { + // Avoids reseting the caret location + var oldEditing = _isEditing; + _isEditing = false; + base.OnLostFocus(); + _isEditing = oldEditing; + } - public override bool OnMouseDown(Vector2 location, MouseButton button) - { - base.OnMouseDown(location, button); - return true; - } + public override bool OnMouseDown(Vector2 location, MouseButton button) + { + base.OnMouseDown(location, button); + return true; + } - public override bool OnMouseWheel(Vector2 location, float delta) - { - return contentBox.OnMouseWheel(location, delta); - } + public override bool OnMouseWheel(Vector2 location, float delta) + { + return contentBox.OnMouseWheel(location, delta); + } - public override void Draw() - { - Profiler.BeginEvent("ConsoleInputTextBoxDraw"); - base.Draw(); - Profiler.EndEvent(); - } - } -} + public override void Draw() + { + Profiler.BeginEvent("ConsoleInputTextBoxDraw"); + base.Draw(); + Profiler.EndEvent(); + } + } +} \ No newline at end of file diff --git a/Source/Game/Cabrito/Console/ConsolePlugin.cs b/Source/Game/Cabrito/Console/ConsolePlugin.cs index ee8bb61..4041521 100644 --- a/Source/Game/Cabrito/Console/ConsolePlugin.cs +++ b/Source/Game/Cabrito/Console/ConsolePlugin.cs @@ -5,29 +5,29 @@ using Console = Cabrito.Console; namespace Game { - public class ConsolePlugin : GamePlugin - { - public override void Initialize() - { - Console.Init(); - base.Initialize(); + public class ConsolePlugin : GamePlugin + { + public override void Initialize() + { + Console.Init(); + base.Initialize(); - Console.Print("ConsolePlugin initialize"); - } + Console.Print("ConsolePlugin initialize"); + } - public override void Deinitialize() - { - base.Deinitialize(); - FlaxEngine.Debug.Log("ConsolePlugin Deinitialize"); - } + public override void Deinitialize() + { + base.Deinitialize(); + FlaxEngine.Debug.Log("ConsolePlugin Deinitialize"); + } - public override PluginDescription Description => new PluginDescription() - { - Author = "Ari Vuollet", - Name = "Console", - Description = "Quake-like console", - Version = Version.Parse("0.1.0"), - IsAlpha = true, - }; - } -} + public override PluginDescription Description => new PluginDescription() + { + Author = "Ari Vuollet", + Name = "Console", + Description = "Quake-like console", + Version = Version.Parse("0.1.0"), + IsAlpha = true, + }; + } +} \ No newline at end of file diff --git a/Source/Game/Cabrito/Console/ConsoleScript.cs b/Source/Game/Cabrito/Console/ConsoleScript.cs index 723a357..528e07b 100644 --- a/Source/Game/Cabrito/Console/ConsoleScript.cs +++ b/Source/Game/Cabrito/Console/ConsoleScript.cs @@ -7,173 +7,167 @@ using FlaxEngine.GUI; namespace Cabrito { - public class ConsoleScript : Script - { - [Limit(5, 720, 1)] - public int ConsoleFontSize = 16; + public class ConsoleScript : Script + { + [Limit(5, 720, 1)] public int ConsoleFontSize = 16; - [Limit(0.05f, 1.0f, 1)] - public float ConsoleHeight = 0.65f; + [Limit(0.05f, 1.0f, 1)] public float ConsoleHeight = 0.65f; - [Limit(0)] - public int ConsoleNotifyLines = 3; + [Limit(0)] public int ConsoleNotifyLines = 3; - [Limit(0f)] - public float ConsoleSpeed = 3500f; + [Limit(0f)] public float ConsoleSpeed = 3500f; - public FontAsset ConsoleFont; + public FontAsset ConsoleFont; - public Texture BackgroundTexture; + public Texture BackgroundTexture; - public Color BackgroundColor; + public Color BackgroundColor; - private UIControl rootControl; - private ConsoleContentTextBox consoleBox; - private ConsoleInputTextBox consoleInputBox; - private ConsoleContentTextBox consoleNotifyBox; + private UIControl rootControl; + private ConsoleContentTextBox consoleBox; + private ConsoleInputTextBox consoleInputBox; + private ConsoleContentTextBox consoleNotifyBox; - internal InputEvent consoleInputEvent; + internal InputEvent consoleInputEvent; - public override void OnStart() - { - Console.Print("ConsoleScript OnStart"); - consoleInputEvent = new InputEvent("Console"); - consoleInputEvent.Triggered += OnConsoleInputEvent; + public override void OnStart() + { + Console.Print("ConsoleScript OnStart"); + consoleInputEvent = new InputEvent("Console"); + consoleInputEvent.Triggered += OnConsoleInputEvent; - Vector2 screenSize = Screen.Size; - Vector2 consoleSize = new Vector2(screenSize.X, screenSize.Y * ConsoleHeight); + Vector2 screenSize = Screen.Size; + Vector2 consoleSize = new Vector2(screenSize.X, screenSize.Y * ConsoleHeight); - FontReference fontReference = new FontReference(ConsoleFont, ConsoleFontSize); - Font fontRaw = fontReference.GetFont(); - int fontHeight = (int)(fontRaw.Height / Platform.DpiScale); + FontReference fontReference = new FontReference(ConsoleFont, ConsoleFontSize); + Font fontRaw = fontReference.GetFont(); + int fontHeight = (int) (fontRaw.Height / Platform.DpiScale); - // root actor which holds all the elements - //var rootContainerControl = new ContainerControl(new Rectangle(0, 0, screenSize.X, screenSize.Y)); - var rootContainerControl = new ContainerControl(new Rectangle()); - rootContainerControl.SetAnchorPreset(AnchorPresets.StretchAll, false); + // root actor which holds all the elements + //var rootContainerControl = new ContainerControl(new Rectangle(0, 0, screenSize.X, screenSize.Y)); + var rootContainerControl = new ContainerControl(new Rectangle()); + rootContainerControl.SetAnchorPreset(AnchorPresets.StretchAll, false); - rootControl = Actor.AddChild(); - rootControl.Name = "ConsoleRoot"; - rootControl.Control = rootContainerControl; + rootControl = Actor.AddChild(); + rootControl.Name = "ConsoleRoot"; + rootControl.Control = rootContainerControl; - // Create a container that keeps the focus in the input box when clicked outside the console window. - // The container must be created before the content box so interacting with the console lines wont get - // stolen by this container. - var containerControl = new ConsoleContainerControl(new Rectangle()); - containerControl.SetAnchorPreset(AnchorPresets.StretchAll, false); - /*var focusControl = rootControl.AddChild(); - focusControl.Name = "ConsoleInputContainer"; - focusControl.Control = containerControl;*/ - var focusControl = new UIControl() - { - Parent = rootControl, - Name = "ConsoleInputContainer", - Control = containerControl - }; + // Create a container that keeps the focus in the input box when clicked outside the console window. + // The container must be created before the content box so interacting with the console lines wont get + // stolen by this container. + var containerControl = new ConsoleContainerControl(new Rectangle()); + containerControl.SetAnchorPreset(AnchorPresets.StretchAll, false); + /*var focusControl = rootControl.AddChild(); + focusControl.Name = "ConsoleInputContainer"; + focusControl.Control = containerControl;*/ + var focusControl = new UIControl() + { + Parent = rootControl, + Name = "ConsoleInputContainer", + Control = containerControl + }; - var contentContainer = new VerticalPanel() - { - AutoSize = true, - Margin = Margin.Zero, - Spacing = 0, - Bounds = new Rectangle(), - BackgroundColor = BackgroundColor - }; - contentContainer.SetAnchorPreset(AnchorPresets.StretchAll, true); + var contentContainer = new VerticalPanel() + { + AutoSize = true, + Margin = Margin.Zero, + Spacing = 0, + Bounds = new Rectangle(), + BackgroundColor = BackgroundColor + }; + contentContainer.SetAnchorPreset(AnchorPresets.StretchAll, true); - var contentContainerControl = rootControl.AddChild(); - contentContainerControl.Name = "ContentContainer"; - contentContainerControl.Control = contentContainer; + var contentContainerControl = rootControl.AddChild(); + contentContainerControl.Name = "ContentContainer"; + contentContainerControl.Control = contentContainer; - { - if (consoleBox == null) - { - //consoleBox = new ConsoleContentTextBox(null, 0, 0, consoleSize.X, consoleSize.Y - fontHeight); - consoleBox = new ConsoleContentTextBox(null, 0, 0, 0, 0); - - - consoleBox.SetAnchorPreset(AnchorPresets.HorizontalStretchTop, true); - //consoleBox.AnchorMax = new Vector2(1.0f, ConsoleHeight); - //consoleBox.Height = consoleSize.Y - fontHeight; - consoleBox.Font = fontReference; - - //consoleBox.HorizontalAlignment = TextAlignment.Near; - //consoleBox.VerticalAlignment = TextAlignment.Near; - consoleBox.HeightMultiplier = ConsoleHeight; - consoleBox.Wrapping = TextWrapping.WrapWords; - consoleBox.BackgroundColor = Color.Transparent; - consoleBox.BackgroundSelectedColor = Color.Transparent; - consoleBox.BackgroundSelectedFlashSpeed = 0; - consoleBox.BorderSelectedColor = Color.Transparent; - consoleBox.CaretFlashSpeed = 0; - } - - var locationFix = consoleBox.Location; - var parentControl = contentContainerControl.AddChild(); - parentControl.Name = "ConsoleContent"; - parentControl.Control = consoleBox; - consoleBox.Location = locationFix; // workaround to UIControl.Control overriding the old position - - if (consoleNotifyBox == null) - { - //consoleBox = new ConsoleContentTextBox(null, 0, 0, consoleSize.X, consoleSize.Y - fontHeight); - consoleNotifyBox = new ConsoleContentTextBox(null, 0, 0, 0, 0); - consoleNotifyBox.HeightMultiplier = 0; - consoleNotifyBox.Height = ConsoleNotifyLines * fontHeight; - consoleNotifyBox.SetAnchorPreset(AnchorPresets.HorizontalStretchTop, true); - //consoleBox.AnchorMax = new Vector2(1.0f, ConsoleHeight); - - consoleNotifyBox.Font = fontReference; - - //consoleBox.HorizontalAlignment = TextAlignment.Near; - //consoleBox.VerticalAlignment = TextAlignment.Near; - //consoleNotifyBox.HeightMultiplier = ConsoleHeight; - consoleNotifyBox.Wrapping = TextWrapping.WrapWords; - consoleNotifyBox.BackgroundColor = Color.Transparent; - consoleNotifyBox.BackgroundSelectedColor = Color.Transparent; - consoleNotifyBox.BackgroundSelectedFlashSpeed = 0; - consoleNotifyBox.BorderSelectedColor = Color.Transparent; - consoleNotifyBox.CaretFlashSpeed = 0; - } - - var locationFix2 = consoleNotifyBox.Location; - var parentControl2 = Actor.AddChild(); - parentControl2.Name = "ConsoleNotifyContent"; - parentControl2.Control = consoleNotifyBox; - consoleNotifyBox.Location = locationFix2; // workaround to UIControl.Control overriding the old position - } - { - if (consoleInputBox == null) - { - //consoleInputBox = new ConsoleInputTextBox(consoleBox, 0, consoleSize.Y - fontHeight, consoleSize.X, fontHeight); - consoleInputBox = new ConsoleInputTextBox(consoleBox, 0, 0, 0, 0); - consoleInputBox.SetAnchorPreset(AnchorPresets.HorizontalStretchTop, false); - //consoleInputBox.Location = new Vector2(0, consoleSize.Y - fontHeight); - consoleInputBox.Height = fontHeight; - - consoleInputBox.Font = fontReference; - consoleBox.inputBox = consoleInputBox; - - consoleInputBox.Wrapping = TextWrapping.WrapWords; - consoleInputBox.BackgroundColor = Color.Transparent; - consoleInputBox.BackgroundSelectedColor = Color.Transparent; - consoleInputBox.BackgroundSelectedFlashSpeed = 0; - consoleInputBox.BorderSelectedColor = Color.Transparent; - consoleInputBox.CaretFlashSpeed = 0; - } - containerControl.inputBox = consoleInputBox; + { + if (consoleBox == null) + { + //consoleBox = new ConsoleContentTextBox(null, 0, 0, consoleSize.X, consoleSize.Y - fontHeight); + consoleBox = new ConsoleContentTextBox(null, 0, 0, 0, 0); + consoleBox.SetAnchorPreset(AnchorPresets.HorizontalStretchTop, true); + //consoleBox.AnchorMax = new Vector2(1.0f, ConsoleHeight); + //consoleBox.Height = consoleSize.Y - fontHeight; + consoleBox.Font = fontReference; - var locationFix = consoleInputBox.Location; - var parentControl = contentContainerControl.AddChild(); - parentControl.Name = "ConsoleInput"; - parentControl.Control = consoleInputBox; + //consoleBox.HorizontalAlignment = TextAlignment.Near; + //consoleBox.VerticalAlignment = TextAlignment.Near; + consoleBox.HeightMultiplier = ConsoleHeight; + consoleBox.Wrapping = TextWrapping.WrapWords; + consoleBox.BackgroundColor = Color.Transparent; + consoleBox.BackgroundSelectedColor = Color.Transparent; + consoleBox.BackgroundSelectedFlashSpeed = 0; + consoleBox.BorderSelectedColor = Color.Transparent; + consoleBox.CaretFlashSpeed = 0; + } - consoleInputBox.Location = locationFix; // workaround to UIControl.Control overriding the old position + var locationFix = consoleBox.Location; + var parentControl = contentContainerControl.AddChild(); + parentControl.Name = "ConsoleContent"; + parentControl.Control = consoleBox; + consoleBox.Location = locationFix; // workaround to UIControl.Control overriding the old position + + if (consoleNotifyBox == null) + { + //consoleBox = new ConsoleContentTextBox(null, 0, 0, consoleSize.X, consoleSize.Y - fontHeight); + consoleNotifyBox = new ConsoleContentTextBox(null, 0, 0, 0, 0); + consoleNotifyBox.HeightMultiplier = 0; + consoleNotifyBox.Height = ConsoleNotifyLines * fontHeight; + consoleNotifyBox.SetAnchorPreset(AnchorPresets.HorizontalStretchTop, true); + //consoleBox.AnchorMax = new Vector2(1.0f, ConsoleHeight); + + consoleNotifyBox.Font = fontReference; + + //consoleBox.HorizontalAlignment = TextAlignment.Near; + //consoleBox.VerticalAlignment = TextAlignment.Near; + //consoleNotifyBox.HeightMultiplier = ConsoleHeight; + consoleNotifyBox.Wrapping = TextWrapping.WrapWords; + consoleNotifyBox.BackgroundColor = Color.Transparent; + consoleNotifyBox.BackgroundSelectedColor = Color.Transparent; + consoleNotifyBox.BackgroundSelectedFlashSpeed = 0; + consoleNotifyBox.BorderSelectedColor = Color.Transparent; + consoleNotifyBox.CaretFlashSpeed = 0; + } + + var locationFix2 = consoleNotifyBox.Location; + var parentControl2 = Actor.AddChild(); + parentControl2.Name = "ConsoleNotifyContent"; + parentControl2.Control = consoleNotifyBox; + consoleNotifyBox.Location = locationFix2; // workaround to UIControl.Control overriding the old position + } + { + if (consoleInputBox == null) + { + //consoleInputBox = new ConsoleInputTextBox(consoleBox, 0, consoleSize.Y - fontHeight, consoleSize.X, fontHeight); + consoleInputBox = new ConsoleInputTextBox(consoleBox, 0, 0, 0, 0); + consoleInputBox.SetAnchorPreset(AnchorPresets.HorizontalStretchTop, false); + //consoleInputBox.Location = new Vector2(0, consoleSize.Y - fontHeight); + consoleInputBox.Height = fontHeight; + + consoleInputBox.Font = fontReference; + consoleBox.inputBox = consoleInputBox; + + consoleInputBox.Wrapping = TextWrapping.WrapWords; + consoleInputBox.BackgroundColor = Color.Transparent; + consoleInputBox.BackgroundSelectedColor = Color.Transparent; + consoleInputBox.BackgroundSelectedFlashSpeed = 0; + consoleInputBox.BorderSelectedColor = Color.Transparent; + consoleInputBox.CaretFlashSpeed = 0; + } + + containerControl.inputBox = consoleInputBox; - } + var locationFix = consoleInputBox.Location; + var parentControl = contentContainerControl.AddChild(); + parentControl.Name = "ConsoleInput"; + parentControl.Control = consoleInputBox; + + consoleInputBox.Location = locationFix; // workaround to UIControl.Control overriding the old position + } #if false //for (int i = 0; i < 10; i++) @@ -236,176 +230,178 @@ namespace Cabrito Console.Print(l); } #endif - /*FlaxEditor.Editor.Options.OptionsChanged += (FlaxEditor.Options.EditorOptions options) => - { + /*FlaxEditor.Editor.Options.OptionsChanged += (FlaxEditor.Options.EditorOptions options) => + { - };*/ + };*/ - /*Console.Print("normal line"); - Console.Print( - "a very very very long long long line in repeat a very very very long long long line in repeat 1 a very very ver" - + "y long long long line in repeat a very very very 2 long long long line in repeat a very very very 3 long long" - + " long line in repeat a very very very long long long 4 line in repeat"); - Console.Print("another normal line");*/ + /*Console.Print("normal line"); + Console.Print( + "a very very very long long long line in repeat a very very very long long long line in repeat 1 a very very ver" + + "y long long long line in repeat a very very very 2 long long long line in repeat a very very very 3 long long" + + " long line in repeat a very very very long long long 4 line in repeat"); + Console.Print("another normal line");*/ - Debug.Logger.LogHandler.SendLog += OnSendLog; - Debug.Logger.LogHandler.SendExceptionLog += OnSendExceptionLog; + Debug.Logger.LogHandler.SendLog += OnSendLog; + Debug.Logger.LogHandler.SendExceptionLog += OnSendExceptionLog; - Console.OnOpen += OnConsoleOpen; - Console.OnClose += OnConsoleClose; - Console.OnPrint += OnPrint; + Console.OnOpen += OnConsoleOpen; + Console.OnClose += OnConsoleClose; + Console.OnPrint += OnPrint; - // hide console by default, and close it instantly - Console.Close(); - var rootlocation = rootControl.Control.Location; - rootlocation.Y = -rootControl.Control.Height; - rootControl.Control.Location = rootlocation; - } + // hide console by default, and close it instantly + Console.Close(); + var rootlocation = rootControl.Control.Location; + rootlocation.Y = -rootControl.Control.Height; + rootControl.Control.Location = rootlocation; + } - private void OnSendLog(LogType level, string msg, FlaxEngine.Object obj, string stackTrace) - { - Console.Print("[DEBUG] " + msg); - } - - private void OnSendExceptionLog(Exception exception, FlaxEngine.Object obj) - { - Console.Print("[EXCEP] " + exception.Message); - } + private void OnSendLog(LogType level, string msg, FlaxEngine.Object obj, string stackTrace) + { + Console.Print("[DEBUG] " + msg); + } - public override void OnDestroy() - { - //consoleInputEvent.Triggered -= OnConsoleInputEvent; - consoleInputEvent?.Dispose(); - consoleBox?.Dispose(); - consoleNotifyBox?.Dispose(); + private void OnSendExceptionLog(Exception exception, FlaxEngine.Object obj) + { + Console.Print("[EXCEP] " + exception.Message); + } - Console.OnOpen -= OnConsoleOpen; - Console.OnClose -= OnConsoleClose; - Console.OnPrint -= OnPrint; + public override void OnDestroy() + { + //consoleInputEvent.Triggered -= OnConsoleInputEvent; + consoleInputEvent?.Dispose(); + consoleBox?.Dispose(); + consoleNotifyBox?.Dispose(); - Debug.Logger.LogHandler.SendLog -= OnSendLog; - Debug.Logger.LogHandler.SendExceptionLog -= OnSendExceptionLog; - } + Console.OnOpen -= OnConsoleOpen; + Console.OnClose -= OnConsoleClose; + Console.OnPrint -= OnPrint; - private void OnConsoleInputEvent() - { - string currentInput = Input.InputText; + Debug.Logger.LogHandler.SendLog -= OnSendLog; + Debug.Logger.LogHandler.SendExceptionLog -= OnSendExceptionLog; + } - if (Input.InputText.Length > 0) - { - // Really need rawinput support with separate ActionConfig.RawKey values, bound to physical keys/scancode instead of virtual ones - var consoleKeys = Input.ActionMappings.Where(x => x.Name == "Console" && x.Key != KeyboardKeys.None); - bool backslash = consoleKeys.Any(x => x.Key == KeyboardKeys.Backslash); - bool backquote = consoleKeys.Any(x => x.Key == KeyboardKeys.BackQuote); + private void OnConsoleInputEvent() + { + string currentInput = Input.InputText; - // Workaround to only trigger Console key from key bound to left side of 1 (tilde/backquote/backslash key) - if ((backslash || backquote) && - (Input.InputText.ToLowerInvariant().Contains('ö') || - Input.InputText.ToLowerInvariant().Contains('æ') || - Input.InputText.ToLowerInvariant().Contains('ø'))) // Scandinavian keyboard layouts - { - return; - } - else if (backquote && Input.InputText.ToLowerInvariant().Contains('\'')) // UK keyboard layouts - return; - else if (backslash && (Input.InputText.ToLowerInvariant().Contains('\\') || Input.InputText.ToLowerInvariant().Contains('|'))) // US/International keyboard layouts - return; - } + if (Input.InputText.Length > 0) + { + // Really need rawinput support with separate ActionConfig.RawKey values, bound to physical keys/scancode instead of virtual ones + var consoleKeys = Input.ActionMappings.Where(x => x.Name == "Console" && x.Key != KeyboardKeys.None); + bool backslash = consoleKeys.Any(x => x.Key == KeyboardKeys.Backslash); + bool backquote = consoleKeys.Any(x => x.Key == KeyboardKeys.BackQuote); - if (!consoleInputBox.IsFocused) - Console.Open(); - else - Console.Close(); - } + // Workaround to only trigger Console key from key bound to left side of 1 (tilde/backquote/backslash key) + if ((backslash || backquote) && + (Input.InputText.ToLowerInvariant().Contains('ö') || + Input.InputText.ToLowerInvariant().Contains('æ') || + Input.InputText.ToLowerInvariant().Contains('ø'))) // Scandinavian keyboard layouts + { + return; + } + else if (backquote && Input.InputText.ToLowerInvariant().Contains('\'')) // UK keyboard layouts + return; + else if (backslash && (Input.InputText.ToLowerInvariant().Contains('\\') || + Input.InputText.ToLowerInvariant() + .Contains('|'))) // US/International keyboard layouts + return; + } - public void OnConsoleOpen() - { - Screen.CursorVisible = true; - Screen.CursorLock = CursorLockMode.None; + if (!consoleInputBox.IsFocused) + Console.Open(); + else + Console.Close(); + } - consoleInputBox.Focus(); - Parent.As().ReceivesEvents = true; - } + public void OnConsoleOpen() + { + Screen.CursorVisible = true; + Screen.CursorLock = CursorLockMode.None; - public void OnConsoleClose() - { - Console.Print("closed console"); - Screen.CursorVisible = false; - Screen.CursorLock = CursorLockMode.Locked; + consoleInputBox.Focus(); + Parent.As().ReceivesEvents = true; + } - consoleInputBox.Defocus(); + public void OnConsoleClose() + { + Console.Print("closed console"); + Screen.CursorVisible = false; + Screen.CursorLock = CursorLockMode.Locked; + + consoleInputBox.Defocus(); #if FLAX_EDITOR - Editor.Instance.Windows.GameWin.Focus(); + Editor.Instance.Windows.GameWin.Focus(); #endif - Parent.As().ReceivesEvents = false; - } + Parent.As().ReceivesEvents = false; + } - public override void OnUpdate() - { - base.OnUpdate(); + public override void OnUpdate() + { + base.OnUpdate(); - if (!Console.IsOpen && Input.GetAction("ClearConsole")) - Console.Clear(); + if (!Console.IsOpen && Input.GetAction("ClearConsole")) + Console.Clear(); - float targetY; - float conHeight = rootControl.Control.Height /*/ Platform.DpiScale*/; - if (!Console.IsOpen) - targetY = -conHeight; - else - targetY = 0.0f; + float targetY; + float conHeight = rootControl.Control.Height /*/ Platform.DpiScale*/; + if (!Console.IsOpen) + targetY = -conHeight; + else + targetY = 0.0f; - Vector2 location = rootControl.Control.Location; - if (location.Y != targetY) - { - if (location.Y > targetY) - { - // closing - location.Y -= Time.UnscaledDeltaTime * ConsoleSpeed; - if (location.Y < targetY) - location.Y = targetY; + Vector2 location = rootControl.Control.Location; + if (location.Y != targetY) + { + if (location.Y > targetY) + { + // closing + location.Y -= Time.UnscaledDeltaTime * ConsoleSpeed; + if (location.Y < targetY) + location.Y = targetY; - if (location.Y < targetY * ConsoleHeight) - location.Y = targetY; - } - else if (location.Y < targetY) - { - // opening - if (location.Y < -conHeight * ConsoleHeight) - location.Y = -conHeight * ConsoleHeight; + if (location.Y < targetY * ConsoleHeight) + location.Y = targetY; + } + else if (location.Y < targetY) + { + // opening + if (location.Y < -conHeight * ConsoleHeight) + location.Y = -conHeight * ConsoleHeight; - location.Y += Time.UnscaledDeltaTime * ConsoleSpeed; - if (location.Y > targetY) - location.Y = targetY; - } + location.Y += Time.UnscaledDeltaTime * ConsoleSpeed; + if (location.Y > targetY) + location.Y = targetY; + } - rootControl.Control.Location = location; + rootControl.Control.Location = location; - if (Console.IsOpen) - { - consoleNotifyBox.Visible = false; - consoleInputBox.Visible = true; - } - else if (!Console.IsOpen) - { - int fontHeight = (int)(consoleNotifyBox.Font.GetFont().Height / Platform.DpiScale); - if (location.Y < (-conHeight * ConsoleHeight) + fontHeight) - { - consoleNotifyBox.Visible = true; - consoleInputBox.Visible = false; - } - } - } - } + if (Console.IsOpen) + { + consoleNotifyBox.Visible = false; + consoleInputBox.Visible = true; + } + else if (!Console.IsOpen) + { + int fontHeight = (int) (consoleNotifyBox.Font.GetFont().Height / Platform.DpiScale); + if (location.Y < (-conHeight * ConsoleHeight) + fontHeight) + { + consoleNotifyBox.Visible = true; + consoleInputBox.Visible = false; + } + } + } + } - public void OnPrint(string text) - { - int fontHeight = (int)(consoleNotifyBox.Font.GetFont().Height / Platform.DpiScale); - consoleNotifyBox.Height = Math.Min(ConsoleNotifyLines, Console.Lines.Count) * fontHeight; - } + public void OnPrint(string text) + { + int fontHeight = (int) (consoleNotifyBox.Font.GetFont().Height / Platform.DpiScale); + consoleNotifyBox.Height = Math.Min(ConsoleNotifyLines, Console.Lines.Count) * fontHeight; + } - public void SetInput(string text) - { - consoleInputBox.Text = text; - } - } -} + public void SetInput(string text) + { + consoleInputBox.Text = text; + } + } +} \ No newline at end of file diff --git a/Source/Game/Cabrito/Console/ConsoleTextBoxBase.cs b/Source/Game/Cabrito/Console/ConsoleTextBoxBase.cs index 489b009..a1d6fff 100644 --- a/Source/Game/Cabrito/Console/ConsoleTextBoxBase.cs +++ b/Source/Game/Cabrito/Console/ConsoleTextBoxBase.cs @@ -7,389 +7,392 @@ using FlaxEngine.GUI; namespace Cabrito { - // Mostly based on TextBox - public class ConsoleTextBoxBase : TextBoxBase - { - protected TextLayoutOptions _layout; + // Mostly based on TextBox + public class ConsoleTextBoxBase : TextBoxBase + { + protected TextLayoutOptions _layout; - /// - /// Gets or sets the text wrapping within the control bounds. - /// - [EditorDisplay("Style"), EditorOrder(2000), Tooltip("The text wrapping within the control bounds.")] - public TextWrapping Wrapping - { - get => _layout.TextWrapping; - set => _layout.TextWrapping = value; - } + /// + /// Gets or sets the text wrapping within the control bounds. + /// + [EditorDisplay("Style"), EditorOrder(2000), Tooltip("The text wrapping within the control bounds.")] + public TextWrapping Wrapping + { + get => _layout.TextWrapping; + set => _layout.TextWrapping = value; + } - /// - /// Gets or sets the font. - /// - [EditorDisplay("Style"), EditorOrder(2000)] - public FontReference Font { get; set; } + /// + /// Gets or sets the font. + /// + [EditorDisplay("Style"), EditorOrder(2000)] + public FontReference Font { get; set; } - /// - /// Gets or sets the color of the text. - /// - [EditorDisplay("Style"), EditorOrder(2000), Tooltip("The color of the text.")] - public Color TextColor { get; set; } + /// + /// Gets or sets the color of the text. + /// + [EditorDisplay("Style"), EditorOrder(2000), Tooltip("The color of the text.")] + public Color TextColor { get; set; } - /// - /// Gets or sets the color of the selection (Transparent if not used). - /// - [EditorDisplay("Style"), EditorOrder(2000), Tooltip("The color of the selection (Transparent if not used).")] - public Color SelectionColor { get; set; } + /// + /// Gets or sets the color of the selection (Transparent if not used). + /// + [EditorDisplay("Style"), EditorOrder(2000), Tooltip("The color of the selection (Transparent if not used).")] + public Color SelectionColor { get; set; } - [HideInEditor] - public virtual string TextPrefix { get; set; } = ""; + [HideInEditor] public virtual string TextPrefix { get; set; } = ""; - //[HideInEditor] - //public override string Text => _text; + //[HideInEditor] + //public override string Text => _text; - public ConsoleTextBoxBase() : base() - { + public ConsoleTextBoxBase() : base() + { + } - } + public ConsoleTextBoxBase(float x, float y, float width, float height) : base(false, x, y, width) + { + Height = height; - public ConsoleTextBoxBase(float x, float y, float width, float height) : base(false, x, y, width) - { - Height = height; + IsReadOnly = false; + CaretColor = new Color(1f, 1f, 1f, 1f); + AutoFocus = true; - IsReadOnly = false; - CaretColor = new Color(1f, 1f, 1f, 1f); - AutoFocus = true; - - _layout = TextLayoutOptions.Default; - _layout.VerticalAlignment = IsMultiline ? TextAlignment.Near : TextAlignment.Center; - _layout.TextWrapping = TextWrapping.NoWrap; - _layout.Bounds = new Rectangle(0, 0, Width, Height);//new Rectangle(DefaultMargin, 1, Width - 2 * DefaultMargin, Height - 2); + _layout = TextLayoutOptions.Default; + _layout.VerticalAlignment = IsMultiline ? TextAlignment.Near : TextAlignment.Center; + _layout.TextWrapping = TextWrapping.NoWrap; + _layout.Bounds = + new Rectangle(0, 0, Width, + Height); //new Rectangle(DefaultMargin, 1, Width - 2 * DefaultMargin, Height - 2); #if FLAX_EDITOR - var style = Style.Current; - if (style.FontMedium != null) - Font = new FontReference(style.FontMedium); - TextColor = style.Foreground; - SelectionColor = style.BackgroundSelected; + var style = Style.Current; + if (style.FontMedium != null) + Font = new FontReference(style.FontMedium); + TextColor = style.Foreground; + SelectionColor = style.BackgroundSelected; #endif - } + } - /*protected override void SetText(string value) - { - // Prevent from null problems - if (value == null) - value = string.Empty; + /*protected override void SetText(string value) + { + // Prevent from null problems + if (value == null) + value = string.Empty; - // Filter text - if (value.IndexOf('\r') != -1) - value = value.Replace("\r", ""); + // Filter text + if (value.IndexOf('\r') != -1) + value = value.Replace("\r", ""); - // Clamp length - if (value.Length > MaxLength) - value = value.Substring(0, MaxLength); + // Clamp length + if (value.Length > MaxLength) + value = value.Substring(0, MaxLength); - // Ensure to use only single line - if (_isMultiline == false && value.Length > 0) - { - // Extract only the first line - value = value.GetLines()[0]; - } + // Ensure to use only single line + if (_isMultiline == false && value.Length > 0) + { + // Extract only the first line + value = value.GetLines()[0]; + } - if (Text != value) - { - Deselect(); - ResetViewOffset(); + if (Text != value) + { + Deselect(); + ResetViewOffset(); - Text = value; + Text = value; - OnTextChanged(); - } - }*/ + OnTextChanged(); + } + }*/ - public int GetFontHeight() - { - var font = Font.GetFont(); - if (font == null) - return (int)Height; + public int GetFontHeight() + { + var font = Font.GetFont(); + if (font == null) + return (int) Height; - return (int)Mathf.Round(font.Height * Scale.Y); - } + return (int) Mathf.Round(font.Height * Scale.Y); + } - public override void Clear() - { - // Can't clear the text while user is editing it... - var oldEditing = _isEditing; - _isEditing = false; - base.Clear(); - _isEditing = oldEditing; - } + public override void Clear() + { + // Can't clear the text while user is editing it... + var oldEditing = _isEditing; + _isEditing = false; + base.Clear(); + _isEditing = oldEditing; + } - public override void ResetViewOffset() - { - TargetViewOffset = new Vector2(0, 0); - } + public override void ResetViewOffset() + { + TargetViewOffset = new Vector2(0, 0); + } - /*public void ScrollToEnd() - { - float maxY = TextSize.Y - Height; - float spacing = GetRealLineSpacing(); - maxY += spacing; + /*public void ScrollToEnd() + { + float maxY = TextSize.Y - Height; + float spacing = GetRealLineSpacing(); + maxY += spacing; - TargetViewOffset = new Vector2(0, Math.Max(0, maxY)); - }*/ + TargetViewOffset = new Vector2(0, Math.Max(0, maxY)); + }*/ - public override void ScrollToCaret() - { - if (Text.Length == 0) - return; + public override void ScrollToCaret() + { + if (Text.Length == 0) + return; - Rectangle caretBounds = CaretBounds; + Rectangle caretBounds = CaretBounds; - float maxY = TextSize.Y - Height; + float maxY = TextSize.Y - Height; - Vector2 newLocation = CaretBounds.Location; - TargetViewOffset = Vector2.Clamp(newLocation, new Vector2(0, 0), new Vector2(_targetViewOffset.X, maxY)); - } + Vector2 newLocation = CaretBounds.Location; + TargetViewOffset = Vector2.Clamp(newLocation, new Vector2(0, 0), new Vector2(_targetViewOffset.X, maxY)); + } - /*const bool smoothScrolling = false; + /*const bool smoothScrolling = false; - public override bool OnMouseWheel(Vector2 location, float delta) - { - if (!IsMultiline || Text.Length == 0) - return false; + public override bool OnMouseWheel(Vector2 location, float delta) + { + if (!IsMultiline || Text.Length == 0) + return false; - if (!smoothScrolling) - delta = GetFontHeight() * Math.Sign(delta) * 3; - else - delta *= 30; - - float maxY = TextSize.Y - Height; - float offset = GetRealLineSpacing(); - maxY += offset; - TargetViewOffset = Vector2.Clamp(_targetViewOffset - new Vector2(0, delta), new Vector2(0, offset), new Vector2(_targetViewOffset.X, maxY)); - return true; - }*/ + if (!smoothScrolling) + delta = GetFontHeight() * Math.Sign(delta) * 3; + else + delta *= 30; - public override Vector2 GetTextSize() - { - var font = Font.GetFont(); - if (font == null) - return Vector2.Zero; + float maxY = TextSize.Y - Height; + float offset = GetRealLineSpacing(); + maxY += offset; + TargetViewOffset = Vector2.Clamp(_targetViewOffset - new Vector2(0, delta), new Vector2(0, offset), new Vector2(_targetViewOffset.X, maxY)); + return true; + }*/ - return font.MeasureText(Text, ref _layout); - } + public override Vector2 GetTextSize() + { + var font = Font.GetFont(); + if (font == null) + return Vector2.Zero; - public override Vector2 GetCharPosition(int index, out float height) - { - var font = Font.GetFont(); - if (font == null) - { - height = Height; - return Vector2.Zero; - } + return font.MeasureText(Text, ref _layout); + } - height = GetFontHeight(); - return font.GetCharPosition(Text, index, ref _layout); - } + public override Vector2 GetCharPosition(int index, out float height) + { + var font = Font.GetFont(); + if (font == null) + { + height = Height; + return Vector2.Zero; + } - public override int HitTestText(Vector2 location) - { - var font = Font.GetFont(); - if (font == null) - return 0; + height = GetFontHeight(); + return font.GetCharPosition(Text, index, ref _layout); + } - if (TextPrefix != "") - { - var prefixSize = font.MeasureText(TextPrefix); - location.X -= prefixSize.X; - } + public override int HitTestText(Vector2 location) + { + var font = Font.GetFont(); + if (font == null) + return 0; - return font.HitTestText(Text, location, ref _layout); - } + if (TextPrefix != "") + { + var prefixSize = font.MeasureText(TextPrefix); + location.X -= prefixSize.X; + } - protected override void OnIsMultilineChanged() - { - base.OnIsMultilineChanged(); + return font.HitTestText(Text, location, ref _layout); + } - _layout.VerticalAlignment = IsMultiline ? TextAlignment.Near : TextAlignment.Center; - } + protected override void OnIsMultilineChanged() + { + base.OnIsMultilineChanged(); - public override bool OnKeyDown(KeyboardKeys key) - { - bool shiftDown = Root.GetKey(KeyboardKeys.Shift); - bool ctrlDown = Root.GetKey(KeyboardKeys.Control); + _layout.VerticalAlignment = IsMultiline ? TextAlignment.Near : TextAlignment.Center; + } - if (shiftDown && key == KeyboardKeys.Delete) - Cut(); - else if (ctrlDown && key == KeyboardKeys.Insert) - Copy(); - else if (shiftDown && key == KeyboardKeys.Insert) - Paste(); - if (shiftDown && key == KeyboardKeys.Home) - { - if (!IsReadOnly) - SetSelection(_selectionStart, 0); - return true; - } - else if (shiftDown && key == KeyboardKeys.End) - { - if (!IsReadOnly) - SetSelection(_selectionStart, TextLength); - return true; - } - return base.OnKeyDown(key); - } + public override bool OnKeyDown(KeyboardKeys key) + { + bool shiftDown = Root.GetKey(KeyboardKeys.Shift); + bool ctrlDown = Root.GetKey(KeyboardKeys.Control); - bool doubleClicked = false; - System.Diagnostics.Stopwatch lastDoubleClick = new System.Diagnostics.Stopwatch(); - Vector2 lastDoubleClickLocation = new Vector2(0, 0); + if (shiftDown && key == KeyboardKeys.Delete) + Cut(); + else if (ctrlDown && key == KeyboardKeys.Insert) + Copy(); + else if (shiftDown && key == KeyboardKeys.Insert) + Paste(); + if (shiftDown && key == KeyboardKeys.Home) + { + if (!IsReadOnly) + SetSelection(_selectionStart, 0); + return true; + } + else if (shiftDown && key == KeyboardKeys.End) + { + if (!IsReadOnly) + SetSelection(_selectionStart, TextLength); + return true; + } - public override bool OnMouseDown(Vector2 location, MouseButton button) - { - if (doubleClicked && lastDoubleClick.Elapsed.TotalSeconds < 0.5 && location == lastDoubleClickLocation) // Windows defaults to 500ms window - { - doubleClicked = false; - if (OnMouseTripleClick(location, button)) - return true; - } + return base.OnKeyDown(key); + } - return base.OnMouseDown(location, button); - } + bool doubleClicked = false; + System.Diagnostics.Stopwatch lastDoubleClick = new System.Diagnostics.Stopwatch(); + Vector2 lastDoubleClickLocation = new Vector2(0, 0); + + public override bool OnMouseDown(Vector2 location, MouseButton button) + { + if (doubleClicked && lastDoubleClick.Elapsed.TotalSeconds < 0.5 && + location == lastDoubleClickLocation) // Windows defaults to 500ms window + { + doubleClicked = false; + if (OnMouseTripleClick(location, button)) + return true; + } + + return base.OnMouseDown(location, button); + } - public override bool OnMouseDoubleClick(Vector2 location, MouseButton button) - { - doubleClicked = true; - lastDoubleClick.Restart(); - lastDoubleClickLocation = location; + public override bool OnMouseDoubleClick(Vector2 location, MouseButton button) + { + doubleClicked = true; + lastDoubleClick.Restart(); + lastDoubleClickLocation = location; - return base.OnMouseDoubleClick(location, button); - } + return base.OnMouseDoubleClick(location, button); + } - public bool OnMouseTripleClick(Vector2 location, MouseButton button) - { - if (!IsMultiline) - SelectAll(); - else - { - // TODO: select the line - SelectAll(); - } - return true; - } + public bool OnMouseTripleClick(Vector2 location, MouseButton button) + { + if (!IsMultiline) + SelectAll(); + else + { + // TODO: select the line + SelectAll(); + } - protected override void OnSizeChanged() - { - base.OnSizeChanged(); + return true; + } - _layout.Bounds = TextRectangle; - } + protected override void OnSizeChanged() + { + base.OnSizeChanged(); - public override void Draw() - { - // Cache data - var rect = new Rectangle(Vector2.Zero, Size); - var font = Font.GetFont(); - if (!font) - return; + _layout.Bounds = TextRectangle; + } - // Background - Color backColor = BackgroundColor; - if (IsMouseOver) - backColor = BackgroundSelectedColor; - if (backColor.A > 0.0f) - Render2D.FillRectangle(rect, backColor); + public override void Draw() + { + // Cache data + var rect = new Rectangle(Vector2.Zero, Size); + var font = Font.GetFont(); + if (!font) + return; - Color borderColor = IsFocused ? BorderSelectedColor : BorderColor; - if (borderColor.A > 0.0f) - Render2D.DrawRectangle(rect, borderColor); + // Background + Color backColor = BackgroundColor; + if (IsMouseOver) + backColor = BackgroundSelectedColor; + if (backColor.A > 0.0f) + Render2D.FillRectangle(rect, backColor); - //string text = TextPrefix + Text; - string text = TextPrefix + Text; + Color borderColor = IsFocused ? BorderSelectedColor : BorderColor; + if (borderColor.A > 0.0f) + Render2D.DrawRectangle(rect, borderColor); - if (text.Length == 0) - return; + //string text = TextPrefix + Text; + string text = TextPrefix + Text; - // Apply view offset and clip mask - Render2D.PushClip(TextClipRectangle); - bool useViewOffset = !_viewOffset.IsZero; - if (useViewOffset) - Render2D.PushTransform(Matrix3x3.Translation2D(-_viewOffset)); + if (text.Length == 0) + return; - // Check if any text is selected to draw selection - if (HasSelection) - { - Vector2 leftEdge = font.GetCharPosition(text, SelectionLeft + TextPrefix.Length, ref _layout); - Vector2 rightEdge = font.GetCharPosition(text, SelectionRight + TextPrefix.Length, ref _layout); - float fontHeight = GetFontHeight(); + // Apply view offset and clip mask + Render2D.PushClip(TextClipRectangle); + bool useViewOffset = !_viewOffset.IsZero; + if (useViewOffset) + Render2D.PushTransform(Matrix3x3.Translation2D(-_viewOffset)); - // Draw selection background - float alpha = Mathf.Min(1.0f, Mathf.Cos(_animateTime * BackgroundSelectedFlashSpeed) * 0.5f + 1.3f); - alpha = alpha * alpha; - Color selectionColor = SelectionColor * alpha; + // Check if any text is selected to draw selection + if (HasSelection) + { + Vector2 leftEdge = font.GetCharPosition(text, SelectionLeft + TextPrefix.Length, ref _layout); + Vector2 rightEdge = font.GetCharPosition(text, SelectionRight + TextPrefix.Length, ref _layout); + float fontHeight = GetFontHeight(); - int selectedLinesCount = 1 + Mathf.FloorToInt((rightEdge.Y - leftEdge.Y) / fontHeight); - if (selectedLinesCount == 1) // Selected is part of single line - { - Rectangle r1 = new Rectangle(leftEdge.X, leftEdge.Y, rightEdge.X - leftEdge.X, fontHeight); - Render2D.FillRectangle(r1, selectionColor); - } - else // Selected is more than one line - { - float leftMargin = _layout.Bounds.Location.X; - Rectangle r1 = new Rectangle(leftEdge.X, leftEdge.Y, 1000000000, fontHeight); - Render2D.FillRectangle(r1, selectionColor); + // Draw selection background + float alpha = Mathf.Min(1.0f, Mathf.Cos(_animateTime * BackgroundSelectedFlashSpeed) * 0.5f + 1.3f); + alpha = alpha * alpha; + Color selectionColor = SelectionColor * alpha; - for (int i = 3; i <= selectedLinesCount; i++) - { - leftEdge.Y += fontHeight; - Rectangle r = new Rectangle(leftMargin, leftEdge.Y, 1000000000, fontHeight); - Render2D.FillRectangle(r, selectionColor); - } + int selectedLinesCount = 1 + Mathf.FloorToInt((rightEdge.Y - leftEdge.Y) / fontHeight); + if (selectedLinesCount == 1) // Selected is part of single line + { + Rectangle r1 = new Rectangle(leftEdge.X, leftEdge.Y, rightEdge.X - leftEdge.X, fontHeight); + Render2D.FillRectangle(r1, selectionColor); + } + else // Selected is more than one line + { + float leftMargin = _layout.Bounds.Location.X; + Rectangle r1 = new Rectangle(leftEdge.X, leftEdge.Y, 1000000000, fontHeight); + Render2D.FillRectangle(r1, selectionColor); - Rectangle r2 = new Rectangle(leftMargin, rightEdge.Y, rightEdge.X - leftMargin, fontHeight); - Render2D.FillRectangle(r2, selectionColor); - } - } + for (int i = 3; i <= selectedLinesCount; i++) + { + leftEdge.Y += fontHeight; + Rectangle r = new Rectangle(leftMargin, leftEdge.Y, 1000000000, fontHeight); + Render2D.FillRectangle(r, selectionColor); + } - Render2D.DrawText(font, text, TextColor, ref _layout); + Rectangle r2 = new Rectangle(leftMargin, rightEdge.Y, rightEdge.X - leftMargin, fontHeight); + Render2D.FillRectangle(r2, selectionColor); + } + } - if (CaretPosition > -1) - { - var prefixSize = TextPrefix != "" ? font.MeasureText(TextPrefix) : new Vector2(); - var caretBounds = CaretBounds; - caretBounds.X += prefixSize.X; + Render2D.DrawText(font, text, TextColor, ref _layout); - float alpha = Mathf.Saturate(Mathf.Cos(_animateTime * CaretFlashSpeed) * 0.5f + 0.7f); - alpha = alpha * alpha * alpha * alpha * alpha * alpha; - Render2D.FillRectangle(caretBounds, CaretColor * alpha); - } + if (CaretPosition > -1) + { + var prefixSize = TextPrefix != "" ? font.MeasureText(TextPrefix) : new Vector2(); + var caretBounds = CaretBounds; + caretBounds.X += prefixSize.X; - // Restore rendering state - if (useViewOffset) - Render2D.PopTransform(); - Render2D.PopClip(); - } + float alpha = Mathf.Saturate(Mathf.Cos(_animateTime * CaretFlashSpeed) * 0.5f + 0.7f); + alpha = alpha * alpha * alpha * alpha * alpha * alpha; + Render2D.FillRectangle(caretBounds, CaretColor * alpha); + } - public override void Paste() - { - if (IsReadOnly) - return; + // Restore rendering state + if (useViewOffset) + Render2D.PopTransform(); + Render2D.PopClip(); + } - var clipboardText = Clipboard.Text; - // Handle newlines in clipboard text - if (!string.IsNullOrEmpty(clipboardText)) - { - // TODO: probably better to just split these lines and parse each line separately - clipboardText = clipboardText.Replace("\r\n", ""); - clipboardText = clipboardText.Replace("\n", ""); - } + public override void Paste() + { + if (IsReadOnly) + return; - if (!string.IsNullOrEmpty(clipboardText)) - { - var right = SelectionRight; - Insert(clipboardText); - SetSelection(Mathf.Max(right, 0) + clipboardText.Length); - } - } - } -} + var clipboardText = Clipboard.Text; + // Handle newlines in clipboard text + if (!string.IsNullOrEmpty(clipboardText)) + { + // TODO: probably better to just split these lines and parse each line separately + clipboardText = clipboardText.Replace("\r\n", ""); + clipboardText = clipboardText.Replace("\n", ""); + } + + if (!string.IsNullOrEmpty(clipboardText)) + { + var right = SelectionRight; + Insert(clipboardText); + SetSelection(Mathf.Max(right, 0) + clipboardText.Length); + } + } + } +} \ No newline at end of file diff --git a/Source/Game/Cabrito/Console/ConsoleVariable.cs b/Source/Game/Cabrito/Console/ConsoleVariable.cs index 6c92a4f..96db87c 100644 --- a/Source/Game/Cabrito/Console/ConsoleVariable.cs +++ b/Source/Game/Cabrito/Console/ConsoleVariable.cs @@ -7,69 +7,69 @@ using System.Threading.Tasks; namespace Cabrito { - [Flags] - public enum ConsoleFlags - { - NoSerialize = 1, // Value does not persist + [Flags] + public enum ConsoleFlags + { + NoSerialize = 1, // Value does not persist - Alias = NoSerialize, - } + Alias = NoSerialize, + } - internal struct ConsoleVariable - { - public string name { get; private set; } - public ConsoleFlags flags { get; private set; } + internal struct ConsoleVariable + { + public string name { get; private set; } + public ConsoleFlags flags { get; private set; } - private FieldInfo field; - private MethodInfo getter; - private MethodInfo setter; + private FieldInfo field; + private MethodInfo getter; + private MethodInfo setter; - public ConsoleVariable(string name, ConsoleFlags flags, FieldInfo field) - { - this.name = name; - this.flags = flags; - this.field = field; - this.getter = null; - this.setter = null; - } + public ConsoleVariable(string name, ConsoleFlags flags, FieldInfo field) + { + this.name = name; + this.flags = flags; + this.field = field; + this.getter = null; + this.setter = null; + } - public ConsoleVariable(string name, ConsoleFlags flags, MethodInfo getter, MethodInfo setter) - { - this.name = name; - this.flags = flags; - this.field = null; - this.getter = getter; - this.setter = setter; - } + public ConsoleVariable(string name, ConsoleFlags flags, MethodInfo getter, MethodInfo setter) + { + this.name = name; + this.flags = flags; + this.field = null; + this.getter = getter; + this.setter = setter; + } - public string GetValueString() - { - var type = field != null ? field.FieldType : getter.ReturnType; - if (type == typeof(string)) - { - if (field != null) - return (string)field.GetValue(null); - else if (setter != null) - return (string)getter.Invoke(null, null); - } - else - throw new Exception("cvar is not type of string"); + public string GetValueString() + { + var type = field != null ? field.FieldType : getter.ReturnType; + if (type == typeof(string)) + { + if (field != null) + return (string) field.GetValue(null); + else if (setter != null) + return (string) getter.Invoke(null, null); + } + else + throw new Exception("cvar is not type of string"); - throw new Exception("GetValueString no field or getter specified"); - } + throw new Exception("GetValueString no field or getter specified"); + } - public void SetValue(string value) - { - var type = field != null ? field.FieldType : getter.ReturnType; - if (type == typeof(string)) - { - if (field != null) - field.SetValue(null, value); - else if (setter != null) - setter.Invoke(null, new object[] { value }); - } - else - throw new Exception("Unsupported type for SetValue: " + type.Name); - } - } -} + public void SetValue(string value) + { + var type = field != null ? field.FieldType : getter.ReturnType; + if (type == typeof(string)) + { + if (field != null) + field.SetValue(null, value); + else if (setter != null) + setter.Invoke(null, new object[] {value}); + } + else + throw new Exception("Unsupported type for SetValue: " + type.Name); + } + } +} \ No newline at end of file diff --git a/Source/Game/Cabrito/FpsScript.cs b/Source/Game/Cabrito/FpsScript.cs index 174e367..13e14cf 100644 --- a/Source/Game/Cabrito/FpsScript.cs +++ b/Source/Game/Cabrito/FpsScript.cs @@ -8,132 +8,133 @@ using FlaxEngine.GUI; namespace Cabrito { - [ExecuteInEditMode] - public class FpsScript : Script - { - public UIControl control; - Label label; + [ExecuteInEditMode] + public class FpsScript : Script + { + public UIControl control; + Label label; - Stopwatch sw; - double updateTimeAvg = 0.0; - ulong updateTimeCount; - const double updateInterval = 0.25; + Stopwatch sw; + double updateTimeAvg = 0.0; + ulong updateTimeCount; + const double updateInterval = 0.25; - Stopwatch sw2; - double drawTimeAvg = 0.0; - ulong drawTimeCount; - const double drawInterval = 0.25; + Stopwatch sw2; + double drawTimeAvg = 0.0; + ulong drawTimeCount; + const double drawInterval = 0.25; - Stopwatch sw3; - double physicsTimeAvg = 0.0; - ulong physicsTimeCount; - const double physicsInterval = 0.25; + Stopwatch sw3; + double physicsTimeAvg = 0.0; + ulong physicsTimeCount; + const double physicsInterval = 0.25; - string currentRenderer = "Unknown"; + string currentRenderer = "Unknown"; - RenderTask t; + RenderTask t; - TimeSettings timeSettings; + TimeSettings timeSettings; - public override void OnAwake() - { - label = (Label)control.Control; + public override void OnAwake() + { + label = (Label) control.Control; - sw = Stopwatch.StartNew(); + sw = Stopwatch.StartNew(); - currentRenderer = GPUDevice.Instance.RendererType.ToString(); + currentRenderer = GPUDevice.Instance.RendererType.ToString(); - sw2 = Stopwatch.StartNew(); - if (t == null) - { - //Destroy(t); - t = new RenderTask(); - t.Render += OnDraw; - } + sw2 = Stopwatch.StartNew(); + if (t == null) + { + //Destroy(t); + t = new RenderTask(); + t.Render += OnDraw; + } - sw3 = Stopwatch.StartNew(); + sw3 = Stopwatch.StartNew(); - var settings = FlaxEditor.Content.Settings.GameSettings.Load(); - timeSettings = settings.Time.CreateInstance(); - } + var settings = FlaxEditor.Content.Settings.GameSettings.Load(); + timeSettings = settings.Time.CreateInstance(); + } - public override void OnDestroy() - { - Destroy(t); - t = null; - } + public override void OnDestroy() + { + Destroy(t); + t = null; + } - double conTime = 0.0; - public override void OnUpdate() - { - updateTimeCount++; - double elapsed = sw.Elapsed.TotalSeconds; - if (elapsed >= updateInterval) - { - sw.Restart(); - updateTimeAvg = elapsed / updateTimeCount; - updateTimeCount = 0; + double conTime = 0.0; - conTime = ((ConsoleContentTextBox.accumDrawTime / ConsoleContentTextBox.accumDrawTimes) * 1000.0); - ConsoleContentTextBox.accumDrawTime = 0.0; - ConsoleContentTextBox.accumDrawTimes = 0; - } + public override void OnUpdate() + { + updateTimeCount++; + double elapsed = sw.Elapsed.TotalSeconds; + if (elapsed >= updateInterval) + { + sw.Restart(); + updateTimeAvg = elapsed / updateTimeCount; + updateTimeCount = 0; - StringBuilder sb = new StringBuilder(); - sb.Append("eFPS: " + Engine.FramesPerSecond); - sb.Append("\nuFPS: " + ((int)Math.Round(1.0f / updateTimeAvg)).ToString()); - sb.Append("\nrFPS: " + ((int)Math.Round(1.0f / drawTimeAvg)).ToString()); - sb.Append("\npFPS: " + ((int)Math.Round(1.0f / physicsTimeAvg)).ToString()); - sb.Append("\nCon: " + conTime.ToString() + "ms"); - sb.Append("\n" + currentRenderer); - sb.Append("\nGC memory: " + (GC.GetTotalMemory(false)/1000000.0f).ToString() + "MB"); + conTime = ((ConsoleContentTextBox.accumDrawTime / ConsoleContentTextBox.accumDrawTimes) * 1000.0); + ConsoleContentTextBox.accumDrawTime = 0.0; + ConsoleContentTextBox.accumDrawTimes = 0; + } - ((Label) control.Control).Text = sb.ToString(); - /*if (!Platform.HasFocus) - { - Time.UpdateFPS = 15; - Time.DrawFPS = 15; - Time.PhysicsFPS = 15; - } + StringBuilder sb = new StringBuilder(); + sb.Append("eFPS: " + Engine.FramesPerSecond); + sb.Append("\nuFPS: " + ((int) Math.Round(1.0f / updateTimeAvg)).ToString()); + sb.Append("\nrFPS: " + ((int) Math.Round(1.0f / drawTimeAvg)).ToString()); + sb.Append("\npFPS: " + ((int) Math.Round(1.0f / physicsTimeAvg)).ToString()); + sb.Append("\nCon: " + conTime.ToString() + "ms"); + sb.Append("\n" + currentRenderer); + sb.Append("\nGC memory: " + (GC.GetTotalMemory(false) / 1000000.0f).ToString() + "MB"); + + ((Label) control.Control).Text = sb.ToString(); + /*if (!Platform.HasFocus) + { + Time.UpdateFPS = 15; + Time.DrawFPS = 15; + Time.PhysicsFPS = 15; + } #if FLAX_EDITOR - else if (!FlaxEditor.Editor.IsPlayMode) - { - var editorFPS = FlaxEditor.Editor.Instance.Options.Options.General.EditorFPS; - Time.UpdateFPS = editorFPS; - Time.DrawFPS = editorFPS; - Time.PhysicsFPS = timeSettings.PhysicsFPS; - } + else if (!FlaxEditor.Editor.IsPlayMode) + { + var editorFPS = FlaxEditor.Editor.Instance.Options.Options.General.EditorFPS; + Time.UpdateFPS = editorFPS; + Time.DrawFPS = editorFPS; + Time.PhysicsFPS = timeSettings.PhysicsFPS; + } #endif - else - { - Time.UpdateFPS = timeSettings.UpdateFPS; - Time.DrawFPS = timeSettings.DrawFPS; - Time.PhysicsFPS = timeSettings.PhysicsFPS; - }*/ - } + else + { + Time.UpdateFPS = timeSettings.UpdateFPS; + Time.DrawFPS = timeSettings.DrawFPS; + Time.PhysicsFPS = timeSettings.PhysicsFPS; + }*/ + } - public override void OnFixedUpdate() - { - physicsTimeCount++; - double elapsed = sw3.Elapsed.TotalSeconds; - if (elapsed >= physicsInterval) - { - sw3.Restart(); - physicsTimeAvg = elapsed / physicsTimeCount; - physicsTimeCount = 0; - } - } + public override void OnFixedUpdate() + { + physicsTimeCount++; + double elapsed = sw3.Elapsed.TotalSeconds; + if (elapsed >= physicsInterval) + { + sw3.Restart(); + physicsTimeAvg = elapsed / physicsTimeCount; + physicsTimeCount = 0; + } + } - void OnDraw(RenderTask tt, GPUContext context) - { - drawTimeCount++; - double elapsed = sw2.Elapsed.TotalSeconds; - if (elapsed >= drawInterval) - { - sw2.Restart(); - drawTimeAvg = elapsed / drawTimeCount; - drawTimeCount = 0; - } - } - } -} + void OnDraw(RenderTask tt, GPUContext context) + { + drawTimeCount++; + double elapsed = sw2.Elapsed.TotalSeconds; + if (elapsed >= drawInterval) + { + sw2.Restart(); + drawTimeAvg = elapsed / drawTimeCount; + drawTimeCount = 0; + } + } + } +} \ No newline at end of file diff --git a/Source/Game/Cabrito/SystemCommands.cs b/Source/Game/Cabrito/SystemCommands.cs index f5b0719..d736dfb 100644 --- a/Source/Game/Cabrito/SystemCommands.cs +++ b/Source/Game/Cabrito/SystemCommands.cs @@ -7,123 +7,119 @@ using FlaxEngine; namespace Cabrito { - // Holds Consol§e variables and commands to control engine behaviour and other common - public static class SystemCommands - { - [ConsoleCommand("")] - public static void NullCommand() - { - } + // Holds Consol§e variables and commands to control engine behaviour and other common + public static class SystemCommands + { + [ConsoleCommand("")] + public static void NullCommand() + { + } - [ConsoleCommand("quit", "exit")] - public static void ExitCommand() - { - Engine.RequestExit(); - } + [ConsoleCommand("quit", "exit")] + public static void ExitCommand() + { + Engine.RequestExit(); + } - [ConsoleCommand("echo")] - public static void EchoCommand() - { - Console.Print("nothing"); - } + [ConsoleCommand("echo")] + public static void EchoCommand() + { + Console.Print("nothing"); + } - [ConsoleCommand("echo")] - public static void EchoCommand(string[] text) - { - Console.Print(string.Join(" ", text)); - } + [ConsoleCommand("echo")] + public static void EchoCommand(string[] text) + { + Console.Print(string.Join(" ", text)); + } - [ConsoleCommand("debuglog")] - public static void DebugLogCommand(string[] text) - { - Debug.Log(string.Join(" ", text)); - } + [ConsoleCommand("debuglog")] + public static void DebugLogCommand(string[] text) + { + Debug.Log(string.Join(" ", text)); + } - [ConsoleCommand("debugthrow")] - public static void DebugThrowCommand(string[] text) - { - throw new Exception(string.Join(" ", text)); - } + [ConsoleCommand("debugthrow")] + public static void DebugThrowCommand(string[] text) + { + throw new Exception(string.Join(" ", text)); + } - // TODO: this should manually set all postprocessing values to 0 or disabled - /*[ConsoleVariable("r_postprocessing")] - public static string PostProcessing - { - get - { - PostFxVolume postFx = Level.FindActor(); - if (postFx != null) - return postFx.CameraArtifacts.OverrideFlags.ToString(); - return ""; - } - set - { - bool valueBoolean = false; - if (int.TryParse(value, out int valueInt)) - valueBoolean = valueInt != 0; - else - return; + // TODO: this should manually set all postprocessing values to 0 or disabled + /*[ConsoleVariable("r_postprocessing")] + public static string PostProcessing + { + get + { + PostFxVolume postFx = Level.FindActor(); + if (postFx != null) + return postFx.CameraArtifacts.OverrideFlags.ToString(); + return ""; + } + set + { + bool valueBoolean = false; + if (int.TryParse(value, out int valueInt)) + valueBoolean = valueInt != 0; + else + return; - PostFxVolume postFx = Level.FindActor(); - if (postFx != null) - { - var cameraArtifacts = postFx.CameraArtifacts; - cameraArtifacts.OverrideFlags = valueBoolean ? CameraArtifactsSettingsOverride.None : CameraArtifactsSettingsOverride.All; - postFx.CameraArtifacts = cameraArtifacts; - } - } - }*/ + PostFxVolume postFx = Level.FindActor(); + if (postFx != null) + { + var cameraArtifacts = postFx.CameraArtifacts; + cameraArtifacts.OverrideFlags = valueBoolean ? CameraArtifactsSettingsOverride.None : CameraArtifactsSettingsOverride.All; + postFx.CameraArtifacts = cameraArtifacts; + } + } + }*/ - [ConsoleVariable("r_vignette")] - public static string Vignette - { - get - { - PostFxVolume postFx = Level.FindActor(); - if (postFx != null) - return postFx.CameraArtifacts.VignetteIntensity.ToString(); - return ""; - } - set - { - if (float.TryParse(value, out float valueFloat)) - { - PostFxVolume postFx = Level.FindActor(); - if (postFx != null) - { - valueFloat = Mathf.Clamp(valueFloat, 0.0f, 2.0f); + [ConsoleVariable("r_vignette")] + public static string Vignette + { + get + { + PostFxVolume postFx = Level.FindActor(); + if (postFx != null) + return postFx.CameraArtifacts.VignetteIntensity.ToString(); + return ""; + } + set + { + if (float.TryParse(value, out float valueFloat)) + { + PostFxVolume postFx = Level.FindActor(); + if (postFx != null) + { + valueFloat = Mathf.Clamp(valueFloat, 0.0f, 2.0f); - var cameraArtifacts = postFx.CameraArtifacts; - cameraArtifacts.VignetteIntensity = valueFloat; - postFx.CameraArtifacts = cameraArtifacts; - } - } - } - } + var cameraArtifacts = postFx.CameraArtifacts; + cameraArtifacts.VignetteIntensity = valueFloat; + postFx.CameraArtifacts = cameraArtifacts; + } + } + } + } - [ConsoleVariable("cl_maxfps")] - public static string MaxFps - { - get - { - return Time.UpdateFPS.ToString(); - } - set - { - if (float.TryParse(value, out float valueFloat)) - { - if (valueFloat <= 0.0f) - valueFloat = 0.0f; - else - valueFloat = Mathf.Clamp(valueFloat, 10f, 99999999999.0f); + [ConsoleVariable("cl_maxfps")] + public static string MaxFps + { + get { return Time.UpdateFPS.ToString(); } + set + { + if (float.TryParse(value, out float valueFloat)) + { + if (valueFloat <= 0.0f) + valueFloat = 0.0f; + else + valueFloat = Mathf.Clamp(valueFloat, 10f, 99999999999.0f); - if (Time.UpdateFPS != valueFloat) - Time.UpdateFPS = valueFloat; - if (Time.DrawFPS != valueFloat) - Time.DrawFPS = valueFloat; - } - } - } - - } -} + if (Time.UpdateFPS != valueFloat) + Time.UpdateFPS = valueFloat; + if (Time.DrawFPS != valueFloat) + Time.DrawFPS = valueFloat; + } + } + } + } +} \ No newline at end of file diff --git a/Source/Game/CameraMovement.cs b/Source/Game/CameraMovement.cs index c86fc01..4498324 100644 --- a/Source/Game/CameraMovement.cs +++ b/Source/Game/CameraMovement.cs @@ -4,118 +4,118 @@ using System.Diagnostics; namespace Game { - public class CameraMovement : Script - { - [Limit(0, 9000), Tooltip("Camera speed")] - public float MoveSpeed { get; set; } = 400; + public class CameraMovement : Script + { + [Limit(0, 9000), Tooltip("Camera speed")] + public float MoveSpeed { get; set; } = 400; - private float _pitch; - private float _yaw; + private float _pitch; + private float _yaw; - private float xAxis; - private float yAxis; - private float inputH; - private float inputV; + private float xAxis; + private float yAxis; + private float inputH; + private float inputV; - private InputEvent onExit = new InputEvent("Exit"); + private InputEvent onExit = new InputEvent("Exit"); public override void OnAwake() { base.OnAwake(); - onExit.Triggered += () => - { - if (Console.IsSafeToQuit) - Engine.RequestExit(); - }; - } + onExit.Triggered += () => + { + if (Console.IsSafeToQuit) + Engine.RequestExit(); + }; + } public override void OnDestroy() { base.OnDestroy(); - onExit.Dispose(); + onExit.Dispose(); } - public override void OnStart() - { - var initialEulerAngles = Actor.Orientation.EulerAngles; - _pitch = initialEulerAngles.X; - _yaw = initialEulerAngles.Y; - } + public override void OnStart() + { + var initialEulerAngles = Actor.Orientation.EulerAngles; + _pitch = initialEulerAngles.X; + _yaw = initialEulerAngles.Y; + } - public override void OnUpdate() - { - var camTrans = Actor.Transform; + public override void OnUpdate() + { + var camTrans = Actor.Transform; - xAxis = InputManager.GetAxis("Mouse X"); - yAxis = InputManager.GetAxis("Mouse Y"); + xAxis = InputManager.GetAxis("Mouse X"); + yAxis = InputManager.GetAxis("Mouse Y"); - if (xAxis != 0.0f || yAxis != 0.0f) - { - _pitch += yAxis; - _yaw += xAxis; + if (xAxis != 0.0f || yAxis != 0.0f) + { + _pitch += yAxis; + _yaw += xAxis; - camTrans.Orientation = Quaternion.Euler(_pitch, _yaw, 0); - } + camTrans.Orientation = Quaternion.Euler(_pitch, _yaw, 0); + } - inputH = InputManager.GetAxis("Horizontal"); - inputV = InputManager.GetAxis("Vertical"); - var move = new Vector3(inputH, 0.0f, inputV); + inputH = InputManager.GetAxis("Horizontal"); + inputV = InputManager.GetAxis("Vertical"); + var move = new Vector3(inputH, 0.0f, inputV); - if (!move.IsZero) - { - move.Normalize(); - move = camTrans.TransformDirection(move) * MoveSpeed; - - { - Vector3 delta = move * Time.UnscaledDeltaTime; - float movementLeft = delta.Length; + if (!move.IsZero) + { + move.Normalize(); + move = camTrans.TransformDirection(move) * MoveSpeed; - // TODO: check multiple times in case we get stuck in walls + { + Vector3 delta = move * Time.UnscaledDeltaTime; + float movementLeft = delta.Length; - float sphereRadius = 10.0f; // TODO: use collider radius - RayCastHit[] hitInfos; - float moveDist = delta.Length; - Physics.SphereCastAll(Actor.Transform.Translation, sphereRadius, move.Normalized, out hitInfos, moveDist); + // TODO: check multiple times in case we get stuck in walls - //bool nohit = true; - float hitDistance = moveDist; - Vector3 hitNormal = move.Normalized; - foreach (RayCastHit hitInfo in hitInfos) - { - if (hitInfo.Collider.Parent == Parent) - continue; + float sphereRadius = 10.0f; // TODO: use collider radius + RayCastHit[] hitInfos; + float moveDist = delta.Length; + Physics.SphereCastAll(Actor.Transform.Translation, sphereRadius, move.Normalized, out hitInfos, + moveDist); - if (hitInfo.Distance < hitDistance) - { - hitDistance = hitInfo.Distance; - hitNormal = hitInfo.Normal; - } - //nohit = false; - //break; - } + //bool nohit = true; + float hitDistance = moveDist; + Vector3 hitNormal = move.Normalized; + foreach (RayCastHit hitInfo in hitInfos) + { + if (hitInfo.Collider.Parent == Parent) + continue; - if (hitDistance != moveDist) - { - //camTrans.Translation = Vector3.Lerp(Actor.Transform.Translation, camTrans.Translation, hitDistance); + if (hitInfo.Distance < hitDistance) + { + hitDistance = hitInfo.Distance; + hitNormal = hitInfo.Normal; + } + //nohit = false; + //break; + } - //projected = normal * dot(direction, normal); - //direction = direction - projected + if (hitDistance != moveDist) + { + //camTrans.Translation = Vector3.Lerp(Actor.Transform.Translation, camTrans.Translation, hitDistance); + + //projected = normal * dot(direction, normal); + //direction = direction - projected - //camTrans.Translation += hitNormal * (moveDist - hitDistance); // correct? - //camTrans.Translation = hitNormal * (move * hitNormal); // correct? - //camTrans.Translation = Actor.Transform.Translation; - delta += -Vector3.Dot(delta, hitNormal) * hitNormal; // correct? - } + //camTrans.Translation += hitNormal * (moveDist - hitDistance); // correct? + //camTrans.Translation = hitNormal * (move * hitNormal); // correct? + //camTrans.Translation = Actor.Transform.Translation; + delta += -Vector3.Dot(delta, hitNormal) * hitNormal; // correct? + } - camTrans.Translation += delta; - - } - } + camTrans.Translation += delta; + } + } - Actor.Transform = camTrans; - } - } -} + Actor.Transform = camTrans; + } + } +} \ No newline at end of file diff --git a/Source/Game/CustomCharacterController.cs b/Source/Game/CustomCharacterController.cs index 15405b0..73d4f1e 100644 --- a/Source/Game/CustomCharacterController.cs +++ b/Source/Game/CustomCharacterController.cs @@ -4,8 +4,7 @@ using FlaxEngine; namespace Game { - public class CustomCharacterController : CharacterController - { - - } -} + public class CustomCharacterController : CharacterController + { + } +} \ No newline at end of file diff --git a/Source/Game/InputManager.cs b/Source/Game/InputManager.cs index 492fabe..a7e311b 100644 --- a/Source/Game/InputManager.cs +++ b/Source/Game/InputManager.cs @@ -4,27 +4,27 @@ using Cabrito; namespace Game { - public static class InputManager - { - public static bool GetAction(string name) - { - if (Console.IsOpen) - return false; - return Input.GetAction(name); - } + public static class InputManager + { + public static bool GetAction(string name) + { + if (Console.IsOpen) + return false; + return Input.GetAction(name); + } - public static float GetAxis(string name) - { - if (Console.IsOpen) - return 0.0f; - return Input.GetAxis(name); - } + public static float GetAxis(string name) + { + if (Console.IsOpen) + return 0.0f; + return Input.GetAxis(name); + } - public static float GetAxisRaw(string name) - { - if (Console.IsOpen) - return 0.0f; - return Input.GetAxisRaw(name); - } - } -} + public static float GetAxisRaw(string name) + { + if (Console.IsOpen) + return 0.0f; + return Input.GetAxisRaw(name); + } + } +} \ No newline at end of file diff --git a/Source/Game/PlayerMovement.cs b/Source/Game/PlayerMovement.cs index 4745bcd..94bb9c1 100644 --- a/Source/Game/PlayerMovement.cs +++ b/Source/Game/PlayerMovement.cs @@ -9,644 +9,662 @@ using Object = FlaxEngine.Object; namespace Game { - public struct TraceInfo - { - public RayCastHit[] hitInfos; - public bool startSolid; - - // closest hit - public float fraction; - public Vector3 endPosition; - public Vector3 hitNormal; - public Vector3 hitPosition; - - // furthest hit - //public float maxFraction; - //public Vector3 maxHitNormal; - //public Vector3 maxEndPosition; - } - - public class PlayerMovement : Script - { - [Limit(0, 9000), Tooltip("Base Movement speed")] - public float MoveSpeed { get; set; } = 320; - - private float viewPitch; - private float viewYaw; - private float viewRoll; - - private InputEvent onExit = new InputEvent("Exit"); - - private const float collisionMargin = 0.031f * 1.666f; - - Actor rootActor; - private RigidBody rigidBody; - public override void OnAwake() - { - base.OnAwake(); - - onExit.Triggered += () => - { - if (Console.IsSafeToQuit) - Engine.RequestExit(); - }; - - rootActor = Actor.GetChild(0); - - rigidBody = Actor.As(); - //rigidBody.CollisionEnter += OnCollisionEnter; - //rigidBody.TriggerEnter += OnTriggerEnter; - //rigidBody.TriggerExit += OnTriggerExit; - } - - private List touchingActors = new List(); - private void OnTriggerEnter(PhysicsColliderActor colliderActor) - { - //if (colliderActor.AttachedRigidBody == null) - // return; - touchingActors.Add(colliderActor); - Console.Print("trogger: "); - } - - private void OnTriggerExit(PhysicsColliderActor colliderActor) - { - //if (colliderActor.AttachedRigidBody == null) - // return; - - touchingActors.Remove(colliderActor); - Console.Print("untrogger: "); - } - - private void OnCollisionEnter(Collision collision) - { - //Console.Print("collision: "); - } - - public override void OnDestroy() - { - base.OnDestroy(); - - onExit.Dispose(); - } - - public override void OnStart() - { - var initialEulerAngles = Actor.Orientation.EulerAngles; - viewPitch = initialEulerAngles.X; - viewYaw = initialEulerAngles.Y; - viewRoll = initialEulerAngles.Z; - } - - /// - /// Sweeps the player rigidbody in world and returns geometry which was hit during the trace. - /// - /// Start position - /// End position - /// - private TraceInfo TracePlayer(Vector3 start, Vector3 end) - { - TraceInfo traceInfo = new TraceInfo(); - - Vector3 delta = end - start; - float maxDistance = delta.Length; - Vector3 direction = delta.Normalized; - - bool collided = false; - var capsuleCollider = Actor.GetChild(); - var boxCollider = Actor.GetChild(); - var meshCollider = Actor.GetChild(); - PhysicsColliderActor colliderActor = null; - if (capsuleCollider && capsuleCollider.IsActive) - { - colliderActor = capsuleCollider; - collided = Physics.CapsuleCastAll(start, - capsuleCollider.Radius, capsuleCollider.Height, - direction, out traceInfo.hitInfos, capsuleCollider.Orientation, maxDistance, - uint.MaxValue, - false); - } - else if (meshCollider && meshCollider.IsActive) - { - colliderActor = meshCollider; - collided = Physics.ConvexCastAll(start, - meshCollider.CollisionData, meshCollider.Scale, - direction, out traceInfo.hitInfos, meshCollider.Orientation, maxDistance, - uint.MaxValue, - false); - } - else if (boxCollider && boxCollider.IsActive) - { - colliderActor = boxCollider; - collided = Physics.BoxCastAll(start, - boxCollider.OrientedBox.Extents, - direction, out traceInfo.hitInfos, boxCollider.Orientation, maxDistance, uint.MaxValue, - false); - } - - if (collided) - { - List hitInfosFiltered = new List(); - RayCastHit closest = new RayCastHit(); - closest.Distance = float.MaxValue; - foreach (var hitInfo in traceInfo.hitInfos) - { - if (hitInfo.Collider == colliderActor) - continue; - - hitInfosFiltered.Add(hitInfo); - - if (hitInfo.Distance < closest.Distance && hitInfo.Distance != 0.0f) - closest = hitInfo; - } - - if (hitInfosFiltered.Count == 0) - collided = false; // self-collision? - else //if (closest.Distance > 0f) - { - if (closest.Distance == float.MaxValue) - { - foreach (var hitInfo in hitInfosFiltered) - { - if (hitInfo.Distance < closest.Distance) - closest = hitInfo; - } - } - - traceInfo.hitInfos = hitInfosFiltered.ToArray(); - - traceInfo.fraction = closest.Distance / maxDistance; - traceInfo.hitNormal = closest.Normal; - traceInfo.hitPosition = closest.Point; - traceInfo.endPosition = start + (delta * traceInfo.fraction); - - if (traceInfo.fraction == 0f && maxDistance > 0f) - traceInfo.startSolid = true; - } - /*else - { - traceInfo.startSolid = true; - traceInfo.fraction = 0f; - }*/ - } - - if (!collided) - { - traceInfo.hitInfos = new RayCastHit[0]; - traceInfo.fraction = 1f; - traceInfo.endPosition = end; - } - - return traceInfo; - } - - public override void OnDebugDraw() - { - base.OnDebugDraw(); - - var capsuleCollider = Actor.GetChild(); - var boxCollider = Actor.GetChild(); - var meshCollider = Actor.GetChild(); - if (capsuleCollider && capsuleCollider.IsActive) - { - Quaternion rotation = capsuleCollider.LocalOrientation * Quaternion.Euler(0f, 90f, 0f); - DebugDraw.DrawWireTube(capsuleCollider.Position, rotation, capsuleCollider.Radius, capsuleCollider.Height, Color.GreenYellow * 0.8f); - } - else if (meshCollider && meshCollider.IsActive) - { - //Quaternion rotation = meshCollider.LocalOrientation * Quaternion.Euler(0f, 90f, 0f); - DebugDraw.DrawWireCylinder(meshCollider.Position, meshCollider.Orientation, capsuleCollider.Radius, capsuleCollider.Height + capsuleCollider.Radius * 2, Color.GreenYellow * 0.8f); - //DebugDraw.DrawWireTube(meshCollider.Position, rotation, meshCollider.Radius, meshCollider.Height, Color.GreenYellow * 0.8f); - } - else if (boxCollider && boxCollider.IsActive) - { - DebugDraw.DrawWireBox(boxCollider.OrientedBox.GetBoundingBox(), Color.GreenYellow * 0.8f); - } - } - - private SlideMoveHit StepSlideMove(ref Vector3 position, ref Vector3 velocity, bool onGround) - { - if (velocity.IsZero) - return SlideMoveHit.Nothing; - - Vector3 originalPosition = position; - Vector3 originalVelocity = velocity; - - SlideMoveHit slideMoveHit = SlideMove(ref position, ref velocity); - if (slideMoveHit == SlideMoveHit.Nothing) - return slideMoveHit; - - // hit something, try to step up - if (onGround) - { - Vector3 slidePosition = position; - Vector3 slideVelocity = velocity; - position = originalPosition; - velocity = originalVelocity; - - Vector3 stepUp = position + (-Physics.Gravity.Normalized * stepSize); - TraceInfo traceUp = TracePlayer(position, stepUp); - if (traceUp.fraction > 0f) - position = traceUp.endPosition; - - SlideMoveHit slideMoveStepHit = SlideMove(ref position, ref velocity); - - Vector3 stepDown = position + (Physics.Gravity.Normalized * stepSize); - TraceInfo traceDown = TracePlayer(position, stepDown); - if (traceDown.fraction < 1f && -Vector3.Dot(Physics.Gravity.Normalized, traceDown.hitNormal) < 0.7) - { - // can't step down, slide move like normally - Console.Print("no stepping 1, frac: " + traceDown.fraction.ToString() + ", dot: " + (-Vector3.Dot(Physics.Gravity.Normalized, traceDown.hitNormal)).ToString() + ", norm: " + traceDown.hitNormal.ToString()); - position = slidePosition; - velocity = slideVelocity; - return slideMoveHit; - } - else if (traceDown.fraction > 0f) - position = traceDown.endPosition; - - if (traceDown.fraction < 1f) - position.Y += collisionMargin; - - var d1 = -Vector3.Dot(Physics.Gravity.Normalized, position); - var d2 = -Vector3.Dot(Physics.Gravity.Normalized, originalPosition); - if (d1 < d2) - { - // ? - Console.Print("no stepping 2, " + d1.ToString() + " < " + d2.ToString()); - position = slidePosition; - velocity = slideVelocity; - return slideMoveHit; - } - - Vector3 stepPosition = position; - Vector3 slidePosition2 = slidePosition; - Vector3 stepPosition2 = stepPosition; - - slidePosition2.Y = 0f; - stepPosition2.Y = 0f; - - // choose which one went furthest away from the original position - if ((stepPosition2 - originalPosition).Length < (slidePosition2 - originalPosition).Length) - { - Console.Print("no stepping 3"); - position = slidePosition; - velocity = slideVelocity; - return slideMoveHit; - } - - slideMoveHit = slideMoveStepHit; - } - - return slideMoveHit; - } - - [Flags] - enum SlideMoveHit - { - Nothing = 0, - Step = 1, - Floor = 2, - Other = 4, - } - - private SlideMoveHit SlideMove(ref Vector3 position, ref Vector3 velocity) - { - if (velocity.IsZero) - return SlideMoveHit.Nothing; - - Vector3 originalPosition = position; - Vector3 originalVelocity = velocity; - SlideMoveHit slideMoveHit = SlideMoveHit.Nothing; - - float timeleft = Time.DeltaTime; - - List hitNormals = new List(); - - for (int bump = 0; bump < 4; bump++) - { - Vector3 startPos = position; - Vector3 endPos = position + (velocity * timeleft); - - TraceInfo trace = TracePlayer(startPos, endPos); - // TODO: handle portals here - - float fraction = trace.fraction; - Vector3 hitNormal = trace.hitNormal; - - if (trace.startSolid) - { - velocity = Vector3.Zero; - break; - } - - if (fraction > 0f) - { - position = trace.endPosition; - hitNormals.Clear(); // this is present in some forks, not in Q3 - } - - if (fraction >= 1f) - break; - - timeleft *= 1.0f - fraction; - - if (trace.hitNormal.Y > 0.7) - slideMoveHit |= SlideMoveHit.Floor; - else if (Math.Abs(trace.hitNormal.Y) < 0.0001f) - slideMoveHit |= SlideMoveHit.Step; - else - slideMoveHit |= SlideMoveHit.Other; - - // this doesn't seem to do anything, we never have any hitNormals stored here - bool hitPreviousNormal = false; - foreach (Vector3 normal in hitNormals) - { - if (Vector3.Dot(hitNormal, normal) > 0.99) - { - // nudge away from the same wall we hit earlier and try again - velocity += hitNormal; - hitPreviousNormal = true; - break; - } - } - if (hitPreviousNormal) - continue; - - hitNormals.Add(hitNormal); - if (hitNormals.Count != 1) - Console.Print("hitNormals: " + hitNormals.Count); - - int plane; - Vector3 normalMargin = Vector3.Zero; - for (plane = 0; plane < hitNormals.Count; plane++) - { - Vector3 normal = hitNormals[plane]; - - // clip velocity - velocity -= normal * Vector3.Dot(velocity, normal); - //velocity = Vector3.ProjectOnPlane(velocity, normal); - - //traceOffset = normal * 1f; - normalMargin += normal; - //position += normal * 0.031f; - - int plane2; - for (plane2 = 0; plane2 < hitNormals.Count; plane2++) - { - if (plane == plane2) - continue; - - if (Vector3.Dot(velocity, hitNormals[plane2]) < 0f) - break; - } - - if (plane2 == hitNormals.Count) - break; - } - - // push off slightly away from the walls to not get stuck - position += normalMargin.Normalized * collisionMargin; - - if (plane == hitNormals.Count) - { - if (hitNormals.Count == 2) - { - Vector3 dir = Vector3.Cross(hitNormals[0], hitNormals[1]); - //dir.Normalize(); - float dist = Vector3.Dot(dir, velocity); - velocity = dist * dir; - } - else - { - velocity = Vector3.Zero; - break; - } - } - else - { - // nudge very slightly away from the wall to avoid getting stuck - //position += trace.hitNormal * 0.01f; - //velocity += trace.hitNormal * 0.01f; - } - - // prevents bouncing against the wall - if (/*velocity.Length > 0f && */Vector3.Dot(velocity, originalVelocity) <= 0f) - { - velocity = Vector3.Zero; - break; - } - } - - return slideMoveHit; - } - - public override void OnUpdate() - { - float xAxis = InputManager.GetAxisRaw("Mouse X"); - float yAxis = InputManager.GetAxisRaw("Mouse Y"); - if (xAxis != 0.0f || yAxis != 0.0f) - { - var camera = rootActor.GetChild(); - - viewPitch += yAxis; - viewYaw += xAxis; - - viewPitch = Mathf.Clamp(viewPitch, -90.0f, 90.0f); - - // root orientation must be set first - rootActor.Orientation = Quaternion.Euler(0, viewYaw, 0); - camera.Orientation = Quaternion.Euler(viewPitch, viewYaw, viewRoll); - } - } - - [ReadOnly] - public bool onGround = false; - - private const float friction = 4f; - private const float stopspeed = 100f; - private const float accelerationGround = 10f; - private const float jumpVelocity = 270f; - - private const float maxAirSpeed = 320f; - private const float maxAirStrafeSpeed = 30f; //Q2+ - private const float airAcceleration = 0.4f * 0f; //Q2+ - private const float airStopAcceleration = 2.5f * 0f; //Q2+ - private const float airStrafeAcceleration = 70f * 0f; //CPM? - private const float strafeAcceleration = 10f; //QW - private const float airControl = 0f; //CPM - private const float stepSize = 16f; - private bool physicsInteractions = false; - - private bool jumped = false; - - private Vector3 safePosition; - - [ReadOnly] - public float CurrentVelocity { get { return currentVelocity.Length; } set {} } - - [ReadOnly] - public float UPS { get - { - Vector3 horizontalSpeed = currentVelocity; - horizontalSpeed.Y = 0f; - return horizontalSpeed.Length; - - } set {} } - - private Vector3 currentVelocity; - public override void OnFixedUpdate() - { - Transform rootTrans = rootActor.Transform; - - Vector3 inputDirection = new Vector3(InputManager.GetAxis("Horizontal"), 0.0f, InputManager.GetAxis("Vertical")); - Vector3 moveDirection = rootTrans.TransformDirection(inputDirection); - - Vector3 position = rigidBody.Position; - Vector3 velocity = currentVelocity;//rigidBody.LinearVelocity; - - Vector3 wishVelocity = Vector3.Zero; - if (!inputDirection.IsZero) - wishVelocity = moveDirection.Normalized * MoveSpeed; - - // categorize position - onGround = true; - Vector3 groundDelta = Physics.Gravity.Normalized * (collisionMargin*2); - TraceInfo traceGround = TracePlayer(position, position + groundDelta); - - if (!traceGround.startSolid && traceGround.fraction < 1f && - -Vector3.Dot(Physics.Gravity.Normalized, traceGround.hitNormal) < 0.7f) - { - // slope - // clip velocity - Vector3 bounce = groundDelta; - //Vector3 velocityProjected = Vector3.ProjectOnPlane(velocity, normal); - float backoff = Vector3.Dot(bounce, traceGround.hitNormal) * 2f; - bounce -= traceGround.hitNormal * backoff; - //velocity = velocityProjected; - - Vector3 point = (position + groundDelta) + - (1f - traceGround.fraction) * bounce; - - // retrace - traceGround = TracePlayer(position, position + point); - } - - if (!traceGround.startSolid && (traceGround.fraction >= 1f || - -Vector3.Dot(Physics.Gravity.Normalized, traceGround.hitNormal) < 0.7f)) - { - // falling or sliding down a slope - onGround = false; - } - else - { - onGround = !traceGround.startSolid; - } - - // TODO: snap to ground here - - // jump - if (onGround) - { - if (!jumped && InputManager.GetAction("Jump")) - { - // reset velocity from gravity - if (-Vector3.Dot(Physics.Gravity.Normalized, velocity) < 0 && - Vector3.Dot(velocity, traceGround.hitNormal) < -0.1) - { - velocity = Vector3.ProjectOnPlane(velocity, traceGround.hitNormal); - } - - velocity += Vector3.Up * jumpVelocity; - onGround = false; - - Guid jumpguid; - FlaxEngine.Json.JsonSerializer.ParseID("1ef4565844a4b36cdfda54b51f338c77", out jumpguid); - AudioClip jumpAsset = AudioClip.Find(ref jumpguid); - if (jumpAsset != null && jumpAsset.IsLoaded) - { - var audioSource = new AudioSource(); - audioSource.Clip = jumpAsset; - audioSource.Position = rootActor.Position;//new Vector3(-350, 176, 61);//rootActor.Position; - audioSource.Parent = Actor.Parent; - - - audioSource.Play(); - Destroy(audioSource, jumpAsset.Length); - Console.Print("jumping sound!"); - } - else if (jumpAsset == null) - Console.Print("jumpAsset not found"); - else - Console.Print("jumpAsset not loaded"); - } - else if (jumped) // jump released - jumped = false; - } - - // ground friction - if (onGround) - { - float currentSpeed = velocity.Length; - - float control = currentSpeed < stopspeed ? stopspeed : currentSpeed; - var drop = control * friction * Time.DeltaTime; - - float newspeed = currentSpeed - drop; - if (newspeed < 0) - newspeed = 0; - - if (currentSpeed < 0.0001f) - velocity *= 0; - else - velocity *= newspeed / currentSpeed; - } - - if (onGround) // ground acceleration - { - ApplyAcceleration(ref velocity, wishVelocity.Normalized, wishVelocity.Length, float.MaxValue, accelerationGround); - } - else // air acceleration - { - var wishspeed = wishVelocity.Length; - if (wishspeed > maxAirSpeed) - wishspeed = maxAirSpeed; - - if (strafeAcceleration != 0f) - ApplyAcceleration(ref velocity, wishVelocity.Normalized, wishspeed, maxAirStrafeSpeed, strafeAcceleration); - } - - if (!onGround) - velocity += Physics.Gravity * Time.DeltaTime; - - safePosition = rigidBody.Position; - currentVelocity = velocity; - if (!rigidBody.IsKinematic) - rigidBody.LinearVelocity = velocity; - else - { - StepSlideMove(ref position, ref velocity, onGround); - - rigidBody.Position = position; - currentVelocity = velocity; - //rigidBody.LinearVelocity = velocity; - } - } - - void ApplyAcceleration(ref Vector3 velocity, Vector3 wishDir, float wishspeed, float maxWishspeed, float acceleration) - { - float wishspeedOrig = wishspeed; - if (wishspeed > maxWishspeed) - wishspeed = maxWishspeed; - - float currentSpeed = Vector3.Dot(velocity, wishDir); - float addSpeed = wishspeed - currentSpeed; - if (addSpeed <= 0f) - return; - - float accelSpeed = acceleration * wishspeedOrig * Time.DeltaTime; - if (accelSpeed > addSpeed) - accelSpeed = addSpeed; - - velocity += accelSpeed * wishDir; - } - } -} + public struct TraceInfo + { + public RayCastHit[] hitInfos; + public bool startSolid; + + // closest hit + public float fraction; + public Vector3 endPosition; + public Vector3 hitNormal; + public Vector3 hitPosition; + + // furthest hit + //public float maxFraction; + //public Vector3 maxHitNormal; + //public Vector3 maxEndPosition; + } + + public class PlayerMovement : Script + { + [Limit(0, 9000), Tooltip("Base Movement speed")] + public float MoveSpeed { get; set; } = 320; + + private float viewPitch; + private float viewYaw; + private float viewRoll; + + private InputEvent onExit = new InputEvent("Exit"); + + private const float collisionMargin = 0.031f * 1.666f; + + Actor rootActor; + private RigidBody rigidBody; + + public override void OnAwake() + { + base.OnAwake(); + + onExit.Triggered += () => + { + if (Console.IsSafeToQuit) + Engine.RequestExit(); + }; + + rootActor = Actor.GetChild(0); + + rigidBody = Actor.As(); + //rigidBody.CollisionEnter += OnCollisionEnter; + //rigidBody.TriggerEnter += OnTriggerEnter; + //rigidBody.TriggerExit += OnTriggerExit; + } + + private List touchingActors = new List(); + + private void OnTriggerEnter(PhysicsColliderActor colliderActor) + { + //if (colliderActor.AttachedRigidBody == null) + // return; + touchingActors.Add(colliderActor); + Console.Print("trogger: "); + } + + private void OnTriggerExit(PhysicsColliderActor colliderActor) + { + //if (colliderActor.AttachedRigidBody == null) + // return; + + touchingActors.Remove(colliderActor); + Console.Print("untrogger: "); + } + + private void OnCollisionEnter(Collision collision) + { + //Console.Print("collision: "); + } + + public override void OnDestroy() + { + base.OnDestroy(); + + onExit.Dispose(); + } + + public override void OnStart() + { + var initialEulerAngles = Actor.Orientation.EulerAngles; + viewPitch = initialEulerAngles.X; + viewYaw = initialEulerAngles.Y; + viewRoll = initialEulerAngles.Z; + } + + /// + /// Sweeps the player rigidbody in world and returns geometry which was hit during the trace. + /// + /// Start position + /// End position + /// + private TraceInfo TracePlayer(Vector3 start, Vector3 end) + { + TraceInfo traceInfo = new TraceInfo(); + + Vector3 delta = end - start; + float maxDistance = delta.Length; + Vector3 direction = delta.Normalized; + + bool collided = false; + var capsuleCollider = Actor.GetChild(); + var boxCollider = Actor.GetChild(); + var meshCollider = Actor.GetChild(); + PhysicsColliderActor colliderActor = null; + if (capsuleCollider && capsuleCollider.IsActive) + { + colliderActor = capsuleCollider; + collided = Physics.CapsuleCastAll(start, + capsuleCollider.Radius, capsuleCollider.Height, + direction, out traceInfo.hitInfos, capsuleCollider.Orientation, maxDistance, + uint.MaxValue, + false); + } + else if (meshCollider && meshCollider.IsActive) + { + colliderActor = meshCollider; + collided = Physics.ConvexCastAll(start, + meshCollider.CollisionData, meshCollider.Scale, + direction, out traceInfo.hitInfos, meshCollider.Orientation, maxDistance, + uint.MaxValue, + false); + } + else if (boxCollider && boxCollider.IsActive) + { + colliderActor = boxCollider; + collided = Physics.BoxCastAll(start, + boxCollider.OrientedBox.Extents, + direction, out traceInfo.hitInfos, boxCollider.Orientation, maxDistance, uint.MaxValue, + false); + } + + if (collided) + { + List hitInfosFiltered = new List(); + RayCastHit closest = new RayCastHit(); + closest.Distance = float.MaxValue; + foreach (var hitInfo in traceInfo.hitInfos) + { + if (hitInfo.Collider == colliderActor) + continue; + + hitInfosFiltered.Add(hitInfo); + + if (hitInfo.Distance < closest.Distance && hitInfo.Distance != 0.0f) + closest = hitInfo; + } + + if (hitInfosFiltered.Count == 0) + collided = false; // self-collision? + else //if (closest.Distance > 0f) + { + if (closest.Distance == float.MaxValue) + { + foreach (var hitInfo in hitInfosFiltered) + { + if (hitInfo.Distance < closest.Distance) + closest = hitInfo; + } + } + + traceInfo.hitInfos = hitInfosFiltered.ToArray(); + + traceInfo.fraction = closest.Distance / maxDistance; + traceInfo.hitNormal = closest.Normal; + traceInfo.hitPosition = closest.Point; + traceInfo.endPosition = start + (delta * traceInfo.fraction); + + if (traceInfo.fraction == 0f && maxDistance > 0f) + traceInfo.startSolid = true; + } + /*else + { + traceInfo.startSolid = true; + traceInfo.fraction = 0f; + }*/ + } + + if (!collided) + { + traceInfo.hitInfos = new RayCastHit[0]; + traceInfo.fraction = 1f; + traceInfo.endPosition = end; + } + + return traceInfo; + } + + public override void OnDebugDraw() + { + base.OnDebugDraw(); + + var capsuleCollider = Actor.GetChild(); + var boxCollider = Actor.GetChild(); + var meshCollider = Actor.GetChild(); + if (capsuleCollider && capsuleCollider.IsActive) + { + Quaternion rotation = capsuleCollider.LocalOrientation * Quaternion.Euler(0f, 90f, 0f); + DebugDraw.DrawWireTube(capsuleCollider.Position, rotation, capsuleCollider.Radius, + capsuleCollider.Height, Color.GreenYellow * 0.8f); + } + else if (meshCollider && meshCollider.IsActive) + { + //Quaternion rotation = meshCollider.LocalOrientation * Quaternion.Euler(0f, 90f, 0f); + DebugDraw.DrawWireCylinder(meshCollider.Position, meshCollider.Orientation, capsuleCollider.Radius, + capsuleCollider.Height + capsuleCollider.Radius * 2, Color.GreenYellow * 0.8f); + //DebugDraw.DrawWireTube(meshCollider.Position, rotation, meshCollider.Radius, meshCollider.Height, Color.GreenYellow * 0.8f); + } + else if (boxCollider && boxCollider.IsActive) + { + DebugDraw.DrawWireBox(boxCollider.OrientedBox.GetBoundingBox(), Color.GreenYellow * 0.8f); + } + } + + private SlideMoveHit StepSlideMove(ref Vector3 position, ref Vector3 velocity, bool onGround) + { + if (velocity.IsZero) + return SlideMoveHit.Nothing; + + Vector3 originalPosition = position; + Vector3 originalVelocity = velocity; + + SlideMoveHit slideMoveHit = SlideMove(ref position, ref velocity); + if (slideMoveHit == SlideMoveHit.Nothing) + return slideMoveHit; + + // hit something, try to step up + if (onGround) + { + Vector3 slidePosition = position; + Vector3 slideVelocity = velocity; + position = originalPosition; + velocity = originalVelocity; + + Vector3 stepUp = position + (-Physics.Gravity.Normalized * stepSize); + TraceInfo traceUp = TracePlayer(position, stepUp); + if (traceUp.fraction > 0f) + position = traceUp.endPosition; + + SlideMoveHit slideMoveStepHit = SlideMove(ref position, ref velocity); + + Vector3 stepDown = position + (Physics.Gravity.Normalized * stepSize); + TraceInfo traceDown = TracePlayer(position, stepDown); + if (traceDown.fraction < 1f && -Vector3.Dot(Physics.Gravity.Normalized, traceDown.hitNormal) < 0.7) + { + // can't step down, slide move like normally + Console.Print("no stepping 1, frac: " + traceDown.fraction.ToString() + ", dot: " + + (-Vector3.Dot(Physics.Gravity.Normalized, traceDown.hitNormal)).ToString() + + ", norm: " + traceDown.hitNormal.ToString()); + position = slidePosition; + velocity = slideVelocity; + return slideMoveHit; + } + else if (traceDown.fraction > 0f) + position = traceDown.endPosition; + + if (traceDown.fraction < 1f) + position.Y += collisionMargin; + + var d1 = -Vector3.Dot(Physics.Gravity.Normalized, position); + var d2 = -Vector3.Dot(Physics.Gravity.Normalized, originalPosition); + if (d1 < d2) + { + // ? + Console.Print("no stepping 2, " + d1.ToString() + " < " + d2.ToString()); + position = slidePosition; + velocity = slideVelocity; + return slideMoveHit; + } + + Vector3 stepPosition = position; + Vector3 slidePosition2 = slidePosition; + Vector3 stepPosition2 = stepPosition; + + slidePosition2.Y = 0f; + stepPosition2.Y = 0f; + + // choose which one went furthest away from the original position + if ((stepPosition2 - originalPosition).Length < (slidePosition2 - originalPosition).Length) + { + Console.Print("no stepping 3"); + position = slidePosition; + velocity = slideVelocity; + return slideMoveHit; + } + + slideMoveHit = slideMoveStepHit; + } + + return slideMoveHit; + } + + [Flags] + enum SlideMoveHit + { + Nothing = 0, + Step = 1, + Floor = 2, + Other = 4, + } + + private SlideMoveHit SlideMove(ref Vector3 position, ref Vector3 velocity) + { + if (velocity.IsZero) + return SlideMoveHit.Nothing; + + Vector3 originalPosition = position; + Vector3 originalVelocity = velocity; + SlideMoveHit slideMoveHit = SlideMoveHit.Nothing; + + float timeleft = Time.DeltaTime; + + List hitNormals = new List(); + + for (int bump = 0; bump < 4; bump++) + { + Vector3 startPos = position; + Vector3 endPos = position + (velocity * timeleft); + + TraceInfo trace = TracePlayer(startPos, endPos); + // TODO: handle portals here + + float fraction = trace.fraction; + Vector3 hitNormal = trace.hitNormal; + + if (trace.startSolid) + { + velocity = Vector3.Zero; + break; + } + + if (fraction > 0f) + { + position = trace.endPosition; + hitNormals.Clear(); // this is present in some forks, not in Q3 + } + + if (fraction >= 1f) + break; + + timeleft *= 1.0f - fraction; + + if (trace.hitNormal.Y > 0.7) + slideMoveHit |= SlideMoveHit.Floor; + else if (Math.Abs(trace.hitNormal.Y) < 0.0001f) + slideMoveHit |= SlideMoveHit.Step; + else + slideMoveHit |= SlideMoveHit.Other; + + // this doesn't seem to do anything, we never have any hitNormals stored here + bool hitPreviousNormal = false; + foreach (Vector3 normal in hitNormals) + { + if (Vector3.Dot(hitNormal, normal) > 0.99) + { + // nudge away from the same wall we hit earlier and try again + velocity += hitNormal; + hitPreviousNormal = true; + break; + } + } + + if (hitPreviousNormal) + continue; + + hitNormals.Add(hitNormal); + if (hitNormals.Count != 1) + Console.Print("hitNormals: " + hitNormals.Count); + + int plane; + Vector3 normalMargin = Vector3.Zero; + for (plane = 0; plane < hitNormals.Count; plane++) + { + Vector3 normal = hitNormals[plane]; + + // clip velocity + velocity -= normal * Vector3.Dot(velocity, normal); + //velocity = Vector3.ProjectOnPlane(velocity, normal); + + //traceOffset = normal * 1f; + normalMargin += normal; + //position += normal * 0.031f; + + int plane2; + for (plane2 = 0; plane2 < hitNormals.Count; plane2++) + { + if (plane == plane2) + continue; + + if (Vector3.Dot(velocity, hitNormals[plane2]) < 0f) + break; + } + + if (plane2 == hitNormals.Count) + break; + } + + // push off slightly away from the walls to not get stuck + position += normalMargin.Normalized * collisionMargin; + + if (plane == hitNormals.Count) + { + if (hitNormals.Count == 2) + { + Vector3 dir = Vector3.Cross(hitNormals[0], hitNormals[1]); + //dir.Normalize(); + float dist = Vector3.Dot(dir, velocity); + velocity = dist * dir; + } + else + { + velocity = Vector3.Zero; + break; + } + } + else + { + // nudge very slightly away from the wall to avoid getting stuck + //position += trace.hitNormal * 0.01f; + //velocity += trace.hitNormal * 0.01f; + } + + // prevents bouncing against the wall + if ( /*velocity.Length > 0f && */Vector3.Dot(velocity, originalVelocity) <= 0f) + { + velocity = Vector3.Zero; + break; + } + } + + return slideMoveHit; + } + + public override void OnUpdate() + { + float xAxis = InputManager.GetAxisRaw("Mouse X"); + float yAxis = InputManager.GetAxisRaw("Mouse Y"); + if (xAxis != 0.0f || yAxis != 0.0f) + { + var camera = rootActor.GetChild(); + + viewPitch += yAxis; + viewYaw += xAxis; + + viewPitch = Mathf.Clamp(viewPitch, -90.0f, 90.0f); + + // root orientation must be set first + rootActor.Orientation = Quaternion.Euler(0, viewYaw, 0); + camera.Orientation = Quaternion.Euler(viewPitch, viewYaw, viewRoll); + } + } + + [ReadOnly] public bool onGround = false; + + private const float friction = 4f; + private const float stopspeed = 100f; + private const float accelerationGround = 10f; + private const float jumpVelocity = 270f; + + private const float maxAirSpeed = 320f; + private const float maxAirStrafeSpeed = 30f; //Q2+ + private const float airAcceleration = 0.4f * 0f; //Q2+ + private const float airStopAcceleration = 2.5f * 0f; //Q2+ + private const float airStrafeAcceleration = 70f * 0f; //CPM? + private const float strafeAcceleration = 10f; //QW + private const float airControl = 0f; //CPM + private const float stepSize = 16f; + //private bool physicsInteractions = false; + + private bool jumped = false; + + private Vector3 safePosition; + + [ReadOnly] + public float CurrentVelocity + { + get { return currentVelocity.Length; } + set { } + } + + [ReadOnly] + public float UPS + { + get + { + Vector3 horizontalSpeed = currentVelocity; + horizontalSpeed.Y = 0f; + return horizontalSpeed.Length; + } + set { } + } + + private Vector3 currentVelocity; + + public override void OnFixedUpdate() + { + Transform rootTrans = rootActor.Transform; + + Vector3 inputDirection = + new Vector3(InputManager.GetAxis("Horizontal"), 0.0f, InputManager.GetAxis("Vertical")); + Vector3 moveDirection = rootTrans.TransformDirection(inputDirection); + + Vector3 position = rigidBody.Position; + Vector3 velocity = currentVelocity; //rigidBody.LinearVelocity; + + Vector3 wishVelocity = Vector3.Zero; + if (!inputDirection.IsZero) + wishVelocity = moveDirection.Normalized * MoveSpeed; + + // categorize position + onGround = true; + Vector3 groundDelta = Physics.Gravity.Normalized * (collisionMargin * 2); + TraceInfo traceGround = TracePlayer(position, position + groundDelta); + + if (!traceGround.startSolid && traceGround.fraction < 1f && + -Vector3.Dot(Physics.Gravity.Normalized, traceGround.hitNormal) < 0.7f) + { + // slope + // clip velocity + Vector3 bounce = groundDelta; + //Vector3 velocityProjected = Vector3.ProjectOnPlane(velocity, normal); + float backoff = Vector3.Dot(bounce, traceGround.hitNormal) * 2f; + bounce -= traceGround.hitNormal * backoff; + //velocity = velocityProjected; + + Vector3 point = (position + groundDelta) + + (1f - traceGround.fraction) * bounce; + + // retrace + traceGround = TracePlayer(position, position + point); + } + + if (!traceGround.startSolid && (traceGround.fraction >= 1f || + -Vector3.Dot(Physics.Gravity.Normalized, traceGround.hitNormal) < 0.7f)) + { + // falling or sliding down a slope + onGround = false; + } + else + { + onGround = !traceGround.startSolid; + } + + // TODO: snap to ground here + + // jump + if (onGround) + { + if (!jumped && InputManager.GetAction("Jump")) + { + // reset velocity from gravity + if (-Vector3.Dot(Physics.Gravity.Normalized, velocity) < 0 && + Vector3.Dot(velocity, traceGround.hitNormal) < -0.1) + { + velocity = Vector3.ProjectOnPlane(velocity, traceGround.hitNormal); + } + + velocity += Vector3.Up * jumpVelocity; + onGround = false; + + Guid jumpguid; + FlaxEngine.Json.JsonSerializer.ParseID("1ef4565844a4b36cdfda54b51f338c77", out jumpguid); + AudioClip jumpAsset = AudioClip.Find(ref jumpguid); + if (jumpAsset != null && jumpAsset.IsLoaded) + { + var audioSource = new AudioSource(); + audioSource.Clip = jumpAsset; + audioSource.Position = rootActor.Position; //new Vector3(-350, 176, 61);//rootActor.Position; + audioSource.Parent = Actor.Parent; + + + audioSource.Play(); + Destroy(audioSource, jumpAsset.Length); + Console.Print("jumping sound!"); + } + else if (jumpAsset == null) + Console.Print("jumpAsset not found"); + else + Console.Print("jumpAsset not loaded"); + } + else if (jumped) // jump released + jumped = false; + } + + // ground friction + if (onGround) + { + float currentSpeed = velocity.Length; + + float control = currentSpeed < stopspeed ? stopspeed : currentSpeed; + var drop = control * friction * Time.DeltaTime; + + float newspeed = currentSpeed - drop; + if (newspeed < 0) + newspeed = 0; + + if (currentSpeed < 0.0001f) + velocity *= 0; + else + velocity *= newspeed / currentSpeed; + } + + if (onGround) // ground acceleration + { + ApplyAcceleration(ref velocity, wishVelocity.Normalized, wishVelocity.Length, float.MaxValue, + accelerationGround); + } + else // air acceleration + { + var wishspeed = wishVelocity.Length; + if (wishspeed > maxAirSpeed) + wishspeed = maxAirSpeed; + + if (strafeAcceleration != 0f) + ApplyAcceleration(ref velocity, wishVelocity.Normalized, wishspeed, maxAirStrafeSpeed, + strafeAcceleration); + } + + if (!onGround) + velocity += Physics.Gravity * Time.DeltaTime; + + safePosition = rigidBody.Position; + currentVelocity = velocity; + if (!rigidBody.IsKinematic) + rigidBody.LinearVelocity = velocity; + else + { + StepSlideMove(ref position, ref velocity, onGround); + + rigidBody.Position = position; + currentVelocity = velocity; + //rigidBody.LinearVelocity = velocity; + } + } + + void ApplyAcceleration(ref Vector3 velocity, Vector3 wishDir, float wishspeed, float maxWishspeed, + float acceleration) + { + float wishspeedOrig = wishspeed; + if (wishspeed > maxWishspeed) + wishspeed = maxWishspeed; + + float currentSpeed = Vector3.Dot(velocity, wishDir); + float addSpeed = wishspeed - currentSpeed; + if (addSpeed <= 0f) + return; + + float accelSpeed = acceleration * wishspeedOrig * Time.DeltaTime; + if (accelSpeed > addSpeed) + accelSpeed = addSpeed; + + velocity += accelSpeed * wishDir; + } + } +} \ No newline at end of file diff --git a/Source/Game/PlayerMovement_NK.cs b/Source/Game/PlayerMovement_NK.cs index 08197a5..ece04d9 100644 --- a/Source/Game/PlayerMovement_NK.cs +++ b/Source/Game/PlayerMovement_NK.cs @@ -445,7 +445,8 @@ namespace Game RigidBody rigidBody = Actor.As(); Transform rootTrans = rootActor.Transform; - Vector3 inputDirection = new Vector3(InputManager.GetAxis("Horizontal"), 0.0f, InputManager.GetAxis("Vertical")); + Vector3 inputDirection = + new Vector3(InputManager.GetAxis("Horizontal"), 0.0f, InputManager.GetAxis("Vertical")); Vector3 moveDirection = rootTrans.TransformDirection(inputDirection); //Vector3 position = rigidBody.Position; diff --git a/Source/Game/Q3MapImporter.cs b/Source/Game/Q3MapImporter.cs index c3895cc..61a92af 100644 --- a/Source/Game/Q3MapImporter.cs +++ b/Source/Game/Q3MapImporter.cs @@ -5,105 +5,103 @@ using System.IO; namespace Game { - public class MapBrush - { + public class MapBrush + { + } - } + public class MapEntity + { + public Dictionary properties = new Dictionary(); + public List entities = new List(); + public List brushes = new List(); + } - public class MapEntity - { - public Dictionary properties = new Dictionary(); - public List entities = new List(); - public List brushes = new List(); - } + public class Q3MapImporter : Script + { + string mapPath = @"C:\dev\Goake\maps\aerowalk\aerowalk.map"; - public class Q3MapImporter : Script - { - string mapPath = @"C:\dev\Goake\maps\aerowalk\aerowalk.map"; + public override void OnStart() + { + string[] lines = File.ReadAllLines(mapPath); - public override void OnStart() - { - string[] lines = File.ReadAllLines(mapPath); + MapEntity rootEntity = new MapEntity(); + MapEntity currentEntity = rootEntity; - MapEntity rootEntity = new MapEntity(); - MapEntity currentEntity = rootEntity; + int level = 0; + uint lineNumber = 0; + foreach (string lineRaw in lines) + { + lineNumber++; + string line = lineRaw.TrimStart(); + if (line.StartsWith("//")) + continue; - int level = 0; - uint lineNumber = 0; - foreach (string lineRaw in lines) - { - lineNumber++; - string line = lineRaw.TrimStart(); - if (line.StartsWith("//")) - continue; + if (line[0] == '{') + { + level++; - if (line[0] == '{') - { - level++; + if (level == 1) + { + currentEntity = new MapEntity(); + rootEntity.entities.Add(currentEntity); + } + else + { + } + } + else if (line[0] == '}') + { + level--; + currentEntity = rootEntity; + } + //if (level < 0 || level > 2) + // throw new Exception("Failed to parse .map file: unexpected entity found at line " + lineNumber.ToString()); - if (level == 1) - { - currentEntity = new MapEntity(); - rootEntity.entities.Add(currentEntity); - } - else - { - - } - } - else if (line[0] == '}') - { - level--; - currentEntity = rootEntity; - } - //if (level < 0 || level > 2) - // throw new Exception("Failed to parse .map file: unexpected entity found at line " + lineNumber.ToString()); + if (line[0] == '"') + { + string[] prop = line.Split('\"'); + if (prop.Length != 5) + throw new Exception("Failed to parse .map file: failed to parse property at line " + + lineNumber.ToString()); - if (line[0] == '"') - { - string[] prop = line.Split('\"'); - if (prop.Length != 5) - throw new Exception("Failed to parse .map file: failed to parse property at line " + lineNumber.ToString()); + string propName = prop[1]; + string propValue = prop[3]; - string propName = prop[1]; - string propValue = prop[3]; + if (currentEntity.properties.ContainsKey(propName)) + throw new Exception("Failed to parse .map file: multiple properties defined for " + propName + + " at line " + lineNumber.ToString()); + currentEntity.properties.Add(propName, propValue); + } + else if (line[0] == '(') + { + //"( -16 302 431 ) ( -16 302 361 ) ( -16 321 361 ) dev/dev_128_gray 0 0 0 0.0625 0.0625 0 0 0" + string[] bru = line.Split(new char[] {'(', ')'}); - if (currentEntity.properties.ContainsKey(propName)) - throw new Exception("Failed to parse .map file: multiple properties defined for " + propName + " at line " + lineNumber.ToString()); - currentEntity.properties.Add(propName, propValue); - } - else if (line[0] == '(') - { - //"( -16 302 431 ) ( -16 302 361 ) ( -16 321 361 ) dev/dev_128_gray 0 0 0 0.0625 0.0625 0 0 0" - string[] bru = line.Split(new char[] { '(', ')' }); + // TODO: make geometry out of this, use planes? + foreach (var b in bru) + { + //Console.WriteLine(b); + } + } + } - // TODO: make geometry out of this, use planes? - foreach (var b in bru) - { - //Console.WriteLine(b); - } - } - } + // Here you can add code that needs to be called when script is created, just before the first game update + } - + public override void OnEnable() + { + // Here you can add code that needs to be called when script is enabled (eg. register for events) + } - // Here you can add code that needs to be called when script is created, just before the first game update - } + public override void OnDisable() + { + // Here you can add code that needs to be called when script is disabled (eg. unregister from events) + } - public override void OnEnable() - { - // Here you can add code that needs to be called when script is enabled (eg. register for events) - } - - public override void OnDisable() - { - // Here you can add code that needs to be called when script is disabled (eg. unregister from events) - } - - public override void OnUpdate() - { - // Here you can add code that needs to be called every frame - } - } -} + public override void OnUpdate() + { + // Here you can add code that needs to be called every frame + } + } +} \ No newline at end of file diff --git a/Source/Game/QBrush.cs b/Source/Game/QBrush.cs index dc5a568..17f9750 100644 --- a/Source/Game/QBrush.cs +++ b/Source/Game/QBrush.cs @@ -4,58 +4,58 @@ using FlaxEngine; namespace Game { - [ExecuteInEditMode] - public class QBrush : Script - { - Model model; + [ExecuteInEditMode] + public class QBrush : Script + { + Model model; - public MaterialBase material; + public MaterialBase material; - public override void OnAwake() - { - model = Content.CreateVirtualAsset(); - model.SetupLODs(new int[] { 1 }); + public override void OnAwake() + { + model = Content.CreateVirtualAsset(); + model.SetupLODs(new int[] {1}); - { - var mesh = model.LODs[0].Meshes[0]; + { + var mesh = model.LODs[0].Meshes[0]; - const float X = 0.525731112119133606f * 100f; - const float Z = 0.850650808352039932f * 100f; - const float N = 0.0f; - var vertices = new[] - { - new Vector3(-X, N, Z), - new Vector3(X, N, Z), - new Vector3(-X, N, -Z), - new Vector3(X, N, -Z), - new Vector3(N, Z, X), - new Vector3(N, Z, -X), - new Vector3(N, -Z, X), - new Vector3(N, -Z, -X), - new Vector3(Z, X, N), - new Vector3(-Z, X, N), - new Vector3(Z, -X, N), - new Vector3(-Z, -X, N) - }; - var triangles = new[] - { - 1, 4, 0, 4, 9, 0, 4, 5, 9, 8, 5, 4, - 1, 8, 4, 1, 10, 8, 10, 3, 8, 8, 3, 5, - 3, 2, 5, 3, 7, 2, 3, 10, 7, 10, 6, 7, - 6, 11, 7, 6, 0, 11, 6, 1, 0, 10, 1, 6, - 11, 0, 9, 2, 11, 9, 5, 2, 9, 11, 2, 7 - }; - mesh.UpdateMesh(vertices, triangles, vertices); - } + const float X = 0.525731112119133606f * 100f; + const float Z = 0.850650808352039932f * 100f; + const float N = 0.0f; + var vertices = new[] + { + new Vector3(-X, N, Z), + new Vector3(X, N, Z), + new Vector3(-X, N, -Z), + new Vector3(X, N, -Z), + new Vector3(N, Z, X), + new Vector3(N, Z, -X), + new Vector3(N, -Z, X), + new Vector3(N, -Z, -X), + new Vector3(Z, X, N), + new Vector3(-Z, X, N), + new Vector3(Z, -X, N), + new Vector3(-Z, -X, N) + }; + var triangles = new[] + { + 1, 4, 0, 4, 9, 0, 4, 5, 9, 8, 5, 4, + 1, 8, 4, 1, 10, 8, 10, 3, 8, 8, 3, 5, + 3, 2, 5, 3, 7, 2, 3, 10, 7, 10, 6, 7, + 6, 11, 7, 6, 0, 11, 6, 1, 0, 10, 1, 6, + 11, 0, 9, 2, 11, 9, 5, 2, 9, 11, 2, 7 + }; + mesh.UpdateMesh(vertices, triangles, vertices); + } - StaticModel childModel = Actor.GetOrAddChild(); - childModel.Model = model; - childModel.SetMaterial(0, material); - } + StaticModel childModel = Actor.GetOrAddChild(); + childModel.Model = model; + childModel.SetMaterial(0, material); + } - public override void OnDestroy() - { - Destroy(ref model); - } - } -} + public override void OnDestroy() + { + Destroy(ref model); + } + } +} \ No newline at end of file