35个文件已修改
11个文件已删除
57 文件已复制
54个文件已添加
2 文件已重命名
copy from Main/Core/GameEngine/Common.meta
copy to Main/Common/Jace.meta
File was copied from Main/Core/GameEngine/Common.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 6b68b2e87cfa2fc48aff8e7f40a5c555 |
| | | guid: ca353b9337f7a0749a543c104493ccc5 |
| | | folderAsset: yes |
| | | DefaultImporter: |
| | | externalObjects: {} |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using Jace.Execution; |
| | | using Jace.Operations; |
| | | using Jace.Tokenizer; |
| | | using Jace.Util; |
| | | |
| | | namespace Jace |
| | | { |
| | | public class AstBuilder |
| | | { |
| | | private readonly IFunctionRegistry functionRegistry; |
| | | private readonly IConstantRegistry localConstantRegistry; |
| | | private readonly bool caseSensitive; |
| | | private Dictionary<char, int> operationPrecedence = new Dictionary<char, int>(); |
| | | private Stack<Operation> resultStack = new Stack<Operation>(); |
| | | private Stack<Token> operatorStack = new Stack<Token>(); |
| | | private Stack<int> parameterCount = new Stack<int>(); |
| | | |
| | | public AstBuilder(IFunctionRegistry functionRegistry, bool caseSensitive, IConstantRegistry compiledConstants = null) |
| | | { |
| | | if (functionRegistry == null) |
| | | throw new ArgumentNullException("functionRegistry"); |
| | | |
| | | this.functionRegistry = functionRegistry; |
| | | this.localConstantRegistry = compiledConstants ?? new ConstantRegistry(caseSensitive); |
| | | this.caseSensitive = caseSensitive; |
| | | |
| | | operationPrecedence.Add('(', 0); |
| | | operationPrecedence.Add('&', 1); |
| | | operationPrecedence.Add('|', 1); |
| | | operationPrecedence.Add('<', 2); |
| | | operationPrecedence.Add('>', 2); |
| | | operationPrecedence.Add('≤', 2); |
| | | operationPrecedence.Add('≥', 2); |
| | | operationPrecedence.Add('≠', 2); |
| | | operationPrecedence.Add('=', 2); |
| | | operationPrecedence.Add('+', 3); |
| | | operationPrecedence.Add('-', 3); |
| | | operationPrecedence.Add('*', 4); |
| | | operationPrecedence.Add('/', 4); |
| | | operationPrecedence.Add('%', 4); |
| | | operationPrecedence.Add('_', 6); |
| | | operationPrecedence.Add('^', 5); |
| | | } |
| | | |
| | | public Operation Build(IList<Token> tokens) |
| | | { |
| | | resultStack.Clear(); |
| | | operatorStack.Clear(); |
| | | |
| | | parameterCount.Clear(); |
| | | |
| | | foreach (Token token in tokens) |
| | | { |
| | | object value = token.Value; |
| | | |
| | | switch (token.TokenType) |
| | | { |
| | | case TokenType.Integer: |
| | | resultStack.Push(new IntegerConstant((int)token.Value)); |
| | | break; |
| | | case TokenType.FloatingPoint: |
| | | resultStack.Push(new FloatingPointConstant((double)token.Value)); |
| | | break; |
| | | case TokenType.Text: |
| | | if (functionRegistry.IsFunctionName((string)token.Value)) |
| | | { |
| | | operatorStack.Push(token); |
| | | parameterCount.Push(1); |
| | | } |
| | | else |
| | | { |
| | | string tokenValue = (string)token.Value; |
| | | if (localConstantRegistry.IsConstantName(tokenValue)) |
| | | { |
| | | resultStack.Push(new FloatingPointConstant(localConstantRegistry.GetConstantInfo(tokenValue).Value)); |
| | | } |
| | | else |
| | | { |
| | | if (!caseSensitive) |
| | | { |
| | | tokenValue = tokenValue.ToLowerFast(); |
| | | } |
| | | resultStack.Push(new Variable(tokenValue)); |
| | | } |
| | | } |
| | | break; |
| | | case TokenType.LeftBracket: |
| | | operatorStack.Push(token); |
| | | break; |
| | | case TokenType.RightBracket: |
| | | PopOperations(true, token); |
| | | //parameterCount.Pop(); |
| | | break; |
| | | case TokenType.ArgumentSeparator: |
| | | PopOperations(false, token); |
| | | parameterCount.Push(parameterCount.Pop() + 1); |
| | | break; |
| | | case TokenType.Operation: |
| | | Token operation1Token = token; |
| | | char operation1 = (char)operation1Token.Value; |
| | | |
| | | while (operatorStack.Count > 0 && (operatorStack.Peek().TokenType == TokenType.Operation || |
| | | operatorStack.Peek().TokenType == TokenType.Text)) |
| | | { |
| | | Token operation2Token = operatorStack.Peek(); |
| | | bool isFunctionOnTopOfStack = operation2Token.TokenType == TokenType.Text; |
| | | |
| | | if (!isFunctionOnTopOfStack) |
| | | { |
| | | char operation2 = (char)operation2Token.Value; |
| | | |
| | | if ((IsLeftAssociativeOperation(operation1) && |
| | | operationPrecedence[operation1] <= operationPrecedence[operation2]) || |
| | | (operationPrecedence[operation1] < operationPrecedence[operation2])) |
| | | { |
| | | operatorStack.Pop(); |
| | | resultStack.Push(ConvertOperation(operation2Token)); |
| | | } |
| | | else |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | operatorStack.Pop(); |
| | | resultStack.Push(ConvertFunction(operation2Token)); |
| | | } |
| | | } |
| | | |
| | | operatorStack.Push(operation1Token); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | PopOperations(false, null); |
| | | |
| | | VerifyResultStack(); |
| | | |
| | | return resultStack.First(); |
| | | } |
| | | |
| | | private void PopOperations(bool untillLeftBracket, Token? currentToken) |
| | | { |
| | | if (untillLeftBracket && !currentToken.HasValue) |
| | | throw new ArgumentNullException("currentToken", "If the parameter \"untillLeftBracket\" is set to true, " + |
| | | "the parameter \"currentToken\" cannot be null."); |
| | | |
| | | while (operatorStack.Count > 0 && operatorStack.Peek().TokenType != TokenType.LeftBracket) |
| | | { |
| | | Token token = operatorStack.Pop(); |
| | | |
| | | switch (token.TokenType) |
| | | { |
| | | case TokenType.Operation: |
| | | resultStack.Push(ConvertOperation(token)); |
| | | break; |
| | | case TokenType.Text: |
| | | resultStack.Push(ConvertFunction(token)); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (untillLeftBracket) |
| | | { |
| | | if (operatorStack.Count > 0 && operatorStack.Peek().TokenType == TokenType.LeftBracket) |
| | | operatorStack.Pop(); |
| | | else |
| | | throw new ParseException(string.Format("No matching left bracket found for the right " + |
| | | "bracket at position {0}.", currentToken.Value.StartPosition)); |
| | | } |
| | | else |
| | | { |
| | | if (operatorStack.Count > 0 && operatorStack.Peek().TokenType == TokenType.LeftBracket |
| | | && !(currentToken.HasValue && currentToken.Value.TokenType == TokenType.ArgumentSeparator)) |
| | | throw new ParseException(string.Format("No matching right bracket found for the left " + |
| | | "bracket at position {0}.", operatorStack.Peek().StartPosition)); |
| | | } |
| | | } |
| | | |
| | | private Operation ConvertOperation(Token operationToken) |
| | | { |
| | | try |
| | | { |
| | | DataType dataType; |
| | | Operation argument1; |
| | | Operation argument2; |
| | | Operation divisor; |
| | | Operation divident; |
| | | |
| | | switch ((char)operationToken.Value) |
| | | { |
| | | case '+': |
| | | argument2 = resultStack.Pop(); |
| | | argument1 = resultStack.Pop(); |
| | | dataType = RequiredDataType(argument1, argument2); |
| | | |
| | | return new Addition(dataType, argument1, argument2); |
| | | case '-': |
| | | argument2 = resultStack.Pop(); |
| | | argument1 = resultStack.Pop(); |
| | | dataType = RequiredDataType(argument1, argument2); |
| | | |
| | | return new Subtraction(dataType, argument1, argument2); |
| | | case '*': |
| | | argument2 = resultStack.Pop(); |
| | | argument1 = resultStack.Pop(); |
| | | dataType = RequiredDataType(argument1, argument2); |
| | | |
| | | return new Multiplication(dataType, argument1, argument2); |
| | | case '/': |
| | | divisor = resultStack.Pop(); |
| | | divident = resultStack.Pop(); |
| | | |
| | | return new Division(DataType.FloatingPoint, divident, divisor); |
| | | case '%': |
| | | divisor = resultStack.Pop(); |
| | | divident = resultStack.Pop(); |
| | | |
| | | return new Modulo(DataType.FloatingPoint, divident, divisor); |
| | | case '_': |
| | | argument1 = resultStack.Pop(); |
| | | |
| | | return new UnaryMinus(argument1.DataType, argument1); |
| | | case '^': |
| | | Operation exponent = resultStack.Pop(); |
| | | Operation @base = resultStack.Pop(); |
| | | |
| | | return new Exponentiation(DataType.FloatingPoint, @base, exponent); |
| | | case '&': |
| | | argument2 = resultStack.Pop(); |
| | | argument1 = resultStack.Pop(); |
| | | dataType = RequiredDataType(argument1, argument2); |
| | | |
| | | return new And(dataType, argument1, argument2); |
| | | case '|': |
| | | argument2 = resultStack.Pop(); |
| | | argument1 = resultStack.Pop(); |
| | | dataType = RequiredDataType(argument1, argument2); |
| | | |
| | | return new Or(dataType, argument1, argument2); |
| | | case '<': |
| | | argument2 = resultStack.Pop(); |
| | | argument1 = resultStack.Pop(); |
| | | dataType = RequiredDataType(argument1, argument2); |
| | | |
| | | return new LessThan(dataType, argument1, argument2); |
| | | case '≤': |
| | | argument2 = resultStack.Pop(); |
| | | argument1 = resultStack.Pop(); |
| | | dataType = RequiredDataType(argument1, argument2); |
| | | |
| | | return new LessOrEqualThan(dataType, argument1, argument2); |
| | | case '>': |
| | | argument2 = resultStack.Pop(); |
| | | argument1 = resultStack.Pop(); |
| | | dataType = RequiredDataType(argument1, argument2); |
| | | |
| | | return new GreaterThan(dataType, argument1, argument2); |
| | | case '≥': |
| | | argument2 = resultStack.Pop(); |
| | | argument1 = resultStack.Pop(); |
| | | dataType = RequiredDataType(argument1, argument2); |
| | | |
| | | return new GreaterOrEqualThan(dataType, argument1, argument2); |
| | | case '=': |
| | | argument2 = resultStack.Pop(); |
| | | argument1 = resultStack.Pop(); |
| | | dataType = RequiredDataType(argument1, argument2); |
| | | |
| | | return new Equal(dataType, argument1, argument2); |
| | | case '≠': |
| | | argument2 = resultStack.Pop(); |
| | | argument1 = resultStack.Pop(); |
| | | dataType = RequiredDataType(argument1, argument2); |
| | | |
| | | return new NotEqual(dataType, argument1, argument2); |
| | | default: |
| | | throw new ArgumentException(string.Format("Unknown operation \"{0}\".", operationToken), "operation"); |
| | | } |
| | | } |
| | | catch (InvalidOperationException) |
| | | { |
| | | // If we encounter a Stack empty issue this means there is a syntax issue in |
| | | // the mathematical formula |
| | | throw new ParseException(string.Format("There is a syntax issue for the operation \"{0}\" at position {1}. " + |
| | | "The number of arguments does not match with what is expected.", operationToken.Value, operationToken.StartPosition)); |
| | | } |
| | | } |
| | | |
| | | private Operation ConvertFunction(Token functionToken) |
| | | { |
| | | try |
| | | { |
| | | string functionName = ((string)functionToken.Value).ToLowerInvariant(); |
| | | |
| | | if (functionRegistry.IsFunctionName(functionName)) |
| | | { |
| | | FunctionInfo functionInfo = functionRegistry.GetFunctionInfo(functionName); |
| | | |
| | | int numberOfParameters; |
| | | |
| | | if (functionInfo.IsDynamicFunc) { |
| | | numberOfParameters = parameterCount.Pop(); |
| | | } |
| | | else { |
| | | parameterCount.Pop(); |
| | | numberOfParameters = functionInfo.NumberOfParameters; |
| | | } |
| | | |
| | | List<Operation> operations = new List<Operation>(); |
| | | for (int i = 0; i < numberOfParameters; i++) |
| | | operations.Add(resultStack.Pop()); |
| | | operations.Reverse(); |
| | | |
| | | return new Function(DataType.FloatingPoint, functionName, operations, functionInfo.IsIdempotent); |
| | | } |
| | | else |
| | | { |
| | | throw new ArgumentException(string.Format("Unknown function \"{0}\".", functionToken.Value), "function"); |
| | | } |
| | | } |
| | | catch (InvalidOperationException) |
| | | { |
| | | // If we encounter a Stack empty issue this means there is a syntax issue in |
| | | // the mathematical formula |
| | | throw new ParseException(string.Format("There is a syntax issue for the function \"{0}\" at position {1}. " + |
| | | "The number of arguments does not match with what is expected.", functionToken.Value, functionToken.StartPosition)); |
| | | } |
| | | } |
| | | |
| | | private void VerifyResultStack() |
| | | { |
| | | if(resultStack.Count > 1) |
| | | { |
| | | Operation[] operations = resultStack.ToArray(); |
| | | |
| | | for (int i = 1; i < operations.Length; i++) |
| | | { |
| | | Operation operation = operations[i]; |
| | | |
| | | if (operation.GetType() == typeof(IntegerConstant)) |
| | | { |
| | | IntegerConstant constant = (IntegerConstant)operation; |
| | | throw new ParseException(string.Format("Unexpected integer constant \"{0}\" found.", constant.Value)); |
| | | } |
| | | else if (operation.GetType() == typeof(FloatingPointConstant)) |
| | | { |
| | | FloatingPointConstant constant = (FloatingPointConstant)operation; |
| | | throw new ParseException(string.Format("Unexpected floating point constant \"{0}\" found.", constant.Value)); |
| | | } |
| | | } |
| | | |
| | | throw new ParseException("The syntax of the provided formula is not valid."); |
| | | } |
| | | } |
| | | |
| | | private bool IsLeftAssociativeOperation(char character) |
| | | { |
| | | return character == '*' || character == '+' || character == '-' || character == '/'; |
| | | } |
| | | |
| | | private DataType RequiredDataType(Operation argument1, Operation argument2) |
| | | { |
| | | return (argument1.DataType == DataType.FloatingPoint || argument2.DataType == DataType.FloatingPoint) ? DataType.FloatingPoint : DataType.Integer; |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/AstBuilder.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: de824ec81c42eae4888376c8a458a540 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Globalization; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using Jace.Execution; |
| | | using Jace.Operations; |
| | | using Jace.Tokenizer; |
| | | using Jace.Util; |
| | | |
| | | namespace Jace |
| | | { |
| | | public delegate TResult DynamicFunc<T, TResult>(params T[] values); |
| | | |
| | | /// <summary> |
| | | /// The CalculationEngine class is the main class of Jace.NET to convert strings containing |
| | | /// mathematical formulas into .NET Delegates and to calculate the result. |
| | | /// It can be configured to run in a number of modes based on the constructor parameters choosen. |
| | | /// </summary> |
| | | public class CalculationEngine |
| | | { |
| | | private readonly IExecutor executor; |
| | | private readonly Optimizer optimizer; |
| | | private readonly CultureInfo cultureInfo; |
| | | private readonly MemoryCache<string, Func<IDictionary<string, double>, double>> executionFormulaCache; |
| | | private readonly bool cacheEnabled; |
| | | private readonly bool optimizerEnabled; |
| | | private readonly bool caseSensitive; |
| | | |
| | | private readonly Random random; |
| | | |
| | | /// <summary> |
| | | /// Creates a new instance of the <see cref="CalculationEngine"/> class with |
| | | /// default parameters. |
| | | /// </summary> |
| | | public CalculationEngine() |
| | | : this(new JaceOptions()) |
| | | { |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Creates a new instance of the <see cref="CalculationEngine"/> class. The dynamic compiler |
| | | /// is used for formula execution and the optimizer and cache are enabled. |
| | | /// </summary> |
| | | /// <param name="cultureInfo"> |
| | | /// The <see cref="CultureInfo"/> required for correctly reading floating poin numbers. |
| | | /// </param> |
| | | public CalculationEngine(CultureInfo cultureInfo) |
| | | : this(new JaceOptions() { CultureInfo = cultureInfo }) |
| | | { |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Creates a new instance of the <see cref="CalculationEngine"/> class. The optimizer and |
| | | /// cache are enabled. |
| | | /// </summary> |
| | | /// <param name="cultureInfo"> |
| | | /// The <see cref="CultureInfo"/> required for correctly reading floating poin numbers. |
| | | /// </param> |
| | | /// <param name="executionMode">The execution mode that must be used for formula execution.</param> |
| | | public CalculationEngine(CultureInfo cultureInfo, ExecutionMode executionMode) |
| | | : this (new JaceOptions() { CultureInfo = cultureInfo, ExecutionMode = executionMode }) |
| | | { |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Creates a new instance of the <see cref="CalculationEngine"/> class. |
| | | /// </summary> |
| | | /// <param name="cultureInfo"> |
| | | /// The <see cref="CultureInfo"/> required for correctly reading floating poin numbers. |
| | | /// </param> |
| | | /// <param name="executionMode">The execution mode that must be used for formula execution.</param> |
| | | /// <param name="cacheEnabled">Enable or disable caching of mathematical formulas.</param> |
| | | /// <param name="optimizerEnabled">Enable or disable optimizing of formulas.</param> |
| | | /// <param name="adjustVariableCaseEnabled">Enable or disable auto lowercasing of variables.</param> |
| | | [Obsolete] |
| | | public CalculationEngine(CultureInfo cultureInfo, ExecutionMode executionMode, bool cacheEnabled, bool optimizerEnabled, bool adjustVariableCaseEnabled) |
| | | : this(new JaceOptions() { CultureInfo = cultureInfo, ExecutionMode = executionMode, CacheEnabled = cacheEnabled, OptimizerEnabled = optimizerEnabled, CaseSensitive = !adjustVariableCaseEnabled }) |
| | | { |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Creates a new instance of the <see cref="CalculationEngine"/> class. |
| | | /// </summary> |
| | | /// <param name="cultureInfo"> |
| | | /// The <see cref="CultureInfo"/> required for correctly reading floating poin numbers. |
| | | /// </param> |
| | | /// <param name="executionMode">The execution mode that must be used for formula execution.</param> |
| | | /// <param name="cacheEnabled">Enable or disable caching of mathematical formulas.</param> |
| | | /// <param name="optimizerEnabled">Enable or disable optimizing of formulas.</param> |
| | | /// <param name="adjustVariableCaseEnabled">Enable or disable converting to lower case.</param> |
| | | /// <param name="defaultFunctions">Enable or disable the default functions.</param> |
| | | /// <param name="defaultConstants">Enable or disable the default constants.</param> |
| | | /// <param name="cacheMaximumSize">Configure the maximum cache size for mathematical formulas.</param> |
| | | /// <param name="cacheReductionSize">Configure the cache reduction size for mathematical formulas.</param> |
| | | [Obsolete] |
| | | public CalculationEngine(CultureInfo cultureInfo, ExecutionMode executionMode, bool cacheEnabled, |
| | | bool optimizerEnabled, bool adjustVariableCaseEnabled, bool defaultFunctions, bool defaultConstants, int cacheMaximumSize, int cacheReductionSize) |
| | | : this(new JaceOptions() { CultureInfo = cultureInfo, ExecutionMode = executionMode, CacheEnabled = cacheEnabled, OptimizerEnabled = optimizerEnabled, |
| | | CaseSensitive = !adjustVariableCaseEnabled, DefaultFunctions = defaultFunctions, DefaultConstants = defaultConstants, |
| | | CacheMaximumSize = cacheMaximumSize, CacheReductionSize = cacheReductionSize }) |
| | | { |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Creates a new instance of the <see cref="CalculationEngine"/> class. |
| | | /// </summary> |
| | | /// <param name="options">The <see cref="JaceOptions"/> to configure the behaviour of the engine.</param> |
| | | public CalculationEngine(JaceOptions options) |
| | | { |
| | | this.executionFormulaCache = new MemoryCache<string, Func<IDictionary<string, double>, double>>(options.CacheMaximumSize, options.CacheReductionSize); |
| | | this.FunctionRegistry = new FunctionRegistry(false); |
| | | this.ConstantRegistry = new ConstantRegistry(false); |
| | | this.cultureInfo = options.CultureInfo; |
| | | this.cacheEnabled = options.CacheEnabled; |
| | | this.optimizerEnabled = options.OptimizerEnabled; |
| | | this.caseSensitive = options.CaseSensitive; |
| | | |
| | | this.random = new Random(); |
| | | |
| | | if (options.ExecutionMode == ExecutionMode.Interpreted) |
| | | executor = new Interpreter(caseSensitive); |
| | | else if (options.ExecutionMode == ExecutionMode.Compiled) |
| | | executor = new DynamicCompiler(caseSensitive); |
| | | else |
| | | throw new ArgumentException(string.Format("Unsupported execution mode \"{0}\".", options.ExecutionMode), |
| | | "executionMode"); |
| | | |
| | | optimizer = new Optimizer(new Interpreter()); // We run the optimizer with the interpreter |
| | | |
| | | // Register the default constants of Jace.NET into the constant registry |
| | | if (options.DefaultConstants) |
| | | RegisterDefaultConstants(); |
| | | |
| | | // Register the default functions of Jace.NET into the function registry |
| | | if (options.DefaultFunctions) |
| | | RegisterDefaultFunctions(); |
| | | } |
| | | |
| | | internal IFunctionRegistry FunctionRegistry { get; private set; } |
| | | |
| | | internal IConstantRegistry ConstantRegistry { get; private set; } |
| | | |
| | | public IEnumerable<FunctionInfo> Functions { get { return FunctionRegistry; } } |
| | | |
| | | public IEnumerable<ConstantInfo> Constants { get { return ConstantRegistry; } } |
| | | |
| | | public double Calculate(string formulaText) |
| | | { |
| | | return Calculate(formulaText, new Dictionary<string, double>()); |
| | | } |
| | | |
| | | public double Calculate(string formulaText, IDictionary<string, double> variables) |
| | | { |
| | | if (string.IsNullOrEmpty(formulaText)) |
| | | throw new ArgumentNullException("formulaText"); |
| | | |
| | | if (variables == null) |
| | | throw new ArgumentNullException("variables"); |
| | | |
| | | if (!caseSensitive) |
| | | { |
| | | variables = EngineUtil.ConvertVariableNamesToLowerCase(variables); |
| | | } |
| | | VerifyVariableNames(variables); |
| | | |
| | | // Add the reserved variables to the dictionary |
| | | foreach (ConstantInfo constant in ConstantRegistry) |
| | | variables.Add(constant.ConstantName, constant.Value); |
| | | |
| | | if (IsInFormulaCache(formulaText, null, out var function)) |
| | | { |
| | | return function(variables); |
| | | } |
| | | else |
| | | { |
| | | Operation operation = BuildAbstractSyntaxTree(formulaText, new ConstantRegistry(caseSensitive)); |
| | | function = BuildFormula(formulaText, null, operation); |
| | | return function(variables); |
| | | } |
| | | } |
| | | |
| | | public FormulaBuilder Formula(string formulaText) |
| | | { |
| | | if (string.IsNullOrEmpty(formulaText)) |
| | | throw new ArgumentNullException("formulaText"); |
| | | |
| | | return new FormulaBuilder(formulaText, caseSensitive, this); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Build a .NET func for the provided formula. |
| | | /// </summary> |
| | | /// <param name="formulaText">The formula that must be converted into a .NET func.</param> |
| | | /// <returns>A .NET func for the provided formula.</returns> |
| | | public Func<IDictionary<string, double>, double> Build(string formulaText) |
| | | { |
| | | if (string.IsNullOrEmpty(formulaText)) |
| | | throw new ArgumentNullException("formulaText"); |
| | | |
| | | if (IsInFormulaCache(formulaText, null, out var result)) |
| | | { |
| | | return result; |
| | | } |
| | | else |
| | | { |
| | | Operation operation = BuildAbstractSyntaxTree(formulaText, new ConstantRegistry(caseSensitive)); |
| | | return BuildFormula(formulaText, null, operation); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Build a .NET func for the provided formula. |
| | | /// </summary> |
| | | /// <param name="formulaText">The formula that must be converted into a .NET func.</param> |
| | | /// <param name="constants">Constant values for variables defined into the formula. They variables will be replaced by the constant value at pre-compilation time.</param> |
| | | /// <returns>A .NET func for the provided formula.</returns> |
| | | public Func<IDictionary<string, double>, double> Build(string formulaText, IDictionary<string, double> constants) |
| | | { |
| | | if (string.IsNullOrEmpty(formulaText)) |
| | | throw new ArgumentNullException("formulaText"); |
| | | |
| | | |
| | | ConstantRegistry compiledConstants = new ConstantRegistry(caseSensitive); |
| | | if (constants != null) |
| | | { |
| | | foreach (var constant in constants) |
| | | { |
| | | compiledConstants.RegisterConstant(constant.Key, constant.Value); |
| | | } |
| | | } |
| | | |
| | | if (IsInFormulaCache(formulaText, compiledConstants, out var result)) |
| | | { |
| | | return result; |
| | | } |
| | | else |
| | | { |
| | | Operation operation = BuildAbstractSyntaxTree(formulaText, compiledConstants); |
| | | return BuildFormula(formulaText, compiledConstants, operation); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Add a function to the calculation engine. |
| | | /// </summary> |
| | | /// <param name="functionName">The name of the function. This name can be used in mathematical formulas.</param> |
| | | /// <param name="function">The implemenation of the function.</param> |
| | | /// <param name="isIdempotent">Does the function provide the same result when it is executed multiple times.</param> |
| | | public void AddFunction(string functionName, Func<double> function, bool isIdempotent = true) |
| | | { |
| | | FunctionRegistry.RegisterFunction(functionName, function, isIdempotent, true); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Add a function to the calculation engine. |
| | | /// </summary> |
| | | /// <param name="functionName">The name of the function. This name can be used in mathematical formulas.</param> |
| | | /// <param name="function">The implemenation of the function.</param> |
| | | /// <param name="isIdempotent">Does the function provide the same result when it is executed multiple times.</param> |
| | | public void AddFunction(string functionName, Func<double, double> function, bool isIdempotent = true) |
| | | { |
| | | FunctionRegistry.RegisterFunction(functionName, function, isIdempotent, true); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Add a function to the calculation engine. |
| | | /// </summary> |
| | | /// <param name="functionName">The name of the function. This name can be used in mathematical formulas.</param> |
| | | /// <param name="function">The implemenation of the function.</param> |
| | | /// <param name="isIdempotent">Does the function provide the same result when it is executed multiple times.</param> |
| | | public void AddFunction(string functionName, Func<double, double, double> function, bool isIdempotent = true) |
| | | { |
| | | FunctionRegistry.RegisterFunction(functionName, function, isIdempotent, true); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Add a function to the calculation engine. |
| | | /// </summary> |
| | | /// <param name="functionName">The name of the function. This name can be used in mathematical formulas.</param> |
| | | /// <param name="function">The implemenation of the function.</param> |
| | | /// <param name="isIdempotent">Does the function provide the same result when it is executed multiple times.</param> |
| | | public void AddFunction(string functionName, Func<double, double, double, double> function, bool isIdempotent = true) |
| | | { |
| | | FunctionRegistry.RegisterFunction(functionName, function, isIdempotent, true); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Add a function to the calculation engine. |
| | | /// </summary> |
| | | /// <param name="functionName">The name of the function. This name can be used in mathematical formulas.</param> |
| | | /// <param name="function">The implemenation of the function.</param> |
| | | /// <param name="isIdempotent">Does the function provide the same result when it is executed multiple times.</param> |
| | | public void AddFunction(string functionName, Func<double, double, double, double, double> function, bool isIdempotent = true) |
| | | { |
| | | FunctionRegistry.RegisterFunction(functionName, function, isIdempotent, true); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Add a function to the calculation engine. |
| | | /// </summary> |
| | | /// <param name="functionName">The name of the function. This name can be used in mathematical formulas.</param> |
| | | /// <param name="function">The implemenation of the function.</param> |
| | | /// <param name="isIdempotent">Does the function provide the same result when it is executed multiple times.</param> |
| | | public void AddFunction(string functionName, Func<double, double, double, double, double, double> function, bool isIdempotent = true) |
| | | { |
| | | FunctionRegistry.RegisterFunction(functionName, function, isIdempotent, true); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Add a function to the calculation engine. |
| | | /// </summary> |
| | | /// <param name="functionName">The name of the function. This name can be used in mathematical formulas.</param> |
| | | /// <param name="function">The implemenation of the function.</param> |
| | | /// <param name="isIdempotent">Does the function provide the same result when it is executed multiple times.</param> |
| | | public void AddFunction(string functionName, Func<double, double, double, double, double, double, double> function, bool isIdempotent = true) |
| | | { |
| | | FunctionRegistry.RegisterFunction(functionName, function, isIdempotent, true); |
| | | } |
| | | |
| | | public void AddFunction(string functionName, Func<double, double, double, double, double, double, double, double> function, bool isIdempotent = true) |
| | | { |
| | | FunctionRegistry.RegisterFunction(functionName, function, isIdempotent, true); |
| | | } |
| | | |
| | | public void AddFunction(string functionName, Func<double, double, double, double, double, double, double, double, double> function, bool isIdempotent = true) |
| | | { |
| | | FunctionRegistry.RegisterFunction(functionName, function, isIdempotent, true); |
| | | } |
| | | |
| | | public void AddFunction(string functionName, Func<double, double, double, double, double, double, double, double, double, double> function, bool isIdempotent = true) |
| | | { |
| | | FunctionRegistry.RegisterFunction(functionName, function, isIdempotent, true); |
| | | } |
| | | |
| | | public void AddFunction(string functionName, Func<double, double, double, double, double, double, double, double, double, double, double> function, bool isIdempotent = true) |
| | | { |
| | | FunctionRegistry.RegisterFunction(functionName, function, isIdempotent, true); |
| | | } |
| | | |
| | | public void AddFunction(string functionName, Func<double, double, double, double, double, double, double, double, double, double, double, double> function, bool isIdempotent = true) |
| | | { |
| | | FunctionRegistry.RegisterFunction(functionName, function, isIdempotent, true); |
| | | } |
| | | |
| | | public void AddFunction(string functionName, Func<double, double, double, double, double, double, double, double, double, double, double, double, double> function, bool isIdempotent = true) |
| | | { |
| | | FunctionRegistry.RegisterFunction(functionName, function, isIdempotent, true); |
| | | } |
| | | |
| | | public void AddFunction(string functionName, Func<double, double, double, double, double, double, double, double, double, double, double, double, double, double> function, bool isIdempotent = true) |
| | | { |
| | | FunctionRegistry.RegisterFunction(functionName, function, isIdempotent, true); |
| | | } |
| | | |
| | | public void AddFunction(string functionName, Func<double, double, double, double, double, double, double, double, double, double, double, double, double, double, double> function, bool isIdempotent = true) |
| | | { |
| | | FunctionRegistry.RegisterFunction(functionName, function, isIdempotent, true); |
| | | } |
| | | |
| | | public void AddFunction(string functionName, Func<double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double> function, bool isIdempotent = true) |
| | | { |
| | | FunctionRegistry.RegisterFunction(functionName, function, isIdempotent, true); |
| | | } |
| | | |
| | | public void AddFunction(string functionName, Func<double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double> function, bool isIdempotent = true) |
| | | { |
| | | FunctionRegistry.RegisterFunction(functionName, function, isIdempotent, true); |
| | | } |
| | | |
| | | public void AddFunction(string functionName, DynamicFunc<double, double> functionDelegate, bool isIdempotent = true) |
| | | { |
| | | FunctionRegistry.RegisterFunction(functionName, functionDelegate, isIdempotent, true); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Add a constant to the calculation engine. |
| | | /// </summary> |
| | | /// <param name="constantName">The name of the constant. This name can be used in mathematical formulas.</param> |
| | | /// <param name="value">The value of the constant.</param> |
| | | public void AddConstant(string constantName, double value) |
| | | { |
| | | ConstantRegistry.RegisterConstant(constantName, value); |
| | | } |
| | | |
| | | private void RegisterDefaultFunctions() |
| | | { |
| | | FunctionRegistry.RegisterFunction("sin", (Func<double, double>)Math.Sin, true, false); |
| | | FunctionRegistry.RegisterFunction("cos", (Func<double, double>)Math.Cos, true, false); |
| | | FunctionRegistry.RegisterFunction("csc", (Func<double, double>)MathUtil.Csc, true, false); |
| | | FunctionRegistry.RegisterFunction("sec", (Func<double, double>)MathUtil.Sec, true, false); |
| | | FunctionRegistry.RegisterFunction("asin", (Func<double, double>)Math.Asin, true, false); |
| | | FunctionRegistry.RegisterFunction("acos", (Func<double, double>)Math.Acos, true, false); |
| | | FunctionRegistry.RegisterFunction("tan", (Func<double, double>)Math.Tan, true, false); |
| | | FunctionRegistry.RegisterFunction("cot", (Func<double, double>)MathUtil.Cot, true, false); |
| | | FunctionRegistry.RegisterFunction("atan", (Func<double, double>)Math.Atan, true, false); |
| | | FunctionRegistry.RegisterFunction("acot", (Func<double, double>)MathUtil.Acot, true, false); |
| | | FunctionRegistry.RegisterFunction("loge", (Func<double, double>)Math.Log, true, false); |
| | | FunctionRegistry.RegisterFunction("log10", (Func<double, double>)Math.Log10, true, false); |
| | | FunctionRegistry.RegisterFunction("logn", (Func<double, double, double>)((a, b) => Math.Log(a, b)), true, false); |
| | | FunctionRegistry.RegisterFunction("sqrt", (Func<double, double>)Math.Sqrt, true, false); |
| | | FunctionRegistry.RegisterFunction("abs", (Func<double, double>)Math.Abs, true, false); |
| | | FunctionRegistry.RegisterFunction("if", (Func<double, double, double, double>)((a, b, c) => (a != 0.0 ? b : c)), true, false); |
| | | FunctionRegistry.RegisterFunction("ifless", (Func<double, double, double, double, double>)((a, b, c, d) => (a < b ? c : d)), true, false); |
| | | FunctionRegistry.RegisterFunction("ifmore", (Func<double, double, double, double, double>)((a, b, c, d) => (a > b ? c : d)), true, false); |
| | | FunctionRegistry.RegisterFunction("ifequal", (Func<double, double, double, double, double>)((a, b, c, d) => (a == b ? c : d)), true, false); |
| | | FunctionRegistry.RegisterFunction("ceiling", (Func<double, double>)Math.Ceiling, true, false); |
| | | FunctionRegistry.RegisterFunction("floor", (Func<double, double>)Math.Floor, true, false); |
| | | FunctionRegistry.RegisterFunction("truncate", (Func<double, double>)Math.Truncate, true, false); |
| | | FunctionRegistry.RegisterFunction("round", (Func<double, double>)Math.Round, true, false); |
| | | |
| | | // Dynamic based arguments Functions |
| | | FunctionRegistry.RegisterFunction("max", (DynamicFunc<double, double>)((a) => a.Max()), true, false); |
| | | FunctionRegistry.RegisterFunction("min", (DynamicFunc<double, double>)((a) => a.Min()), true, false); |
| | | FunctionRegistry.RegisterFunction("avg", (DynamicFunc<double, double>)((a) => a.Average()), true, false); |
| | | FunctionRegistry.RegisterFunction("median", (DynamicFunc<double, double>)((a) => MathExtended.Median(a)), true, false); |
| | | |
| | | // Non Idempotent Functions |
| | | FunctionRegistry.RegisterFunction("random", (Func<double>)random.NextDouble, false, false); |
| | | } |
| | | |
| | | private void RegisterDefaultConstants() |
| | | { |
| | | ConstantRegistry.RegisterConstant("e", Math.E, false); |
| | | ConstantRegistry.RegisterConstant("pi", Math.PI, false); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Build the abstract syntax tree for a given formula. The formula string will |
| | | /// be first tokenized. |
| | | /// </summary> |
| | | /// <param name="formulaText">A string containing the mathematical formula that must be converted |
| | | /// into an abstract syntax tree.</param> |
| | | /// <returns>The abstract syntax tree of the formula.</returns> |
| | | private Operation BuildAbstractSyntaxTree(string formulaText, ConstantRegistry compiledConstants) |
| | | { |
| | | TokenReader tokenReader = new TokenReader(cultureInfo); |
| | | List<Token> tokens = tokenReader.Read(formulaText); |
| | | |
| | | AstBuilder astBuilder = new AstBuilder(FunctionRegistry, caseSensitive, compiledConstants); |
| | | Operation operation = astBuilder.Build(tokens); |
| | | |
| | | if (optimizerEnabled) |
| | | return optimizer.Optimize(operation, this.FunctionRegistry, this.ConstantRegistry); |
| | | else |
| | | return operation; |
| | | } |
| | | |
| | | private Func<IDictionary<string, double>, double> BuildFormula(string formulaText, ConstantRegistry compiledConstants, Operation operation) |
| | | { |
| | | return executionFormulaCache.GetOrAdd(GenerateFormulaCacheKey(formulaText, compiledConstants), v => executor.BuildFormula(operation, this.FunctionRegistry, this.ConstantRegistry)); |
| | | } |
| | | |
| | | private bool IsInFormulaCache(string formulaText, ConstantRegistry compiledConstants, out Func<IDictionary<string, double>, double> function) |
| | | { |
| | | function = null; |
| | | return cacheEnabled && executionFormulaCache.TryGetValue(GenerateFormulaCacheKey(formulaText, compiledConstants), out function); |
| | | } |
| | | |
| | | private string GenerateFormulaCacheKey(string formulaText, ConstantRegistry compiledConstants) |
| | | { |
| | | return (compiledConstants != null && compiledConstants.Any()) ? $"{formulaText}@{String.Join(",", compiledConstants?.Select(x => $"{x.ConstantName}:{x.Value}"))}" : formulaText; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Verify a collection of variables to ensure that all the variable names are valid. |
| | | /// Users are not allowed to overwrite reserved variables or use function names as variables. |
| | | /// If an invalid variable is detected an exception is thrown. |
| | | /// </summary> |
| | | /// <param name="variables">The colletion of variables that must be verified.</param> |
| | | internal void VerifyVariableNames(IDictionary<string, double> variables) |
| | | { |
| | | foreach (string variableName in variables.Keys) |
| | | { |
| | | if(ConstantRegistry.IsConstantName(variableName) && !ConstantRegistry.GetConstantInfo(variableName).IsOverWritable) |
| | | throw new ArgumentException(string.Format("The name \"{0}\" is a reservered variable name that cannot be overwritten.", variableName), "variables"); |
| | | |
| | | if (FunctionRegistry.IsFunctionName(variableName)) |
| | | throw new ArgumentException(string.Format("The name \"{0}\" is a function name. Parameters cannot have this name.", variableName), "variables"); |
| | | } |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/CalculationEngine.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 7605496412e5ed546a6ab8ccba648580 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace |
| | | { |
| | | public enum DataType |
| | | { |
| | | Integer, |
| | | FloatingPoint |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/DataType.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: f30cb87ce5accbe4ebcbc950c4eaae28 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
File was renamed from Main/Core/GameEngine/Common.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 6b68b2e87cfa2fc48aff8e7f40a5c555 |
| | | guid: 9d45a5ae0f6671f4783425dac0689ce4 |
| | | folderAsset: yes |
| | | DefaultImporter: |
| | | externalObjects: {} |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Execution |
| | | { |
| | | public class ConstantInfo |
| | | { |
| | | public ConstantInfo(string constantName, double value, bool isOverWritable) |
| | | { |
| | | this.ConstantName = constantName; |
| | | this.Value = value; |
| | | this.IsOverWritable = isOverWritable; |
| | | } |
| | | |
| | | public string ConstantName { get; private set; } |
| | | |
| | | public double Value { get; private set; } |
| | | |
| | | public bool IsOverWritable { get; set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Execution/ConstantInfo.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 80e7b1aba7b9c2245b2b872f018c07d6 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using Jace.Util; |
| | | |
| | | namespace Jace.Execution |
| | | { |
| | | public class ConstantRegistry : IConstantRegistry |
| | | { |
| | | private readonly bool caseSensitive; |
| | | private readonly Dictionary<string, ConstantInfo> constants; |
| | | |
| | | public ConstantRegistry(bool caseSensitive) |
| | | { |
| | | this.caseSensitive = caseSensitive; |
| | | this.constants = new Dictionary<string, ConstantInfo>(); |
| | | } |
| | | |
| | | public IEnumerator<ConstantInfo> GetEnumerator() |
| | | { |
| | | return constants.Values.GetEnumerator(); |
| | | } |
| | | |
| | | IEnumerator System.Collections.IEnumerable.GetEnumerator() |
| | | { |
| | | return this.GetEnumerator(); |
| | | } |
| | | |
| | | public ConstantInfo GetConstantInfo(string constantName) |
| | | { |
| | | if (string.IsNullOrEmpty(constantName)) |
| | | throw new ArgumentNullException("constantName"); |
| | | |
| | | ConstantInfo constantInfo = null; |
| | | return constants.TryGetValue(ConvertConstantName(constantName), out constantInfo) ? constantInfo : null; |
| | | } |
| | | |
| | | public bool IsConstantName(string constantName) |
| | | { |
| | | if (string.IsNullOrEmpty(constantName)) |
| | | throw new ArgumentNullException("constantName"); |
| | | |
| | | return constants.ContainsKey(ConvertConstantName(constantName)); |
| | | } |
| | | |
| | | public void RegisterConstant(string constantName, double value) |
| | | { |
| | | RegisterConstant(constantName, value, true); |
| | | } |
| | | |
| | | public void RegisterConstant(string constantName, double value, bool isOverWritable) |
| | | { |
| | | if(string.IsNullOrEmpty(constantName)) |
| | | throw new ArgumentNullException("constantName"); |
| | | |
| | | constantName = ConvertConstantName(constantName); |
| | | |
| | | if (constants.ContainsKey(constantName) && !constants[constantName].IsOverWritable) |
| | | { |
| | | string message = string.Format("The constant \"{0}\" cannot be overwriten.", constantName); |
| | | throw new Exception(message); |
| | | } |
| | | |
| | | ConstantInfo constantInfo = new ConstantInfo(constantName, value, isOverWritable); |
| | | |
| | | if (constants.ContainsKey(constantName)) |
| | | constants[constantName] = constantInfo; |
| | | else |
| | | constants.Add(constantName, constantInfo); |
| | | } |
| | | |
| | | private string ConvertConstantName(string constantName) |
| | | { |
| | | return caseSensitive ? constantName : constantName.ToLowerFast(); |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Execution/ConstantRegistry.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 4c5b0410c8fc58445a69f737f244707e |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Linq.Expressions; |
| | | using System.Reflection; |
| | | using System.Reflection.Emit; |
| | | using System.Text; |
| | | using Jace.Operations; |
| | | using Jace.Util; |
| | | |
| | | namespace Jace.Execution |
| | | { |
| | | public class DynamicCompiler : IExecutor |
| | | { |
| | | private string FuncAssemblyQualifiedName; |
| | | private readonly bool caseSensitive; |
| | | |
| | | public DynamicCompiler(): this(false) { } |
| | | public DynamicCompiler(bool caseSensitive) |
| | | { |
| | | this.caseSensitive = caseSensitive; |
| | | // The lower func reside in mscorelib, the higher ones in another assembly. |
| | | // This is an easy cross platform way to to have this AssemblyQualifiedName. |
| | | FuncAssemblyQualifiedName = |
| | | typeof(Func<double, double, double, double, double, double, double, double, double, double>).GetTypeInfo().Assembly.FullName; |
| | | } |
| | | |
| | | public double Execute(Operation operation, IFunctionRegistry functionRegistry, IConstantRegistry constantRegistry) |
| | | { |
| | | return Execute(operation, functionRegistry, constantRegistry, new Dictionary<string, double>()); |
| | | } |
| | | |
| | | public double Execute(Operation operation, IFunctionRegistry functionRegistry, IConstantRegistry constantRegistry, |
| | | IDictionary<string, double> variables) |
| | | { |
| | | return BuildFormula(operation, functionRegistry, constantRegistry)(variables); |
| | | } |
| | | |
| | | public Func<IDictionary<string, double>, double> BuildFormula(Operation operation, |
| | | IFunctionRegistry functionRegistry, IConstantRegistry constantRegistry) |
| | | { |
| | | Func<FormulaContext, double> func = BuildFormulaInternal(operation, functionRegistry); |
| | | return caseSensitive |
| | | ? (Func<IDictionary<string, double>, double>)(variables => |
| | | { |
| | | return func(new FormulaContext(variables, functionRegistry, constantRegistry)); |
| | | }) |
| | | : (Func<IDictionary<string, double>, double>)(variables => |
| | | { |
| | | variables = EngineUtil.ConvertVariableNamesToLowerCase(variables); |
| | | FormulaContext context = new FormulaContext(variables, functionRegistry, constantRegistry); |
| | | return func(context); |
| | | }); |
| | | } |
| | | |
| | | private Func<FormulaContext, double> BuildFormulaInternal(Operation operation, |
| | | IFunctionRegistry functionRegistry) |
| | | { |
| | | ParameterExpression contextParameter = Expression.Parameter(typeof(FormulaContext), "context"); |
| | | |
| | | LabelTarget returnLabel = Expression.Label(typeof(double)); |
| | | |
| | | Expression<Func<FormulaContext, double>> lambda = Expression.Lambda<Func<FormulaContext, double>>( |
| | | GenerateMethodBody(operation, contextParameter, functionRegistry), |
| | | contextParameter |
| | | ); |
| | | return lambda.Compile(); |
| | | } |
| | | |
| | | |
| | | |
| | | private Expression GenerateMethodBody(Operation operation, ParameterExpression contextParameter, |
| | | IFunctionRegistry functionRegistry) |
| | | { |
| | | if (operation == null) |
| | | throw new ArgumentNullException("operation"); |
| | | |
| | | if (operation.GetType() == typeof(IntegerConstant)) |
| | | { |
| | | IntegerConstant constant = (IntegerConstant)operation; |
| | | |
| | | double value = constant.Value; |
| | | return Expression.Constant(value, typeof(double)); |
| | | } |
| | | else if (operation.GetType() == typeof(FloatingPointConstant)) |
| | | { |
| | | FloatingPointConstant constant = (FloatingPointConstant)operation; |
| | | |
| | | return Expression.Constant(constant.Value, typeof(double)); |
| | | } |
| | | else if (operation.GetType() == typeof(Variable)) |
| | | { |
| | | Variable variable = (Variable)operation; |
| | | |
| | | Func<string, FormulaContext, double> getVariableValueOrThrow = PrecompiledMethods.GetVariableValueOrThrow; |
| | | return Expression.Call(null, |
| | | getVariableValueOrThrow.GetMethodInfo(), |
| | | Expression.Constant(variable.Name), |
| | | contextParameter); |
| | | } |
| | | else if (operation.GetType() == typeof(Multiplication)) |
| | | { |
| | | Multiplication multiplication = (Multiplication)operation; |
| | | Expression argument1 = GenerateMethodBody(multiplication.Argument1, contextParameter, functionRegistry); |
| | | Expression argument2 = GenerateMethodBody(multiplication.Argument2, contextParameter, functionRegistry); |
| | | |
| | | return Expression.Multiply(argument1, argument2); |
| | | } |
| | | else if (operation.GetType() == typeof(Addition)) |
| | | { |
| | | Addition addition = (Addition)operation; |
| | | Expression argument1 = GenerateMethodBody(addition.Argument1, contextParameter, functionRegistry); |
| | | Expression argument2 = GenerateMethodBody(addition.Argument2, contextParameter, functionRegistry); |
| | | |
| | | return Expression.Add(argument1, argument2); |
| | | } |
| | | else if (operation.GetType() == typeof(Subtraction)) |
| | | { |
| | | Subtraction addition = (Subtraction)operation; |
| | | Expression argument1 = GenerateMethodBody(addition.Argument1, contextParameter, functionRegistry); |
| | | Expression argument2 = GenerateMethodBody(addition.Argument2, contextParameter, functionRegistry); |
| | | |
| | | return Expression.Subtract(argument1, argument2); |
| | | } |
| | | else if (operation.GetType() == typeof(Division)) |
| | | { |
| | | Division division = (Division)operation; |
| | | Expression dividend = GenerateMethodBody(division.Dividend, contextParameter, functionRegistry); |
| | | Expression divisor = GenerateMethodBody(division.Divisor, contextParameter, functionRegistry); |
| | | |
| | | return Expression.Divide(dividend, divisor); |
| | | } |
| | | else if (operation.GetType() == typeof(Modulo)) |
| | | { |
| | | Modulo modulo = (Modulo)operation; |
| | | Expression dividend = GenerateMethodBody(modulo.Dividend, contextParameter, functionRegistry); |
| | | Expression divisor = GenerateMethodBody(modulo.Divisor, contextParameter, functionRegistry); |
| | | |
| | | return Expression.Modulo(dividend, divisor); |
| | | } |
| | | else if (operation.GetType() == typeof(Exponentiation)) |
| | | { |
| | | Exponentiation exponentation = (Exponentiation)operation; |
| | | Expression @base = GenerateMethodBody(exponentation.Base, contextParameter, functionRegistry); |
| | | Expression exponent = GenerateMethodBody(exponentation.Exponent, contextParameter, functionRegistry); |
| | | |
| | | return Expression.Call(null, typeof(Math).GetRuntimeMethod("Pow", new Type[] { typeof(double), typeof(double) }), @base, exponent); |
| | | } |
| | | else if (operation.GetType() == typeof(UnaryMinus)) |
| | | { |
| | | UnaryMinus unaryMinus = (UnaryMinus)operation; |
| | | Expression argument = GenerateMethodBody(unaryMinus.Argument, contextParameter, functionRegistry); |
| | | return Expression.Negate(argument); |
| | | } |
| | | else if (operation.GetType() == typeof(And)) |
| | | { |
| | | And and = (And)operation; |
| | | Expression argument1 = Expression.NotEqual(GenerateMethodBody(and.Argument1, contextParameter, functionRegistry), Expression.Constant(0.0)); |
| | | Expression argument2 = Expression.NotEqual(GenerateMethodBody(and.Argument2, contextParameter, functionRegistry), Expression.Constant(0.0)); |
| | | |
| | | return Expression.Condition(Expression.And(argument1, argument2), |
| | | Expression.Constant(1.0), |
| | | Expression.Constant(0.0)); |
| | | } |
| | | else if (operation.GetType() == typeof(Or)) |
| | | { |
| | | Or and = (Or)operation; |
| | | Expression argument1 = Expression.NotEqual(GenerateMethodBody(and.Argument1, contextParameter, functionRegistry), Expression.Constant(0.0)); |
| | | Expression argument2 = Expression.NotEqual(GenerateMethodBody(and.Argument2, contextParameter, functionRegistry), Expression.Constant(0.0)); |
| | | |
| | | return Expression.Condition(Expression.Or(argument1, argument2), |
| | | Expression.Constant(1.0), |
| | | Expression.Constant(0.0)); |
| | | } |
| | | else if (operation.GetType() == typeof(LessThan)) |
| | | { |
| | | LessThan lessThan = (LessThan)operation; |
| | | Expression argument1 = GenerateMethodBody(lessThan.Argument1, contextParameter, functionRegistry); |
| | | Expression argument2 = GenerateMethodBody(lessThan.Argument2, contextParameter, functionRegistry); |
| | | |
| | | return Expression.Condition(Expression.LessThan(argument1, argument2), |
| | | Expression.Constant(1.0), |
| | | Expression.Constant(0.0)); |
| | | } |
| | | else if (operation.GetType() == typeof(LessOrEqualThan)) |
| | | { |
| | | LessOrEqualThan lessOrEqualThan = (LessOrEqualThan)operation; |
| | | Expression argument1 = GenerateMethodBody(lessOrEqualThan.Argument1, contextParameter, functionRegistry); |
| | | Expression argument2 = GenerateMethodBody(lessOrEqualThan.Argument2, contextParameter, functionRegistry); |
| | | |
| | | return Expression.Condition(Expression.LessThanOrEqual(argument1, argument2), |
| | | Expression.Constant(1.0), |
| | | Expression.Constant(0.0)); |
| | | } |
| | | else if (operation.GetType() == typeof(GreaterThan)) |
| | | { |
| | | GreaterThan greaterThan = (GreaterThan)operation; |
| | | Expression argument1 = GenerateMethodBody(greaterThan.Argument1, contextParameter, functionRegistry); |
| | | Expression argument2 = GenerateMethodBody(greaterThan.Argument2, contextParameter, functionRegistry); |
| | | |
| | | return Expression.Condition(Expression.GreaterThan(argument1, argument2), |
| | | Expression.Constant(1.0), |
| | | Expression.Constant(0.0)); |
| | | } |
| | | else if (operation.GetType() == typeof(GreaterOrEqualThan)) |
| | | { |
| | | GreaterOrEqualThan greaterOrEqualThan = (GreaterOrEqualThan)operation; |
| | | Expression argument1 = GenerateMethodBody(greaterOrEqualThan.Argument1, contextParameter, functionRegistry); |
| | | Expression argument2 = GenerateMethodBody(greaterOrEqualThan.Argument2, contextParameter, functionRegistry); |
| | | |
| | | return Expression.Condition(Expression.GreaterThanOrEqual(argument1, argument2), |
| | | Expression.Constant(1.0), |
| | | Expression.Constant(0.0)); |
| | | } |
| | | else if (operation.GetType() == typeof(Equal)) |
| | | { |
| | | Equal equal = (Equal)operation; |
| | | Expression argument1 = GenerateMethodBody(equal.Argument1, contextParameter, functionRegistry); |
| | | Expression argument2 = GenerateMethodBody(equal.Argument2, contextParameter, functionRegistry); |
| | | |
| | | return Expression.Condition(Expression.Equal(argument1, argument2), |
| | | Expression.Constant(1.0), |
| | | Expression.Constant(0.0)); |
| | | } |
| | | else if (operation.GetType() == typeof(NotEqual)) |
| | | { |
| | | NotEqual notEqual = (NotEqual)operation; |
| | | Expression argument1 = GenerateMethodBody(notEqual.Argument1, contextParameter, functionRegistry); |
| | | Expression argument2 = GenerateMethodBody(notEqual.Argument2, contextParameter, functionRegistry); |
| | | |
| | | return Expression.Condition(Expression.NotEqual(argument1, argument2), |
| | | Expression.Constant(1.0), |
| | | Expression.Constant(0.0)); |
| | | } |
| | | else if (operation.GetType() == typeof(Function)) |
| | | { |
| | | Function function = (Function)operation; |
| | | |
| | | FunctionInfo functionInfo = functionRegistry.GetFunctionInfo(function.FunctionName); |
| | | Type funcType; |
| | | Type[] parameterTypes; |
| | | Expression[] arguments; |
| | | |
| | | if (functionInfo.IsDynamicFunc) |
| | | { |
| | | funcType = typeof(DynamicFunc<double, double>); |
| | | parameterTypes = new Type[] { typeof(double[]) }; |
| | | |
| | | |
| | | Expression[] arrayArguments = new Expression[function.Arguments.Count]; |
| | | for (int i = 0; i < function.Arguments.Count; i++) |
| | | arrayArguments[i] = GenerateMethodBody(function.Arguments[i], contextParameter, functionRegistry); |
| | | |
| | | arguments = new Expression[1]; |
| | | arguments[0] = NewArrayExpression.NewArrayInit(typeof(double), arrayArguments); |
| | | } |
| | | else |
| | | { |
| | | funcType = GetFuncType(functionInfo.NumberOfParameters); |
| | | parameterTypes = (from i in Enumerable.Range(0, functionInfo.NumberOfParameters) |
| | | select typeof(double)).ToArray(); |
| | | |
| | | arguments = new Expression[functionInfo.NumberOfParameters]; |
| | | for (int i = 0; i < functionInfo.NumberOfParameters; i++) |
| | | arguments[i] = GenerateMethodBody(function.Arguments[i], contextParameter, functionRegistry); |
| | | } |
| | | |
| | | Expression getFunctionRegistry = Expression.Property(contextParameter, "FunctionRegistry"); |
| | | |
| | | ParameterExpression functionInfoVariable = Expression.Variable(typeof(FunctionInfo)); |
| | | |
| | | Expression funcInstance; |
| | | if (!functionInfo.IsOverWritable) |
| | | { |
| | | funcInstance = Expression.Convert( |
| | | Expression.Property( |
| | | Expression.Call( |
| | | getFunctionRegistry, |
| | | typeof(IFunctionRegistry).GetRuntimeMethod("GetFunctionInfo", new Type[] { typeof(string) }), |
| | | Expression.Constant(function.FunctionName)), |
| | | "Function"), |
| | | funcType); |
| | | } |
| | | else |
| | | funcInstance = Expression.Constant(functionInfo.Function, funcType); |
| | | |
| | | return Expression.Call( |
| | | funcInstance, |
| | | funcType.GetRuntimeMethod("Invoke", parameterTypes), |
| | | arguments); |
| | | } |
| | | else |
| | | { |
| | | throw new ArgumentException(string.Format("Unsupported operation \"{0}\".", operation.GetType().FullName), "operation"); |
| | | } |
| | | } |
| | | |
| | | private Type GetFuncType(int numberOfParameters) |
| | | { |
| | | string funcTypeName; |
| | | if (numberOfParameters < 9) |
| | | funcTypeName = string.Format("System.Func`{0}", numberOfParameters + 1); |
| | | else |
| | | funcTypeName = string.Format("System.Func`{0}, {1}", numberOfParameters + 1, FuncAssemblyQualifiedName); |
| | | Type funcType = Type.GetType(funcTypeName); |
| | | |
| | | Type[] typeArguments = new Type[numberOfParameters + 1]; |
| | | for (int i = 0; i < typeArguments.Length; i++) |
| | | typeArguments[i] = typeof(double); |
| | | |
| | | return funcType.MakeGenericType(typeArguments); |
| | | } |
| | | |
| | | private static class PrecompiledMethods |
| | | { |
| | | public static double GetVariableValueOrThrow(string variableName, FormulaContext context) |
| | | { |
| | | if (context.Variables.TryGetValue(variableName, out double result)) |
| | | return result; |
| | | else if (context.ConstantRegistry.IsConstantName(variableName)) |
| | | return context.ConstantRegistry.GetConstantInfo(variableName).Value; |
| | | else |
| | | throw new VariableNotDefinedException($"The variable \"{variableName}\" used is not defined."); |
| | | } |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Execution/DynamicCompiler.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: c058c0ded31899643b05723eafcafc40 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Execution |
| | | { |
| | | public enum ExecutionMode |
| | | { |
| | | Interpreted, |
| | | Compiled |
| | | } |
| | | } |
File was renamed from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 0d9522fc6bc25a644b4074177b045fc6 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Reflection; |
| | | using System.Reflection.Emit; |
| | | using System.Text; |
| | | using Jace.Operations; |
| | | using Jace.Util; |
| | | |
| | | namespace Jace.Execution |
| | | { |
| | | public class FormulaBuilder |
| | | { |
| | | private readonly CalculationEngine engine; |
| | | |
| | | private string formulaText; |
| | | private bool caseSensitive; |
| | | private DataType? resultDataType; |
| | | private List<ParameterInfo> parameters; |
| | | private IDictionary<string, double> constants; |
| | | |
| | | /// <summary> |
| | | /// Creates a new instance of the FormulaBuilder class. |
| | | /// </summary> |
| | | /// <param name="formulaText"> |
| | | /// A calculation engine instance that can be used for interpreting and executing |
| | | /// the formula. |
| | | /// </param> |
| | | internal FormulaBuilder(string formulaText, bool caseSensitive, CalculationEngine engine) |
| | | { |
| | | this.parameters = new List<ParameterInfo>(); |
| | | this.constants = new Dictionary<string, double>(); |
| | | this.formulaText = formulaText; |
| | | this.engine = engine; |
| | | this.caseSensitive = caseSensitive; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Add a new parameter to the formula being constructed. Parameters are |
| | | /// added in the order of which they are defined. |
| | | /// </summary> |
| | | /// <param name="name">The name of the parameter.</param> |
| | | /// <param name="dataType">The date type of the parameter.</param> |
| | | /// <returns>The <see cref="FormulaBuilder"/> instance.</returns> |
| | | public FormulaBuilder Parameter(string name, DataType dataType) |
| | | { |
| | | if (string.IsNullOrEmpty(name)) |
| | | throw new ArgumentNullException("name"); |
| | | |
| | | if (engine.FunctionRegistry.IsFunctionName(name)) |
| | | throw new ArgumentException(string.Format("The name \"{0}\" is a function name. Parameters cannot have this name.", name), "name"); |
| | | |
| | | if (parameters.Any(p => p.Name == name)) |
| | | throw new ArgumentException(string.Format("A parameter with the name \"{0}\" was already defined.", name), "name"); |
| | | |
| | | parameters.Add(new ParameterInfo() {Name = name, DataType = dataType}); |
| | | return this; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Add a new constant to the formula being constructed. |
| | | /// </summary> |
| | | /// <param name="name">The name of the constant.</param> |
| | | /// <param name="constantValue">The value of the constant. Variables for which a constant value is defined will be replaced at pre-compilation time.</param> |
| | | /// <returns>The <see cref="FormulaBuilder"/> instance.</returns> |
| | | public FormulaBuilder Constant(string name, int constantValue) |
| | | { |
| | | return Constant(name, (double)constantValue); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Add a new constant to the formula being constructed. The |
| | | /// </summary> |
| | | /// <param name="name">The name of the constant.</param> |
| | | /// <param name="constantValue">The value of the constant.</param> |
| | | /// <returns>The <see cref="FormulaBuilder"/> instance.</returns> |
| | | public FormulaBuilder Constant(string name, double constantValue) |
| | | { |
| | | if (string.IsNullOrEmpty(name)) |
| | | throw new ArgumentNullException("name"); |
| | | |
| | | if (constants.Any(p => p.Key == name)) |
| | | throw new ArgumentException(string.Format("A constant with the name \"{0}\" was already defined.", name), "name"); |
| | | |
| | | constants[name] = constantValue; |
| | | return this; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Define the result data type for the formula. |
| | | /// </summary> |
| | | /// <param name="dataType">The result data type for the formula.</param> |
| | | /// <returns>The <see cref="FormulaBuilder"/> instance.</returns> |
| | | public FormulaBuilder Result(DataType dataType) |
| | | { |
| | | if (resultDataType.HasValue) |
| | | throw new InvalidOperationException("The result can only be defined once for a given formula."); |
| | | |
| | | resultDataType = dataType; |
| | | return this; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Build the formula defined. This will create a func delegate matching with the parameters |
| | | /// and the return type specified. |
| | | /// </summary> |
| | | /// <returns>The func delegate for the defined formula.</returns> |
| | | public Delegate Build() |
| | | { |
| | | if (!resultDataType.HasValue) |
| | | throw new Exception("Please define a result data type for the formula."); |
| | | |
| | | Func<IDictionary<string, double>, double> formula = engine.Build(formulaText, constants); |
| | | |
| | | FuncAdapter adapter = new FuncAdapter(); |
| | | return adapter.Wrap(parameters, variables => { |
| | | |
| | | if(!caseSensitive) |
| | | variables = EngineUtil.ConvertVariableNamesToLowerCase(variables); |
| | | |
| | | engine.VerifyVariableNames(variables); |
| | | |
| | | // Add the reserved variables to the dictionary |
| | | foreach (ConstantInfo constant in engine.ConstantRegistry) |
| | | variables.Add(constant.ConstantName, constant.Value); |
| | | |
| | | return formula(variables); |
| | | }); |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Execution/FormulaBuilder.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: b422f2fc8278c544db048c826ec43f40 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Execution |
| | | { |
| | | public class FunctionInfo |
| | | { |
| | | public FunctionInfo(string functionName, int numberOfParameters, bool isIdempotent, bool isOverWritable, bool isDynamicFunc, Delegate function) |
| | | { |
| | | this.FunctionName = functionName; |
| | | this.NumberOfParameters = numberOfParameters; |
| | | this.IsIdempotent = isIdempotent; |
| | | this.IsOverWritable = isOverWritable; |
| | | this.IsDynamicFunc = isDynamicFunc; |
| | | this.Function = function; |
| | | } |
| | | |
| | | public string FunctionName { get; private set; } |
| | | |
| | | public int NumberOfParameters { get; private set; } |
| | | |
| | | public bool IsOverWritable { get; set; } |
| | | |
| | | public bool IsIdempotent { get; set; } |
| | | |
| | | public bool IsDynamicFunc { get; private set; } |
| | | |
| | | public Delegate Function { get; private set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Execution/FunctionInfo.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 68afcf59c23204e4f83b55a9555fa566 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Reflection; |
| | | using System.Collections; |
| | | using Jace.Util; |
| | | |
| | | namespace Jace.Execution |
| | | { |
| | | public class FunctionRegistry : IFunctionRegistry |
| | | { |
| | | private const string DynamicFuncName = "Jace.DynamicFunc"; |
| | | |
| | | private readonly bool caseSensitive; |
| | | private readonly Dictionary<string, FunctionInfo> functions; |
| | | |
| | | public FunctionRegistry(bool caseSensitive) |
| | | { |
| | | this.caseSensitive = caseSensitive; |
| | | this.functions = new Dictionary<string, FunctionInfo>(); |
| | | } |
| | | |
| | | public IEnumerator<FunctionInfo> GetEnumerator() |
| | | { |
| | | return functions.Values.GetEnumerator(); |
| | | } |
| | | |
| | | IEnumerator IEnumerable.GetEnumerator() |
| | | { |
| | | return this.GetEnumerator(); |
| | | } |
| | | |
| | | public FunctionInfo GetFunctionInfo(string functionName) |
| | | { |
| | | if (string.IsNullOrEmpty(functionName)) |
| | | throw new ArgumentNullException("functionName"); |
| | | |
| | | FunctionInfo functionInfo = null; |
| | | return functions.TryGetValue(ConvertFunctionName(functionName), out functionInfo) ? functionInfo : null; |
| | | } |
| | | |
| | | public void RegisterFunction(string functionName, Delegate function) |
| | | { |
| | | RegisterFunction(functionName, function, true, true); |
| | | } |
| | | |
| | | public void RegisterFunction(string functionName, Delegate function, bool isIdempotent, bool isOverWritable) |
| | | { |
| | | if (string.IsNullOrEmpty(functionName)) |
| | | throw new ArgumentNullException("functionName"); |
| | | |
| | | if (function == null) |
| | | throw new ArgumentNullException("function"); |
| | | |
| | | Type funcType = function.GetType(); |
| | | bool isDynamicFunc = false; |
| | | int numberOfParameters = -1; |
| | | |
| | | if (funcType.FullName.StartsWith("System.Func")) |
| | | { |
| | | foreach (Type genericArgument in funcType.GenericTypeArguments) |
| | | if (genericArgument != typeof(double)) |
| | | throw new ArgumentException("Only doubles are supported as function arguments.", "function"); |
| | | |
| | | numberOfParameters = function |
| | | .GetMethodInfo() |
| | | .GetParameters() |
| | | .Count(p => p.ParameterType == typeof(double)); |
| | | } |
| | | else if (funcType.FullName.StartsWith(DynamicFuncName)) |
| | | { |
| | | isDynamicFunc = true; |
| | | } |
| | | else |
| | | throw new ArgumentException("Only System.Func and " + DynamicFuncName + " delegates are permitted.", "function"); |
| | | |
| | | functionName = ConvertFunctionName(functionName); |
| | | |
| | | if (functions.ContainsKey(functionName) && !functions[functionName].IsOverWritable) |
| | | { |
| | | string message = string.Format("The function \"{0}\" cannot be overwriten.", functionName); |
| | | throw new Exception(message); |
| | | } |
| | | |
| | | if (functions.ContainsKey(functionName) && functions[functionName].NumberOfParameters != numberOfParameters) |
| | | { |
| | | string message = string.Format("The number of parameters cannot be changed when overwriting a method."); |
| | | throw new Exception(message); |
| | | } |
| | | |
| | | if (functions.ContainsKey(functionName) && functions[functionName].IsDynamicFunc != isDynamicFunc) |
| | | { |
| | | string message = string.Format("A Func can only be overwritten by another Func and a DynamicFunc can only be overwritten by another DynamicFunc."); |
| | | throw new Exception(message); |
| | | } |
| | | |
| | | FunctionInfo functionInfo = new FunctionInfo(functionName, numberOfParameters, isIdempotent, isOverWritable, isDynamicFunc, function); |
| | | |
| | | if (functions.ContainsKey(functionName)) |
| | | functions[functionName] = functionInfo; |
| | | else |
| | | functions.Add(functionName, functionInfo); |
| | | } |
| | | |
| | | public bool IsFunctionName(string functionName) |
| | | { |
| | | if (string.IsNullOrEmpty(functionName)) |
| | | throw new ArgumentNullException("functionName"); |
| | | |
| | | return functions.ContainsKey(ConvertFunctionName(functionName)); |
| | | } |
| | | |
| | | private string ConvertFunctionName(string functionName) |
| | | { |
| | | return caseSensitive ? functionName : functionName.ToLowerFast(); |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Execution/FunctionRegistry.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: a23e9d8bb99397f4b932d1802e5e1a30 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Execution |
| | | { |
| | | public interface IConstantRegistry : IEnumerable<ConstantInfo> |
| | | { |
| | | ConstantInfo GetConstantInfo(string constantName); |
| | | bool IsConstantName(string constantName); |
| | | void RegisterConstant(string constantName, double value); |
| | | void RegisterConstant(string constantName, double value, bool isOverWritable); |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Execution/IConstantRegistry.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: ac1d9141e70689a4ea802b6b9d653707 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using Jace.Operations; |
| | | |
| | | namespace Jace.Execution |
| | | { |
| | | public interface IExecutor |
| | | { |
| | | double Execute(Operation operation, IFunctionRegistry functionRegistry, IConstantRegistry constantRegistry); |
| | | double Execute(Operation operation, IFunctionRegistry functionRegistry, IConstantRegistry constantRegistry, IDictionary<string, double> variables); |
| | | |
| | | Func<IDictionary<string, double>, double> BuildFormula(Operation operation, IFunctionRegistry functionRegistry, IConstantRegistry constantRegistry); |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Execution/IExecutor.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 5cc438b6f6efc8143b63e3107ce1eb9c |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | |
| | | namespace Jace.Execution |
| | | { |
| | | public interface IFunctionRegistry : IEnumerable<FunctionInfo> |
| | | { |
| | | FunctionInfo GetFunctionInfo(string functionName); |
| | | bool IsFunctionName(string functionName); |
| | | void RegisterFunction(string functionName, Delegate function); |
| | | void RegisterFunction(string functionName, Delegate function, bool isIdempotent, bool isOverWritable); |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Execution/IFunctionRegistry.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 5c0e119822c96154a90ac4a9e37de0d9 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Reflection; |
| | | using System.Text; |
| | | using Jace.Operations; |
| | | using Jace.Util; |
| | | |
| | | namespace Jace.Execution |
| | | { |
| | | public class Interpreter : IExecutor |
| | | { |
| | | private readonly bool caseSensitive; |
| | | |
| | | public Interpreter(): this(false) { } |
| | | |
| | | public Interpreter(bool caseSensitive) |
| | | { |
| | | this.caseSensitive = caseSensitive; |
| | | } |
| | | public Func<IDictionary<string, double>, double> BuildFormula(Operation operation, |
| | | IFunctionRegistry functionRegistry, |
| | | IConstantRegistry constantRegistry) |
| | | { |
| | | return caseSensitive |
| | | ? (Func<IDictionary<string, double>, double>)(variables => |
| | | { |
| | | return Execute(operation, functionRegistry, constantRegistry, variables); |
| | | }) |
| | | : (Func<IDictionary<string, double>, double>)(variables => |
| | | { |
| | | variables = EngineUtil.ConvertVariableNamesToLowerCase(variables); |
| | | return Execute(operation, functionRegistry, constantRegistry, variables); |
| | | }); |
| | | } |
| | | |
| | | public double Execute(Operation operation, IFunctionRegistry functionRegistry, IConstantRegistry constantRegistry) |
| | | { |
| | | return Execute(operation, functionRegistry, constantRegistry, new Dictionary<string, double>()); |
| | | } |
| | | |
| | | public double Execute(Operation operation, |
| | | IFunctionRegistry functionRegistry, |
| | | IConstantRegistry constantRegistry, |
| | | IDictionary<string, double> variables) |
| | | { |
| | | if (operation == null) |
| | | throw new ArgumentNullException("operation"); |
| | | |
| | | if (operation.GetType() == typeof(IntegerConstant)) |
| | | { |
| | | IntegerConstant constant = (IntegerConstant)operation; |
| | | return constant.Value; |
| | | } |
| | | else if (operation.GetType() == typeof(FloatingPointConstant)) |
| | | { |
| | | FloatingPointConstant constant = (FloatingPointConstant)operation; |
| | | return constant.Value; |
| | | } |
| | | else if (operation.GetType() == typeof(Variable)) |
| | | { |
| | | Variable variable = (Variable)operation; |
| | | |
| | | double value; |
| | | bool variableFound = variables.TryGetValue(variable.Name, out value); |
| | | |
| | | if (variableFound) |
| | | return value; |
| | | else |
| | | throw new VariableNotDefinedException(string.Format("The variable \"{0}\" used is not defined.", variable.Name)); |
| | | } |
| | | else if (operation.GetType() == typeof(Multiplication)) |
| | | { |
| | | Multiplication multiplication = (Multiplication)operation; |
| | | return Execute(multiplication.Argument1, functionRegistry, constantRegistry, variables) * Execute(multiplication.Argument2, functionRegistry, constantRegistry, variables); |
| | | } |
| | | else if (operation.GetType() == typeof(Addition)) |
| | | { |
| | | Addition addition = (Addition)operation; |
| | | return Execute(addition.Argument1, functionRegistry, constantRegistry, variables) + Execute(addition.Argument2, functionRegistry, constantRegistry, variables); |
| | | } |
| | | else if (operation.GetType() == typeof(Subtraction)) |
| | | { |
| | | Subtraction addition = (Subtraction)operation; |
| | | return Execute(addition.Argument1, functionRegistry, constantRegistry, variables) - Execute(addition.Argument2, functionRegistry, constantRegistry, variables); |
| | | } |
| | | else if (operation.GetType() == typeof(Division)) |
| | | { |
| | | Division division = (Division)operation; |
| | | return Execute(division.Dividend, functionRegistry, constantRegistry, variables) / Execute(division.Divisor, functionRegistry, constantRegistry, variables); |
| | | } |
| | | else if (operation.GetType() == typeof(Modulo)) |
| | | { |
| | | Modulo division = (Modulo)operation; |
| | | return Execute(division.Dividend, functionRegistry, constantRegistry, variables) % Execute(division.Divisor, functionRegistry, constantRegistry, variables); |
| | | } |
| | | else if (operation.GetType() == typeof(Exponentiation)) |
| | | { |
| | | Exponentiation exponentiation = (Exponentiation)operation; |
| | | return Math.Pow(Execute(exponentiation.Base, functionRegistry, constantRegistry, variables), Execute(exponentiation.Exponent, functionRegistry, constantRegistry, variables)); |
| | | } |
| | | else if (operation.GetType() == typeof(UnaryMinus)) |
| | | { |
| | | UnaryMinus unaryMinus = (UnaryMinus)operation; |
| | | return -Execute(unaryMinus.Argument, functionRegistry, constantRegistry, variables); |
| | | } |
| | | else if (operation.GetType() == typeof(And)) |
| | | { |
| | | And and = (And)operation; |
| | | var operation1 = Execute(and.Argument1, functionRegistry, constantRegistry, variables) != 0; |
| | | var operation2 = Execute(and.Argument2, functionRegistry, constantRegistry, variables) != 0; |
| | | |
| | | return (operation1 && operation2) ? 1.0 : 0.0; |
| | | } |
| | | else if (operation.GetType() == typeof(Or)) |
| | | { |
| | | Or or = (Or)operation; |
| | | var operation1 = Execute(or.Argument1, functionRegistry, constantRegistry, variables) != 0; |
| | | var operation2 = Execute(or.Argument2, functionRegistry, constantRegistry, variables) != 0; |
| | | |
| | | return (operation1 || operation2) ? 1.0 : 0.0; |
| | | } |
| | | else if(operation.GetType() == typeof(LessThan)) |
| | | { |
| | | LessThan lessThan = (LessThan)operation; |
| | | return (Execute(lessThan.Argument1, functionRegistry, constantRegistry, variables) < Execute(lessThan.Argument2, functionRegistry, constantRegistry, variables)) ? 1.0 : 0.0; |
| | | } |
| | | else if (operation.GetType() == typeof(LessOrEqualThan)) |
| | | { |
| | | LessOrEqualThan lessOrEqualThan = (LessOrEqualThan)operation; |
| | | return (Execute(lessOrEqualThan.Argument1, functionRegistry, constantRegistry, variables) <= Execute(lessOrEqualThan.Argument2, functionRegistry, constantRegistry, variables)) ? 1.0 : 0.0; |
| | | } |
| | | else if (operation.GetType() == typeof(GreaterThan)) |
| | | { |
| | | GreaterThan greaterThan = (GreaterThan)operation; |
| | | return (Execute(greaterThan.Argument1, functionRegistry, constantRegistry, variables) > Execute(greaterThan.Argument2, functionRegistry, constantRegistry, variables)) ? 1.0 : 0.0; |
| | | } |
| | | else if (operation.GetType() == typeof(GreaterOrEqualThan)) |
| | | { |
| | | GreaterOrEqualThan greaterOrEqualThan = (GreaterOrEqualThan)operation; |
| | | return (Execute(greaterOrEqualThan.Argument1, functionRegistry, constantRegistry, variables) >= Execute(greaterOrEqualThan.Argument2, functionRegistry, constantRegistry, variables)) ? 1.0 : 0.0; |
| | | } |
| | | else if (operation.GetType() == typeof(Equal)) |
| | | { |
| | | Equal equal = (Equal)operation; |
| | | return (Execute(equal.Argument1, functionRegistry, constantRegistry, variables) == Execute(equal.Argument2, functionRegistry, constantRegistry, variables)) ? 1.0 : 0.0; |
| | | } |
| | | else if (operation.GetType() == typeof(NotEqual)) |
| | | { |
| | | NotEqual notEqual = (NotEqual)operation; |
| | | return (Execute(notEqual.Argument1, functionRegistry, constantRegistry, variables) != Execute(notEqual.Argument2, functionRegistry, constantRegistry, variables)) ? 1.0 : 0.0; |
| | | } |
| | | else if (operation.GetType() == typeof(Function)) |
| | | { |
| | | Function function = (Function)operation; |
| | | |
| | | FunctionInfo functionInfo = functionRegistry.GetFunctionInfo(function.FunctionName); |
| | | |
| | | double[] arguments = new double[functionInfo.IsDynamicFunc ? function.Arguments.Count : functionInfo.NumberOfParameters]; |
| | | for (int i = 0; i < arguments.Length; i++) |
| | | arguments[i] = Execute(function.Arguments[i], functionRegistry, constantRegistry, variables); |
| | | |
| | | return Invoke(functionInfo.Function, arguments); |
| | | } |
| | | else |
| | | { |
| | | throw new ArgumentException(string.Format("Unsupported operation \"{0}\".", operation.GetType().FullName), "operation"); |
| | | } |
| | | } |
| | | |
| | | private double Invoke(Delegate function, double[] arguments) |
| | | { |
| | | // DynamicInvoke is slow, so we first try to convert it to a Func |
| | | if (function is Func<double>) |
| | | { |
| | | return ((Func<double>)function).Invoke(); |
| | | } |
| | | else if (function is Func<double, double>) |
| | | { |
| | | return ((Func<double, double>)function).Invoke(arguments[0]); |
| | | } |
| | | else if (function is Func<double, double, double>) |
| | | { |
| | | return ((Func<double, double, double>)function).Invoke(arguments[0], arguments[1]); |
| | | } |
| | | else if (function is Func<double, double, double, double>) |
| | | { |
| | | return ((Func<double, double, double, double>)function).Invoke(arguments[0], arguments[1], arguments[2]); |
| | | } |
| | | else if (function is Func<double, double, double, double, double>) |
| | | { |
| | | return ((Func<double, double, double, double, double>)function).Invoke(arguments[0], arguments[1], arguments[2], arguments[3]); |
| | | } |
| | | else if (function is Func<double, double, double, double, double, double>) |
| | | { |
| | | return ((Func<double, double, double, double, double, double>)function).Invoke(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]); |
| | | } |
| | | else if (function is Func<double, double, double, double, double, double, double>) |
| | | { |
| | | return ((Func<double, double, double, double, double, double, double>)function).Invoke(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]); |
| | | } |
| | | else if (function is Func<double, double, double, double, double, double, double, double>) |
| | | { |
| | | return ((Func<double, double, double, double, double, double, double, double>)function).Invoke(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6]); |
| | | } |
| | | else if (function is Func<double, double, double, double, double, double, double, double, double>) |
| | | { |
| | | return ((Func<double, double, double, double, double, double, double, double, double>)function).Invoke(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7]); |
| | | } |
| | | else if (function is Func<double, double, double, double, double, double, double, double, double, double>) |
| | | { |
| | | return ((Func<double, double, double, double, double, double, double, double, double, double>)function).Invoke(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8]); |
| | | } |
| | | else if (function is Func<double, double, double, double, double, double, double, double, double, double, double>) |
| | | { |
| | | return ((Func<double, double, double, double, double, double, double, double, double, double, double>)function).Invoke(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], arguments[9]); |
| | | } |
| | | else if (function is Func<double, double, double, double, double, double, double, double, double, double, double, double>) |
| | | { |
| | | return ((Func<double, double, double, double, double, double, double, double, double, double, double, double>)function).Invoke(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], arguments[9], arguments[10]); |
| | | } |
| | | else if (function is Func<double, double, double, double, double, double, double, double, double, double, double, double, double>) |
| | | { |
| | | return ((Func<double, double, double, double, double, double, double, double, double, double, double, double, double>)function).Invoke(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], arguments[9], arguments[10], arguments[11]); |
| | | } |
| | | else if (function is Func<double, double, double, double, double, double, double, double, double, double, double, double, double, double>) |
| | | { |
| | | return ((Func<double, double, double, double, double, double, double, double, double, double, double, double, double, double>)function).Invoke(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], arguments[9], arguments[10], arguments[11], arguments[12]); |
| | | } |
| | | else if (function is Func<double, double, double, double, double, double, double, double, double, double, double, double, double, double, double>) |
| | | { |
| | | return ((Func<double, double, double, double, double, double, double, double, double, double, double, double, double, double, double>)function).Invoke(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], arguments[9], arguments[10], arguments[11], arguments[12], arguments[13]); |
| | | } |
| | | else if (function is Func<double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double>) |
| | | { |
| | | return ((Func<double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double>)function).Invoke(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], arguments[9], arguments[10], arguments[11], arguments[12], arguments[13], arguments[14]); |
| | | } |
| | | else if (function is Func<double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double>) |
| | | { |
| | | return ((Func<double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double>)function).Invoke(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], arguments[9], arguments[10], arguments[11], arguments[12], arguments[13], arguments[14], arguments[15]); |
| | | } |
| | | else if (function is DynamicFunc<double, double>) |
| | | { |
| | | return ((DynamicFunc<double, double>)function).Invoke(arguments); |
| | | } |
| | | else |
| | | { |
| | | return (double)function.DynamicInvoke((from s in arguments select (object)s).ToArray()); |
| | | } |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Execution/Interpreter.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 880be476462899f4aa9a1e05d9b1e50f |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using Jace.Operations; |
| | | |
| | | namespace Jace.Execution |
| | | { |
| | | public struct ParameterInfo |
| | | { |
| | | public string Name; |
| | | public DataType DataType; |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Execution/ParameterInfo.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: f118a37bdba42b8459abfd0f2cc2179b |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using Jace.Execution; |
| | | |
| | | namespace Jace |
| | | { |
| | | public class FormulaContext |
| | | { |
| | | public FormulaContext(IDictionary<string, double> variables, |
| | | IFunctionRegistry functionRegistry, |
| | | IConstantRegistry constantRegistry) |
| | | { |
| | | this.Variables = variables; |
| | | this.FunctionRegistry = functionRegistry; |
| | | this.ConstantRegistry = constantRegistry; |
| | | } |
| | | |
| | | public IDictionary<string, double> Variables { get; private set; } |
| | | |
| | | public IFunctionRegistry FunctionRegistry { get; private set; } |
| | | public IConstantRegistry ConstantRegistry { get; private set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/FormulaContext.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 766328a00fcb8a545bd00380387bbc50 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using Jace.Execution; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Globalization; |
| | | using System.Text; |
| | | |
| | | namespace Jace |
| | | { |
| | | public class JaceOptions |
| | | { |
| | | internal const int DefaultCacheMaximumSize = 500; |
| | | internal const int DefaultCacheReductionSize = 50; |
| | | |
| | | public JaceOptions() |
| | | { |
| | | CultureInfo = CultureInfo.CurrentCulture; |
| | | ExecutionMode = ExecutionMode.Compiled; |
| | | CacheEnabled = true; |
| | | OptimizerEnabled = true; |
| | | CaseSensitive = false; |
| | | DefaultFunctions = true; |
| | | DefaultConstants = true; |
| | | CacheMaximumSize = DefaultCacheMaximumSize; |
| | | CacheReductionSize = DefaultCacheReductionSize; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// The <see cref="CultureInfo"/> required for correctly reading floating poin numbers. |
| | | /// </summary> |
| | | public CultureInfo CultureInfo { get; set; } |
| | | |
| | | /// <summary> |
| | | /// The execution mode that must be used for formula execution. |
| | | /// </summary> |
| | | public ExecutionMode ExecutionMode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// Enable or disable caching of mathematical formulas. |
| | | /// </summary> |
| | | public bool CacheEnabled { get; set; } |
| | | |
| | | /// <summary> |
| | | /// Configure the maximum cache size for mathematical formulas. |
| | | /// </summary> |
| | | public int CacheMaximumSize { get; set; } |
| | | |
| | | /// <summary> |
| | | /// Configure the cache reduction size for mathematical formulas. |
| | | /// </summary> |
| | | public int CacheReductionSize { get; set; } |
| | | |
| | | /// <summary> |
| | | /// Enable or disable optimizing of formulas. |
| | | /// </summary> |
| | | public bool OptimizerEnabled { get; set; } |
| | | |
| | | /// <summary> |
| | | /// Enable or disable converting to lower case. This parameter is the inverse of <see cref="CaseSensitive"/>. |
| | | /// </summary> |
| | | [Obsolete] |
| | | public bool AdjustVariableCase { |
| | | get |
| | | { |
| | | return !CaseSensitive; |
| | | } |
| | | set |
| | | { |
| | | CaseSensitive = !value; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Enable case sensitive or case insensitive processing mode. |
| | | /// </summary> |
| | | public bool CaseSensitive { get; set; } |
| | | |
| | | /// <summary> |
| | | /// Enable or disable the default functions. |
| | | /// </summary> |
| | | public bool DefaultFunctions { get; set; } |
| | | |
| | | /// <summary> |
| | | /// Enable or disable the default constants. |
| | | /// </summary> |
| | | public bool DefaultConstants { get; set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/JaceOptions.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: da15a14f53646d442988e85bc2545dc8 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
copy from Main/Core/GameEngine/Common.meta
copy to Main/Common/Jace/Operations.meta
File was copied from Main/Core/GameEngine/Common.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 6b68b2e87cfa2fc48aff8e7f40a5c555 |
| | | guid: d825ff71751c9124885a7751c284959d |
| | | folderAsset: yes |
| | | DefaultImporter: |
| | | externalObjects: {} |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Operations |
| | | { |
| | | public class Addition : Operation |
| | | { |
| | | public Addition(DataType dataType, Operation argument1, Operation argument2) |
| | | : base(dataType, argument1.DependsOnVariables || argument2.DependsOnVariables, argument1.IsIdempotent && argument2.IsIdempotent) |
| | | { |
| | | this.Argument1 = argument1; |
| | | this.Argument2 = argument2; |
| | | } |
| | | |
| | | public Operation Argument1 { get; internal set; } |
| | | public Operation Argument2 { get; internal set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Operations/Addition.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 340301d5fb1dce54ab7dec7873ceea4d |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Operations |
| | | { |
| | | public class And : Operation |
| | | { |
| | | public And(DataType dataType, Operation argument1, Operation argument2) |
| | | : base(dataType, argument1.DependsOnVariables || argument2.DependsOnVariables, argument1.IsIdempotent && argument2.IsIdempotent) |
| | | { |
| | | this.Argument1 = argument1; |
| | | this.Argument2 = argument2; |
| | | } |
| | | |
| | | public Operation Argument1 { get; internal set; } |
| | | public Operation Argument2 { get; internal set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Operations/And.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: c88e04049f2269a498cfedbd3fc9576c |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Operations |
| | | { |
| | | public abstract class Constant<T> : Operation |
| | | { |
| | | public Constant(DataType dataType, T value) |
| | | : base(dataType, false, true) |
| | | { |
| | | this.Value = value; |
| | | } |
| | | |
| | | public T Value { get; private set; } |
| | | |
| | | public override bool Equals(object obj) |
| | | { |
| | | Constant<T> other = obj as Constant<T>; |
| | | if (other != null) |
| | | return this.Value.Equals(other.Value); |
| | | else |
| | | return false; |
| | | } |
| | | |
| | | public override int GetHashCode() |
| | | { |
| | | return this.Value.GetHashCode(); |
| | | } |
| | | } |
| | | |
| | | public class IntegerConstant : Constant<int> |
| | | { |
| | | public IntegerConstant(int value) |
| | | : base(DataType.Integer, value) |
| | | { |
| | | } |
| | | } |
| | | |
| | | public class FloatingPointConstant : Constant<double> |
| | | { |
| | | public FloatingPointConstant(double value) |
| | | : base(DataType.FloatingPoint, value) |
| | | { |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Operations/Constant.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 65575909546ce144e83dd420135e0a01 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Operations |
| | | { |
| | | public class Division : Operation |
| | | { |
| | | public Division(DataType dataType, Operation dividend, Operation divisor) |
| | | : base(dataType, dividend.DependsOnVariables || divisor.DependsOnVariables, dividend.IsIdempotent && divisor.IsIdempotent) |
| | | { |
| | | this.Dividend = dividend; |
| | | this.Divisor = divisor; |
| | | } |
| | | |
| | | public Operation Dividend { get; internal set; } |
| | | public Operation Divisor { get; internal set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Operations/Division.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 353c124902c7984429815571216959bf |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Operations |
| | | { |
| | | public class Equal : Operation |
| | | { |
| | | public Equal(DataType dataType, Operation argument1, Operation argument2) |
| | | : base(dataType, argument1.DependsOnVariables || argument2.DependsOnVariables, argument1.IsIdempotent && argument2.IsIdempotent) |
| | | { |
| | | this.Argument1 = argument1; |
| | | this.Argument2 = argument2; |
| | | } |
| | | |
| | | public Operation Argument1 { get; internal set; } |
| | | public Operation Argument2 { get; internal set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Operations/Equal.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 87cffdc974ef87a4ab8c92b5321424c6 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Operations |
| | | { |
| | | public class Exponentiation : Operation |
| | | { |
| | | public Exponentiation(DataType dataType, Operation @base, Operation exponent) |
| | | : base(dataType, @base.DependsOnVariables || exponent.DependsOnVariables, @base.IsIdempotent && exponent.IsIdempotent) |
| | | { |
| | | Base = @base; |
| | | Exponent = exponent; |
| | | } |
| | | |
| | | public Operation Base { get; internal set; } |
| | | public Operation Exponent { get; internal set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Operations/Exponentiation.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 2491ad50c77e631489551371d36bab46 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Operations |
| | | { |
| | | public class Function : Operation |
| | | { |
| | | private IList<Operation> arguments; |
| | | |
| | | public Function(DataType dataType, string functionName, IList<Operation> arguments, bool isIdempotent) |
| | | : base(dataType, arguments.FirstOrDefault(o => o.DependsOnVariables) != null, isIdempotent && arguments.All(o => o.IsIdempotent)) |
| | | { |
| | | this.FunctionName = functionName; |
| | | this.arguments = arguments; |
| | | } |
| | | |
| | | public string FunctionName { get; private set; } |
| | | |
| | | public IList<Operation> Arguments { |
| | | get |
| | | { |
| | | return arguments; |
| | | } |
| | | internal set |
| | | { |
| | | this.arguments = value; |
| | | this.DependsOnVariables = arguments.FirstOrDefault(o => o.DependsOnVariables) != null; |
| | | } |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Operations/Function.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 8cea584356c80194eac8e7f5905d7764 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Operations |
| | | { |
| | | public class GreaterOrEqualThan : Operation |
| | | { |
| | | public GreaterOrEqualThan(DataType dataType, Operation argument1, Operation argument2) |
| | | : base(dataType, argument1.DependsOnVariables || argument2.DependsOnVariables, argument1.IsIdempotent && argument2.IsIdempotent) |
| | | { |
| | | this.Argument1 = argument1; |
| | | this.Argument2 = argument2; |
| | | } |
| | | |
| | | public Operation Argument1 { get; internal set; } |
| | | public Operation Argument2 { get; internal set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Operations/GreaterOrEqualThan.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: a5f7058c1a38e5e4da81a637c5ca0fb8 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Operations |
| | | { |
| | | public class GreaterThan : Operation |
| | | { |
| | | public GreaterThan(DataType dataType, Operation argument1, Operation argument2) |
| | | : base(dataType, argument1.DependsOnVariables || argument2.DependsOnVariables, argument1.IsIdempotent && argument2.IsIdempotent) |
| | | { |
| | | this.Argument1 = argument1; |
| | | this.Argument2 = argument2; |
| | | } |
| | | |
| | | public Operation Argument1 { get; internal set; } |
| | | public Operation Argument2 { get; internal set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Operations/GreaterThan.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: aa4d6a9b5c1549743bd305b4e87c56b8 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Operations |
| | | { |
| | | public class LessOrEqualThan : Operation |
| | | { |
| | | public LessOrEqualThan(DataType dataType, Operation argument1, Operation argument2) |
| | | : base(dataType, argument1.DependsOnVariables || argument2.DependsOnVariables, argument1.IsIdempotent && argument2.IsIdempotent) |
| | | { |
| | | this.Argument1 = argument1; |
| | | this.Argument2 = argument2; |
| | | } |
| | | |
| | | public Operation Argument1 { get; internal set; } |
| | | public Operation Argument2 { get; internal set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Operations/LessOrEqualThan.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 22813b990f9481c41b94640a98d29719 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Operations |
| | | { |
| | | public class LessThan : Operation |
| | | { |
| | | public LessThan(DataType dataType, Operation argument1, Operation argument2) |
| | | : base(dataType, argument1.DependsOnVariables || argument2.DependsOnVariables, argument1.IsIdempotent && argument2.IsIdempotent) |
| | | { |
| | | this.Argument1 = argument1; |
| | | this.Argument2 = argument2; |
| | | } |
| | | |
| | | public Operation Argument1 { get; internal set; } |
| | | public Operation Argument2 { get; internal set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Operations/LessThan.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 259c10599a2e2a74b86a83682dc05cc1 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Operations |
| | | { |
| | | public class Modulo : Operation |
| | | { |
| | | public Modulo(DataType dataType, Operation dividend, Operation divisor) |
| | | : base(dataType, dividend.DependsOnVariables || divisor.DependsOnVariables, dividend.IsIdempotent && divisor.IsIdempotent) |
| | | { |
| | | this.Dividend = dividend; |
| | | this.Divisor = divisor; |
| | | } |
| | | |
| | | public Operation Dividend { get; internal set; } |
| | | public Operation Divisor { get; internal set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Operations/Modulo.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 20b05091ee3aab546b21bcbde58b826c |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Operations |
| | | { |
| | | public class Multiplication : Operation |
| | | { |
| | | public Multiplication(DataType dataType, Operation argument1, Operation argument2) |
| | | : base(dataType, argument1.DependsOnVariables || argument2.DependsOnVariables, argument1.IsIdempotent && argument2.IsIdempotent) |
| | | { |
| | | this.Argument1 = argument1; |
| | | this.Argument2 = argument2; |
| | | } |
| | | |
| | | public Operation Argument1 { get; internal set; } |
| | | public Operation Argument2 { get; internal set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Operations/Multiplication.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 6156d0f899a0b484383f5a552a76e328 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Operations |
| | | { |
| | | public class NotEqual : Operation |
| | | { |
| | | public NotEqual(DataType dataType, Operation argument1, Operation argument2) |
| | | : base(dataType, argument1.DependsOnVariables || argument2.DependsOnVariables, argument1.IsIdempotent && argument2.IsIdempotent) |
| | | { |
| | | this.Argument1 = argument1; |
| | | this.Argument2 = argument2; |
| | | } |
| | | |
| | | public Operation Argument1 { get; internal set; } |
| | | public Operation Argument2 { get; internal set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Operations/NotEqual.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: b52548570632a8a449c662af67df863b |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Operations |
| | | { |
| | | public abstract class Operation |
| | | { |
| | | public Operation(DataType dataType, bool dependsOnVariables, bool isIdempotent) |
| | | { |
| | | this.DataType = dataType; |
| | | this.DependsOnVariables = dependsOnVariables; |
| | | this.IsIdempotent = isIdempotent; |
| | | } |
| | | |
| | | public DataType DataType { get; private set; } |
| | | |
| | | public bool DependsOnVariables { get; internal set; } |
| | | |
| | | public bool IsIdempotent { get; private set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Operations/Operation.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: f31df8e25e70f36488d2dc2f14ba66d7 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Operations |
| | | { |
| | | public class Or : Operation |
| | | { |
| | | public Or(DataType dataType, Operation argument1, Operation argument2) |
| | | : base(dataType, argument1.DependsOnVariables || argument2.DependsOnVariables, argument1.IsIdempotent && argument2.IsIdempotent) |
| | | { |
| | | this.Argument1 = argument1; |
| | | this.Argument2 = argument2; |
| | | } |
| | | |
| | | public Operation Argument1 { get; internal set; } |
| | | public Operation Argument2 { get; internal set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Operations/Or.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: c39d4b13c7751e34587665bc39443e2a |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Operations |
| | | { |
| | | public class Subtraction : Operation |
| | | { |
| | | public Subtraction(DataType dataType, Operation argument1, Operation argument2) |
| | | : base(dataType, argument1.DependsOnVariables || argument2.DependsOnVariables, argument1.IsIdempotent && argument2.IsIdempotent) |
| | | { |
| | | this.Argument1 = argument1; |
| | | this.Argument2 = argument2; |
| | | } |
| | | |
| | | public Operation Argument1 { get; internal set; } |
| | | public Operation Argument2 { get; internal set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Operations/Subtraction.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: ddba1b68f54ac7841ac6b91dfb55a185 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Operations |
| | | { |
| | | public class UnaryMinus : Operation |
| | | { |
| | | public UnaryMinus(DataType dataType, Operation argument) |
| | | : base(dataType, argument.DependsOnVariables, argument.IsIdempotent) |
| | | { |
| | | this.Argument = argument; |
| | | } |
| | | |
| | | public Operation Argument { get; internal set; } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Operations/UnaryMinus.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 350a4f213d50975468899e32708859b1 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Operations |
| | | { |
| | | /// <summary> |
| | | /// Represents a variable in a mathematical formula. |
| | | /// </summary> |
| | | public class Variable : Operation |
| | | { |
| | | public Variable(string name) |
| | | : base(DataType.FloatingPoint, true, false) |
| | | { |
| | | this.Name = name; |
| | | } |
| | | |
| | | public string Name { get; private set; } |
| | | |
| | | public override bool Equals(object obj) |
| | | { |
| | | Variable other = obj as Variable; |
| | | if (other != null) |
| | | { |
| | | return this.Name.Equals(other.Name); |
| | | } |
| | | else |
| | | return false; |
| | | } |
| | | |
| | | public override int GetHashCode() |
| | | { |
| | | return this.Name.GetHashCode(); |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Operations/Variable.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 34fb9551f3d90cf418e9557742735a18 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using Jace.Operations; |
| | | using Jace.Execution; |
| | | |
| | | namespace Jace |
| | | { |
| | | public class Optimizer |
| | | { |
| | | private readonly IExecutor executor; |
| | | |
| | | public Optimizer(IExecutor executor) |
| | | { |
| | | this.executor = executor; |
| | | } |
| | | |
| | | public Operation Optimize(Operation operation, IFunctionRegistry functionRegistry, IConstantRegistry constantRegistry) |
| | | { |
| | | if (!operation.DependsOnVariables && operation.IsIdempotent && operation.GetType() != typeof(IntegerConstant) |
| | | && operation.GetType() != typeof(FloatingPointConstant)) |
| | | { |
| | | double result = executor.Execute(operation, functionRegistry, constantRegistry); |
| | | return new FloatingPointConstant(result); |
| | | } |
| | | else |
| | | { |
| | | if (operation.GetType() == typeof(Addition)) |
| | | { |
| | | Addition addition = (Addition)operation; |
| | | addition.Argument1 = Optimize(addition.Argument1, functionRegistry, constantRegistry); |
| | | addition.Argument2 = Optimize(addition.Argument2, functionRegistry, constantRegistry); |
| | | } |
| | | else if (operation.GetType() == typeof(Subtraction)) |
| | | { |
| | | Subtraction substraction = (Subtraction)operation; |
| | | substraction.Argument1 = Optimize(substraction.Argument1, functionRegistry, constantRegistry); |
| | | substraction.Argument2 = Optimize(substraction.Argument2, functionRegistry, constantRegistry); |
| | | } |
| | | else if (operation.GetType() == typeof(Multiplication)) |
| | | { |
| | | Multiplication multiplication = (Multiplication)operation; |
| | | multiplication.Argument1 = Optimize(multiplication.Argument1, functionRegistry, constantRegistry); |
| | | multiplication.Argument2 = Optimize(multiplication.Argument2, functionRegistry, constantRegistry); |
| | | |
| | | if ((multiplication.Argument1.GetType() == typeof(FloatingPointConstant) && ((FloatingPointConstant)multiplication.Argument1).Value == 0.0) |
| | | || (multiplication.Argument2.GetType() == typeof(FloatingPointConstant) && ((FloatingPointConstant)multiplication.Argument2).Value == 0.0)) |
| | | { |
| | | return new FloatingPointConstant(0.0); |
| | | } |
| | | } |
| | | else if (operation.GetType() == typeof(Division)) |
| | | { |
| | | Division division = (Division)operation; |
| | | division.Dividend = Optimize(division.Dividend, functionRegistry, constantRegistry); |
| | | division.Divisor = Optimize(division.Divisor, functionRegistry, constantRegistry); |
| | | } |
| | | else if (operation.GetType() == typeof(Exponentiation)) |
| | | { |
| | | Exponentiation division = (Exponentiation)operation; |
| | | division.Base = Optimize(division.Base, functionRegistry, constantRegistry); |
| | | division.Exponent = Optimize(division.Exponent, functionRegistry, constantRegistry); |
| | | } |
| | | else if(operation.GetType() == typeof(Function)) |
| | | { |
| | | Function function = (Function)operation; |
| | | IList<Operation> arguments = function.Arguments.Select(a => Optimize(a, functionRegistry, constantRegistry)).ToList(); |
| | | function.Arguments = arguments; |
| | | } |
| | | |
| | | return operation; |
| | | } |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Optimizer.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 3d95e6f9d0000c54c9abd40e1f81ab4a |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace |
| | | { |
| | | /// <summary> |
| | | /// The exception that is thrown when there is a syntax error in the formula provided |
| | | /// to the calculation engine. |
| | | /// </summary> |
| | | public class ParseException : Exception |
| | | { |
| | | public ParseException(string message) |
| | | : base(message) |
| | | { |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/ParseException.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: df2bb315758f36a429552a2b28b667e2 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
copy from Main/Core/GameEngine/Common.meta
copy to Main/Common/Jace/Tokenizer.meta
File was copied from Main/Core/GameEngine/Common.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 6b68b2e87cfa2fc48aff8e7f40a5c555 |
| | | guid: 2b67a41b280e4f143861b982f7dbc630 |
| | | folderAsset: yes |
| | | DefaultImporter: |
| | | externalObjects: {} |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Tokenizer |
| | | { |
| | | /// <summary> |
| | | /// Represents an input token |
| | | /// </summary> |
| | | public struct Token |
| | | { |
| | | /// <summary> |
| | | /// The start position of the token in the input function text. |
| | | /// </summary> |
| | | public int StartPosition; |
| | | |
| | | /// <summary> |
| | | /// The length of token in the input function text. |
| | | /// </summary> |
| | | public int Length; |
| | | |
| | | /// <summary> |
| | | /// The type of the token. |
| | | /// </summary> |
| | | public TokenType TokenType; |
| | | |
| | | /// <summary> |
| | | /// The value of the token. |
| | | /// </summary> |
| | | public object Value; |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Tokenizer/Token.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 9fa03dbd0043c2b41a256b11a7669fc9 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Globalization; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Tokenizer |
| | | { |
| | | /// <summary> |
| | | /// A token reader that converts the input string in a list of tokens. |
| | | /// </summary> |
| | | public class TokenReader |
| | | { |
| | | private readonly CultureInfo cultureInfo; |
| | | private readonly char decimalSeparator; |
| | | private readonly char argumentSeparator; |
| | | |
| | | public TokenReader() |
| | | : this(CultureInfo.CurrentCulture) |
| | | { |
| | | } |
| | | |
| | | public TokenReader(CultureInfo cultureInfo) |
| | | { |
| | | this.cultureInfo = cultureInfo; |
| | | this.decimalSeparator = cultureInfo.NumberFormat.NumberDecimalSeparator[0]; |
| | | this.argumentSeparator = cultureInfo.TextInfo.ListSeparator[0]; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Read in the provided formula and convert it into a list of takens that can be processed by the |
| | | /// Abstract Syntax Tree Builder. |
| | | /// </summary> |
| | | /// <param name="formula">The formula that must be converted into a list of tokens.</param> |
| | | /// <returns>The list of tokens for the provided formula.</returns> |
| | | public List<Token> Read(string formula) |
| | | { |
| | | if (string.IsNullOrEmpty(formula)) |
| | | throw new ArgumentNullException("formula"); |
| | | |
| | | List<Token> tokens = new List<Token>(); |
| | | |
| | | char[] characters = formula.ToCharArray(); |
| | | |
| | | bool isFormulaSubPart = true; |
| | | bool isScientific = false; |
| | | |
| | | for(int i = 0; i < characters.Length; i++) |
| | | { |
| | | if (IsPartOfNumeric(characters[i], true, isFormulaSubPart)) |
| | | { |
| | | StringBuilder buffer = new StringBuilder(); |
| | | buffer.Append(characters[i]); |
| | | //string buffer = "" + characters[i]; |
| | | int startPosition = i; |
| | | |
| | | |
| | | while (++i < characters.Length && IsPartOfNumeric(characters[i], false, isFormulaSubPart)) |
| | | { |
| | | if (isScientific && IsScientificNotation(characters[i])) |
| | | throw new ParseException(string.Format("Invalid token \"{0}\" detected at position {1}.", characters[i], i)); |
| | | |
| | | if (IsScientificNotation(characters[i])) |
| | | { |
| | | isScientific = IsScientificNotation(characters[i]); |
| | | |
| | | if (characters[i + 1] == '-') |
| | | { |
| | | buffer.Append(characters[i++]); |
| | | } |
| | | } |
| | | |
| | | buffer.Append(characters[i]); |
| | | } |
| | | |
| | | // Verify if we do not have an int |
| | | int intValue; |
| | | if (int.TryParse(buffer.ToString(), out intValue)) |
| | | { |
| | | tokens.Add(new Token() { TokenType = TokenType.Integer, Value = intValue, StartPosition = startPosition, Length = i - startPosition }); |
| | | isFormulaSubPart = false; |
| | | } |
| | | else |
| | | { |
| | | double doubleValue; |
| | | if (double.TryParse(buffer.ToString(), NumberStyles.Float | NumberStyles.AllowThousands, |
| | | cultureInfo, out doubleValue)) |
| | | { |
| | | tokens.Add(new Token() { TokenType = TokenType.FloatingPoint, Value = doubleValue, StartPosition = startPosition, Length = i - startPosition }); |
| | | isScientific = false; |
| | | isFormulaSubPart = false; |
| | | } |
| | | else if (buffer.ToString() == "-") |
| | | { |
| | | // Verify if we have a unary minus, we use the token '_' for a unary minus in the AST builder |
| | | tokens.Add(new Token() { TokenType = TokenType.Operation, Value = '_', StartPosition = startPosition, Length = 1 }); |
| | | } |
| | | // Else we skip |
| | | } |
| | | |
| | | if (i == characters.Length) |
| | | { |
| | | // Last character read |
| | | continue; |
| | | } |
| | | } |
| | | |
| | | if (IsPartOfVariable(characters[i], true)) |
| | | { |
| | | string buffer = "" + characters[i]; |
| | | int startPosition = i; |
| | | |
| | | while (++i < characters.Length && IsPartOfVariable(characters[i], false)) |
| | | { |
| | | buffer += characters[i]; |
| | | } |
| | | |
| | | tokens.Add(new Token() { TokenType = TokenType.Text, Value = buffer, StartPosition = startPosition, Length = i -startPosition }); |
| | | isFormulaSubPart = false; |
| | | |
| | | if (i == characters.Length) |
| | | { |
| | | // Last character read |
| | | continue; |
| | | } |
| | | } |
| | | if (characters[i] == this.argumentSeparator) |
| | | { |
| | | tokens.Add(new Token() { TokenType = Tokenizer.TokenType.ArgumentSeparator, Value = characters[i], StartPosition = i, Length = 1 }); |
| | | isFormulaSubPart = false; |
| | | } |
| | | else |
| | | { |
| | | switch (characters[i]) |
| | | { |
| | | case ' ': |
| | | continue; |
| | | case '+': |
| | | case '-': |
| | | case '*': |
| | | case '/': |
| | | case '^': |
| | | case '%': |
| | | case '≤': |
| | | case '≥': |
| | | case '≠': |
| | | if (IsUnaryMinus(characters[i], tokens)) |
| | | { |
| | | // We use the token '_' for a unary minus in the AST builder |
| | | tokens.Add(new Token() { TokenType = TokenType.Operation, Value = '_', StartPosition = i, Length = 1 }); |
| | | } |
| | | else |
| | | { |
| | | tokens.Add(new Token() { TokenType = TokenType.Operation, Value = characters[i], StartPosition = i, Length = 1 }); |
| | | } |
| | | isFormulaSubPart = true; |
| | | break; |
| | | case '(': |
| | | tokens.Add(new Token() { TokenType = TokenType.LeftBracket, Value = characters[i], StartPosition = i, Length = 1 }); |
| | | isFormulaSubPart = true; |
| | | break; |
| | | case ')': |
| | | tokens.Add(new Token() { TokenType = TokenType.RightBracket, Value = characters[i], StartPosition = i, Length = 1 }); |
| | | isFormulaSubPart = false; |
| | | break; |
| | | case '<': |
| | | if (i + 1 < characters.Length && characters[i + 1] == '=') |
| | | tokens.Add(new Token() { TokenType = TokenType.Operation, Value = '≤', StartPosition = i++, Length = 2 }); |
| | | else |
| | | tokens.Add(new Token() { TokenType = TokenType.Operation, Value = '<', StartPosition = i, Length = 1 }); |
| | | isFormulaSubPart = false; |
| | | break; |
| | | case '>': |
| | | if (i + 1 < characters.Length && characters[i + 1] == '=') |
| | | tokens.Add(new Token() { TokenType = TokenType.Operation, Value = '≥', StartPosition = i++, Length = 2 }); |
| | | else |
| | | tokens.Add(new Token() { TokenType = TokenType.Operation, Value = '>', StartPosition = i, Length = 1 }); |
| | | isFormulaSubPart = false; |
| | | break; |
| | | case '!': |
| | | if (i + 1 < characters.Length && characters[i + 1] == '=') |
| | | { |
| | | tokens.Add(new Token() { TokenType = TokenType.Operation, Value = '≠', StartPosition = i++, Length = 2 }); |
| | | isFormulaSubPart = false; |
| | | } |
| | | else |
| | | throw new ParseException(string.Format("Invalid token \"{0}\" detected at position {1}.", characters[i], i)); |
| | | break; |
| | | case '&': |
| | | if (i + 1 < characters.Length && characters[i + 1] == '&') |
| | | { |
| | | tokens.Add(new Token() { TokenType = TokenType.Operation, Value = '&', StartPosition = i++, Length = 2 }); |
| | | isFormulaSubPart = false; |
| | | } |
| | | else |
| | | throw new ParseException(string.Format("Invalid token \"{0}\" detected at position {1}.", characters[i], i)); |
| | | break; |
| | | case '|': |
| | | if (i + 1 < characters.Length && characters[i + 1] == '|') |
| | | { |
| | | tokens.Add(new Token() { TokenType = TokenType.Operation, Value = '|', StartPosition = i++, Length = 2 }); |
| | | isFormulaSubPart = false; |
| | | } |
| | | else |
| | | throw new ParseException(string.Format("Invalid token \"{0}\" detected at position {1}.", characters[i], i)); |
| | | break; |
| | | case '=': |
| | | if (i + 1 < characters.Length && characters[i + 1] == '=') |
| | | { |
| | | tokens.Add(new Token() { TokenType = TokenType.Operation, Value = '=', StartPosition = i++, Length = 2 }); |
| | | isFormulaSubPart = false; |
| | | } |
| | | else |
| | | throw new ParseException(string.Format("Invalid token \"{0}\" detected at position {1}.", characters[i], i)); |
| | | break; |
| | | default: |
| | | throw new ParseException(string.Format("Invalid token \"{0}\" detected at position {1}.", characters[i], i)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | return tokens; |
| | | } |
| | | |
| | | private bool IsPartOfNumeric(char character, bool isFirstCharacter, bool isFormulaSubPart) |
| | | { |
| | | return character == decimalSeparator || (character >= '0' && character <= '9') || (isFormulaSubPart && isFirstCharacter && character == '-') || (!isFirstCharacter && character == 'e') || (!isFirstCharacter && character == 'E'); |
| | | } |
| | | |
| | | private bool IsPartOfVariable(char character, bool isFirstCharacter) |
| | | { |
| | | return (character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z') || (!isFirstCharacter && character >= '0' && character <= '9') || (!isFirstCharacter && character == '_'); |
| | | } |
| | | |
| | | private bool IsUnaryMinus(char currentToken, List<Token> tokens) |
| | | { |
| | | if (currentToken == '-') |
| | | { |
| | | Token previousToken = tokens[tokens.Count - 1]; |
| | | |
| | | return !(previousToken.TokenType == TokenType.FloatingPoint || |
| | | previousToken.TokenType == TokenType.Integer || |
| | | previousToken.TokenType == TokenType.Text || |
| | | previousToken.TokenType == TokenType.RightBracket); |
| | | } |
| | | else |
| | | return false; |
| | | } |
| | | |
| | | private bool IsScientificNotation(char currentToken) |
| | | { |
| | | return currentToken == 'e' || currentToken == 'E'; |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Tokenizer/TokenReader.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: e7f38551c1077ee4896e7b1d5aabd1a2 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Tokenizer |
| | | { |
| | | public enum TokenType |
| | | { |
| | | Integer, |
| | | FloatingPoint, |
| | | Text, |
| | | Operation, |
| | | LeftBracket, |
| | | RightBracket, |
| | | ArgumentSeparator |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Tokenizer/TokenType.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: ca43eadac5024d040a3f89d8c15e0967 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
copy from Main/Core/GameEngine/Common.meta
copy to Main/Common/Jace/Util.meta
File was copied from Main/Core/GameEngine/Common.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 6b68b2e87cfa2fc48aff8e7f40a5c555 |
| | | guid: 78f08781a2381ff409b92d3767b449bc |
| | | folderAsset: yes |
| | | DefaultImporter: |
| | | externalObjects: {} |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Util |
| | | { |
| | | /// <summary> |
| | | /// Utility methods of Jace.NET that can be used throughout the engine. |
| | | /// </summary> |
| | | internal static class EngineUtil |
| | | { |
| | | static internal IDictionary<string, double> ConvertVariableNamesToLowerCase(IDictionary<string, double> variables) |
| | | { |
| | | Dictionary<string, double> temp = new Dictionary<string, double>(); |
| | | foreach (KeyValuePair<string, double> keyValuePair in variables) |
| | | { |
| | | temp.Add(keyValuePair.Key.ToLowerFast(), keyValuePair.Value); |
| | | } |
| | | |
| | | return temp; |
| | | } |
| | | |
| | | // This is a fast ToLower for strings that are in ASCII |
| | | static internal string ToLowerFast(this string text) |
| | | { |
| | | StringBuilder buffer = new StringBuilder(text.Length); |
| | | |
| | | for(int i = 0; i < text.Length; i++) |
| | | { |
| | | char c = text[i]; |
| | | |
| | | if (c >= 'A' && c <= 'Z') |
| | | { |
| | | buffer.Append((char)(c + 32)); |
| | | } |
| | | else |
| | | { |
| | | buffer.Append(c); |
| | | } |
| | | } |
| | | |
| | | return buffer.ToString(); |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Util/EngineUtil.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 3725a3ccea7f46f4bb6980cdd7823745 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.IO; |
| | | using System.Linq; |
| | | using System.Linq.Expressions; |
| | | using System.Reflection; |
| | | using System.Reflection.Emit; |
| | | using System.Text; |
| | | using Jace.Operations; |
| | | |
| | | namespace Jace.Util |
| | | { |
| | | /// <summary> |
| | | /// An adapter for creating a func wrapper around a func accepting a dictionary. The wrapper |
| | | /// can create a func that has an argument for every expected key in the dictionary. |
| | | /// </summary> |
| | | public class FuncAdapter |
| | | { |
| | | /// <summary> |
| | | /// Wrap the parsed the function into a delegate of the specified type. The delegate must accept |
| | | /// the parameters defined in the parameters collection. The order of parameters is respected as defined |
| | | /// in parameters collection. |
| | | /// <br/> |
| | | /// The function must accept a dictionary of strings and doubles as input. The values passed to the |
| | | /// wrapping function will be passed to the function using the dictionary. The keys in the dictionary |
| | | /// are the names of the parameters of the wrapping function. |
| | | /// </summary> |
| | | /// <param name="parameters">The required parameters of the wrapping function delegate.</param> |
| | | /// <param name="function">The function that must be wrapped.</param> |
| | | /// <returns>A delegate instance of the required type.</returns> |
| | | public Delegate Wrap(IEnumerable<Jace.Execution.ParameterInfo> parameters, |
| | | Func<IDictionary<string, double>, double> function) |
| | | { |
| | | Jace.Execution.ParameterInfo[] parameterArray = parameters.ToArray(); |
| | | |
| | | return GenerateDelegate(parameterArray, function); |
| | | } |
| | | |
| | | // Uncomment for debugging purposes |
| | | //public void CreateDynamicModuleBuilder() |
| | | //{ |
| | | // AssemblyName assemblyName = new AssemblyName("JaceDynamicAssembly"); |
| | | // AppDomain domain = AppDomain.CurrentDomain; |
| | | // AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(assemblyName, |
| | | // AssemblyBuilderAccess.RunAndSave); |
| | | // ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, "test.dll"); |
| | | |
| | | // TypeBuilder typeBuilder = moduleBuilder.DefineType("MyTestClass"); |
| | | |
| | | // MethodBuilder method = typeBuilder.DefineMethod("MyTestMethod", MethodAttributes.Static, typeof(double), |
| | | // new Type[] { typeof(FuncAdapterArguments), typeof(int), typeof(double) }); |
| | | |
| | | // ILGenerator generator = method.GetILGenerator(); |
| | | // GenerateMethodBody(generator, new List<Calculator.Execution.ParameterInfo>() { |
| | | // new Calculator.Execution.ParameterInfo() { Name = "test1", DataType = DataType.Integer }, |
| | | // new Calculator.Execution.ParameterInfo() { Name = "test2", DataType = DataType.FloatingPoint }}, |
| | | // (a) => 0.0); |
| | | |
| | | // typeBuilder.CreateType(); |
| | | |
| | | // assemblyBuilder.Save(@"test.dll"); |
| | | //} |
| | | |
| | | private Delegate GenerateDelegate(Jace.Execution.ParameterInfo[] parameterArray, |
| | | Func<Dictionary<string, double>, double> function) |
| | | { |
| | | Type delegateType = GetDelegateType(parameterArray); |
| | | Type dictionaryType = typeof(Dictionary<string, double>); |
| | | |
| | | ParameterExpression dictionaryExpression = |
| | | Expression.Variable(typeof(Dictionary<string, double>), "dictionary"); |
| | | BinaryExpression dictionaryAssignExpression = |
| | | Expression.Assign(dictionaryExpression, Expression.New(dictionaryType)); |
| | | |
| | | ParameterExpression[] parameterExpressions = new ParameterExpression[parameterArray.Length]; |
| | | |
| | | List<Expression> methodBody = new List<Expression>(); |
| | | methodBody.Add(dictionaryAssignExpression); |
| | | |
| | | for (int i = 0; i < parameterArray.Length; i++) |
| | | { |
| | | // Create parameter expression for each func parameter |
| | | Type parameterType = parameterArray[i].DataType == DataType.FloatingPoint ? typeof(double) : typeof(int); |
| | | parameterExpressions[i] = Expression.Parameter(parameterType, parameterArray[i].Name); |
| | | |
| | | methodBody.Add(Expression.Call(dictionaryExpression, |
| | | dictionaryType.GetRuntimeMethod("Add", new Type[] { typeof(string), typeof(double) }), |
| | | Expression.Constant(parameterArray[i].Name), |
| | | Expression.Convert(parameterExpressions[i], typeof(double))) |
| | | ); |
| | | } |
| | | |
| | | InvocationExpression invokeExpression = Expression.Invoke(Expression.Constant(function), dictionaryExpression); |
| | | methodBody.Add(invokeExpression); |
| | | |
| | | LambdaExpression lambdaExpression = Expression.Lambda(delegateType, |
| | | Expression.Block(new[] { dictionaryExpression }, methodBody), |
| | | parameterExpressions); |
| | | |
| | | return lambdaExpression.Compile(); |
| | | } |
| | | |
| | | private Type GetDelegateType(Jace.Execution.ParameterInfo[] parameters) |
| | | { |
| | | string funcTypeName = string.Format("System.Func`{0}", parameters.Length + 1); |
| | | Type funcType = Type.GetType(funcTypeName); |
| | | |
| | | Type[] typeArguments = new Type[parameters.Length + 1]; |
| | | for (int i = 0; i < parameters.Length; i++) |
| | | typeArguments[i] = (parameters[i].DataType == DataType.FloatingPoint) ? typeof(double) : typeof(int); |
| | | typeArguments[typeArguments.Length - 1] = typeof(double); |
| | | |
| | | return funcType.MakeGenericType(typeArguments); |
| | | } |
| | | |
| | | private class FuncAdapterArguments |
| | | { |
| | | private readonly Func<Dictionary<string, double>, double> function; |
| | | |
| | | public FuncAdapterArguments(Func<Dictionary<string, double>, double> function) |
| | | { |
| | | this.function = function; |
| | | } |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Util/FuncAdapter.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 878d5799cfe90cb4dbf7aebc38c3e9ae |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Text; |
| | | using System.Linq; |
| | | |
| | | namespace Jace.Util |
| | | { |
| | | static class MathExtended |
| | | { |
| | | /// <summary> |
| | | /// Partitions the given list around a pivot element such that all elements on left of pivot are <= pivot |
| | | /// and the ones at thr right are > pivot. This method can be used for sorting, N-order statistics such as |
| | | /// as median finding algorithms. |
| | | /// Pivot is selected ranodmly if random number generator is supplied else its selected as last element in the list. |
| | | /// Reference: Introduction to Algorithms 3rd Edition, Corman et al, pp 171 |
| | | /// </summary> |
| | | private static int Partition<T>(this IList<T> list, int start, int end, Random rnd = null) where T : IComparable<T> |
| | | { |
| | | if (rnd != null) |
| | | list.Swap(end, rnd.Next(start, end + 1)); |
| | | |
| | | var pivot = list[end]; |
| | | var lastLow = start - 1; |
| | | for (var i = start; i < end; i++) |
| | | { |
| | | if (list[i].CompareTo(pivot) <= 0) |
| | | list.Swap(i, ++lastLow); |
| | | } |
| | | list.Swap(end, ++lastLow); |
| | | return lastLow; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Returns Nth smallest element from the list. Here n starts from 0 so that n=0 returns minimum, n=1 returns 2nd smallest element etc. |
| | | /// Note: specified list would be mutated in the process. |
| | | /// Reference: Introduction to Algorithms 3rd Edition, Corman et al, pp 216 |
| | | /// </summary> |
| | | public static T NthOrderStatistic<T>(this IList<T> list, int n, Random rnd = null) where T : IComparable<T> |
| | | { |
| | | return NthOrderStatistic(list, n, 0, list.Count - 1, rnd); |
| | | } |
| | | private static T NthOrderStatistic<T>(this IList<T> list, int n, int start, int end, Random rnd) where T : IComparable<T> |
| | | { |
| | | while (true) |
| | | { |
| | | var pivotIndex = list.Partition(start, end, rnd); |
| | | if (pivotIndex == n) |
| | | return list[pivotIndex]; |
| | | |
| | | if (n < pivotIndex) |
| | | end = pivotIndex - 1; |
| | | else |
| | | start = pivotIndex + 1; |
| | | } |
| | | } |
| | | |
| | | public static void Swap<T>(this IList<T> list, int i, int j) |
| | | { |
| | | if (i == j) //This check is not required but Partition function may make many calls so its for perf reason |
| | | return; |
| | | var temp = list[i]; |
| | | list[i] = list[j]; |
| | | list[j] = temp; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Note: specified list would be mutated in the process. |
| | | /// </summary> |
| | | public static T Median<T>(this IList<T> list) where T : IComparable<T> |
| | | { |
| | | return list.NthOrderStatistic((list.Count - 1) / 2); |
| | | } |
| | | |
| | | public static double Median<T>(this IEnumerable<T> sequence, Func<T, double> getValue) |
| | | { |
| | | var list = sequence.Select(getValue).ToList(); |
| | | var mid = (list.Count - 1) / 2; |
| | | return list.NthOrderStatistic(mid); |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Util/MathExtended.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 9fd567b7004de6e41ae2720dd0b3c1ce |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Util |
| | | { |
| | | public static class MathUtil |
| | | { |
| | | public static double Cot(double a) |
| | | { |
| | | return 1 / Math.Tan(a); |
| | | } |
| | | |
| | | public static double Acot(double d) |
| | | { |
| | | return Math.Atan(1 / d); |
| | | } |
| | | |
| | | public static double Csc(double a) |
| | | { |
| | | return 1 / Math.Sin(a); |
| | | } |
| | | |
| | | public static double Sec(double d) |
| | | { |
| | | return 1 / Math.Cos(d); |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Util/MathUtil.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: b51d1dc4b0eab6e4c9cfb6bdec1d86ea |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Collections.Concurrent; |
| | | using System.Threading; |
| | | |
| | | namespace Jace.Util |
| | | { |
| | | /// <summary> |
| | | /// An in-memory based cache to store objects. The implementation is thread safe and supports |
| | | /// the multiple platforms supported by Jace (.NET, WinRT, WP7 and WP8). |
| | | /// </summary> |
| | | /// <typeparam name="TKey">The type of the keys.</typeparam> |
| | | /// <typeparam name="TValue">The type of the values.</typeparam> |
| | | public class MemoryCache<TKey, TValue> |
| | | { |
| | | private readonly int maximumSize; |
| | | private readonly int reductionSize; |
| | | |
| | | private long counter; // We cannot use DateTime.Now, because the precission is not high enough. |
| | | |
| | | private readonly ConcurrentDictionary<TKey, CacheItem> dictionary; |
| | | |
| | | /// <summary> |
| | | /// Create a new instance of the <see cref="MemoryCache"/>. |
| | | /// </summary> |
| | | /// <param name="maximumSize">The maximum allowed number of items in the cache.</param> |
| | | /// <param name="reductionSize">The number of items to be deleted per cleanup of the cache.</param> |
| | | public MemoryCache(int maximumSize, int reductionSize) |
| | | { |
| | | if (maximumSize < 1) |
| | | throw new ArgumentOutOfRangeException("maximumSize", |
| | | "The maximum allowed number of items in the cache must be at least one."); |
| | | |
| | | if (reductionSize < 1) |
| | | throw new ArgumentOutOfRangeException("reductionSize", |
| | | "The cache reduction size must be at least one."); |
| | | |
| | | this.maximumSize = maximumSize; |
| | | this.reductionSize = reductionSize; |
| | | |
| | | this.dictionary = new ConcurrentDictionary<TKey, CacheItem>(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Get the value in the cache for the given key. |
| | | /// </summary> |
| | | /// <param name="key">The key to lookup in the cache.</param> |
| | | /// <returns>The value for the given key.</returns> |
| | | public TValue this[TKey key] |
| | | { |
| | | get |
| | | { |
| | | CacheItem cacheItem = dictionary[key]; |
| | | cacheItem.Accessed(); |
| | | return cacheItem.Value; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Gets the number of items in the cache. |
| | | /// </summary> |
| | | public int Count |
| | | { |
| | | get |
| | | { |
| | | return dictionary.Count; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Returns true if an item with the given key is present in the cache. |
| | | /// </summary> |
| | | /// <param name="key">The key to lookup in the cache.</param> |
| | | /// <returns>True if an item is present in the cache for the given key.</returns> |
| | | public bool ContainsKey(TKey key) |
| | | { |
| | | return dictionary.ContainsKey(key); |
| | | } |
| | | |
| | | public bool TryGetValue (TKey key, out TValue result) |
| | | { |
| | | if (dictionary.TryGetValue(key, out var cachedItem)) |
| | | { |
| | | cachedItem.Accessed(); |
| | | result = cachedItem.Value; |
| | | return true; |
| | | } |
| | | else |
| | | { |
| | | result = default(TValue); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// If for a given key an item is present in the cache, this method will return |
| | | /// the value for the given key. If no item is present in the cache for the given |
| | | /// key, the valueFactory is executed to produce the value. This value is stored in |
| | | /// the cache and returned to the caller. |
| | | /// </summary> |
| | | /// <param name="key">The key to lookup in the cache.</param> |
| | | /// <param name="valueFactory">The factory to produce the value matching with the key.</param> |
| | | /// <returns>The value for the given key.</returns> |
| | | public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory) |
| | | { |
| | | if (valueFactory == null) |
| | | throw new ArgumentNullException("valueFactory"); |
| | | |
| | | CacheItem cacheItem = dictionary.GetOrAdd(key, k => |
| | | { |
| | | EnsureCacheStorageAvailable(); |
| | | |
| | | TValue value = valueFactory(k); |
| | | return new CacheItem(this, valueFactory(k)); |
| | | }); |
| | | return cacheItem.Value; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Ensure that the cache has room for an additional item. |
| | | /// If there is not enough room anymore, force a removal of oldest |
| | | /// accessed items in the cache. |
| | | /// </summary> |
| | | private void EnsureCacheStorageAvailable() |
| | | { |
| | | if (dictionary.Count >= maximumSize) // >= because we want to add an item after this method |
| | | { |
| | | IList<TKey> keysToDelete = (from p in dictionary.ToArray() |
| | | where p.Key != null && p.Value != null |
| | | orderby p.Value.LastAccessed ascending |
| | | select p.Key).Take(reductionSize).ToList(); |
| | | |
| | | foreach (TKey key in keysToDelete) |
| | | { |
| | | CacheItem cacheItem; |
| | | dictionary.TryRemove(key, out cacheItem); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private class CacheItem |
| | | { |
| | | private MemoryCache<TKey, TValue> cache; |
| | | |
| | | public CacheItem(MemoryCache<TKey, TValue> cache, TValue value) |
| | | { |
| | | this.cache = cache; |
| | | this.Value = value; |
| | | |
| | | Accessed(); |
| | | } |
| | | |
| | | public TValue Value { get; private set; } |
| | | |
| | | public long LastAccessed { get; private set; } |
| | | |
| | | public void Accessed() |
| | | { |
| | | this.LastAccessed = Interlocked.Increment(ref cache.counter); |
| | | } |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Util/MemoryCache.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: da84d8440a462ad44b25f3e1ae8d0c36 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Reflection; |
| | | using System.Text; |
| | | |
| | | namespace Jace.Util |
| | | { |
| | | public static class TypeExtensions |
| | | { |
| | | /// <summary> |
| | | /// Get constructor for a given type matching with the parameter types provided. |
| | | /// </summary> |
| | | /// <param name="type">The type for witch a matching constructor must be found.</param> |
| | | /// <param name="parameters">The types of the parameters of the constructor.</param> |
| | | /// <returns>The matching constructor.</returns> |
| | | public static ConstructorInfo GetConstructor(this Type type, Type[] parameters) |
| | | { |
| | | IEnumerable<ConstructorInfo> constructors = |
| | | type.GetTypeInfo().DeclaredConstructors.Where(c => c.GetParameters().Length == parameters.Length); |
| | | |
| | | foreach (ConstructorInfo constructor in constructors) |
| | | { |
| | | bool parametersMatch = true; |
| | | |
| | | ParameterInfo[] constructorParameters = constructor.GetParameters(); |
| | | for (int i = 0; i < parameters.Length; i++) |
| | | { |
| | | if (parameters[i] != constructorParameters[i].ParameterType) |
| | | { |
| | | parametersMatch = false; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (parametersMatch) |
| | | return constructor; |
| | | } |
| | | |
| | | throw new Exception("No constructor was found matching with the provided parameters."); |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/Util/TypeExtensions.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: adedcd02cabd3f94d8be60ce8b3b4a1e |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | |
| | | namespace Jace |
| | | { |
| | | /// <summary> |
| | | /// An exception thrown when a formula must be executed with a variable that is not defined. |
| | | /// </summary> |
| | | public class VariableNotDefinedException : Exception |
| | | { |
| | | public VariableNotDefinedException(string message) |
| | | : base(message) |
| | | { |
| | | } |
| | | |
| | | public VariableNotDefinedException(string message, Exception innerException) |
| | | : base(message, innerException) |
| | | { |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Common/Jace/VariableNotDefinedException.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: b54823a4c30c0db4992f01e0a5b4bcb6 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
| | |
| | | if (!isInit) |
| | | { |
| | | InitComponent(showLog); |
| | | //effeid 为0也初始化成功,避免重复处理,在变更effectid时会重新初始化 |
| | | isInit = true; |
| | | } |
| | | else |
| | |
| | | { |
| | | this.gameObject.SetActive(true); |
| | | } |
| | | if (effectConfig.isSpine != 0) |
| | | //防范effeid 为0 |
| | | if (effectConfig != null && effectConfig.isSpine != 0) |
| | | { |
| | | PlayerTheSpineAnim(); |
| | | } |
| | |
| | | typeof(DamageNumConfig),
|
| | | typeof(DirtyWordConfig),
|
| | | typeof(FaceConfig),
|
| | | typeof(FightPowerRatioConfig),
|
| | | typeof(HeroLineupHaloConfig),
|
| | | typeof(HeroQualityLVConfig),
|
| | | typeof(ItemConfig),
|
| | |
| | | ClearConfigDictionary<DirtyWordConfig>();
|
| | | // 清空 FaceConfig 字典
|
| | | ClearConfigDictionary<FaceConfig>();
|
| | | // 清空 FightPowerRatioConfig 字典
|
| | | ClearConfigDictionary<FightPowerRatioConfig>();
|
| | | // 清空 HeroLineupHaloConfig 字典
|
| | | ClearConfigDictionary<HeroLineupHaloConfig>();
|
| | | // 清空 HeroQualityLVConfig 字典
|
New file |
| | |
| | | //--------------------------------------------------------
|
| | | // [Author]: YYL
|
| | | // [ Date ]: 2025年8月18日
|
| | | //--------------------------------------------------------
|
| | |
|
| | | using System.Collections.Generic;
|
| | | using System;
|
| | | using UnityEngine;
|
| | | using LitJson;
|
| | |
|
| | | public partial class FightPowerRatioConfig : ConfigBase<int, FightPowerRatioConfig>
|
| | | {
|
| | | static FightPowerRatioConfig()
|
| | | {
|
| | | // 访问过静态构造函数
|
| | | visit = true; |
| | | }
|
| | |
|
| | | public int LV;
|
| | | public float AtkRatio;
|
| | | public float MaxHPRatio;
|
| | | public float DefRatio;
|
| | | public float StunRateRatio;
|
| | | public float SuperHitRateRatio;
|
| | | public float ComboRateRatio;
|
| | | public float MissRateRatio;
|
| | | public float ParryRateRatio;
|
| | | public float SuckHPPerRatio;
|
| | | public float StunRateDefRatio;
|
| | | public float SuperHitRateDefRatio;
|
| | | public float ComboRateDefRatio;
|
| | | public float MissRateDefRatio;
|
| | | public float ParryRateDefRatio;
|
| | | public float SuckHPPerDefRatio;
|
| | | public float NormalSkillPerRatio;
|
| | | public float NormalSkillPerDefRatio;
|
| | | public float AngerSkillPerRatio;
|
| | | public float AngerSkillPerDefRatio;
|
| | | public float SuperDamPerRatio;
|
| | | public float SuperDamPerDefRatio;
|
| | | public float ShieldPerRatio;
|
| | | public float ShieldPerDefRatio;
|
| | |
|
| | | public override int LoadKey(string _key)
|
| | | {
|
| | | int key = GetKey(_key);
|
| | | return key;
|
| | | }
|
| | |
|
| | | public override void LoadConfig(string input)
|
| | | {
|
| | | try {
|
| | | string[] tables = input.Split('\t');
|
| | | int.TryParse(tables[0],out LV); |
| | |
|
| | | float.TryParse(tables[1],out AtkRatio); |
| | |
|
| | | float.TryParse(tables[2],out MaxHPRatio); |
| | |
|
| | | float.TryParse(tables[3],out DefRatio); |
| | |
|
| | | float.TryParse(tables[4],out StunRateRatio); |
| | |
|
| | | float.TryParse(tables[5],out SuperHitRateRatio); |
| | |
|
| | | float.TryParse(tables[6],out ComboRateRatio); |
| | |
|
| | | float.TryParse(tables[7],out MissRateRatio); |
| | |
|
| | | float.TryParse(tables[8],out ParryRateRatio); |
| | |
|
| | | float.TryParse(tables[9],out SuckHPPerRatio); |
| | |
|
| | | float.TryParse(tables[10],out StunRateDefRatio); |
| | |
|
| | | float.TryParse(tables[11],out SuperHitRateDefRatio); |
| | |
|
| | | float.TryParse(tables[12],out ComboRateDefRatio); |
| | |
|
| | | float.TryParse(tables[13],out MissRateDefRatio); |
| | |
|
| | | float.TryParse(tables[14],out ParryRateDefRatio); |
| | |
|
| | | float.TryParse(tables[15],out SuckHPPerDefRatio); |
| | |
|
| | | float.TryParse(tables[16],out NormalSkillPerRatio); |
| | |
|
| | | float.TryParse(tables[17],out NormalSkillPerDefRatio); |
| | |
|
| | | float.TryParse(tables[18],out AngerSkillPerRatio); |
| | |
|
| | | float.TryParse(tables[19],out AngerSkillPerDefRatio); |
| | |
|
| | | float.TryParse(tables[20],out SuperDamPerRatio); |
| | |
|
| | | float.TryParse(tables[21],out SuperDamPerDefRatio); |
| | |
|
| | | float.TryParse(tables[22],out ShieldPerRatio); |
| | |
|
| | | float.TryParse(tables[23],out ShieldPerDefRatio); |
| | | }
|
| | | catch (Exception exception)
|
| | | {
|
| | | Debug.LogError(exception);
|
| | | }
|
| | | }
|
| | | }
|
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Config/Configs/FightPowerRatioConfig.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 600fc786340faaf44aed165f5642df6d |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
| | |
| | | //--------------------------------------------------------
|
| | | // [Author]: YYL
|
| | | // [ Date ]: Wednesday, August 6, 2025
|
| | | // [ Date ]: 2025年8月17日
|
| | | //--------------------------------------------------------
|
| | |
|
| | | using System.Collections.Generic;
|
| | |
| | | public int AtkInheritPer;
|
| | | public int DefInheritPer;
|
| | | public int HPInheritPer;
|
| | | public string BatAttrDict;
|
| | | public Dictionary<int, int> BatAttrDict;
|
| | | public int[] FetterIDList;
|
| | | public float UIScale;
|
| | | public string Desc;
|
| | |
| | |
|
| | | int.TryParse(tables[11],out HPInheritPer);
|
| | |
|
| | | BatAttrDict = tables[12];
|
| | | BatAttrDict = ConfigParse.ParseIntDict(tables[12]); |
| | |
|
| | | if (tables[13].Contains("[")) |
| | | { |
| | |
| | | //--------------------------------------------------------
|
| | | // [Author]: YYL
|
| | | // [ Date ]: 2025年8月5日
|
| | | // [ Date ]: 2025年8月16日
|
| | | //--------------------------------------------------------
|
| | |
|
| | | using System.Collections.Generic;
|
| | |
| | |
|
| | | public int LV;
|
| | | public long EXP;
|
| | | public int MaxHP;
|
| | | public int Atk;
|
| | | public int Def;
|
| | |
|
| | | public override int LoadKey(string _key)
|
| | | {
|
| | |
| | | int.TryParse(tables[0],out LV);
|
| | |
|
| | | long.TryParse(tables[1],out EXP);
|
| | |
|
| | | int.TryParse(tables[2],out MaxHP); |
| | |
|
| | | int.TryParse(tables[3],out Atk); |
| | |
|
| | | int.TryParse(tables[4],out Def); |
| | | }
|
| | | catch (Exception exception)
|
| | | {
|
| | |
| | | |
| | | public partial class HeroTalentConfig : ConfigBase<int, HeroTalentConfig> |
| | | { |
| | | // public int Quality; |
| | | // public int AttrID; |
| | | |
| | | // Quality, List<HeroTalentConfig> |
| | | public static Dictionary<int, List<HeroTalentConfig>> configDics = new Dictionary<int, List<HeroTalentConfig>>(); |
| | | |
| | | protected override void OnConfigParseCompleted() |
| | |
| | | |
| | | public partial class PlayerPropertyConfig : ConfigBase<int, PlayerPropertyConfig> |
| | | { |
| | | public const int baseType = 1; //基础属性 |
| | | public const int fightType = 2; //战斗属性 |
| | | public const int fightAntiType = 3; //战斗抗性 |
| | | public const int specialType = 4; //特殊属性 |
| | | |
| | | // 按显示类型分 |
| | | private static Dictionary<int, List<int>> m_PlayerPropertyDict = new Dictionary<int, List<int>>(); |
| | | public static Dictionary<int, List<int>> playerPropertyDict |
| | |
| | | } |
| | | } |
| | | |
| | | private static int[] m_inheritAttrs;//攻防血 继承的百分比 |
| | | public static int[] inheritAttrs |
| | | { |
| | | get |
| | | { |
| | | if (m_inheritAttrs.IsNullOrEmpty()) |
| | | { |
| | | if (playerPropertyDict.ContainsKey(5)) |
| | | { |
| | | m_inheritAttrs = playerPropertyDict[5].ToArray(); |
| | | } |
| | | } |
| | | return m_inheritAttrs; |
| | | } |
| | | } |
| | | public static int[] inheritAttrs = new int[] { 13, 14, 15 }; |
| | | |
| | | private static int[] m_basePerAttrs; //攻防血 加成百分比 |
| | | public static int[] basePerAttrs |
| | | { |
| | | get |
| | | { |
| | | if (m_basePerAttrs.IsNullOrEmpty()) |
| | | { |
| | | if (playerPropertyDict.ContainsKey(6)) |
| | | { |
| | | m_basePerAttrs = playerPropertyDict[6].ToArray(); |
| | | } |
| | | } |
| | | return m_basePerAttrs; |
| | | } |
| | | } |
| | | |
| | | public const int baseType = 1; //基础属性 |
| | | public const int fightType = 2; //战斗属性 |
| | | public const int fightAntiType = 3; //战斗抗性 |
| | | public const int specialType = 4; //特殊属性 |
| | | //不同的功能表调用对应自己的功能含义和使用方式,如阵容光环配置就用在对应计算层 |
| | | public static int[] basePerAttrs = new int[] { 16, 17, 18 }; |
| | | |
| | | public static int[] baseAttrs = new int[] { 6, 7, 8 }; |
| | | |
| | | public static Dictionary<int, int> baseAttr2perDict = new Dictionary<int, int>() |
| | | { |
| | | { 6,16 }, |
| | | { 7,17 }, |
| | | { 8,18 } |
| | | }; |
| | | |
| | | private static Dictionary<int, List<int>> RefreshShowDict() |
| | | { |
| | | if (m_PlayerPropertyDict.IsNullOrEmpty()) |
| | |
| | | public static bool finishedLogin = false;
|
| | | public static event Action playerLoginOkEvent;
|
| | | //public static event Action mapInitOkEvent; 服务端通知场景切换成功
|
| | | |
| | |
|
| | |
|
| | | public override void Done(GameNetPackBasic vNetPack)
|
| | | {
|
| | |
| | | playerLoginOkEvent?.Invoke();
|
| | | }
|
| | | finishedLogin = true;
|
| | | if (PlayerDatas.Instance.baseData.FightPoint == 0)
|
| | | { |
| | | BattleManager.Instance.MainFightRequest(1, 1);
|
| | | }
|
| | | //if (mapInitOkEvent != null)
|
| | | //{
|
| | | // mapInitOkEvent();
|
| | |
| | | // B1 22 武将图鉴信息 #tagSCHeroInfo
|
| | |
|
| | | public class DTCB122_tagSCHeroInfo : DtcBasic {
|
| | | public override void Done(GameNetPackBasic vNetPack) {
|
| | | public override void Done(GameNetPackBasic vNetPack)
|
| | | {
|
| | | base.Done(vNetPack);
|
| | | HB122_tagSCHeroInfo vNetData = vNetPack as HB122_tagSCHeroInfo;
|
| | | HeroUIManager.Instance.UpdateHeroCollectInfo(vNetData);
|
| | | }
|
| | | }
|
| | |
| | | |
| | | public const int activityType = (int)OpenServerActivityCenter.ActivityType.AT_Activity2; |
| | | public const int activityID = (int)NewDayActivityID.CustomizedGiftWin; |
| | | public static Operation operaType = Operation.default35; |
| | | public static OperationType operaType = OperationType.default35; |
| | | |
| | | public int actNum; //对应界面 |
| | | public event Action UpdateRechargeGiftActEvent; |
| | |
| | | } |
| | | } |
| | | |
| | | private void OperationEndEvent(Operation type, int state) |
| | | private void OperationEndEvent(OperationType type, int state) |
| | | { |
| | | if (type == operaType && state == 0) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | private void OperationAdvanceEvent(Operation type) |
| | | private void OperationAdvanceEvent(OperationType type) |
| | | { |
| | | if (type == operaType) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | private void OperationStartEvent(Operation type, int state) |
| | | private void OperationStartEvent(OperationType type, int state) |
| | | { |
| | | if (type == operaType && state == 0) |
| | | { |
| | |
| | | |
| | | if (showFightPower < 0) |
| | | { |
| | | fightPowerNum.text = UIHelper.AppendColor(TextColType.Red, $"-{UIHelper.ReplaceLargeNum(showFightPower)}", false); |
| | | fightPowerNum.text = UIHelper.AppendColor(TextColType.Red, $"-{UIHelper.ReplaceLargeNum(Math.Abs(showFightPower))}", false); |
| | | cmpResult = 2; |
| | | } |
| | | else |
| | | { |
| | | cmpResult = showFightPower > 0 ? 1 : 0; |
| | | fightPowerNum.text = UIHelper.AppendColor(TextColType.Green, $"+{UIHelper.ReplaceLargeNum(showFightPower)}", false); |
| | | |
| | | } |
| | | } |
| | | |
| | |
| | |
|
| | | protected override void OnPreOpen()
|
| | | {
|
| | |
|
| | | // 通知主战场暂停
|
| | | BattleManager.Instance.storyBattleField.IsPause = true;
|
| | | EquipModel.Instance.OnEquipOPResultAction += OnRefreshItem;
|
| | | Display();
|
| | |
|
| | | // if (EquipModel.Instance.newEquipIDToGuideID.ContainsKey(EquipModel.Instance.selectFloorEquip.itemId))
|
| | | // {
|
| | | // // if (!NewBieCenter.Instance.IsGuideCompleted(EquipModel.Instance.newEquipIDToGuideID[EquipModel.Instance.selectFloorEquip.itemId]))
|
| | |
| | | |
| | | public class EquipModel : GameSystemManager<EquipModel> |
| | | { |
| | | public const int TotleEquip = 12; //装备栏大小 |
| | | public bool waitEquipOPPack = false; |
| | | public event Action<bool, int > OnEquipOPResultAction; //是否换上了新装备且分解了 装备索引 |
| | | public event Action<bool, int> OnEquipOPResultAction; //是否换上了新装备且分解了 装备索引 |
| | | public event Action<List<int>, RectTransform> OnItemDropEvent; |
| | | |
| | | //用于飘动逻辑 |
| | |
| | | } |
| | | |
| | | void OnDropEvent(string guid, BattleDrops drops, Action action) |
| | | { |
| | | { |
| | | NotifyItemDrop(drops.dropItemPackIndex, drops.rectTransform); |
| | | action?.Invoke(); |
| | | } |
| | |
| | | else |
| | | { |
| | | if (!UIManager.Instance.IsOpened<EquipExchangeWin>()) |
| | | { |
| | | { |
| | | UIManager.Instance.OpenWindow<EquipExchangeWin>(); |
| | | } |
| | | } |
| | |
| | | { |
| | | if (waitEquipOP.Count == 0) |
| | | return null; |
| | | |
| | | |
| | | ItemModel item = PackManager.Instance.GetItemByIndex(PackType.DropItem, waitEquipOP.Dequeue()); |
| | | if (AutoFightModel.Instance.isAutoAttack) |
| | | { |
| | |
| | | return null; |
| | | |
| | | } |
| | | |
| | | |
| | | return item; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | public bool IsEquip(int itemID) |
| | | { |
| | | { |
| | | return ItemConfig.Get(itemID).EquipPlace != 0; |
| | | } |
| | | |
| | | public ItemModel GetEquip(int index) |
| | | { |
| | | return PackManager.Instance.GetItemByIndex(PackType.Equip, index); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | public enum HeroAttrType |
| | | { |
| | | // 生命 |
| | | hp, |
| | | // 攻击力 |
| | | attack, |
| | | attack = 6, |
| | | // 防御力 |
| | | defense, |
| | | defense = 7, |
| | | // 生命 |
| | | hp = 8, |
| | | //眩晕概率 |
| | | stunRate, |
| | | //暴击概率 |
| | |
| | | { |
| | | |
| | | // 觉醒配置 |
| | | public HeroAwakeConfig awakeConfig |
| | | { |
| | | get |
| | | { |
| | | return HeroAwakeConfig.GetHeroAwakeConfig(heroId, awakeLevel); |
| | | } |
| | | } |
| | | public HeroAwakeConfig awakeConfig { get; private set; } |
| | | |
| | | |
| | | // 品质觉醒配置 |
| | | public HeroQualityAwakeConfig qualityAwakeConfig |
| | | { |
| | | get |
| | | { |
| | | return HeroQualityAwakeConfig.GetQualityAwakeConfig(Quality, awakeLevel); |
| | | } |
| | | } |
| | | public HeroQualityAwakeConfig qualityAwakeConfig { get; private set; } |
| | | |
| | | // 武将觉醒等级 |
| | | public int awakeLevel |
| | |
| | | } |
| | | } |
| | | |
| | | protected int GetIFByInheritAwakePercent(HeroAttrType attrType) |
| | | { |
| | | // YYL TODO |
| | | return 0; |
| | | } |
| | | |
| | | Dictionary<int, int> awakeAttrs = new Dictionary<int, int>(); |
| | | //计算觉醒属性 |
| | | public void RefreshAwakeAttr() |
| | | { |
| | | awakeAttrs.Clear(); |
| | | |
| | | for (int i = 0; i < awakeLevel; i++) |
| | | { |
| | | var tmpAwakeConfig = HeroAwakeConfig.GetHeroAwakeConfig(heroId, awakeLevel); |
| | | if (tmpAwakeConfig == null) |
| | | continue; |
| | | for(int j = 0; j < tmpAwakeConfig.AttrIDList.Length; j++) |
| | | { |
| | | int id = tmpAwakeConfig.AttrIDList[j]; |
| | | if (!breakAttrs.ContainsKey(id)) |
| | | { |
| | | breakAttrs.Add(id, tmpAwakeConfig.AttrValueList[j]); |
| | | } |
| | | else |
| | | { |
| | | breakAttrs[id] += tmpAwakeConfig.AttrValueList[j]; |
| | | } |
| | | } |
| | | |
| | | if (tmpAwakeConfig.SkillID != 0) |
| | | { |
| | | var skillConfig = SkillConfig.Get(tmpAwakeConfig.SkillID); |
| | | if (allSkillTypeIDToID.ContainsKey(skillConfig.SkillTypeID)) |
| | | { |
| | | var tmpSkillConfig = SkillConfig.Get(allSkillTypeIDToID[skillConfig.SkillTypeID]); |
| | | if (skillConfig.SkillID > tmpSkillConfig.SkillID) |
| | | { |
| | | //取最大技能 |
| | | allSkillTypeIDToID[skillConfig.SkillTypeID] = tmpAwakeConfig.SkillID; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | allSkillTypeIDToID[skillConfig.SkillTypeID] = tmpAwakeConfig.SkillID; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | public int GetAwakeAttrValue(int attrType) |
| | | { |
| | | int value = 0; |
| | | awakeAttrs.TryGetValue(attrType, out value); |
| | | return value; |
| | | } |
| | | |
| | | public int GetAwakeAttrPer(int attrType) |
| | | { |
| | | if (PlayerPropertyConfig.baseAttr2perDict.ContainsKey(attrType)) |
| | | { |
| | | var pertype = PlayerPropertyConfig.baseAttr2perDict[attrType]; |
| | | return awakeAttrs.ContainsKey(pertype) ? awakeAttrs[pertype] : 0; |
| | | } |
| | | return 0; |
| | | } |
| | | } |
| | |
| | | |
| | | |
| | | //武将突破:武将升级后需要突破才能继续升级,突破可获得潜能 |
| | | using System.Collections.Generic; |
| | | |
| | | public partial class HeroInfo |
| | | { |
| | | // 突破配置 |
| | | public HeroBreakConfig breakConfig |
| | | { |
| | | get |
| | | { |
| | | return HeroBreakConfig.GetHeroBreakConfig(heroId, breakLevel); |
| | | } |
| | | } |
| | | public HeroBreakConfig breakConfig { get; private set;} |
| | | |
| | | // 品质突破配置 |
| | | public HeroQualityBreakConfig qualityBreakConfig; |
| | | public HeroQualityBreakConfig qualityBreakConfig { get; private set;} |
| | | |
| | | // 武将突破等级 |
| | | public int breakLevel |
| | |
| | | } |
| | | } |
| | | |
| | | protected int GetBreakCultivationPercent(HeroAttrType attrType) |
| | | Dictionary<int, int> breakAttrs = new Dictionary<int, int>(); //潜能属性id:潜能值 |
| | | //计算潜能属性 |
| | | public void RefreshBreakAttr() |
| | | { |
| | | // YYL TODO |
| | | return 0; |
| | | } |
| | | |
| | | protected int GetIFByInheritBreakPercent(HeroAttrType attrType) |
| | | { |
| | | // YYL TODO |
| | | return 0; |
| | | } |
| | | |
| | | breakAttrs.Clear(); |
| | | for (int i = 0; i < breakLevel; i++) |
| | | { |
| | | var tmpBreakConfig = HeroBreakConfig.GetHeroBreakConfig(heroId, i); |
| | | if (tmpBreakConfig == null) |
| | | continue; |
| | | for(int j = 0; j < tmpBreakConfig.AttrIDList.Length; j++) |
| | | { |
| | | int id = tmpBreakConfig.AttrIDList[j]; |
| | | if (!breakAttrs.ContainsKey(id)) |
| | | { |
| | | breakAttrs.Add(id, tmpBreakConfig.AttrValueList[j]); |
| | | } |
| | | else |
| | | { |
| | | breakAttrs[id] += tmpBreakConfig.AttrValueList[j]; |
| | | } |
| | | } |
| | | |
| | | if (tmpBreakConfig.SkillID != 0) |
| | | { |
| | | var skillConfig = SkillConfig.Get(tmpBreakConfig.SkillID); |
| | | if (skillConfig == null) continue; |
| | | if (allSkillTypeIDToID.ContainsKey(skillConfig.SkillTypeID)) |
| | | { |
| | | var tmpSkillConfig = SkillConfig.Get(allSkillTypeIDToID[skillConfig.SkillTypeID]); |
| | | if (skillConfig.SkillID > tmpSkillConfig.SkillID) |
| | | { |
| | | //取最大技能 |
| | | allSkillTypeIDToID[skillConfig.SkillTypeID] = tmpBreakConfig.SkillID; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | allSkillTypeIDToID[skillConfig.SkillTypeID] = tmpBreakConfig.SkillID; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | public int GetBreakAttrValue(int attrType) |
| | | { |
| | | int value = 0; |
| | | breakAttrs.TryGetValue(attrType, out value); |
| | | return value; |
| | | } |
| | | |
| | | public int GetBreakAttrPer(int attrType) |
| | | { |
| | | if (PlayerPropertyConfig.baseAttr2perDict.ContainsKey(attrType)) |
| | | { |
| | | var pertype = PlayerPropertyConfig.baseAttr2perDict[attrType]; |
| | | return breakAttrs.ContainsKey(pertype) ? breakAttrs[pertype] : 0; |
| | | } |
| | | return 0; |
| | | } |
| | | } |
| | |
| | | |
| | | |
| | | |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | |
| | | //羁绊:上阵后的武将组合可激活羁绊 |
| | | public partial class HeroInfo |
| | | { |
| | | // 羁绊配置 |
| | | public HeroFetterConfig fetterConfig; |
| | | Dictionary<int, int> fetterAttrs = new Dictionary<int, int>(); //羁绊属性ID:属性值 |
| | | |
| | | |
| | | //不同阵容羁绊属性不同,实时计算,与其他缓存的不同 |
| | | public void RefreshFetterAttrsWhenCalcPower(TeamType teamType) |
| | | { |
| | | fetterAttrs.Clear(); |
| | | var list = GetActiveFetter(heroConfig, TeamManager.Instance.GetTeam(teamType)); |
| | | |
| | | foreach (var id in list) |
| | | { |
| | | var config = HeroFetterConfig.Get(id); |
| | | var attrIDs = config.AttrIDList; |
| | | var attrValues = config.AttrValueList; |
| | | for (int i = 0; i < attrIDs.Length; i++) |
| | | { |
| | | if (!fetterAttrs.ContainsKey(attrIDs[i])) |
| | | { |
| | | fetterAttrs.Add(attrIDs[i], attrValues[i]); |
| | | } |
| | | else |
| | | { |
| | | fetterAttrs[attrIDs[i]] += attrValues[i]; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | public int GetFetterAttrValue(int attrType) |
| | | { |
| | | int value = 0; |
| | | fetterAttrs.TryGetValue(attrType, out value); |
| | | return value; |
| | | } |
| | | |
| | | public int GetFetterAttrPer(int attrType) |
| | | { |
| | | if (PlayerPropertyConfig.baseAttr2perDict.ContainsKey(attrType)) |
| | | { |
| | | var pertype = PlayerPropertyConfig.baseAttr2perDict[attrType]; |
| | | return fetterAttrs.ContainsKey(pertype) ? fetterAttrs[pertype] : 0; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | public List<int> GetActiveFetter(HeroConfig config, TeamBase teamBase) |
| | | { |
| | | List<int> list = new List<int>(); |
New file |
| | |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | |
| | | public partial class HeroInfo |
| | | { |
| | | //继承百分比对应三围,对应属性条目表里的ID |
| | | Dictionary<int, int> inheritPer |
| | | { |
| | | get |
| | | { |
| | | return new Dictionary<int, int>() { |
| | | { 6, heroConfig.AtkInheritPer }, |
| | | { 7, heroConfig.DefInheritPer }, |
| | | { 8, heroConfig.HPInheritPer }, |
| | | }; |
| | | } |
| | | } |
| | | |
| | | public int GetInheritAttrPer(int attrType) |
| | | { |
| | | return inheritPer.ContainsKey(attrType) ? inheritPer[attrType] : 0; |
| | | } |
| | | |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/System/Hero/HeroInfo.InheritPer.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: 43bccdd0f6575254591fc49d33072614 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
| | |
| | | using System.Collections.Generic; |
| | | using UnityEngine; |
| | | |
| | | //阵容布阵 |
| | | public partial class HeroInfo |
| | | { |
| | | public Dictionary<TeamType, KeyValuePair<int, int>> GetTeamTypeShapeTypePositionDict() |
| | |
| | | teamTypeShapeTypePositionDict.Add((TeamType)teamType, shapeTypePosition); |
| | | } |
| | | } |
| | | |
| | | |
| | | return teamTypeShapeTypePositionDict; |
| | | } |
| | | } |
| | |
| | | |
| | | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | |
| | | public partial class HeroInfo |
| | | { |
| | | // 战斗属性的触发几率计算是1对1的,可同时触发多个属性且多次触发,触发几率不会随着目标数量多少而改变,只会根据同一目标的触发次数增多而降低。 |
| | | // 即在一回合内,同一个目标反击、连击、击晕、暴击、闪避可以同时并多次触发,触发几率随机触发次数的增加而降低,每个属性开公式来(参数:触发几率、抵抗几率、已触发次数) |
| | | // 优先判断是否命中,必中后同时判断此次攻击是否连击、击晕、暴击生效 |
| | | // 反击时必命中目标 |
| | | // 武将属性需时时计算,根据技能、BUFF、装备等属性来源改变而改变 |
| | | |
| | | // 基础属性 |
| | | // 生命 |
| | | public int hp = 0; |
| | | // 攻击力 |
| | |
| | | public int shieldSkillReduce; |
| | | |
| | | |
| | | |
| | | //计算个人/职业/种族养成属性加成 |
| | | public void CalculateProperties() |
| | | { |
| | | // 武将单体属性,根据继承比例,从全体属性继承得到 |
| | | // 例如:武将攻击力= |
| | | // [(装备基础固定值+其它模块的固定值)* (1+初始加成%+武将升级加成%+武将突破加成%+武将吞噬星级加成%+图鉴加成%)] |
| | | // * |
| | | // [ 继承比例*(1+羁绊加成%+潜能加成%+天赋加成%+觉醒效果加成%)] |
| | | hp = GetProperties(HeroAttrType.hp); |
| | | attack = GetProperties(HeroAttrType.attack); |
| | | defense = GetProperties(HeroAttrType.defense); |
| | | stunRate = GetProperties(HeroAttrType.stunRate); |
| | | critRate = GetProperties(HeroAttrType.critRate); |
| | | comboRate = GetProperties(HeroAttrType.comboRate); |
| | | blockRate = GetProperties(HeroAttrType.blockRate); |
| | | counterAttackRate = GetProperties(HeroAttrType.counterAttackRate); |
| | | recoverRate = GetProperties(HeroAttrType.recoverRate); |
| | | stunResist = GetProperties(HeroAttrType.stunResist); |
| | | critResist = GetProperties(HeroAttrType.critResist); |
| | | comboResist = GetProperties(HeroAttrType.comboResist); |
| | | blockResist = GetProperties(HeroAttrType.blockResist); |
| | | counterAttackResist = GetProperties(HeroAttrType.counterAttackResist); |
| | | recoverResist = GetProperties(HeroAttrType.recoverResist); |
| | | } |
| | | allSkillTypeIDToID.Clear(); |
| | | var skill = SkillConfig.Get(heroConfig.AtkSkillID); |
| | | if (skill != null) |
| | | { |
| | | allSkillTypeIDToID[skill.SkillTypeID] = heroConfig.AtkSkillID; |
| | | } |
| | | skill = SkillConfig.Get(heroConfig.AngerSkillID); |
| | | if (skill != null) |
| | | { |
| | | allSkillTypeIDToID[skill.SkillTypeID] = heroConfig.AngerSkillID; |
| | | } |
| | | |
| | | protected int GetProperties(HeroAttrType attrType) |
| | | { |
| | | return GetStableProperties(attrType) |
| | | * GetCultivationPercent(attrType) |
| | | * GetInheritRate(attrType) |
| | | * GetTotalPercent(attrType); |
| | | RefreshTalentAttr(); |
| | | RefreshBreakAttr(); |
| | | RefreshAwakeAttr(); |
| | | } |
| | | |
| | | |
| | | // 固定值属性 |
| | | public int GetStableProperties(HeroAttrType attrType) |
| | | { |
| | | int stableValue = 0; |
| | | stableValue += GetEquipStableProperties(attrType); |
| | | return stableValue; |
| | | } |
| | | |
| | | // 培养百分比 |
| | | public int GetCultivationPercent(HeroAttrType attrType) |
| | | long tmpFightPower = 0; |
| | | public long CalculatePower(bool forceRefresh = true) |
| | | { |
| | | int cultivationPercent = 100; |
| | | cultivationPercent += GetQualityCultivationPercent(attrType);//初始加成根据武将品质决定,不同品质武将初始加成不同 HeroInfo.Quality.cs |
| | | cultivationPercent += GetLevelCultivationPercent(attrType);// 等级给的百分比 HeroInfo.Level.cs |
| | | cultivationPercent += GetBreakCultivationPercent(attrType);// 突破给的百分比 HeroInfo.Break.cs |
| | | cultivationPercent += GetStarCultivationPercent(attrType);// 吞噬星级给的百分比 HeroInfo.Star.cs |
| | | return cultivationPercent; |
| | | } |
| | | |
| | | // 被继承比例影响的百分比属性 |
| | | public int GetTotalPercent(HeroAttrType attrType) |
| | | { |
| | | // (1+羁绊加成%+潜能加成%+天赋加成%+觉醒效果加成%) |
| | | |
| | | int IFByInheritPercent = 100; |
| | | // IFByInheritPercent += GetIFByInheritFetterPercent(attrType); //羁绊加成 HeroInfo.Fetter |
| | | // IFByInheritPercent += GetIFByInheritBreakPercent(attrType); //潜能加成 HeroInfo.Break |
| | | // IFByInheritPercent += GetIFByInheritTalentPercent(attrType); //天赋加成 HeroInfo.Talent |
| | | // IFByInheritPercent += GetIFByInheritAwakePercent(attrType); //觉醒加成 HeroInfo.Awake |
| | | return IFByInheritPercent; |
| | | } |
| | | |
| | | public int CalculatePower() |
| | | { |
| | | // 暂行 |
| | | return hp + |
| | | attack + |
| | | defense + |
| | | stunRate + |
| | | critRate + |
| | | comboRate + |
| | | blockRate + |
| | | counterAttackRate + |
| | | recoverRate + |
| | | stunResist + |
| | | critResist + |
| | | comboResist + |
| | | blockResist + |
| | | counterAttackResist + |
| | | recoverResist; |
| | | if (forceRefresh || tmpFightPower == 0) |
| | | { |
| | | tmpFightPower = FightPowerManager.Instance.GetHeroFightPower(this); |
| | | } |
| | | return tmpFightPower; |
| | | } |
| | | |
| | | |
| | | //上阵属性:攻防血 |
| | | public int GetOnBattleAddPer() |
| | | { |
| | | { |
| | | return qualityConfig.InitAddPer + qualityConfig.LVAddPer * heroLevel + qualityConfig.BreakLVAddPer * breakLevel + qualityConfig.StarAddPer * heroStar; |
| | | } |
| | | |
| | | public int GetLineupLVAddPer() |
| | | { |
| | | return qualityConfig.LVAddPer * heroLevel; |
| | | } |
| | | |
| | | public int GetLineupBreakLVAddPer() |
| | | { |
| | | return qualityConfig.BreakLVAddPer * breakLevel; |
| | | } |
| | | |
| | | public int GetLineupStarAddPer() |
| | | { |
| | | return qualityConfig.StarAddPer * heroStar; |
| | | } |
| | | |
| | | //额外配置的百分百比加成 三围对应的 百分比加成 |
| | | public int GetSelfAddPer(int attrType) |
| | | { |
| | | if (PlayerPropertyConfig.baseAttr2perDict.ContainsKey(attrType)) |
| | | { |
| | | var pertype = PlayerPropertyConfig.baseAttr2perDict[attrType]; |
| | | return heroConfig.BatAttrDict.ContainsKey(pertype) ? heroConfig.BatAttrDict[pertype] : 0; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | public int GetSelfAddValue(int attrType) |
| | | { |
| | | return heroConfig.BatAttrDict.ContainsKey(attrType) ? heroConfig.BatAttrDict[attrType] : 0; |
| | | } |
| | | |
| | | } |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | |
| | | |
| | | |
| | | //武将天赋:升星获得天赋,可洗练 |
| | | public partial class HeroInfo |
| | | { |
| | | protected int GetIFByInheritTalentPercent(HeroAttrType attrType) |
| | | |
| | | public int heroStar |
| | | { |
| | | get |
| | | { |
| | | if (itemHero == null) |
| | | return 0; |
| | | return itemHero.GetUseDataFirstValue(72); |
| | | } |
| | | } |
| | | |
| | | public List<HeroTalentInfo> talentList = new List<HeroTalentInfo>(); |
| | | |
| | | |
| | | Dictionary<int, int> talentAttrDic = new Dictionary<int, int>(); //属性ID : 天赋属性值 |
| | | // 71 # 英雄天赋ID列表 |
| | | // 73 # 英雄天赋ID等级列表,对应71天赋ID的等级 |
| | | // 75 # 英雄天赋洗炼锁定索引列表,对应71天赋ID索引 |
| | | // 77 # 英雄天赋洗炼随机ID列表 |
| | | // 79 # 英雄觉醒时随机天赋选项ID列表 |
| | | protected void RefreshTalentAttr() |
| | | { |
| | | // YYL TODO |
| | | return 0; |
| | | // 71 # 英雄天赋ID列表 |
| | | List<int> talentIDList = itemHero.GetUseData(71); |
| | | // // 73 # 英雄天赋ID等级列表,对应71天赋ID的等级 |
| | | List<int> talentLvList = itemHero.GetUseData(73); |
| | | talentAttrDic.Clear(); |
| | | |
| | | for (int i = 0; i < talentIDList.Count; i++) |
| | | { |
| | | if (talentIDList[i] == 0) |
| | | { |
| | | continue; |
| | | } |
| | | var config = HeroTalentConfig.Get(talentIDList[i]); |
| | | if (!talentAttrDic.ContainsKey(config.AttrID)) |
| | | { |
| | | //天赋属性,值*天赋等级 |
| | | talentAttrDic[config.AttrID] = config.AttrValue * talentLvList[i]; |
| | | } |
| | | else |
| | | { |
| | | talentAttrDic[config.AttrID] += config.AttrValue * talentLvList[i]; |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | public int GetTalentAttrValue(int attrType) |
| | | { |
| | | int value = 0; |
| | | talentAttrDic.TryGetValue(attrType, out value); |
| | | return value; |
| | | } |
| | | |
| | | public int GetTalentAttrPer(int attrType) |
| | | { |
| | | if (PlayerPropertyConfig.baseAttr2perDict.ContainsKey(attrType)) |
| | | { |
| | | var pertype = PlayerPropertyConfig.baseAttr2perDict[attrType]; |
| | | return talentAttrDic.ContainsKey(pertype) ? talentAttrDic[pertype] : 0; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | } |
| | |
| | | public int heroId; |
| | | |
| | | // 武将配置 |
| | | public HeroConfig heroConfig; |
| | | public HeroConfig heroConfig { get; private set; } |
| | | public ItemModel itemHero; //引用背包里的 数据同步 |
| | | |
| | | public HeroCountry heroCountry |
| | |
| | | } |
| | | } |
| | | |
| | | // 品质配置 |
| | | public HeroQualityConfig qualityConfig { get; private set; } |
| | | |
| | | public int Quality |
| | | { |
| | | get |
| | | { |
| | | return heroConfig.Quality; |
| | | } |
| | | } |
| | | |
| | | // 武将等级 |
| | | public int heroLevel |
| | | { |
| | | get |
| | | { |
| | | if (itemHero == null) |
| | | return 0; |
| | | return itemHero.GetUseDataFirstValue(70); |
| | | } |
| | | } |
| | | // 优先功能提醒类型:1觉醒 2升级 3突破 4升星 |
| | | // 优先顺序: |
| | | public int funcState |
| | |
| | | } |
| | | |
| | | |
| | | |
| | | public List<HeroTalentInfo> talentList = new List<HeroTalentInfo>(); |
| | | //已学习的所有技能取最高级的技能 |
| | | Dictionary<int, int> allSkillTypeIDToID = new Dictionary<int, int>(); //技能类型ID: 最高技能ID |
| | | |
| | | |
| | | public HeroInfo(ItemModel _itemHero) |
| | |
| | | UpdateHero(_itemHero); |
| | | } |
| | | |
| | | #if UNITY_EDITOR |
| | | public HeroInfo() |
| | | { |
| | | heroId = 520001; // 默认英雄ID |
| | | |
| | | heroConfig = HeroConfig.Get(heroId); |
| | | qualityConfig = HeroQualityConfig.Get(Quality); |
| | | qualityBreakConfig = HeroQualityBreakConfig.GetQualityBreakConfig(Quality, awakeLevel); |
| | | CalculateProperties(); |
| | | } |
| | | #endif |
| | | |
| | | |
| | | public void UpdateHero(ItemModel _itemHero) |
| | |
| | | // HeroConfigUtility |
| | | heroId = itemHero.config.ID; |
| | | |
| | | |
| | | InitConfigs(); |
| | | // 71 # 英雄天赋ID列表 |
| | | // List<int> talentSkillList = itemHero.GetUseData(71); |
| | | // // 73 # 英雄天赋ID等级列表,对应71天赋ID的等级 |
| | | // List<int> talentLvList = itemHero.GetUseData(73); |
| | | // // 75 # 英雄天赋洗炼锁定索引列表,对应71天赋ID索引 |
| | | // List<int> talentLockList = itemHero.GetUseData(75); |
| | | |
| | | |
| | | // if (talentLockList.Count != talentLvList.Count || talentLvList.Count != talentSkillList.Count) |
| | | // { |
| | | // Debug.LogError("天赋ID列表及后续的数据数量没对上"); |
| | | // } |
| | | |
| | | // // 天赋 |
| | | // talentList.Clear(); |
| | | // for (int i = 0; i < talentSkillList.Count; i++) |
| | | // { |
| | | // talentList.Add(new HeroTalentInfo(this, talentSkillList[i], talentLvList[i], talentLockList[i])); |
| | | // } |
| | | |
| | | CalculateProperties(); |
| | | // // 羁绊 |
| | | // fetterInfoList.Clear(); |
| | | // for (int i = 0; i < heroConfig.FetterIDList.Length; i++) |
| | |
| | | // fetterInfoList.Add(new HeroFetterInfo(this, heroConfig.FetterIDList[i])); |
| | | // } |
| | | |
| | | // 77 # 英雄天赋洗炼随机ID列表 |
| | | // 79 # 英雄觉醒时随机天赋选项ID列表 |
| | | // 80 # 主阵型上阵位置 |
| | | } |
| | | |
| | |
| | | { |
| | | // 武将配置 |
| | | heroConfig = HeroConfig.Get(heroId); |
| | | |
| | | |
| | | // 品质配置 |
| | | qualityConfig = HeroQualityConfig.Get(Quality); |
| | | |
| | | // 品质突破配置 |
| | | qualityBreakConfig = HeroQualityBreakConfig.GetQualityBreakConfig(Quality, breakLevel); |
| | | |
| | | breakConfig = HeroBreakConfig.GetHeroBreakConfig(heroId, breakLevel); |
| | | awakeConfig = HeroAwakeConfig.GetHeroAwakeConfig(heroId, awakeLevel); |
| | | qualityAwakeConfig = HeroQualityAwakeConfig.GetQualityAwakeConfig(Quality, awakeLevel); |
| | | |
| | | } |
| | | |
| | | public int GetInheritRate(HeroAttrType attrType) |
| | | { |
| | | return heroConfig.GetInheritPercent(attrType); |
| | | } |
| | | |
| | | //是否上x阵 81 # 所在阵容信息列表 [阵容类型*10000+阵型类型*100+位置编号, ...] |
| | | |
| | | |
| | | //是否上x阵 服务端队伍 |
| | | public bool IsInTeamByTeamType(TeamType teamType) |
| | | { |
| | | var list = itemHero.GetUseData(81); |
| | | if (list != null && list.Count > 0) |
| | | { |
| | | var index = list.FindIndex((item) => item / 10000 == (int)teamType); |
| | | if (index >= 0) |
| | | { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | return TeamManager.Instance.GetTeam(teamType).HasHeroInServer(itemHero.guid); |
| | | } |
| | | |
| | | public long GetSkillsFightPower() |
| | | { |
| | | long fightPower = 0; |
| | | foreach (var skillID in allSkillTypeIDToID.Values) |
| | | { |
| | | fightPower += SkillConfig.Get(skillID).FightPower; |
| | | } |
| | | return fightPower; |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | heroList.Sort((a, b) => |
| | | { |
| | | int power1 = a.CalculatePower(); |
| | | int power2 = b.CalculatePower(); |
| | | long power1 = a.CalculatePower(false); |
| | | long power2 = b.CalculatePower(false); |
| | | |
| | | if (power1 == power2) |
| | | { |
| | |
| | | |
| | | public void Display(int index) |
| | | { |
| | | Int2 result = HeroUIManager.Instance.GetMaxCountHeroCountry(HeroUIManager.Instance.selectTeamType); |
| | | Int2 result = HeroUIManager.Instance.GetMaxCountHeroCountry(HeroUIManager.Instance.selectTeamType, true); |
| | | |
| | | var config = HeroLineupHaloConfig.GetConfig(result.x, result.y); |
| | | bool sameCountry = result.x == (index + 1); |
| | |
| | | scroller.OnRefreshCell += OnRefreshCell; |
| | | CreateScroller(); |
| | | |
| | | Int2 result = HeroUIManager.Instance.GetMaxCountHeroCountry(HeroUIManager.Instance.selectTeamType); |
| | | Int2 result = HeroUIManager.Instance.GetMaxCountHeroCountry(HeroUIManager.Instance.selectTeamType, true); |
| | | |
| | | var config = HeroLineupHaloConfig.GetConfig(result.x, result.y); |
| | | if (config == null) |
| | |
| | | } |
| | | if (nextQualityBreakConfig.SkillID != 0) |
| | | { |
| | | attrStrArr.Add(SkillConfig.Get(nextQualityBreakConfig.SkillID).Description); |
| | | attrStrArr.Add(SkillConfig.Get(nextQualityBreakConfig.SkillID)?.Description); |
| | | } |
| | | potentialText.text = Language.Get("L1100", Language.Get("herocard56"), string.Join(Language.Get("L1112"), attrStrArr)); |
| | | } |
| | |
| | | |
| | | private bool m_IsToggleOn = false; |
| | | private bool isToggleOn |
| | | { |
| | | { |
| | | get { return m_IsToggleOn; } |
| | | set |
| | | { |
| | |
| | | HeroUIManager.Instance.SortHeroOnTeamList(); |
| | | heroListScroller.OnRefreshCell += OnRefreshCell; |
| | | HeroUIManager.Instance.OnTeamPosChangeEvent += TeamChangeEvent; |
| | | TeamManager.Instance.OnTeamChange += OnTeamChange; |
| | | CreateScroller(); |
| | | Refresh(); |
| | | } |
| | |
| | | CancelCurrentTask(); |
| | | heroListScroller.OnRefreshCell -= OnRefreshCell; |
| | | HeroUIManager.Instance.OnTeamPosChangeEvent -= TeamChangeEvent; |
| | | TeamManager.Instance.OnTeamChange -= OnTeamChange; |
| | | TeamManager.Instance.GetTeam(HeroUIManager.Instance.selectTeamType).RestoreTeam(); |
| | | } |
| | | |
| | |
| | | fiterManager.Display(0, HeroUIManager.Instance.selectTeamPosJob, HeroUIManager.Instance.selectTeamPosCountry, SelectJobCountry); |
| | | |
| | | |
| | | fightPowerText.text = "1234k"; |
| | | fightPowerText.text = UIHelper.ReplaceLargeArtNum(FightPowerManager.Instance.GetTeamFightPower(HeroUIManager.Instance.selectTeamType, true)); |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | void RefreshFlyHead() |
| | |
| | | } |
| | | |
| | | void RefreshEmptyTip() |
| | | { |
| | | { |
| | | if (HeroUIManager.Instance.heroOnTeamSortList.Count <= 0) |
| | | { |
| | | heroListEmpty.SetActive(true); |
| | |
| | | //上阵武将国家光环激活 |
| | | void RefreshOnTeamCountry(bool playEffect = false) |
| | | { |
| | | Int2 result = HeroUIManager.Instance.GetMaxCountHeroCountry(HeroUIManager.Instance.selectTeamType); |
| | | Int2 result = HeroUIManager.Instance.GetMaxCountHeroCountry(HeroUIManager.Instance.selectTeamType, true); |
| | | |
| | | var config = HeroLineupHaloConfig.GetConfig(result.x, result.y); |
| | | if (config == null) |
| | |
| | | sequence.onComplete = () => { flyHead.transform.localScale = Vector3.zero; }; |
| | | |
| | | if (isToggleOn) |
| | | { |
| | | { |
| | | ShowFetter(flyHero); |
| | | } |
| | | } |
| | | fightPowerText.text = UIHelper.ReplaceLargeArtNum(FightPowerManager.Instance.GetTeamFightPower(HeroUIManager.Instance.selectTeamType, true)); |
| | | |
| | | } |
| | | |
| | | void ShowFetter(HeroInfo hero) |
| | |
| | | var fetterList = hero.GetActiveFetter(heroConfig, TeamManager.Instance.GetTeam(HeroUIManager.Instance.selectTeamType)); |
| | | for (int i = 0; i < fetterList.Count; i++) |
| | | { |
| | | if(!showConnectTipQueue.Contains(fetterList[i])) |
| | | if (!showConnectTipQueue.Contains(fetterList[i])) |
| | | showConnectTipQueue.Enqueue(fetterList[i]); |
| | | } |
| | | |
| | |
| | | { |
| | | return; |
| | | } |
| | | |
| | | HeroUIManager.Instance.selectTeamPosJob = 0; |
| | | HeroUIManager.Instance.selectTeamPosCountry = 0; |
| | | HeroUIManager.Instance.SortHeroOnTeamList(); |
| | | HeroUIManager.Instance.selectTeamType = type; |
| | | HeroUIManager.Instance.SortHeroOnTeamList(); |
| | | Refresh(); |
| | | heroListScroller.m_Scorller.RefreshActiveCellViews(); |
| | | } |
| | | |
| | | protected void OnTeamChange(TeamType teamType) |
| | | { |
| | | if (HeroUIManager.Instance.selectTeamType == teamType) |
| | | { |
| | | HeroUIManager.Instance.SortHeroOnTeamList(); |
| | | heroListScroller.m_Scorller.RefreshActiveCellViews(); |
| | | } |
| | | } |
| | | } |
| | |
| | | jobImg.SetSprite(HeroUIManager.Instance.GetJobIconName(hero.heroConfig.Class)); |
| | | jobPosNameText.text = HeroUIManager.Instance.GetJobName(hero.heroConfig.Class); |
| | | descText.text = hero.heroConfig.Desc; |
| | | fightPowerText.text = hero.CalculatePower().ToString(); |
| | | fightPowerText.text = UIHelper.ReplaceLargeArtNum(hero.CalculatePower()); |
| | | lockImg.SetActive(hero.isLock); |
| | | unLockImg.SetActive(!hero.isLock); |
| | | nameText.text = hero.breakLevel == 0 ? hero.heroConfig.Name : Language.Get("herocardbreaklv", hero.heroConfig.Name, hero.breakLevel); |
| | |
| | | for (int i = 0; i < list.Count; i++) |
| | | { |
| | | var nextQualityBreakConfig = HeroBreakConfig.GetHeroBreakConfig(hero.heroId, i + 1); |
| | | if (nextQualityBreakConfig == null) |
| | | break; |
| | | List<string> attrStrArr = new List<string>(); |
| | | for (int j = 0; j < nextQualityBreakConfig.AttrIDList.Length; j++) |
| | | { |
| | |
| | | } |
| | | if (nextQualityBreakConfig.SkillID != 0) |
| | | { |
| | | attrStrArr.Add(SkillConfig.Get(nextQualityBreakConfig.SkillID).Description); |
| | | attrStrArr.Add(SkillConfig.Get(nextQualityBreakConfig.SkillID)?.Description); |
| | | } |
| | | if (i < hero.breakLevel) |
| | | { |
New file |
| | |
| | | using System; |
| | | using System.Collections; |
| | | using System.Collections.Generic; |
| | | |
| | | using UnityEngine; |
| | | |
| | | public partial class HeroUIManager : GameSystemManager<HeroUIManager> |
| | | { |
| | | |
| | | #region 图鉴和皮肤 |
| | | |
| | | //图鉴和皮肤的激活情况 |
| | | public Dictionary<int, HB122_tagSCHeroInfo.tagSCHero> heroCollectInfoDic { get; private set; } = new Dictionary<int, HB122_tagSCHeroInfo.tagSCHero>(); |
| | | |
| | | public int bookPer; |
| | | public event Action OnHeroCollectEvent; |
| | | |
| | | public void UpdateHeroCollectInfo(HB122_tagSCHeroInfo netPack) |
| | | { |
| | | for (int i = 0; i < netPack.HeroCnt; i++) |
| | | { |
| | | heroCollectInfoDic[(int)netPack.HeroInfoList[i].HeroID] = netPack.HeroInfoList[i]; |
| | | } |
| | | bookPer = GetHeroCollectBookPer(); |
| | | OnHeroCollectEvent?.Invoke(); |
| | | } |
| | | |
| | | |
| | | public int GetHeroCollectBookPer() |
| | | { |
| | | int per = 0; |
| | | foreach (var kv in heroCollectInfoDic) |
| | | { |
| | | var config = HeroQualityConfig.Get(HeroConfig.Get(kv.Key).Quality); |
| | | if (kv.Value.BookInitState != 2) |
| | | continue; |
| | | per += config.BookInitAddPer; |
| | | per += kv.Value.BookStarLV * config.BookStarAddPer; |
| | | per += kv.Value.BookBreakLV * config.BookBreakLVAddPer; |
| | | } |
| | | return per; |
| | | } |
| | | |
| | | #endregion |
| | | } |
| | | |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/System/HeroUI/HeroUIManager.Collect.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: fde2bfe0f6468dc49951c562fd445d51 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections; |
| | | using System.Collections.Generic; |
| | | |
| | | using UnityEngine; |
| | | |
| | | public partial class HeroUIManager : GameSystemManager<HeroUIManager> |
| | | { |
| | | |
| | | |
| | | #region 布阵界面 |
| | | public List<string> heroOnTeamSortList { get; private set; } = new List<string>(); //不同上阵的列表排序 |
| | | |
| | | private TeamType m_SelectTeamType = TeamType.Story; //当前选中的是哪个阵容, 布阵相关逻辑使用 |
| | | public TeamType selectTeamType |
| | | { |
| | | get { return m_SelectTeamType; } |
| | | set |
| | | { |
| | | if (m_SelectTeamType == value) |
| | | return; |
| | | //上一个阵容需要恢复到原状态 |
| | | if (m_SelectTeamType != TeamType.None) |
| | | { |
| | | TeamManager.Instance.GetTeam(m_SelectTeamType).RestoreTeam(); |
| | | } |
| | | |
| | | m_SelectTeamType = value; |
| | | } |
| | | } |
| | | |
| | | public int selectTeamPosJob = 0; //布阵界面 筛选职业 |
| | | public int selectTeamPosCountry = 0; //布阵界面 筛选国家 |
| | | |
| | | public const float clickFlyPosTime = 0.5f; //点击列表中的武将图标时, 飞入布阵的时间 |
| | | |
| | | public event Action<List<int>, int, Vector3> OnTeamPosChangeEvent; //布阵变化 位置,列表的起飞索引,起飞坐标 |
| | | |
| | | |
| | | // 【阵容属性】 - 该阵容所有武将有效 |
| | | // 初始加成 lineupInitAddPer |
| | | // 升级加成 lineupLVAddPer |
| | | // 突破加成 lineupBreakLVAddPer |
| | | // 吞噬加成 lineupStarAddPer |
| | | // 阵容光环 lineupHaloValue 、 lineupHaloPer |
| | | |
| | | /// <summary> |
| | | /// 按队伍汇总上阵属性 |
| | | /// </summary> |
| | | /// <param name="type"></param> |
| | | /// <param name="isPreview">true 客户端预览阵容,默认false 服务器阵容</param> |
| | | /// <returns></returns> |
| | | public Dictionary<string, int> GetLineupPer(TeamType type, bool isPreview = false) |
| | | { |
| | | Dictionary<string, int> lineUPPer = new Dictionary<string, int>() |
| | | { |
| | | {"lineupInitAddPer", 0}, |
| | | {"lineupLVAddPer", 0}, |
| | | {"lineupBreakLVAddPer", 0}, |
| | | {"lineupStarAddPer", 0}, |
| | | }; |
| | | |
| | | var team = TeamManager.Instance.GetTeam(type); |
| | | if (team == null) |
| | | { |
| | | return lineUPPer; |
| | | } |
| | | TeamHero[] teamHeroes = isPreview ? team.tempHeroes : team.serverHeroes; |
| | | |
| | | foreach (var teamHero in teamHeroes) |
| | | { |
| | | if (teamHero == null) |
| | | { |
| | | continue; |
| | | } |
| | | var config = HeroQualityConfig.Get(HeroConfig.Get(teamHero.heroId).Quality); |
| | | lineUPPer["lineupInitAddPer"] += config.InitAddPer; |
| | | |
| | | HeroInfo hero = HeroManager.Instance.GetHero(teamHero.guid); |
| | | if (hero == null) continue; |
| | | lineUPPer["lineupLVAddPer"] += hero.GetLineupLVAddPer(); |
| | | lineUPPer["lineupBreakLVAddPer"] += hero.GetLineupBreakLVAddPer(); |
| | | lineUPPer["lineupStarAddPer"] += hero.GetLineupStarAddPer(); |
| | | |
| | | } |
| | | return lineUPPer; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 按队伍获得阵型(国家光环)属性 |
| | | /// </summary> |
| | | /// <param name="teamType"></param> |
| | | /// <param name="isPreview">true 客户端预览阵容,默认false 服务器阵容</param> |
| | | /// <returns></returns> |
| | | public Dictionary<int, int> GetCountryAttrs(TeamType teamType, bool isPreview = false) |
| | | { |
| | | Dictionary<int, int> countryAttrs = new Dictionary<int, int>(); |
| | | Int2 result = GetMaxCountHeroCountry(teamType, isPreview); |
| | | var lineupconfig = HeroLineupHaloConfig.GetConfig(result.x, result.y); |
| | | if (lineupconfig != null) |
| | | { |
| | | for (int i = 0; i < lineupconfig.AttrIDList.Length; i++) |
| | | { |
| | | countryAttrs[lineupconfig.AttrIDList[i]] = lineupconfig.AttrValueList[i]; |
| | | } |
| | | } |
| | | |
| | | return countryAttrs; |
| | | } |
| | | |
| | | public void SortHeroOnTeamList() |
| | | { |
| | | heroOnTeamSortList = HeroManager.Instance.GetHeroGuidList(selectTeamPosJob, selectTeamPosCountry); |
| | | heroOnTeamSortList.Sort(CmpHeroByTeamType); |
| | | } |
| | | |
| | | |
| | | int CmpHeroByTeamType(string guidA, string guidB) |
| | | { |
| | | HeroInfo heroA = HeroManager.Instance.GetHero(guidA); |
| | | HeroInfo heroB = HeroManager.Instance.GetHero(guidB); |
| | | if (heroA == null || heroB == null) |
| | | { |
| | | return 0; |
| | | } |
| | | |
| | | var team = TeamManager.Instance.GetTeam(selectTeamType); |
| | | // 排序规则:上阵>武将等级>突破等级>武将觉醒阶级>武将品质>武将吞噬星级>武将ID |
| | | bool isInTeamA = team.HasHeroInServer(guidA); |
| | | bool isInTeamB = team.HasHeroInServer(guidB); |
| | | if (isInTeamA != isInTeamB) |
| | | { |
| | | return isInTeamA ? -1 : 1; |
| | | } |
| | | if (heroA.heroLevel != heroB.heroLevel) |
| | | { |
| | | return heroA.heroLevel > heroB.heroLevel ? -1 : 1; |
| | | } |
| | | if (heroA.breakLevel != heroB.breakLevel) |
| | | { |
| | | return heroA.breakLevel > heroB.breakLevel ? -1 : 1; |
| | | } |
| | | if (heroA.awakeLevel != heroB.awakeLevel) |
| | | { |
| | | return heroA.awakeLevel > heroB.awakeLevel ? -1 : 1; |
| | | } |
| | | if (heroA.Quality != heroB.Quality) |
| | | { |
| | | return heroA.Quality > heroB.Quality ? -1 : 1; |
| | | } |
| | | if (heroA.heroStar != heroA.heroStar) |
| | | { |
| | | return heroA.heroStar > heroB.heroStar ? -1 : 1; |
| | | } |
| | | |
| | | return heroA.heroId.CompareTo(heroB.heroId); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /// <summary> |
| | | /// 上阵队伍中各个国家的武将数量 |
| | | /// </summary> |
| | | /// <param name="teamType"></param> |
| | | /// <param name="isPreview">true 客户端预览阵容,默认false 服务器阵容</param> |
| | | /// <returns></returns> |
| | | public Dictionary<HeroCountry, int> GetCountryHeroCountByTeamType(TeamType teamType, bool isPreview = false) |
| | | { |
| | | Dictionary<HeroCountry, int> heroCountryCount = new Dictionary<HeroCountry, int>(); |
| | | |
| | | var team = TeamManager.Instance.GetTeam(teamType); |
| | | if (team == null) |
| | | { |
| | | return heroCountryCount; |
| | | } |
| | | TeamHero[] teamHeroes = isPreview ? team.tempHeroes : team.serverHeroes; |
| | | |
| | | for (int i = 0; i < teamHeroes.Length; i++) |
| | | { |
| | | if (teamHeroes[i] == null) |
| | | continue; |
| | | var country = teamHeroes[i].Country; |
| | | |
| | | if (!heroCountryCount.ContainsKey(country)) |
| | | { |
| | | heroCountryCount.Add(country, 1); |
| | | } |
| | | else |
| | | { |
| | | heroCountryCount[country] += 1; |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | return heroCountryCount; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获得上阵中武将数量最大的国家和数量 |
| | | /// </summary> |
| | | /// <param name="teamType"></param> |
| | | /// <param name="isPreview">true 客户端预览阵容,默认false 服务器阵容</param> |
| | | /// <returns></returns> |
| | | public Int2 GetMaxCountHeroCountry(TeamType teamType, bool isPreview = false) |
| | | { |
| | | var countryCountDict = GetCountryHeroCountByTeamType(teamType, isPreview); |
| | | //找到最大的国家和数量 |
| | | HeroCountry country = HeroCountry.None; |
| | | int maxValue = 0; |
| | | foreach (var data in countryCountDict) |
| | | { |
| | | if (data.Value > maxValue) |
| | | { |
| | | country = data.Key; |
| | | maxValue = data.Value; |
| | | } |
| | | } |
| | | return new Int2((int)country, maxValue); |
| | | } |
| | | |
| | | //在不同页签下选AttackType 0 攻击阵容 1 防守阵容 |
| | | public int GetSelectTeamTypeByAttackType(int AttackType) |
| | | { |
| | | if (selectTeamType == TeamType.Arena || selectTeamType == TeamType.ArenaDefense) |
| | | { |
| | | return AttackType == 0 ? (int)TeamType.Arena : (int)TeamType.ArenaDefense; |
| | | } |
| | | |
| | | |
| | | return (int)TeamType.Story; |
| | | } |
| | | |
| | | |
| | | public void NotifyOnTeamPosChangeEvent(List<int> posList, int flyIndex, Vector3 startPos) |
| | | { |
| | | OnTeamPosChangeEvent?.Invoke(posList, flyIndex, startPos); |
| | | } |
| | | |
| | | //推荐阵容 |
| | | public List<string> SelectRecommend() |
| | | { |
| | | //推荐阵容的算法逻辑 |
| | | //自动选择优先级:武将等级>突破等级>武将觉醒阶级>武将品质>武将吞噬星级>武将ID |
| | | var tmpList = HeroManager.Instance.GetHeroGuidList(); |
| | | tmpList.Sort(CmpHeroRecommend); |
| | | |
| | | |
| | | //推荐最多6个,存在相同heroid,则跳过 |
| | | List<string> selectHeroList = new List<string>(); |
| | | List<int> selectHeroIDList = new List<int>(); |
| | | for (int i = 0; i < tmpList.Count; i++) |
| | | { |
| | | if (selectHeroList.Count >= TeamConst.MaxTeamHeroCount) |
| | | break; |
| | | |
| | | string guid = tmpList[i]; |
| | | HeroInfo heroInfo = HeroManager.Instance.GetHero(guid); |
| | | if (selectHeroIDList.Contains(heroInfo.heroId)) |
| | | continue; |
| | | //如果重复了,跳过 |
| | | if (selectHeroList.Contains(guid)) |
| | | continue; |
| | | selectHeroList.Add(guid); |
| | | selectHeroIDList.Add(heroInfo.heroId); |
| | | } |
| | | return selectHeroList; |
| | | } |
| | | |
| | | |
| | | int CmpHeroRecommend(string guidA, string guidB) |
| | | { |
| | | HeroInfo heroA = HeroManager.Instance.GetHero(guidA); |
| | | HeroInfo heroB = HeroManager.Instance.GetHero(guidB); |
| | | if (heroA == null || heroB == null) |
| | | { |
| | | return 0; |
| | | } |
| | | |
| | | // 排序规则:武将等级>突破等级>武将觉醒阶级>武将品质>武将吞噬星级>武将ID |
| | | if (heroA.heroLevel != heroB.heroLevel) |
| | | { |
| | | return heroA.heroLevel > heroB.heroLevel ? -1 : 1; |
| | | } |
| | | if (heroA.breakLevel != heroB.breakLevel) |
| | | { |
| | | return heroA.breakLevel > heroB.breakLevel ? -1 : 1; |
| | | } |
| | | if (heroA.awakeLevel != heroB.awakeLevel) |
| | | { |
| | | return heroA.awakeLevel > heroB.awakeLevel ? -1 : 1; |
| | | } |
| | | if (heroA.Quality != heroB.Quality) |
| | | { |
| | | return heroA.Quality > heroB.Quality ? -1 : 1; |
| | | } |
| | | if (heroA.heroStar != heroA.heroStar) |
| | | { |
| | | return heroA.heroStar > heroB.heroStar ? -1 : 1; |
| | | } |
| | | |
| | | return heroA.heroId.CompareTo(heroB.heroId); |
| | | } |
| | | |
| | | |
| | | #endregion |
| | | |
| | | |
| | | } |
| | | |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/System/HeroUI/HeroUIManager.OnTeam.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: c8e0c0a46a38f1e49856253add1794e3 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
New file |
| | |
| | | using System; |
| | | using System.Collections; |
| | | using System.Collections.Generic; |
| | | |
| | | using UnityEngine; |
| | | |
| | | public partial class HeroUIManager : GameSystemManager<HeroUIManager> |
| | | { |
| | | |
| | | |
| | | #region 重生 遣散 |
| | | public int awakeRebirthCnt { get; private set; } |
| | | public int payBackMoneyType; |
| | | public int payBackMoney; |
| | | public Dictionary<int, ulong> GetHeroLVPayBack(int quality, int lv) |
| | | { |
| | | //汇总返还总数量 |
| | | Dictionary<int, ulong> itemCounDic = new Dictionary<int, ulong>(); |
| | | for (int i = 1; i < lv; i++) |
| | | { |
| | | var config = HeroQualityLVConfig.GetQualityLVConfig(quality, lv); |
| | | var itemID = config.UPCostItem[0]; |
| | | var count = (ulong)config.UPCostItem[1]; |
| | | if (!itemCounDic.ContainsKey(itemID)) |
| | | { |
| | | itemCounDic[itemID] = count; |
| | | } |
| | | itemCounDic[itemID] = itemCounDic[itemID] + count; |
| | | } |
| | | |
| | | return itemCounDic; |
| | | } |
| | | |
| | | |
| | | public Dictionary<int, ulong> GetHeroBreakPayBack(int quality, int lv) |
| | | { |
| | | //汇总返还总数量 |
| | | Dictionary<int, ulong> itemCounDic = new Dictionary<int, ulong>(); |
| | | for (int i = 0; i < lv; i++) |
| | | { |
| | | var config = HeroQualityBreakConfig.GetQualityBreakConfig(quality, lv); |
| | | var itemID = config.UPCostItem[0]; |
| | | var count = (ulong)config.UPCostItem[1]; |
| | | if (!itemCounDic.ContainsKey(itemID)) |
| | | { |
| | | itemCounDic[itemID] = count; |
| | | } |
| | | itemCounDic[itemID] = itemCounDic[itemID] + count; |
| | | } |
| | | |
| | | return itemCounDic; |
| | | |
| | | |
| | | } |
| | | |
| | | public Dictionary<int, ulong> GetHeroQualityAwakePayBack(int quality, int lv) |
| | | { |
| | | //汇总返还总数量 |
| | | Dictionary<int, ulong> itemCounDic = new Dictionary<int, ulong>(); |
| | | for (int i = 0; i < lv; i++) |
| | | { |
| | | var config = HeroQualityAwakeConfig.GetQualityAwakeConfig(quality, lv); |
| | | var itemID = config.UPCostItem[0]; |
| | | var count = (ulong)config.UPCostItem[1]; |
| | | if (!itemCounDic.ContainsKey(itemID)) |
| | | { |
| | | itemCounDic[itemID] = count; |
| | | } |
| | | itemCounDic[itemID] = itemCounDic[itemID] + count; |
| | | } |
| | | |
| | | return itemCounDic; |
| | | } |
| | | |
| | | public void UpdateHeroInfo(HB125_tagSCPlayerHeroInfo netPack) |
| | | { |
| | | awakeRebirthCnt = netPack.AwakeRebirthCnt; |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | } |
| | | |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/System/HeroUI/HeroUIManager.Reborn.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: bf68f7332b968f14491059586ac32df5 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
| | |
| | | using UnityEngine; |
| | | |
| | | //武将相关界面的操作数据管理 |
| | | public class HeroUIManager : GameSystemManager<HeroUIManager> |
| | | public partial class HeroUIManager : GameSystemManager<HeroUIManager> |
| | | { |
| | | #region 武将列表界面 |
| | | public List<string> heroSortList { get; private set; } = new List<string>(); //上阵为主线的 GUID列表 |
| | |
| | | public string selectHeroGuid; //选中的武将id |
| | | #endregion |
| | | |
| | | public WaitHeroFuncResponse waitResponse; //请求武将功能 |
| | | public WaitHeroFuncResponse waitResponse; //请求武将功能,与服务端交互 |
| | | |
| | | |
| | | public override void Init() |
| | |
| | | heroOnTeamSortList.Clear(); |
| | | awakeRebirthCnt = 0; |
| | | waitResponse = default; |
| | | heroCollectInfoDic.Clear(); |
| | | } |
| | | |
| | | private void OnHeroChangeEvent(HeroInfo hero) |
| | |
| | | } |
| | | |
| | | if (hero.itemHero.guid != waitResponse.guid) |
| | | { |
| | | { |
| | | return; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | waitResponse = default; |
| | | |
| | | |
| | | } |
| | | |
| | | #region 武将UI常用接口 |
| | |
| | | } |
| | | |
| | | public bool IsLVMaxByBreakLevel(HeroInfo hero) |
| | | { |
| | | { |
| | | return hero.heroLevel == GetMaxLVByBreakLV(hero.Quality, hero.breakLevel); |
| | | } |
| | | |
| | |
| | | return heroA.heroId.CompareTo(heroB.heroId); |
| | | } |
| | | |
| | | #region 布阵界面 |
| | | public List<string> heroOnTeamSortList { get; private set; } = new List<string>(); //不同上阵的列表排序 |
| | | |
| | | private TeamType m_SelectTeamType = TeamType.Story; //当前选中的是哪个阵容, 布阵相关逻辑使用 |
| | | public TeamType selectTeamType |
| | | { |
| | | get { return m_SelectTeamType; } |
| | | set |
| | | { |
| | | if (m_SelectTeamType == value) |
| | | return; |
| | | //上一个阵容需要恢复到原状态 |
| | | if (m_SelectTeamType != TeamType.None) |
| | | { |
| | | TeamManager.Instance.GetTeam(m_SelectTeamType).RestoreTeam(); |
| | | } |
| | | |
| | | m_SelectTeamType = value; |
| | | } |
| | | } |
| | | |
| | | public int selectTeamPosJob = 0; //布阵界面 筛选职业 |
| | | public int selectTeamPosCountry = 0; //布阵界面 筛选国家 |
| | | |
| | | public const float clickFlyPosTime = 0.5f; //点击列表中的武将图标时, 飞入布阵的时间 |
| | | |
| | | public event Action<List<int>, int, Vector3> OnTeamPosChangeEvent; //布阵变化 位置,列表的起飞索引,起飞坐标 |
| | | |
| | | |
| | | public void SortHeroOnTeamList() |
| | | { |
| | | heroOnTeamSortList = HeroManager.Instance.GetHeroGuidList(selectTeamPosJob, selectTeamPosCountry); |
| | | heroOnTeamSortList.Sort(CmpHeroByTeamType); |
| | | } |
| | | |
| | | |
| | | int CmpHeroByTeamType(string guidA, string guidB) |
| | | { |
| | | HeroInfo heroA = HeroManager.Instance.GetHero(guidA); |
| | | HeroInfo heroB = HeroManager.Instance.GetHero(guidB); |
| | | if (heroA == null || heroB == null) |
| | | { |
| | | return 0; |
| | | } |
| | | |
| | | // 排序规则:上阵>武将等级>突破等级>武将觉醒阶级>武将品质>武将吞噬星级>武将ID |
| | | bool isInTeamA = heroA.IsInTeamByTeamType(selectTeamType); |
| | | bool isInTeamB = heroB.IsInTeamByTeamType(selectTeamType); |
| | | if (isInTeamA != isInTeamB) |
| | | { |
| | | return isInTeamA ? -1 : 1; |
| | | } |
| | | if (heroA.heroLevel != heroB.heroLevel) |
| | | { |
| | | return heroA.heroLevel > heroB.heroLevel ? -1 : 1; |
| | | } |
| | | if (heroA.breakLevel != heroB.breakLevel) |
| | | { |
| | | return heroA.breakLevel > heroB.breakLevel ? -1 : 1; |
| | | } |
| | | if (heroA.awakeLevel != heroB.awakeLevel) |
| | | { |
| | | return heroA.awakeLevel > heroB.awakeLevel ? -1 : 1; |
| | | } |
| | | if (heroA.Quality != heroB.Quality) |
| | | { |
| | | return heroA.Quality > heroB.Quality ? -1 : 1; |
| | | } |
| | | if (heroA.heroStar != heroA.heroStar) |
| | | { |
| | | return heroA.heroStar > heroB.heroStar ? -1 : 1; |
| | | } |
| | | |
| | | return heroA.heroId.CompareTo(heroB.heroId); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | //上阵队伍中各个国家的武将数量 |
| | | public Dictionary<HeroCountry, int> GetCountryHeroCountByTeamType(TeamType teamType) |
| | | { |
| | | Dictionary<HeroCountry, int> heroCountryCount = new Dictionary<HeroCountry, int>(); |
| | | |
| | | var team = TeamManager.Instance.GetTeam(teamType); |
| | | if (team != null) |
| | | { |
| | | for (int i = 0; i < team.tempHeroes.Length; i++) |
| | | { |
| | | if (team.tempHeroes[i] == null) |
| | | continue; |
| | | var country = (HeroCountry)team.tempHeroes[i].Country; |
| | | |
| | | if (!heroCountryCount.ContainsKey(country)) |
| | | { |
| | | heroCountryCount.Add(country, 1); |
| | | } |
| | | else |
| | | { |
| | | heroCountryCount[country] = heroCountryCount[country] + 1; |
| | | } |
| | | |
| | | } |
| | | |
| | | } |
| | | |
| | | return heroCountryCount; |
| | | } |
| | | |
| | | //获得上阵中武将数量最大的国家和数量 |
| | | public Int2 GetMaxCountHeroCountry(TeamType teamType) |
| | | { |
| | | var countryCount = GetCountryHeroCountByTeamType(teamType); |
| | | //找到最大的国家和数量 |
| | | HeroCountry country = HeroCountry.None; |
| | | int maxValue = 0; |
| | | foreach (var data in countryCount) |
| | | { |
| | | if (data.Value > maxValue) |
| | | { |
| | | country = data.Key; |
| | | maxValue = data.Value; |
| | | } |
| | | } |
| | | return new Int2((int)country, maxValue); |
| | | } |
| | | |
| | | //在不同页签下选AttackType 0 攻击阵容 1 防守阵容 |
| | | public int GetSelectTeamTypeByAttackType(int AttackType) |
| | | { |
| | | if (selectTeamType == TeamType.Arena || selectTeamType == TeamType.ArenaDefense) |
| | | { |
| | | return AttackType == 0 ? (int)TeamType.Arena : (int)TeamType.ArenaDefense; |
| | | } |
| | | |
| | | |
| | | return (int)TeamType.Story; |
| | | } |
| | | |
| | | |
| | | public void NotifyOnTeamPosChangeEvent(List<int> posList, int flyIndex, Vector3 startPos) |
| | | { |
| | | OnTeamPosChangeEvent?.Invoke(posList, flyIndex, startPos); |
| | | } |
| | | |
| | | //推荐阵容 |
| | | public List<string> SelectRecommend() |
| | | { |
| | | //推荐阵容的算法逻辑 |
| | | //自动选择优先级:武将等级>突破等级>武将觉醒阶级>武将品质>武将吞噬星级>武将ID |
| | | var tmpList = HeroManager.Instance.GetHeroGuidList(); |
| | | tmpList.Sort(CmpHeroRecommend); |
| | | |
| | | |
| | | //推荐最多6个,存在相同heroid,则跳过 |
| | | List<string> selectHeroList = new List<string>(); |
| | | List<int> selectHeroIDList = new List<int>(); |
| | | for (int i = 0; i < tmpList.Count; i++) |
| | | { |
| | | if (selectHeroList.Count >= TeamConst.MaxTeamHeroCount) |
| | | break; |
| | | |
| | | string guid = tmpList[i]; |
| | | HeroInfo heroInfo = HeroManager.Instance.GetHero(guid); |
| | | if (selectHeroIDList.Contains(heroInfo.heroId)) |
| | | continue; |
| | | //如果重复了,跳过 |
| | | if (selectHeroList.Contains(guid)) |
| | | continue; |
| | | selectHeroList.Add(guid); |
| | | selectHeroIDList.Add(heroInfo.heroId); |
| | | } |
| | | return selectHeroList; |
| | | } |
| | | |
| | | |
| | | int CmpHeroRecommend(string guidA, string guidB) |
| | | { |
| | | HeroInfo heroA = HeroManager.Instance.GetHero(guidA); |
| | | HeroInfo heroB = HeroManager.Instance.GetHero(guidB); |
| | | if (heroA == null || heroB == null) |
| | | { |
| | | return 0; |
| | | } |
| | | |
| | | // 排序规则:武将等级>突破等级>武将觉醒阶级>武将品质>武将吞噬星级>武将ID |
| | | if (heroA.heroLevel != heroB.heroLevel) |
| | | { |
| | | return heroA.heroLevel > heroB.heroLevel ? -1 : 1; |
| | | } |
| | | if (heroA.breakLevel != heroB.breakLevel) |
| | | { |
| | | return heroA.breakLevel > heroB.breakLevel ? -1 : 1; |
| | | } |
| | | if (heroA.awakeLevel != heroB.awakeLevel) |
| | | { |
| | | return heroA.awakeLevel > heroB.awakeLevel ? -1 : 1; |
| | | } |
| | | if (heroA.Quality != heroB.Quality) |
| | | { |
| | | return heroA.Quality > heroB.Quality ? -1 : 1; |
| | | } |
| | | if (heroA.heroStar != heroA.heroStar) |
| | | { |
| | | return heroA.heroStar > heroB.heroStar ? -1 : 1; |
| | | } |
| | | |
| | | return heroA.heroId.CompareTo(heroB.heroId); |
| | | } |
| | | |
| | | |
| | | #endregion |
| | | |
| | | #region 重生 遣散 |
| | | public int awakeRebirthCnt { get; private set; } |
| | | public int payBackMoneyType; |
| | | public int payBackMoney; |
| | | public Dictionary<int, ulong> GetHeroLVPayBack(int quality, int lv) |
| | | { |
| | | //汇总返还总数量 |
| | | Dictionary<int, ulong> itemCounDic = new Dictionary<int, ulong>(); |
| | | for (int i = 1; i < lv; i++) |
| | | { |
| | | var config = HeroQualityLVConfig.GetQualityLVConfig(quality, lv); |
| | | var itemID = config.UPCostItem[0]; |
| | | var count = (ulong)config.UPCostItem[1]; |
| | | if (!itemCounDic.ContainsKey(itemID)) |
| | | { |
| | | itemCounDic[itemID] = count; |
| | | } |
| | | itemCounDic[itemID] = itemCounDic[itemID] + count; |
| | | } |
| | | |
| | | return itemCounDic; |
| | | } |
| | | |
| | | |
| | | public Dictionary<int, ulong> GetHeroBreakPayBack(int quality, int lv) |
| | | { |
| | | //汇总返还总数量 |
| | | Dictionary<int, ulong> itemCounDic = new Dictionary<int, ulong>(); |
| | | for (int i = 0; i < lv; i++) |
| | | { |
| | | var config = HeroQualityBreakConfig.GetQualityBreakConfig(quality, lv); |
| | | var itemID = config.UPCostItem[0]; |
| | | var count = (ulong)config.UPCostItem[1]; |
| | | if (!itemCounDic.ContainsKey(itemID)) |
| | | { |
| | | itemCounDic[itemID] = count; |
| | | } |
| | | itemCounDic[itemID] = itemCounDic[itemID] + count; |
| | | } |
| | | |
| | | return itemCounDic; |
| | | |
| | | |
| | | } |
| | | |
| | | public Dictionary<int, ulong> GetHeroQualityAwakePayBack(int quality, int lv) |
| | | { |
| | | //汇总返还总数量 |
| | | Dictionary<int, ulong> itemCounDic = new Dictionary<int, ulong>(); |
| | | for (int i = 0; i < lv; i++) |
| | | { |
| | | var config = HeroQualityAwakeConfig.GetQualityAwakeConfig(quality, lv); |
| | | var itemID = config.UPCostItem[0]; |
| | | var count = (ulong)config.UPCostItem[1]; |
| | | if (!itemCounDic.ContainsKey(itemID)) |
| | | { |
| | | itemCounDic[itemID] = count; |
| | | } |
| | | itemCounDic[itemID] = itemCounDic[itemID] + count; |
| | | } |
| | | |
| | | return itemCounDic; |
| | | } |
| | | |
| | | public void UpdateHeroInfo(HB125_tagSCPlayerHeroInfo netPack) |
| | | { |
| | | awakeRebirthCnt = netPack.AwakeRebirthCnt; |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | public struct WaitHeroFuncResponse |
| | |
| | | #endregion
|
| | |
|
| | |
|
| | | private bool CheckIsExtendGrid(int itemId)
|
| | | {
|
| | | SinglePack singlePack = packModel.GetSinglePack(PackType.Item);
|
| | | if (singlePack == null) return false;
|
| | |
|
| | | int startLockIndex = singlePack.unlockedGridCount - PackManager.Instance.initBagGridCount;
|
| | | FuncConfigConfig _tagFuncModel = FuncConfigConfig.Get("OpenBagItem");
|
| | | var haveCount = packModel.GetItemCountByID(PackType.Item, itemId);
|
| | | Equation.Instance.Clear();
|
| | | Equation.Instance.AddKeyValue("index", startLockIndex + 1);
|
| | | int needTool = Equation.Instance.Eval<int>(_tagFuncModel.Numerical2);
|
| | | if (haveCount >= (ulong)needTool)
|
| | | {
|
| | | return true;
|
| | | }
|
| | | else
|
| | | {
|
| | | return false;
|
| | | }
|
| | | }
|
| | |
|
| | | /// <summary>
|
| | | /// <param name="packType 背包类型"></param>
|
| | |
| | | using System.Collections; |
| | | using System; |
| | | using System.Collections; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using UnityEngine; |
| | | using LitJson; |
| | | using Spine; |
| | | |
| | | |
| | | //!单英雄查看战力 只算自己的上阵属性 不算羁绊 总上阵属性 光环 |
| | | // 战力的计算方式 |
| | | // 先算上阵的单武将战力按公式一一算出各个属性(基础/战斗),再把算出来的各个属性代入到战力公式 |
| | | // 所有武将战力加起来 + 技能战力汇总(公式)就是整个号的战力 |
| | | public class FightPowerManager : Singleton<FightPowerManager> |
| | | { |
| | | string propertyFormula; |
| | | public string propertyFormula; |
| | | public string fightPropertyFormula; |
| | | public string fightPowerFormula; |
| | | public string skillFightPowerFormula; |
| | | |
| | | Dictionary<string, double> propertyVariables = new Dictionary<string, double>(); |
| | | Dictionary<string, double> fightPowerVariables = new Dictionary<string, double>(); //总战力中的单武将战力 |
| | | |
| | | |
| | | public FightPowerManager() |
| | | { |
| | | // 数值1:基础三维属性计算公式 |
| | | // 数值2:战斗属性/战斗抗性/特殊属性计算公式 |
| | | // 数值3:属性战力计算公式,计算参数详见 S.属性条目配置 |
| | | var config = FuncConfigConfig.Get("HeroAttrFormula"); |
| | | propertyFormula = config.Numerical1; |
| | | fightPropertyFormula = config.Numerical2; |
| | | fightPowerFormula = config.Numerical3; |
| | | skillFightPowerFormula = config.Numerical4; |
| | | } |
| | | |
| | | #region 初始化战力计算的信息 |
| | | TeamType teamTypeCalc = TeamType.Story; //不同阵容战力不同 |
| | | bool isPreviewTeamPower; //预览阵容(队伍)战力 |
| | | int dropIndexCalc = -1; //掉落装备在阵容的索引,用于预览战力对比 |
| | | |
| | | //装备战力为最终总战力的结果比(提升整个角色总战力) |
| | | public int CalculatePower(int level) |
| | | //计算阵容战力,装备对比等情况需要代入 |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | /// <param name="teamType">阵容类型</param> |
| | | /// <param name="dropindex">掉落装备的索引,-1代表不替换计算</param> |
| | | /// <param name="ispreview">预览阵容战力</param> |
| | | public void InitFightPowerParam(TeamType teamType = TeamType.Story, int dropindex = -1, bool ispreview = false) |
| | | { |
| | | // Equation.Instance.Clear(); |
| | | // Equation.Instance.AddKeyValue("equipScoreTotal", CountEquipScore(level)); |
| | | // var power = Equation.Instance.Eval<int>(scoreFormula); |
| | | teamTypeCalc = teamType; |
| | | isPreviewTeamPower = ispreview; |
| | | |
| | | // var propertyContainer = new Properties(); |
| | | |
| | | // Equation.Instance.Clear(); |
| | | // var keys = propertyContainer.keys; |
| | | // for (int i = 0; i < keys.Count; i++) |
| | | // { |
| | | // var id = keys[i]; |
| | | // var value = propertyContainer[id]; |
| | | // var config = PlayerPropertyConfig.Get(id); |
| | | // Equation.Instance.AddKeyValue(config.Parameter, value); |
| | | // } |
| | | |
| | | // var propertyPower = Equation.Instance.Eval<int>(propertyFormula); |
| | | // power += propertyPower; |
| | | |
| | | |
| | | return 0; |
| | | dropIndexCalc = dropindex; |
| | | #if UNITY_EDITOR |
| | | Debug.Log("战力:初始化参数 dropIndex:" + dropIndexCalc + " 阵型:" + teamTypeCalc + " ispreview:" + ispreview); |
| | | #endif |
| | | } |
| | | #endregion |
| | | |
| | | //和身上装备对比 |
| | | public long GetFightPowerChange(ItemModel item) |
| | | |
| | | |
| | | #region 先计算所有功能的汇总属性 |
| | | |
| | | //功能属性 类型:值 |
| | | public Dictionary<int, int> lvAttrs = new Dictionary<int, int>(); //等级属性 |
| | | |
| | | //分开存储预览和 真实属性 |
| | | public Dictionary<int, int> equipAttrs = new Dictionary<int, int>(); //装备属性 |
| | | public Dictionary<string, int> lineUpPerDict = new Dictionary<string, int>(); //阵容属性加成 |
| | | public Dictionary<int, int> countryAttrs = new Dictionary<int, int>(); //阵容国家(光环)属性 |
| | | |
| | | //等级属性 |
| | | void RefreshLVAttrs() |
| | | { |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | class Properties |
| | | { |
| | | Dictionary<int, int> tables = new Dictionary<int, int>(); |
| | | |
| | | public List<int> keys { get { return new List<int>(tables.Keys); } } |
| | | |
| | | public int this[int id] { get { return tables[id]; } } |
| | | |
| | | public void Add(int id, int value) |
| | | lvAttrs.Clear(); |
| | | var playerLVConfig = PlayerLVConfig.Get(PlayerDatas.Instance.baseData.LV); |
| | | foreach (var attrType in PlayerPropertyConfig.baseAttrs) |
| | | { |
| | | if (id == 7) |
| | | lvAttrs[attrType] = GetPlayerLVValue(playerLVConfig, attrType); |
| | | } |
| | | #if UNITY_EDITOR |
| | | Debug.Log("战力:等级属性 " + JsonMapper.ToJson(lvAttrs)); |
| | | #endif |
| | | |
| | | } |
| | | |
| | | public int GetPlayerLVValue(PlayerLVConfig config, int type) |
| | | { |
| | | if (type == 6) |
| | | { |
| | | return config.Atk; |
| | | } |
| | | else if (type == 7) |
| | | { |
| | | return config.Def; |
| | | } |
| | | else if (type == 8) |
| | | { |
| | | return config.MaxHP; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | //装备属性:身上装备汇总 |
| | | void RefrehEquipAttrs() |
| | | { |
| | | equipAttrs.Clear(); //身上装备属性重置 |
| | | for (int i = 0; i < EquipModel.TotleEquip; i++) |
| | | { |
| | | var equip = EquipModel.Instance.GetEquip(i); |
| | | if (dropIndexCalc != -1) |
| | | { |
| | | Add(67, value); |
| | | Add(68, value); |
| | | var dropEquip = PackManager.Instance.GetItemByIndex(PackType.DropItem, dropIndexCalc); |
| | | if (dropEquip.config.EquipPlace - 1 == i) |
| | | { |
| | | equip = dropEquip; //替换计算总战力 |
| | | } |
| | | } |
| | | if (equip == null) |
| | | { |
| | | continue; |
| | | } |
| | | var baseIDAttrs = EquipModel.Instance.GetEquipBaseAttrs(equip); |
| | | var baseVauleAttrs = EquipModel.Instance.GetEquipBaseValues(equip); |
| | | if (baseIDAttrs != null) |
| | | { |
| | | for (int j = 0; j < baseIDAttrs.Count; j++) |
| | | { |
| | | if (!equipAttrs.ContainsKey(baseIDAttrs[j])) |
| | | { |
| | | equipAttrs[baseIDAttrs[j]] = baseVauleAttrs[j]; |
| | | } |
| | | else |
| | | { |
| | | equipAttrs[baseIDAttrs[j]] += baseVauleAttrs[j]; |
| | | } |
| | | } |
| | | } |
| | | |
| | | var fightIDAttrs = EquipModel.Instance.GetEquipFightAttrs(equip); |
| | | var fightValueAttrs = EquipModel.Instance.GetEquipFightValues(equip); |
| | | if (fightIDAttrs != null) |
| | | { |
| | | for (int j = 0; j < fightIDAttrs.Count; j++) |
| | | { |
| | | if (!equipAttrs.ContainsKey(fightIDAttrs[j])) |
| | | { |
| | | equipAttrs[fightIDAttrs[j]] = fightValueAttrs[j]; |
| | | } |
| | | else |
| | | { |
| | | equipAttrs[fightIDAttrs[j]] += fightValueAttrs[j]; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | #if UNITY_EDITOR |
| | | Debug.Log("战力:装备属性 " + JsonMapper.ToJson(equipAttrs)); |
| | | #endif |
| | | } |
| | | |
| | | // 计算队伍中上阵的所有武将的上阵属性 和 光环 |
| | | void RefreshTeamAttrs() |
| | | { |
| | | //阵容属性 |
| | | // 阵容:所有武将上阵属性 |
| | | lineUpPerDict = HeroUIManager.Instance.GetLineupPer(teamTypeCalc, isPreviewTeamPower); |
| | | |
| | | #if UNITY_EDITOR |
| | | Debug.Log("战力:上阵属性 " + JsonMapper.ToJson(lineUpPerDict)); |
| | | #endif |
| | | // 阵容:国家(光环)属性 |
| | | countryAttrs = HeroUIManager.Instance.GetCountryAttrs(teamTypeCalc, isPreviewTeamPower); |
| | | #if UNITY_EDITOR |
| | | Debug.Log("战力:国家(光环)属性 " + JsonMapper.ToJson(countryAttrs)); |
| | | #endif |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | //单属性公式分基础三维和战斗属性 |
| | | // 【主公属性】 |
| | | // 等级属性 lvValue |
| | | // 装备属性 equipValue |
| | | // 图鉴属性 bookValue 、 bookPer |
| | | |
| | | // 【阵容属性】 - 该阵容所有武将有效 |
| | | // 初始加成 lineupInitAddPer |
| | | // 升级加成 lineupLVAddPer |
| | | // 突破加成 lineupBreakLVAddPer |
| | | // 吞噬加成 lineupStarAddPer |
| | | // 阵容光环 lineupHaloValue 、 lineupHaloPer |
| | | |
| | | // 【武将属性】 |
| | | // 继承比例 inheritPer |
| | | // 自身属性 heroSelfValue 、 heroSelfPer |
| | | // 吞噬属性 starTalentValue 、 starTalentPer |
| | | // 突破属性 breakLVValue 、 breakLVPer |
| | | // 觉醒属性 awakeTalentValue 、 awakeTalentPer |
| | | // 羁绊属性 fetterValue 、 fetterPer |
| | | |
| | | #region 属性公式 |
| | | // 单基础属性计算 |
| | | public double GetPropertyVaule(int attrType, HeroInfo hero, string formula) |
| | | { |
| | | propertyVariables.Clear(); |
| | | propertyVariables["lvValue"] = lvAttrs.ContainsKey(attrType) ? lvAttrs[attrType] : 0; |
| | | propertyVariables["equipValue"] = equipAttrs.ContainsKey(attrType) ? equipAttrs[attrType] : 0; |
| | | propertyVariables["bookValue"] = 0; |
| | | propertyVariables["bookPer"] = GetBookPer(attrType) / 10000.0f; |
| | | |
| | | //!!!单武将战力预览的话需要排除队伍影响战力,只算武将自身的上阵属性 |
| | | propertyVariables["lineupInitAddPer"] = GetLineUpPer(attrType, "lineupInitAddPer") / 10000.0f; |
| | | propertyVariables["lineupLVAddPer"] = GetLineUpPer(attrType, "lineupLVAddPer") / 10000.0f; |
| | | propertyVariables["lineupBreakLVAddPer"] = GetLineUpPer(attrType, "lineupBreakLVAddPer") / 10000.0f; |
| | | propertyVariables["lineupStarAddPer"] = GetLineUpPer(attrType, "lineupStarAddPer") / 10000.0f; |
| | | |
| | | //阵容光环 三围百分比加成 |
| | | propertyVariables["lineupHaloValue"] = countryAttrs.ContainsKey(attrType) ? countryAttrs[attrType] : 0; |
| | | propertyVariables["lineupHaloPer"] = GetCountryPer(attrType) / 10000.0f; |
| | | |
| | | |
| | | //武将属性 |
| | | propertyVariables["inheritPer"] = hero.GetInheritAttrPer(attrType) / 10000.0f; |
| | | propertyVariables["heroSelfValue"] = hero.GetSelfAddValue(attrType); |
| | | propertyVariables["heroSelfPer"] = hero.GetSelfAddPer(attrType) / 10000.0f; |
| | | propertyVariables["starTalentValue"] = hero.GetTalentAttrValue(attrType); |
| | | propertyVariables["starTalentPer"] = hero.GetTalentAttrPer(attrType) / 10000.0f; |
| | | propertyVariables["breakLVValue"] = hero.GetBreakAttrValue(attrType); |
| | | propertyVariables["breakLVPer"] = hero.GetBreakAttrPer(attrType) / 10000.0f; |
| | | propertyVariables["awakeTalentValue"] = hero.GetAwakeAttrValue(attrType); |
| | | propertyVariables["awakeTalentPer"] = hero.GetAwakeAttrPer(attrType) / 10000.0f; |
| | | propertyVariables["fetterValue"] = hero.GetFetterAttrValue(attrType); |
| | | propertyVariables["fetterPer"] = hero.GetFetterAttrPer(attrType) / 10000.0f; |
| | | |
| | | #if UNITY_EDITOR |
| | | //排除值为0的属性输出 |
| | | var tmpPropertyVariables = propertyVariables.Where(x => x.Value > 0).ToDictionary(x => x.Key, x => x.Value); |
| | | if (!tmpPropertyVariables.IsNullOrEmpty()) |
| | | propertyStrForDebug += $"属性ID {attrType} - {JsonMapper.ToJson(tmpPropertyVariables)}"; |
| | | #endif |
| | | return JaceCalculator.Calculate(formula, propertyVariables); |
| | | } |
| | | |
| | | |
| | | int GetLineUpPer(int attrType, string key) |
| | | { |
| | | if (!PlayerPropertyConfig.baseAttrs.Contains(attrType)) |
| | | { |
| | | return 0; |
| | | } |
| | | |
| | | return lineUpPerDict[key]; |
| | | } |
| | | |
| | | int GetBookPer(int attrType) |
| | | { |
| | | if (!PlayerPropertyConfig.baseAttrs.Contains(attrType)) |
| | | { |
| | | return 0; |
| | | } |
| | | return HeroUIManager.Instance.bookPer; |
| | | } |
| | | |
| | | int GetCountryPer(int attrType) |
| | | { |
| | | if (PlayerPropertyConfig.baseAttr2perDict.ContainsKey(attrType)) |
| | | { |
| | | var pertype = PlayerPropertyConfig.baseAttr2perDict[attrType]; |
| | | return countryAttrs.ContainsKey(pertype) ? countryAttrs[pertype] : 0; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | |
| | | #endregion |
| | | |
| | | |
| | | #region 计算战力 |
| | | //如果服务端战力计算有压力,可改成关键点结算(如同步排行榜跨服等),表现由客户端自己计算 |
| | | //装备战力为最终总战力的结果比(提升整个角色总战力) |
| | | |
| | | //计算总战力中的武将战力,几个武将加起来就是总战力,其他功能属性计算应该涵盖在英雄里 |
| | | public long CalculatePower() |
| | | { |
| | | #if UNITY_EDITOR |
| | | Debug.Log("战力:开始计算"); |
| | | #endif |
| | | // --- 先计算所有功能的汇总属性 --- |
| | | RefreshLVAttrs(); |
| | | RefrehEquipAttrs(); |
| | | RefreshTeamAttrs(); |
| | | |
| | | |
| | | // --- 算单武将功能属性战力 后相加--- |
| | | long fightPower = 0; |
| | | var team = TeamManager.Instance.GetTeam(teamTypeCalc); |
| | | if (team == null) |
| | | { |
| | | return fightPower; |
| | | } |
| | | TeamHero[] teamHeroes = isPreviewTeamPower ? team.tempHeroes : team.serverHeroes; |
| | | foreach (var hero in teamHeroes) |
| | | { |
| | | if (hero == null) |
| | | { |
| | | continue; |
| | | } |
| | | HeroInfo heroInfo = HeroManager.Instance.GetHero(hero.guid); |
| | | if (heroInfo == null) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | fightPower += CalculateTeamHeroPower(heroInfo); |
| | | |
| | | } |
| | | |
| | | #if UNITY_EDITOR |
| | | Debug.Log("战力:计算完毕 " + fightPower); |
| | | #endif |
| | | return fightPower; |
| | | } |
| | | |
| | | #if UNITY_EDITOR |
| | | string propertyStrForDebug = ""; |
| | | #endif |
| | | |
| | | //计算阵容中武将战力 |
| | | public long CalculateTeamHeroPower(HeroInfo hero) |
| | | { |
| | | |
| | | fightPowerVariables.Clear(); |
| | | hero.RefreshFetterAttrsWhenCalcPower(teamTypeCalc); //羁绊属性要实时算 |
| | | |
| | | #if UNITY_EDITOR |
| | | propertyStrForDebug = ""; |
| | | #endif |
| | | foreach (var config in PlayerPropertyConfig.GetValues()) |
| | | { |
| | | if (config.showType < 1 || config.showType > 4) |
| | | { |
| | | continue; |
| | | } |
| | | if (config.showType == 1) |
| | | { |
| | | fightPowerVariables[config.Parameter] = (ulong)GetPropertyVaule(config.ID, hero, propertyFormula); |
| | | } |
| | | else |
| | | { |
| | | if (tables.ContainsKey(id)) |
| | | { |
| | | tables[id] = tables[id] + value; |
| | | } |
| | | else |
| | | { |
| | | tables[id] = value; |
| | | } |
| | | fightPowerVariables[config.Parameter] = (ulong)GetPropertyVaule(config.ID, hero, fightPropertyFormula); |
| | | } |
| | | } |
| | | |
| | | public void AddRange(List<int> ids, List<int> values) |
| | | { |
| | | if (ids.IsNullOrEmpty() || values.IsNullOrEmpty()) |
| | | { |
| | | return; |
| | | } |
| | | #if UNITY_EDITOR |
| | | Debug.Log($"战力:武将ID {hero.heroId} 属性信息 {propertyStrForDebug}"); |
| | | #endif |
| | | |
| | | var count = Mathf.Min(ids.Count, values.Count); |
| | | for (int i = 0; i < count; i++) |
| | | { |
| | | Add(ids[i], values[i]); |
| | | } |
| | | } |
| | | //属性系数根据官职等级的加成 |
| | | var fightPowerRatioConfig = FightPowerRatioConfig.Get(PlayerDatas.Instance.baseData.realmLevel); |
| | | |
| | | fightPowerVariables["AtkRatio"] = fightPowerRatioConfig.AtkRatio; |
| | | fightPowerVariables["MaxHPRatio"] = fightPowerRatioConfig.MaxHPRatio; |
| | | fightPowerVariables["DefRatio"] = fightPowerRatioConfig.DefRatio; |
| | | fightPowerVariables["StunRateRatio"] = fightPowerRatioConfig.StunRateRatio; |
| | | fightPowerVariables["SuperHitRateRatio"] = fightPowerRatioConfig.SuperHitRateRatio; |
| | | fightPowerVariables["ComboRateRatio"] = fightPowerRatioConfig.ComboRateRatio; |
| | | fightPowerVariables["MissRateRatio"] = fightPowerRatioConfig.MissRateRatio; |
| | | fightPowerVariables["ParryRateRatio"] = fightPowerRatioConfig.ParryRateRatio; |
| | | fightPowerVariables["SuckHPPerRatio"] = fightPowerRatioConfig.SuckHPPerRatio; |
| | | fightPowerVariables["StunRateDefRatio"] = fightPowerRatioConfig.StunRateDefRatio; |
| | | fightPowerVariables["SuperHitRateDefRatio"] = fightPowerRatioConfig.SuperHitRateDefRatio; |
| | | fightPowerVariables["ComboRateDefRatio"] = fightPowerRatioConfig.ComboRateDefRatio; |
| | | fightPowerVariables["MissRateDefRatio"] = fightPowerRatioConfig.MissRateDefRatio; |
| | | fightPowerVariables["ParryRateDefRatio"] = fightPowerRatioConfig.ParryRateDefRatio; |
| | | fightPowerVariables["SuckHPPerDefRatio"] = fightPowerRatioConfig.SuckHPPerDefRatio; |
| | | fightPowerVariables["NormalSkillPerRatio"] = fightPowerRatioConfig.NormalSkillPerRatio; |
| | | fightPowerVariables["NormalSkillPerDefRatio"] = fightPowerRatioConfig.NormalSkillPerDefRatio; |
| | | fightPowerVariables["AngerSkillPerRatio"] = fightPowerRatioConfig.AngerSkillPerRatio; |
| | | fightPowerVariables["AngerSkillPerDefRatio"] = fightPowerRatioConfig.AngerSkillPerDefRatio; |
| | | fightPowerVariables["SuperDamPerRatio"] = fightPowerRatioConfig.SuperDamPerRatio; |
| | | fightPowerVariables["SuperDamPerDefRatio"] = fightPowerRatioConfig.SuperDamPerDefRatio; |
| | | fightPowerVariables["ShieldPerRatio"] = fightPowerRatioConfig.ShieldPerRatio; |
| | | fightPowerVariables["ShieldPerDefRatio"] = fightPowerRatioConfig.ShieldPerDefRatio; |
| | | |
| | | |
| | | long fightPower = (long)JaceCalculator.Calculate(fightPowerFormula, fightPowerVariables); |
| | | #if UNITY_EDITOR |
| | | //排除值为0的属性输出 |
| | | var tmpFightPowerVariables = fightPowerVariables.Where(x => x.Value > 0).ToDictionary(x => x.Key, x => x.Value); |
| | | if (!tmpFightPowerVariables.IsNullOrEmpty()) |
| | | Debug.Log($"战力:武将ID {hero.heroId} 属性战力 {fightPower} 属性战力参数 {JsonMapper.ToJson(tmpFightPowerVariables)}"); |
| | | #endif |
| | | |
| | | //加上技能战力 |
| | | fightPowerVariables.Clear(); |
| | | fightPowerVariables["PlayerLV"] = PlayerDatas.Instance.baseData.LV; |
| | | fightPowerVariables["OfficialLV"] = PlayerDatas.Instance.baseData.realmLevel; |
| | | fightPowerVariables["SkillPower"] = hero.GetSkillsFightPower(); |
| | | |
| | | long skillPower = (long)JaceCalculator.Calculate(skillFightPowerFormula, fightPowerVariables); |
| | | |
| | | #if UNITY_EDITOR |
| | | Debug.Log($"战力:武将ID {hero.heroId} 技能战力 {skillPower} 技能参数 {JsonMapper.ToJson(fightPowerVariables)}"); |
| | | |
| | | Debug.Log($"战力:武将ID {hero.heroId} 总战力 {fightPower + skillPower}"); |
| | | #endif |
| | | |
| | | return fightPower + skillPower; |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 和身上装备对比差 |
| | | /// </summary> |
| | | /// <param name="item">地板装备</param> |
| | | /// <returns></returns> |
| | | public long GetFightPowerChange(ItemModel item) |
| | | { |
| | | InitFightPowerParam(); |
| | | var fightPower = CalculatePower(); |
| | | |
| | | #region 计算战斗力 |
| | | public static readonly string FightPowerFormula = "FightpowerFormula"; |
| | | InitFightPowerParam(dropindex: item.gridIndex); |
| | | var tmpFightPower = CalculatePower(); |
| | | return tmpFightPower - fightPower; |
| | | } |
| | | |
| | | // public static int GetFightPower(Dictionary<int, int> _propertyDict) |
| | | // { |
| | | // Equation.Instance.Clear(); |
| | | // if (_propertyDict == null || _propertyDict.Count == 0) |
| | | // { |
| | | // return 0; |
| | | // } |
| | | |
| | | // foreach (var _key in _propertyDict.Keys) |
| | | // { |
| | | // PlayerPropertyConfig cfg = PlayerPropertyConfig.Get(_key); |
| | | // if (cfg != null) |
| | | // { |
| | | // if (_key == 7) |
| | | // { |
| | | // Equation.Instance.AddKeyValue("MinAtk", _propertyDict[_key]); |
| | | // Equation.Instance.AddKeyValue("MaxAtk", _propertyDict[_key]); |
| | | // } |
| | | // else if (_key == 24) |
| | | // { |
| | | // Equation.Instance.AddKeyValue("PetMinAtk", _propertyDict[_key]); |
| | | // Equation.Instance.AddKeyValue("PetMaxAtk", _propertyDict[_key]); |
| | | // } |
| | | // else |
| | | // { |
| | | // ulong attrValue = (ulong)_propertyDict[_key]; |
| | | // var fightParm = GetFightPowerParmByAttrId(_key); |
| | | // if (_key == 11) |
| | | // { |
| | | // var playerLv = PlayerDatas.Instance.baseData.LV; |
| | | // var paramConfig = FightPowerParamConfig.Get(playerLv); |
| | | // Equation.Instance.AddKeyValue("AtkSpeedParameter", paramConfig.AtkSpeedParameter); |
| | | // } |
| | | // else |
| | | // { |
| | | // if (fightParm != 0) |
| | | // { |
| | | // attrValue = attrValue * (ulong)fightParm; |
| | | // } |
| | | // } |
| | | // Equation.Instance.AddKeyValue(cfg.Parameter, attrValue); |
| | | // } |
| | | // } |
| | | // 单英雄查看战力 |
| | | // 1. 上阵英雄显示,在主线阵容下的战力 |
| | | // 2. 非上阵或其他上阵阵容:上阵不足6个人的,按增加的方式的计算;人数满的情况下按替换6号位计算 |
| | | public long GetHeroFightPower(HeroInfo heroInfo) |
| | | { |
| | | bool ispreview = false; |
| | | var team = TeamManager.Instance.GetTeam(TeamType.Story); |
| | | if (!team.HasHero(heroInfo.itemHero.guid)) |
| | | { |
| | | //替换上阵位置 |
| | | ispreview = true; |
| | | var index = team.GetEmptyPosition(); |
| | | if (index < 0) |
| | | { |
| | | team.AddHero(heroInfo, 5); |
| | | } |
| | | else |
| | | { |
| | | team.AddHero(heroInfo, index); |
| | | } |
| | | } |
| | | |
| | | // } |
| | | // FuncConfigConfig funcCfg = FuncConfigConfig.Get(FightPowerFormula); |
| | | // return Equation.Instance.Eval<int>(funcCfg.Numerical1); |
| | | // } |
| | | InitFightPowerParam(ispreview: ispreview); |
| | | RefreshLVAttrs(); |
| | | RefrehEquipAttrs(); |
| | | RefreshTeamAttrs(); |
| | | |
| | | // public static int GetFightPowerParmByAttrId(int attrId) |
| | | // { |
| | | // int playerLv = PlayerDatas.Instance.baseData.LV; |
| | | // FightPowerParamConfig paramConfig = FightPowerParamConfig.Get(playerLv); |
| | | // PlayerPropertyConfig cfg = PlayerPropertyConfig.Get(attrId); |
| | | // if (paramConfig == null || cfg == null) return 0; |
| | | var fightPower = CalculateTeamHeroPower(heroInfo); |
| | | |
| | | // switch (cfg.Parameter) |
| | | // { |
| | | // case "Hit": |
| | | // return paramConfig.Hit; |
| | | // case "Miss": |
| | | // return paramConfig.Miss; |
| | | // case "IgnoreDefRate": |
| | | // return paramConfig.IgnoreDefRate; |
| | | // case "DamChanceDef": |
| | | // return paramConfig.DamChanceDef; |
| | | // case "FaintRate": |
| | | // return paramConfig.FaintRate; |
| | | // case "LuckyHitRateReduce": |
| | | // return paramConfig.LuckyHitRateReduce; |
| | | // case "SkillAtkRate": |
| | | // return paramConfig.SkillAtkRate; |
| | | // case "SkillAtkRateReduce": |
| | | // return paramConfig.SkillAtkRateReduce; |
| | | // case "DamagePerPVP": |
| | | // return paramConfig.DamagePerPVP; |
| | | // case "DamagePerPVPReduce": |
| | | // return paramConfig.DamagePerPVPReduce; |
| | | // case "DamBackPer": |
| | | // return paramConfig.DamBackPer; |
| | | // case "IgnoreDefRateReduce": |
| | | // return paramConfig.IgnoreDefRateReduce; |
| | | // case "FaintDefRate": |
| | | // return paramConfig.FaintDefRate; |
| | | // case "AtkSpeedParameter": |
| | | // return paramConfig.AtkSpeedParameter; |
| | | // case "JobAHurtAddPer": |
| | | // return paramConfig.JobAHurtAddPer; |
| | | // case "JobBHurtAddPer": |
| | | // return paramConfig.JobBHurtAddPer; |
| | | // case "JobCHurtAddPer": |
| | | // return paramConfig.JobCHurtAddPer; |
| | | // case "JobAAtkReducePer": |
| | | // return paramConfig.JobAAtkReducePer; |
| | | // case "JobBAtkReducePer": |
| | | // return paramConfig.JobBAtkReducePer; |
| | | // case "JobCAtkReducePer": |
| | | // return paramConfig.JobCAtkReducePer; |
| | | // case "SuperHitRate": |
| | | // return paramConfig.SuperHitRate; |
| | | // case "LuckyHitRate": |
| | | // return paramConfig.LuckyHitRate; |
| | | // case "SuperHitRateReduce": |
| | | // return paramConfig.SuperHitRateReduce; |
| | | // case "FinalHurtPer": |
| | | // return paramConfig.FinalHurtPer; |
| | | // case "FinalHurtReducePer": |
| | | // return paramConfig.FinalHurtReducePer; |
| | | // case "NPCHurtAddPer": |
| | | // return paramConfig.NPCHurtAddPer; |
| | | // case "NormalHurtPer": |
| | | // return paramConfig.NormalHurtPer; |
| | | // case "FabaoHurtPer": |
| | | // return paramConfig.FabaoHurtPer; |
| | | // case "AffairSpeedPer": |
| | | // return paramConfig.AffairSpeedPer; |
| | | // case "FamilyBossHurtPer": |
| | | // return paramConfig.FamilyBossHurtPer; |
| | | // case "FamilyWarHPPer": |
| | | // return paramConfig.FamilyWarHPPer; |
| | | // case "FamilyWarAtkPer": |
| | | // return paramConfig.FamilyWarAtkPer; |
| | | // case "FamilySitExpPer": |
| | | // return paramConfig.FamilySitExpPer; |
| | | // case "BossFinalHurtPer": |
| | | // return paramConfig.BossFinalHurtPer; |
| | | // } |
| | | //计算完恢复队伍 |
| | | if (ispreview) |
| | | team.RestoreTeam(); |
| | | return fightPower; |
| | | } |
| | | |
| | | // return 0; |
| | | // } |
| | | |
| | | //查看阵容战力 |
| | | public long GetTeamFightPower(TeamType team, bool isPreview) |
| | | { |
| | | InitFightPowerParam(team, -1, isPreview); |
| | | return CalculatePower(); |
| | | } |
| | | #endregion |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | |
| | |
|
| | | public class OperationTimeHepler : Singleton<OperationTimeHepler>
|
| | | {
|
| | | public Dictionary<Operation, OperationBase> operationDict = new Dictionary<Operation, OperationBase>();
|
| | | public Dictionary<OperationType, OperationBase> operationDict = new Dictionary<OperationType, OperationBase>();
|
| | |
|
| | | public static StringBuilder textBuilder = new StringBuilder();
|
| | |
|
| | | public event Action<Operation> operationTimeUpdateEvent;
|
| | | public event Action<Operation> operationServerCloseEvent;//特殊情况下触发
|
| | | public event Action<Operation, int> operationEndEvent;//活动结束时间触发 第二个参数0--过活动时间触发 1--过活动天触发
|
| | | public event Action<Operation, int> operationStartEvent;//活动开始时间并且满足开启条件触发 第二个参数0--活动时间触发 1--活动天触发
|
| | | public event Action<OperationType> operationTimeUpdateEvent;
|
| | | public event Action<OperationType> operationServerCloseEvent;//特殊情况下触发
|
| | | public event Action<OperationType, int> operationEndEvent;//活动结束时间触发 第二个参数0--过活动时间触发 1--过活动天触发
|
| | | public event Action<OperationType, int> operationStartEvent;//活动开始时间并且满足开启条件触发 第二个参数0--活动时间触发 1--活动天触发
|
| | | public event Action<int> dayResetEvent;//活动重置事件0-0点 1-5点
|
| | | public event Action<Operation> operationAdvanceEvent;//活动在提前开启的时间内
|
| | | public event Action<OperationType> operationAdvanceEvent;//活动在提前开启的时间内
|
| | |
|
| | | public OperationTimeHepler()
|
| | | {
|
| | |
| | | {
|
| | | return;
|
| | | }
|
| | | for (int i = 0; i < (int)Operation.max; i++)
|
| | | for (int i = 0; i < (int)OperationType.max; i++)
|
| | | {
|
| | | if (operationDict.ContainsKey((Operation)i))
|
| | | if (operationDict.ContainsKey((OperationType)i))
|
| | | {
|
| | | var operation = operationDict[(Operation)i];
|
| | | var operation = operationDict[(OperationType)i];
|
| | | if (!operation.inDateNotify && operation.SatisfyOpenCondition()
|
| | | && operation.InDay(TimeUtility.ServerNow))
|
| | | {
|
| | | operation.inDateNotify = true;
|
| | | operation.stepDateNotify = false;
|
| | | Debug.LogFormat("{0} 活动天开始", (Operation)i);
|
| | | Debug.LogFormat("{0} 活动天开始", (OperationType)i);
|
| | | if (operationStartEvent != null)
|
| | | {
|
| | | operationStartEvent((Operation)i, 1);
|
| | | operationStartEvent((OperationType)i, 1);
|
| | | }
|
| | | }
|
| | | else if (!operation.stepDateNotify && !operation.InDay(TimeUtility.ServerNow))
|
| | | {
|
| | | operation.inDateNotify = false;
|
| | | operation.stepDateNotify = true;
|
| | | Debug.LogFormat("{0} 活动天结束", (Operation)i);
|
| | | Debug.LogFormat("{0} 活动天结束", (OperationType)i);
|
| | | if (operationEndEvent != null)
|
| | | {
|
| | | operationEndEvent((Operation)i, 1);
|
| | | operationEndEvent((OperationType)i, 1);
|
| | | }
|
| | | }
|
| | | if (!operation.inTimeNotify && operation.SatisfyOpenCondition()
|
| | |
| | | {
|
| | | operation.inTimeNotify = true;
|
| | | operation.stepTimeNotify = false;
|
| | | Debug.LogFormat("{0} 活动时间开始", (Operation)i);
|
| | | Debug.LogFormat("{0} 活动时间开始", (OperationType)i);
|
| | | if (operationStartEvent != null)
|
| | | {
|
| | | operationStartEvent((Operation)i, 0);
|
| | | operationStartEvent((OperationType)i, 0);
|
| | | }
|
| | | }
|
| | | else if (!operation.stepTimeNotify && !operation.InTime(TimeUtility.ServerNow))
|
| | |
| | | operation.inTimeNotify = false;
|
| | | operation.stepTimeNotify = true;
|
| | | operation.inAdvanceNotify = false;
|
| | | Debug.LogFormat("{0} 活动时间结束", (Operation)i);
|
| | | Debug.LogFormat("{0} 活动时间结束", (OperationType)i);
|
| | | if (operationEndEvent != null)
|
| | | {
|
| | | operationEndEvent((Operation)i, 0);
|
| | | operationEndEvent((OperationType)i, 0);
|
| | | }
|
| | | }
|
| | |
|
| | |
| | | && operation.InAdvanceTime(TimeUtility.ServerNow))
|
| | | {
|
| | | operation.inAdvanceNotify = true;
|
| | | Debug.LogFormat("{0} 活动提前开启", (Operation)i);
|
| | | Debug.LogFormat("{0} 活动提前开启", (OperationType)i);
|
| | | if (operationAdvanceEvent != null)
|
| | | {
|
| | | operationAdvanceEvent((Operation)i);
|
| | | operationAdvanceEvent((OperationType)i);
|
| | | }
|
| | | }
|
| | | }
|
| | |
| | | // }
|
| | | // }
|
| | |
|
| | | public void ForceStopOperation(Operation operationType)
|
| | | public void ForceStopOperation(OperationType operationType)
|
| | | {
|
| | | if (operationDict.ContainsKey(operationType))
|
| | | {
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | public bool TryGetOperationTime(Operation type, out OperationBase operation)
|
| | | public bool TryGetOperationTime(OperationType type, out OperationBase operation)
|
| | | {
|
| | | return operationDict.TryGetValue(type, out operation);
|
| | | }
|
| | |
|
| | | public bool TryGetOperation<T>(Operation type, out T operation) where T : OperationBase
|
| | | public bool TryGetOperation<T>(OperationType type, out T operation) where T : OperationBase
|
| | | {
|
| | | operation = null;
|
| | | if (operationDict.ContainsKey(type))
|
| | |
| | | return false;
|
| | | }
|
| | |
|
| | | public bool InOperationTime(Operation type)
|
| | | public bool InOperationTime(OperationType type)
|
| | | {
|
| | | OperationBase operation;
|
| | | if (TryGetOperationTime(type, out operation))
|
| | |
| | | return false;
|
| | | }
|
| | |
|
| | | public bool InOperationTime(Operation type, DateTime time)
|
| | | public bool InOperationTime(OperationType type, DateTime time)
|
| | | {
|
| | | OperationBase operation;
|
| | | if (TryGetOperationTime(type, out operation))
|
| | |
| | | return false;
|
| | | }
|
| | |
|
| | | public bool InOperationJoinTime(Operation type, DateTime time)
|
| | | public bool InOperationJoinTime(OperationType type, DateTime time)
|
| | | {
|
| | | OperationBase operation;
|
| | | if (TryGetOperationTime(type, out operation))
|
| | |
| | | return false;
|
| | | }
|
| | |
|
| | | public bool InOperationDay(Operation type)
|
| | | public bool InOperationDay(OperationType type)
|
| | | {
|
| | | OperationBase operation;
|
| | | if (TryGetOperationTime(type, out operation))
|
| | |
| | | return false;
|
| | | }
|
| | |
|
| | | public int GetOperationSurplusTime(Operation type)
|
| | | public int GetOperationSurplusTime(OperationType type)
|
| | | {
|
| | | OperationBase operation;
|
| | | if (TryGetOperationTime(type, out operation))
|
| | |
| | | return 0;
|
| | | }
|
| | |
|
| | | public bool InOperationAdvance(Operation type)
|
| | | public bool InOperationAdvance(OperationType type)
|
| | | {
|
| | | OperationBase operation;
|
| | | if (TryGetOperationTime(type, out operation))
|
| | |
| | | return false;
|
| | | }
|
| | |
|
| | | public int GetOperationSecondsBeforeStart(Operation type)
|
| | | public int GetOperationSecondsBeforeStart(OperationType type)
|
| | | {
|
| | | OperationBase operation;
|
| | | if (TryGetOperationTime(type, out operation))
|
| | |
| | | return 0;
|
| | | }
|
| | |
|
| | | public bool SatisfyOpenCondition(Operation type)
|
| | | public bool SatisfyOpenCondition(OperationType type)
|
| | | {
|
| | | OperationBase operation;
|
| | | if (TryGetOperationTime(type, out operation))
|
| | |
| | | return false;
|
| | | }
|
| | |
|
| | | public bool SatisfyOpenCondition(Operation type, DateTime time)
|
| | | public bool SatisfyOpenCondition(OperationType type, DateTime time)
|
| | | {
|
| | | OperationBase operation;
|
| | | if (TryGetOperationTime(type, out operation))
|
| | |
| | | }
|
| | |
|
| | | //活动开启中,有参与进行时间段
|
| | | public bool SatisfyJoinCondition(Operation type, DateTime time)
|
| | | public bool SatisfyJoinCondition(OperationType type, DateTime time)
|
| | | {
|
| | | OperationBase operation;
|
| | | if (TryGetOperationTime(type, out operation))
|
| | |
| | | return false;
|
| | | }
|
| | |
|
| | | public bool IsPrepareTime(Operation type, DateTime time)
|
| | | public bool IsPrepareTime(OperationType type, DateTime time)
|
| | | {
|
| | | OperationBase operation;
|
| | | if (TryGetOperationTime(type, out operation))
|
| | |
| | | return false;
|
| | | }
|
| | |
|
| | | public bool SatisfyAdvanceCondition(Operation type)
|
| | | public bool SatisfyAdvanceCondition(OperationType type)
|
| | | {
|
| | | OperationBase operation;
|
| | | if (TryGetOperationTime(type, out operation))
|
| | |
| | | return false;
|
| | | }
|
| | |
|
| | | public void ProcessConditionError(Operation type)
|
| | | public void ProcessConditionError(OperationType type)
|
| | | {
|
| | | if (SatisfyOpenCondition(type))
|
| | | {
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | public enum Operation
|
| | | public enum OperationType
|
| | | {
|
| | | MultipleExp,
|
| | | ConsumeRebate,
|
| | |
| | | //排行榜活动的商店
|
| | | public int rankActStore_MoneyType;
|
| | | public int rankActStore_StoreType;
|
| | | public Operation rankActStore_ActType;
|
| | | public OperationType rankActStore_ActType;
|
| | |
|
| | | public override void Init()
|
| | | {
|
| | |
| | | return false; |
| | | } |
| | | |
| | | public bool HasHeroInServer(string guid) |
| | | { |
| | | foreach (var hero in serverHeroes) |
| | | { |
| | | if (hero != null && hero.guid == guid) |
| | | { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | //客户端从0开始,服务端从1开始 |
| | | public int GetEmptyPosition() |
| | | { |
| | |
| | | return; |
| | | } |
| | | |
| | | TeamHero targetHero = tempHeroes[targetPosition]; |
| | | |
| | | if (null == targetHero) |
| | | { |
| | | TeamHero newHero = new TeamHero(heroInfo, targetPosition, this); |
| | | SetTeamHero(targetPosition, newHero); |
| | | } |
| | | else |
| | | { |
| | | SetTeamHero(targetPosition, new TeamHero(heroInfo, targetPosition, this)); |
| | | } |
| | | SetTeamHero(targetPosition, new TeamHero(heroInfo, targetPosition, this)); |
| | | } |
| | | |
| | | |
| | |
| | | using UnityEngine; |
| | | using UnityEngine.PlayerLoop; |
| | | |
| | | public partial class TeamHero |
| | | { |
| | |
| | | heroId = heroInfo.itemHero.config.ID; |
| | | SkinID = heroInfo.SkinID; |
| | | skinConfig = heroInfo.skinConfig; |
| | | Country = heroInfo.heroCountry; |
| | | |
| | | teamBase = _teamBase; |
| | | |
| | |
| | | sequence.Append(txtBase.DOText(DisplayBasePowerNum(nowValue), rollTime).SetEase(rollEaseType).OnComplete(() => { SetInitPosition(nowValue, changePower, isAdd); }));
|
| | | }
|
| | | }
|
| | | #if UNITY_EDITOR
|
| | | Debug.Log($"count {i} changeValue {changeValue} nowValue {nowValue} isAdd {isAdd} basePower {basePower} changePower {changePower} nowPower {nowPower} rollTime {rollTime}");
|
| | | #endif
|
| | | // #if UNITY_EDITOR
|
| | | // Debug.Log($"count {i} changeValue {changeValue} nowValue {nowValue} isAdd {isAdd} basePower {basePower} changePower {changePower} nowPower {nowPower} rollTime {rollTime}");
|
| | | // #endif
|
| | | }
|
| | | sequence.Join(textChangeSequence);
|
| | |
|
| | |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | Debug.LogError($"{uiName}界面的InitComponentInternal报错: {e.Message}"); |
| | | Debug.LogError($"{uiName}界面的InitComponentInternal报错: {e.StackTrace}"); |
| | | } |
| | | |
| | | try |
| | |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | Debug.LogError($"{uiName}界面的InitComponent报错: {e.Message}"); |
| | | Debug.LogError($"{uiName}界面的InitComponent报错: {e.StackTrace}"); |
| | | } |
| | | |
| | | // 保存原始值用于动画 |
| | |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | Debug.LogError($"{uiName}界面的OnPreOpen报错: {e.Message}"); |
| | | Debug.LogError($"{uiName}界面的OnPreOpen报错: {e.StackTrace}"); |
| | | } |
| | | |
| | | StopCurrentAnimation(); |
| | |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | Debug.LogError($"{uiName}界面的OnOpen报错: {e.Message}"); |
| | | Debug.LogError($"{uiName}界面的OnOpen报错: {e.StackTrace}"); |
| | | } |
| | | |
| | | ApplyClickEmptySpaceClose(); |
| | |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | Debug.LogError($"{uiName}界面的NextFrameAfterOpen报错: {e.Message}"); |
| | | Debug.LogError($"{uiName}界面的NextFrameAfterOpen报错: {e.StackTrace}"); |
| | | } |
| | | }); |
| | | } |
| | |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | Debug.LogError($"{uiName}界面的OnPreClose报错: {e.Message}"); |
| | | Debug.LogError($"{uiName}界面的OnPreClose报错: {e.StackTrace}"); |
| | | } |
| | | |
| | | StopCurrentAnimation(); |
| | |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | Debug.LogError($"{uiName}界面的OnClose报错: {e.Message}"); |
| | | Debug.LogError($"{uiName}界面的OnClose报错: {e.StackTrace}"); |
| | | } |
| | | |
| | | if (closeAnimationType == UIAnimationType.None) |
| | |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | Debug.LogError($"{uiName}界面的CompleteClose报错: {e.Message}"); |
| | | Debug.LogError($"{uiName}界面的CompleteClose报错: {e.StackTrace}"); |
| | | } |
| | | } |
| | | // 否则在动画完成后禁用游戏对象(在PlayCloseAnimation中处理) |
| | |
| | | } |
| | | catch (System.Exception e) |
| | | { |
| | | Debug.LogError($"播放打开动画时出错: {e.Message}"); |
| | | Debug.LogError($"播放打开动画时出错: {e.StackTrace}"); |
| | | |
| | | // 出错时确保UI可见并可交互 |
| | | if (canvasGroup != null) |
| | |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | Debug.LogError($"{uiName}界面的CompleteClose报错: {e.Message}"); |
| | | Debug.LogError($"{uiName}界面的CompleteClose报错: {e.StackTrace}"); |
| | | } |
| | | } |
| | | }); |
| | |
| | | } |
| | | catch (System.Exception e) |
| | | { |
| | | Debug.LogError($"播放关闭动画时出错: {e.Message}"); |
| | | Debug.LogError($"播放关闭动画时出错: {e.StackTrace}"); |
| | | |
| | | // 出错时直接完成关闭 |
| | | isAnimating = false; |
New file |
| | |
| | | using Jace; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | |
| | | public static class JaceCalculator |
| | | { |
| | | private static readonly CalculationEngine Engine = new CalculationEngine(); |
| | | |
| | | /// <summary> |
| | | /// 解析并计算数学表达式 |
| | | /// </summary> |
| | | /// <param name="formula">数学表达式字符串</param> |
| | | /// <param name="variables">变量字典</param> |
| | | /// <returns>计算结果</returns> |
| | | public static double Calculate(string formula, Dictionary<string, double> variables) |
| | | { |
| | | if (string.IsNullOrEmpty(formula)) |
| | | { |
| | | throw new ArgumentException("Formula cannot be null or empty."); |
| | | } |
| | | |
| | | if (variables == null || variables.Count == 0) |
| | | { |
| | | throw new ArgumentException("Variables dictionary cannot be null or empty."); |
| | | } |
| | | |
| | | try |
| | | { |
| | | return Engine.Calculate(formula, variables); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | throw new InvalidOperationException($"Failed to calculate formula: {ex.Message}", ex); |
| | | } |
| | | } |
| | | } |
copy from Main/System/Hero/HeroInfo.Quality.cs.meta
copy to Main/Utility/JaceCalculator.cs.meta
File was copied from Main/System/Hero/HeroInfo.Quality.cs.meta |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 8540c5ed5104dfe40b0bff4aaf9a080b |
| | | guid: ebee4528e9596394886463d65c214b23 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |