/// <summary> /// Resolves a template by either loading it from a file or by picking a sub-template from the current context. /// Logs a warning and returns null if the specified template could not be resolved. /// </summary> private MapTemplate ResolveTemplate(string mapPath, string templateName, InstantiationContext context) { if (mapPath != null) { Logger.Verbose($"Resolving map template '{mapPath}'."); // We support both absolute and relative paths. Relative paths are relative to the map that a template is being inserted into. if (!Path.IsPathRooted(mapPath)) { mapPath = Path.Combine(context.CurrentWorkingDirectory, mapPath); } try { // TODO: If no extension is specified, use a certain preferential order (.rmf, .map, ...)? ... return(GetMapTemplate(mapPath, context.Globals)); } catch (Exception ex) { Logger.Warning($"Failed to load map template '{mapPath}':", ex); return(null); } } else if (templateName != null) { Logger.Verbose($"Resolving sub-template '{templateName}'."); // We'll look for sub-templates in the closest parent context whose template has been loaded from a map file. // If there are multiple matches, we'll pick one at random. If there are no matches, we'll fall through and return null. var matchingSubTemplates = context.SubTemplates .Where(subTemplate => context.EvaluateInterpolatedString(subTemplate.Name) == templateName) .Select(subTemplate => new { SubTemplate = subTemplate, Weight = double.TryParse(context.EvaluateInterpolatedString(subTemplate.SelectionWeightExpression), NumberStyles.Float, CultureInfo.InvariantCulture, out var weight) ? weight : 0 })
// TODO: If 'angles' and 'scale' are missing, that could cause issues...? But what if we always insert them, // could that also be problematic in different situations? /// <summary> /// Creates a copy of this entity. The copy is scaled, rotated and translated, /// and by default any expressions in its properties will be evaluated. /// If it contains 'angles' and 'scale' properties, then these will be updated according to how the entity has been transformed. /// Ignores VIS-group and group relationships. /// </summary> public static Entity Copy(this Entity entity, InstantiationContext context, bool applyTransform = true, bool evaluateExpressions = true) { var transform = applyTransform ? context.Transform : Transform.Identity; var copy = new Entity(entity.Brushes.Select(brush => brush.Copy(transform))); if (evaluateExpressions) { foreach (var kv in entity.Properties) { copy.Properties[context.EvaluateInterpolatedString(kv.Key)] = context.EvaluateInterpolatedString(kv.Value); } UpdateSpawnFlags(copy); } else { foreach (var kv in entity.Properties) { copy.Properties[kv.Key] = kv.Value; } } if (applyTransform) { // TODO: Also check whether maybe the angles/scale keys do exist, but contain invalid values! if (copy.Angles is Angles angles) { copy.Angles = (angles.ToMatrix() * context.Transform.Rotation).ToAngles(); } if (copy.Scale is double scale) { copy.Scale = scale * context.Transform.Scale; } if (copy.IsPointBased) { copy.Origin = ApplyTransform(copy.Origin, context.Transform); } } return(copy); }