public TargetInstruction[] BasicInformation(MethodDef method) { var insts = new TargetInstruction[2]; foreach (var instruction in method.Body.Instructions.Where( i => i.Operand is IMethodDefOrRef m && m.IsMethod(nameof(ModTranslation), nameof(ModTranslation.SetDefault)))) { var source = method.Body.FindObjectInstance(instruction); var value = method.Body.FindStringLiteralBefore(instruction); if (source == null || value == null) { continue; } // some mod may have custom translation here // source will be ldloc.x if (((IMethodDefOrRef)source.Operand)?.Name?.ToString() == null) { continue; } switch (((IMethodDefOrRef)source.Operand).Name) { case "get_Tooltip": insts[1] = new TargetInstruction { ReplaceTarget = source, Value = value }; break; case "get_DisplayName": insts[0] = new TargetInstruction { ReplaceTarget = source, Value = value }; break; } } return(insts); }
public TargetInstruction[] SetDefault(MethodDef method) { var targets = new TargetInstruction[2]; foreach (var instruction in method.Body.Instructions.Where( i => i.Operand is IMethodDefOrRef m && m.IsMethod(nameof(ModTranslation), nameof(ModTranslation.SetDefault)))) { var source = method.Body.FindObjectInstance(instruction); var value = method.Body.FindStringLiteralBefore(instruction); if (source == null || value == null) { continue; } switch (((IMethodDefOrRef)source.Operand).Name) { case "get_DisplayName": targets[0] = new TargetInstruction { ReplaceTarget = source, Value = value }; break; case "get_Description": targets[1] = new TargetInstruction { ReplaceTarget = source, Value = value }; break; } } return(targets); }
public TargetInstruction[] ChatButton(MethodDef method) { var targets = new TargetInstruction[2]; var instructions = method.Body.Instructions; for (var index = 0; index < instructions.Count; index++) { var ldstr = instructions[index]; if (ldstr.OpCode != OpCodes.Ldstr) { continue; } // arg_1: shop button 1 // arg_2: shop button 2 // value is assigned to the byRef parameter var ldarg = instructions.ElementAtOrDefault(index - 1); if (ldarg == null) { continue; } if (ldarg.OpCode.Equals(OpCodes.Ldarg_1)) { targets[0] = new TargetInstruction(ldstr); } else if (ldarg.OpCode.Equals(OpCodes.Ldarg_2)) { targets[1] = new TargetInstruction(ldstr); } } return(targets); }
public override KeyValuePair <string, Expression>?GetExpression <TSource>(Type outerSourceType, ParameterExpression rootParameter, IEnumerable <TSource> source) { if (outerSourceType == null) { throw new ArgumentNullException(nameof(outerSourceType)); } // 1. Split the value & extract the field names or requests. var splitted = Parameter.Split(','); var instructions = splitted.Select(s => InstructionHelper.ExtractInstruction(s)).Where(s => s.HasValue); if (!parameters.Any(p => instructions.Any(i => i.Value.Key == p))) { throw new ArgumentException("either inner or outer parameter is not specified"); } // 2. Construct the expressions. var outer = instructions.First(i => i.Value.Key == outerKey).Value.Value; var inner = instructions.First(i => i.Value.Key == innerKey).Value.Value; var select = instructions.FirstOrDefault(i => i.Value.Key == selectKey); var selectValue = string.Empty; if (select != null) { selectValue = select.Value.Value; } Type innerSourceType = outerSourceType; Expression targetExpression = null; if (TargetInstruction != null) { var targetArg = Expression.Parameter(typeof(IQueryable <TSource>), "t"); targetExpression = TargetInstruction.GetExpression(outerSourceType, targetArg, source).Value.Value; innerSourceType = targetExpression.Type.GetGenericArguments().First(); } Type tResult = innerSourceType; var fieldNames = outer.GetParameters(); var outerArg = Expression.Parameter(outerSourceType, "x"); var innerArg = Expression.Parameter(innerSourceType, "y"); LambdaExpression outerLambda = null, innerLambda = null; Type resultType; if (fieldNames.Count() == 1) { resultType = outerSourceType.GetProperty(fieldNames.First()).PropertyType; var outerProperty = Expression.Property(outerArg, fieldNames.First()); var innerProperty = Expression.Property(innerArg, fieldNames.First()); outerLambda = Expression.Lambda(outerProperty, new ParameterExpression[] { outerArg }); innerLambda = Expression.Lambda(innerProperty, new ParameterExpression[] { innerArg }); } else { var commonAnonType = ReflectionHelper.CreateNewAnonymousType(outerSourceType, fieldNames); resultType = commonAnonType.AsType(); var outerNewExpr = ExpressionBuilder.BuildNew(outer, outerSourceType, commonAnonType, outerArg); var innerNewExpr = ExpressionBuilder.BuildNew(inner, innerSourceType, commonAnonType, innerArg); outerLambda = Expression.Lambda(outerNewExpr, new ParameterExpression[] { outerArg }); innerLambda = Expression.Lambda(innerNewExpr, new ParameterExpression[] { innerArg }); } LambdaExpression selectorResult = null; if (string.IsNullOrWhiteSpace(selectValue)) { selectorResult = Expression.Lambda(outerArg, new ParameterExpression[] { outerArg, innerArg }); } else { var selectAttributes = new List <KeyValuePair <string, ICollection <string> > >(); foreach (var val in selectValue.Split('|')) { var values = val.Split('$'); if (values.Count() != 2 && values.Count() != 1) { continue; } var key = values.First(); var kvp = selectAttributes.FirstOrDefault(s => s.Key == key); if (kvp.IsEmpty()) { kvp = new KeyValuePair <string, ICollection <string> >(key, new List <string>()); selectAttributes.Add(kvp); } if (values.Count() == 2) { kvp.Value.Add(values.ElementAt(1)); } } if (!selectAttributes.Any(a => selectParameters.Contains(a.Key))) { throw new InvalidOperationException("At least one parameter in select is not supported"); } Dictionary <string, Type> mapping = new Dictionary <string, Type>(); var outerSelect = selectAttributes.FirstOrDefault(a => a.Key == outerKey); var innerSelect = selectAttributes.FirstOrDefault(a => a.Key == innerKey); AddTypes(mapping, "outer", outerSourceType, outerSelect); AddTypes(mapping, "inner", innerSourceType, innerSelect); var anonymousType = ReflectionHelper.CreateNewAnonymousType(mapping); var parameters = new List <Expression>(); var tmp = GetParameterExpressions(outerArg, outerSelect); if (tmp != null) { parameters.AddRange(tmp); } tmp = GetParameterExpressions(innerArg, innerSelect); if (tmp != null) { parameters.AddRange(tmp); } var newExpr = Expression.New(anonymousType.DeclaredConstructors.First(), parameters); selectorResult = Expression.Lambda(newExpr, new ParameterExpression[] { innerArg, outerArg }); tResult = anonymousType.AsType(); } var enumarableType = typeof(Queryable); var method = enumarableType.GetMethods().Where(m => m.Name == "Join" && m.IsGenericMethodDefinition).Where(m => m.GetParameters().ToList().Count == 5).First(); var genericMethod = method.MakeGenericMethod(outerSourceType, innerSourceType, resultType, tResult); MethodCallExpression call = null; if (targetExpression == null) { call = Expression.Call(genericMethod, Expression.Constant(source), Expression.Constant(source), outerLambda, innerLambda, selectorResult); } else { call = Expression.Call(genericMethod, Expression.Constant(source), targetExpression, Expression.Constant(outerLambda), Expression.Constant(innerLambda), selectorResult); } return(new KeyValuePair <string, Expression>(Name, call)); }
protected void SetAssignmentTarget(TargetInstruction instruction) { if (_currentAssignmentTarget != null) { throw new FormatException("Assignment target already set"); } switch (instruction.Target) { // special strings case DataElement.SStr sstr: _currentAssignmentTarget = new AssignmentTarget.SpecialString(sstr.FlagType.StringValue); break; // integer variable pointers case DataElement.VInt vint when vint.FlagId.IsPointer: _currentAssignmentTarget = new AssignmentTarget.VariablePointer(vint.FlagType.StringValue, vint.FlagId.PointerId); break; // integer variables case DataElement.VInt vint: // range checks if (vint.FlagId.IntValue < 0) { throw new ArgumentOutOfRangeException(nameof(vint.FlagId.IntValue), vint.FlagId.IntValue, "Flag index must be positive"); } if (vint.FlagId.IntValue >= GlobalFlagTableSize && vint.FlagType.StringValue == YksFormat.GlobalFlag) { throw new ArgumentOutOfRangeException(nameof(vint.FlagId.IntValue), vint.FlagId.IntValue, "Global flag index must be smaller than " + GlobalFlagTableSize); } if (vint.FlagId.IntValue >= LocalFlagTableSize && vint.FlagType.StringValue == YksFormat.Flag) { throw new ArgumentOutOfRangeException(nameof(vint.FlagId.IntValue), vint.FlagId.IntValue, "Local flag index must be smaller than " + LocalFlagTableSize); } _currentAssignmentTarget = new AssignmentTarget.Variable(vint.FlagType.StringValue, vint.FlagId.IntValue); break; // string variable pointers case DataElement.VStr vstr when vstr.FlagId.IsPointer: _currentAssignmentTarget = new AssignmentTarget.VariablePointer(vstr.FlagType.StringValue, vstr.FlagId.PointerId); break; // integer variables case DataElement.VStr vstr: // range checks if (vstr.FlagId.IntValue < 0) { throw new ArgumentOutOfRangeException(nameof(vstr.FlagId.IntValue), vstr.FlagId.IntValue, "String index must be positive"); } if (vstr.FlagId.IntValue >= GlobalStringTableSize && vstr.FlagType.StringValue == YksFormat.GlobalString) { throw new ArgumentOutOfRangeException(nameof(vstr.FlagId.IntValue), vstr.FlagId.IntValue, "String flag index must be smaller than " + GlobalStringTableSize); } if (vstr.FlagId.IntValue >= LocalStringTableSize && vstr.FlagType.StringValue == YksFormat.String) { throw new ArgumentOutOfRangeException(nameof(vstr.FlagId.IntValue), vstr.FlagId.IntValue, "String flag index must be smaller than " + LocalStringTableSize); } _currentAssignmentTarget = new AssignmentTarget.Variable(vstr.FlagType.StringValue, vstr.FlagId.IntValue); break; // local variables case DataElement.VLoc vloc: if (vloc.Id >= Script.InstructionList.MaxLocals) { throw new ArgumentOutOfRangeException(nameof(vloc.Id), vloc.Id, "Local variable id must be smaller than local variable pool size (" + Script.InstructionList.MaxLocals + ")"); } _currentAssignmentTarget = new AssignmentTarget.Local(vloc.Id); break; // int pointers case DataElement.CInt cint: cint.Value.PointerId = _flagPointerId++; _currentAssignmentTarget = new AssignmentTarget.IntPointer(cint.Value.PointerId); break; default: throw new ArgumentOutOfRangeException(nameof(instruction), "Invalid assignment target: " + instruction); } }