private void ItemsAfterSelect(object sender, TreeViewEventArgs e) { // Disable OK button until we have a valid image. btnOK.Enabled = false; SelectedItemName = null; pgPreview.SelectedObject = null; // Do we have something new? if (e.Node == null) { return; } // See if the "none" entry is selected. if (e.Node.Name.Equals("")) { btnOK.Enabled = true; return; } // See if the item is valid. var factory = FactoryManager.GetFactory(e.Node.Name) as ItemFactory; if (factory == null) { return; } // OK, allow selecting it. btnOK.Enabled = true; SelectedItemName = e.Node.Name; pgPreview.SelectedObject = factory; }
private void RenderSunSystemPreview(SunSystemFactory factory) { if (!SetPreviews(PreviewType.Default, factory)) { return; } if (factory == null) { return; } pbPreview.Resize += PreviewOnResize; // Get furthest out orbit to know how to scale. var sunFactory = FactoryManager.GetFactory(factory.Sun) as SunFactory; float padding, scale; ComputeScaleAndOffset(Engine.Util.UnitConversion.ToScreenUnits(CellSystem.CellSize) / 2f, out scale, out padding); // Render all objects from left to right, starting with the sun. using (var g = System.Drawing.Graphics.FromImage(pbPreview.Image)) { g.SmoothingMode = SmoothingMode.HighQuality; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.PixelOffsetMode = PixelOffsetMode.HighQuality; using (var brush = new SolidBrush(System.Drawing.Color.White)) { if (sunFactory != null && sunFactory.Radius != null) { var sunColor = System.Drawing.Color.FromArgb( sunFactory.OffsetRadius != null ? 200 : 255, 255, 255, 224); brush.Color = sunColor; var diameter = scale * sunFactory.Radius.Low * 2; g.FillEllipse(brush, padding - diameter / 2f, pbPreview.Image.Height / 2f - diameter / 2f, diameter, diameter); if (sunFactory.OffsetRadius != null) { diameter = scale * (sunFactory.Radius.High + sunFactory.OffsetRadius.High) * 2; g.FillEllipse(brush, padding - diameter / 2f, pbPreview.Image.Height / 2f - diameter / 2f, diameter, diameter); } } RenderOrbit(factory.Planets, padding, scale, g, brush); } } }
private void RenderOrbiterPreview(Orbiter orbiter) { if (!SetPreviews(PreviewType.Default, orbiter)) { return; } if (orbiter == null) { return; } pbPreview.Resize += PreviewOnResize; var planetFactory = FactoryManager.GetFactory(orbiter.Name) as PlanetFactory; float padding, scale; ComputeScaleAndOffset(GetMaxRadius(orbiter.Moons), out scale, out padding); // Render all objects from left to right, starting with the sun. using (var g = System.Drawing.Graphics.FromImage(pbPreview.Image)) { g.SmoothingMode = SmoothingMode.HighQuality; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.PixelOffsetMode = PixelOffsetMode.HighQuality; using (var brush = new SolidBrush(System.Drawing.Color.White)) { if (planetFactory != null && planetFactory.Radius != null) { brush.Color = System.Drawing.Color.FromArgb(150, planetFactory.SurfaceTint.R, planetFactory.SurfaceTint.G, planetFactory.SurfaceTint.B); var diameter = scale * planetFactory.Radius.Low * 2; g.FillEllipse(brush, padding - diameter / 2f, pbPreview.Image.Height / 2f - diameter / 2f, diameter, diameter); diameter = scale * planetFactory.Radius.High * 2; g.FillEllipse(brush, padding - diameter / 2f, pbPreview.Image.Height / 2f - diameter / 2f, diameter, diameter); } RenderOrbit(orbiter.Moons, padding, scale, g, brush); } } }
private void UpdatePreview(bool force = false) { if (force) { SetPreviews(PreviewType.Default, null); } // Figure out what to show. try // evil: using try-catch for flow-control, but who can stop me!? muahahaha { // Nothing selected, so skip. if (pgProperties.SelectedObject == null) { SetPreviews(PreviewType.Default, null); return; } var item = pgProperties.SelectedGridItem; while (item != null) { // If an image asset is selected we simply show that. if (item.PropertyDescriptor != null) { if (item.PropertyDescriptor.Attributes[typeof(EditorAttribute)] != null) { var editorType = Type.GetType(((EditorAttribute)item.PropertyDescriptor.Attributes[typeof(EditorAttribute)]).EditorTypeName); if (editorType == typeof(TextureAssetEditor)) { RenderTextureAssetPreview(item.Value as string); return; } if (editorType == typeof(EffectAssetEditor)) { RenderEffectAssetPreview(item.Value as string); return; } if (editorType == typeof(PlanetEditor)) { RenderPlanetPreview(FactoryManager.GetFactory(item.Value as string) as PlanetFactory); return; } if (editorType == typeof(SunEditor)) { RenderSunPreview(FactoryManager.GetFactory(item.Value as string) as SunFactory); return; } if (editorType == typeof(ItemInfoEditor)) { RenderItemPreview(FactoryManager.GetFactory(item.Value as string) as ItemFactory); return; } } // Render next-best orbit system if possible. if (item.Parent != null && item.Parent.Parent != null && item.Parent.Parent.PropertyDescriptor != null && item.Parent.Parent.PropertyDescriptor.PropertyType == typeof(Orbiter)) { RenderOrbiterPreview(item.Parent.Parent.Value as Orbiter); return; } // Render next-best item system if possible. if (item.PropertyDescriptor.PropertyType == typeof(ShipFactory.ItemInfo)) { var info = item.Value as ShipFactory.ItemInfo; if (info != null) { RenderItemPreview(FactoryManager.GetFactory(info.Name) as ItemFactory); return; } } if (item.PropertyDescriptor.PropertyType == typeof(ItemPool.DropInfo)) { var info = item.Value as ItemPool.DropInfo; if (info != null) { RenderItemPreview(FactoryManager.GetFactory(info.ItemName) as ItemFactory); return; } } // Render next-best projectile if possible. if (item.PropertyDescriptor.PropertyType == typeof(ProjectileFactory[])) { RenderProjectilePreview(item.Value as ProjectileFactory[]); return; } } item = item.Parent; } // We're not rendering based on property grid item selection at this point, so // we just try to render the selected object. if (pgProperties.SelectedObject is PlanetFactory) { RenderPlanetPreview(pgProperties.SelectedObject as PlanetFactory); return; } if (pgProperties.SelectedObject is SunFactory) { RenderSunPreview(pgProperties.SelectedObject as SunFactory); return; } if (pgProperties.SelectedObject is SunSystemFactory) { RenderSunSystemPreview(pgProperties.SelectedObject as SunSystemFactory); return; } if (pgProperties.SelectedObject is ItemFactory) { RenderItemPreview(pgProperties.SelectedObject as ItemFactory); return; } if (pgProperties.SelectedObject is ShipFactory) { RenderShipPreview(pgProperties.SelectedObject as ShipFactory); return; } // Could not render anything, clear previews. SetPreviews(PreviewType.Default, null); } finally { // Update the picture box. pbPreview.Invalidate(); } }
private void RenderOrbit(Orbit orbit, float origin, float scale, System.Drawing.Graphics graphics, SolidBrush brush, int number = 0) { if (orbit == null) { return; } if (orbit.Orbiters != null) { // Check each orbiting object. foreach (var orbiter in orbit.Orbiters) { var localOrigin = origin; // We can only really draw something useful if we have a radius... if (orbiter.OrbitRadius != null) { // Figure out max radius of children. var maxOrbit = scale * GetMaxRadius(orbiter.Moons); // Draw actual stuff at max bounds. localOrigin += orbiter.OrbitRadius.High * scale; var orbiterFactory = FactoryManager.GetFactory(orbiter.Name) as PlanetFactory; if (orbiterFactory != null) { brush.Color = System.Drawing.Color.FromArgb(150, orbiterFactory.SurfaceTint.R, orbiterFactory.SurfaceTint.G, orbiterFactory.SurfaceTint.B); if (orbiterFactory.Radius != null) { var diameter = orbiterFactory.Radius.Low * scale * 2; graphics.FillEllipse(brush, localOrigin - diameter / 2f, pbPreview.Image.Height / 2f - diameter / 2f, diameter, diameter); diameter = orbiterFactory.Radius.High * scale * 2; graphics.FillEllipse(brush, localOrigin - diameter / 2f, pbPreview.Image.Height / 2f - diameter / 2f, diameter, diameter); maxOrbit = Math.Max(maxOrbit, orbiterFactory.Radius.High * scale); } } // Half the interval of variance we have for our radius. var halfVariance = scale * (orbiter.OrbitRadius.High - orbiter.OrbitRadius.Low) / 2f; // Add it to the max orbit to get the overall maximum possible // when rendering a circle with its center in the middle of the // variance interval. (and times two for width/height) maxOrbit = (maxOrbit + halfVariance) * 2; // Show the indicator of the maximum bounds for this orbiter. brush.Color = System.Drawing.Color.FromArgb(20, 255, 165, 0); graphics.FillEllipse(brush, origin + scale * orbiter.OrbitRadius.Low + halfVariance - maxOrbit / 2f, pbPreview.Image.Height / 2f - maxOrbit / 2f, maxOrbit, maxOrbit); // Draw own orbit. var color = OrbitColors[number % OrbitColors.Length]; using (var p = new Pen(System.Drawing.Color.FromArgb(210, color.R, color.G, color.B))) { float orbitX, orbitY; var eccentricity = orbiter.Eccentricity.Low; Orbiter.ComputeRadii(orbiter.OrbitRadius.High * scale, eccentricity, out orbitX, out orbitY); graphics.DrawEllipse(p, origin - orbitX + orbitX * eccentricity, pbPreview.Image.Height / 2f - orbitY, orbitX * 2, orbitY * 2); p.Color = System.Drawing.Color.FromArgb(110, color.R, color.G, color.B); eccentricity = orbiter.Eccentricity.High; Orbiter.ComputeRadii(orbiter.OrbitRadius.Low * scale, eccentricity, out orbitX, out orbitY); graphics.DrawEllipse(p, origin - orbitX + orbitX * eccentricity, pbPreview.Image.Height / 2f - orbitY, orbitX * 2, orbitY * 2); } } // Render children. RenderOrbit(orbiter.Moons, localOrigin, scale, graphics, brush, ++number); } } }
public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value) { var svc = provider.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService; if ((value is string || value == null) && svc != null) { // Preselect old entry. _dialog.SelectedItemName = value as string; // Restrict selection. var giContext = context as GridItem; if (giContext == null || giContext.Parent == null || giContext.Parent.Parent == null || giContext.Parent.Parent.Parent == null || giContext.Parent.Parent.Parent.Value == null) { MessageBox.Show("Cannot edit here.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information); return(value); } if (giContext.Parent.Parent.Parent.Value is ShipFactory) { // Top level item, only allow fuselage. _dialog.AvailableSlots = new[] { new ItemFactory.ItemSlotInfo { Size = ItemSlotSize.Small, Type = ItemFactory.ItemSlotInfo.ItemType.Fuselage } }; } else { // Somewhere in the tree, get parent. var containingItem = giContext.Parent.Parent.Parent.Value as ShipFactory.ItemInfo; if (containingItem == null || string.IsNullOrWhiteSpace(containingItem.Name)) { // Null parent, don't allow adding items. MessageBox.Show("Cannot add to empty items.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information); return(value); } var containingFactory = FactoryManager.GetFactory(containingItem.Name) as ItemFactory; if (containingFactory == null) { // Invalid parent, don't allow adding items. MessageBox.Show("Cannot determine valid items due to invalid parent entry.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information); return(value); } // Figure out available slots. var availableSlots = new List <ItemFactory.ItemSlotInfo>(); if (containingFactory.Slots != null) { availableSlots.AddRange(containingFactory.Slots); } else { // Item has no slots, don't allow adding items. MessageBox.Show("Cannot add any more items: no more free slots.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information); return(value); } // Remove used ones. foreach (var slot in containingItem.Slots) { // Skip self. if (slot == context.Instance) { continue; } // Skip empty ones. if (string.IsNullOrWhiteSpace(slot.Name)) { continue; } // Get the item of that type. var slotItemFactory = FactoryManager.GetFactory(slot.Name) as ItemFactory; if (slotItemFactory == null) { continue; } // OK, try to consume a slot (the smallest one possible). var type = slotItemFactory.GetType().ToItemType(); var size = slotItemFactory.RequiredSlotSize; ItemFactory.ItemSlotInfo bestSlot = null; foreach (var availableSlot in availableSlots) { if (availableSlot.Type != type || availableSlot.Size < size) { continue; } if (bestSlot == null || availableSlot.Size < bestSlot.Size) { bestSlot = availableSlot; } } if (bestSlot != null) { availableSlots.Remove(bestSlot); } } // Skip if no slots remain. if (availableSlots.Count == 0) { MessageBox.Show("Cannot add any more items: no items known that would fit the remaining slots.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information); return(value); } // Set remaining slots. _dialog.AvailableSlots = availableSlots; } if (svc.ShowDialog(_dialog) == DialogResult.OK) { return(_dialog.SelectedItemName); } } return(base.EditValue(context, provider, value)); }
/// <summary> /// Check all known asset reference types for validity (i.e. whether the referenced object exists). /// </summary> /// <param name="main">The main object this relates to.</param> /// <param name="current">The current object being checked (that is some child of the main object).</param> /// <param name="prefix">The "path" to the current object in the main object, separated by dots ('.').</param> private void ScanReferences(object main, object current, string prefix = null) { // Skip null objects. if (main == null || current == null) { return; } // Adjust our prefix. prefix = string.IsNullOrWhiteSpace(prefix) ? "" : (prefix + "."); // Known checks: editor type to recognize the property, display name (in issue) and method to check validity. var checks = new[] { Tuple.Create <Type, string, Func <string, bool> >(typeof(TextureAssetEditor), "texture asset", ContentProjectManager.HasTextureAsset), Tuple.Create <Type, string, Func <string, bool> >(typeof(EffectAssetEditor), "effect asset", ContentProjectManager.HasEffectAsset), Tuple.Create <Type, string, Func <string, bool> >(typeof(ItemInfoEditor), "item", s => FactoryManager.GetFactory(s) as ItemFactory != null), Tuple.Create <Type, string, Func <string, bool> >(typeof(ItemPoolEditor), "item", s => FactoryManager.GetFactory(s) as ItemFactory != null), Tuple.Create <Type, string, Func <string, bool> >(typeof(ItemPoolChooserEditor), "item pool", s => ItemPoolManager.GetItemPool(s) != null), Tuple.Create <Type, string, Func <string, bool> >(typeof(PlanetEditor), "planet", s => FactoryManager.GetFactory(s) as PlanetFactory != null), Tuple.Create <Type, string, Func <string, bool> >(typeof(SunEditor), "sun", s => FactoryManager.GetFactory(s) as SunFactory != null) }; // Perform all checks. foreach (var check in checks) { // Get properties we can handle with this check. foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(current, new Attribute[] { new EditorAttribute(check.Item1, typeof(UITypeEditor)) })) { // See if the actual value is a string, which is the format we store the references in. if (property.PropertyType != typeof(string)) { AddIssue("Property marked as " + check.Item2 + " is not of type string.", main, prefix + property.Name, IssueType.Warning); } else { // Check if the reference is valid, ignore empty ones. var path = (string)property.GetValue(current); if (!string.IsNullOrWhiteSpace(path) && !check.Item3(path.Replace('\\', '/'))) { AddIssue("Invalid or unknown " + check.Item2 + " name.", main, prefix + property.Name, IssueType.Error); } } } } }
/// <summary> /// Checks orbits for validity. /// </summary> /// <param name="factory">The factory.</param> private void ScanFactory(SunSystemFactory factory) { if (factory == null) { return; } // Get sun factory, to extract base radius offset, if possible. var sunFactory = FactoryManager.GetFactory(factory.Sun) as SunFactory; var orbits = new Stack <Tuple <Orbit, float, string> >(); orbits.Push(Tuple.Create(factory.Planets, sunFactory != null && sunFactory.OffsetRadius != null ? sunFactory.OffsetRadius.High : 0f, "Planets")); while (orbits.Count > 0) { var data = orbits.Pop(); var orbit = data.Item1; var radius = data.Item2; var prefix = string.IsNullOrWhiteSpace(data.Item3) ? "" : (data.Item3 + "."); if (orbit == null) { continue; } for (var i = 0; i < orbit.Orbiters.Length; i++) { var orbiter = orbit.Orbiters[i]; var localPrefix = prefix + "Orbiters[" + i + "]."; var childRadius = radius; ScanReferences(factory, orbiter, localPrefix); if (orbiter.ChanceToExist <= 0) { AddIssue("Planet will never be generated (probability <= 0).", factory, localPrefix + "ChanceToExist", IssueType.Information); } if (orbiter.Eccentricity != null && (orbiter.Eccentricity.Low < 0 || orbiter.Eccentricity.High < 0 || orbiter.Eccentricity.Low > 1 || orbiter.Eccentricity.High > 1)) { AddIssue("Planet orbit ellipse eccentricity is in invalid value-range (should be in [0, 1]).", factory, localPrefix + "Eccentricity", IssueType.Warning); } if (orbiter.OrbitRadius == null) { AddIssue("Nor orbit radius set for planet.", factory, localPrefix + "OrbitRadius", IssueType.Error); } else { // Check if we're too large (exceeding cell size). Only trigger this message // for the first object exceeding the bounds, not for its children. childRadius += orbiter.OrbitRadius.High; if (radius < Engine.Util.UnitConversion.ToScreenUnits(CellSystem.CellSize) / 2f && childRadius >= Engine.Util.UnitConversion.ToScreenUnits(CellSystem.CellSize) / 2f) { AddIssue("Accumulative radii of orbits potentially exceed cell size.", factory, localPrefix + "OrbitRadius", IssueType.Warning); } if (orbiter.OrbitRadius.Low <= 0 || orbiter.OrbitRadius.High <= 0) { AddIssue("Orbit radius should be larger than zero for planet.", factory, localPrefix + "OrbitRadius", IssueType.Warning); } } orbits.Push(Tuple.Create(orbiter.Moons, childRadius, localPrefix + "Moons")); } } }
/// <summary> /// Check default loadout (equipment) of ships for validity. /// </summary> /// <param name="factory">The factory.</param> private void ScanFactory(ShipFactory factory) { if (factory == null) { return; } // Check collision bounds. if (factory.CollisionRadius <= 0f) { AddIssue("Ship has no collision radius.", factory, "CollisionRadius", IssueType.Information); } // Validate selected items. Make sure the root item is a fuselage. var root = factory.Items; if (root != null) { // We only check if the root item is a fuselage here, other checks will // we done in the loop below. var rootItem = FactoryManager.GetFactory(root.Name) as ItemFactory; if (rootItem != null && !(rootItem is FuselageFactory)) { AddIssue("Root item must always be a fuselage.", factory, "Items", IssueType.Error); } } else { // Nothing to do. return; } // Start with the fuselage. var items = new Stack <Tuple <ShipFactory.ItemInfo, string> >(); items.Push(Tuple.Create(root, "Items")); while (items.Count > 0) { // Get entry info, skip empty ones. var entry = items.Pop(); var item = entry.Item1; var prefix = entry.Item2; if (item == null) { continue; } // Check asset references. ScanReferences(factory, item, prefix); // Adjust prefix for further access. prefix = string.IsNullOrWhiteSpace(prefix) ? "" : (prefix + "."); // Notify about empty slots that can be removed, but keep going // to properly warn if any items are equipped in this null item. if (string.IsNullOrWhiteSpace(item.Name)) { AddIssue("Empty item name, branch will be skipped when generating the ship.", factory, prefix + "Name", IssueType.Information); } // Queue checks for children. for (var i = 0; i < item.Slots.Length; i++) { items.Push(Tuple.Create(item.Slots[i], prefix + "Slots[" + i + "]")); } // Get slot information to validate occupied slots. var itemFactory = FactoryManager.GetFactory(item.Name) as ItemFactory; var availableSlots = new List <ItemFactory.ItemSlotInfo>(); if (itemFactory != null && itemFactory.Slots != null) { availableSlots.AddRange(itemFactory.Slots); } for (var i = 0; i < item.Slots.Length; i++) { var slot = item.Slots[i]; // Skip empty ones. if (string.IsNullOrWhiteSpace(slot.Name)) { continue; } // Get the item of that type. Skip if unknown (warning will come when that // item itself is processed). var slotItemFactory = FactoryManager.GetFactory(slot.Name) as ItemFactory; if (slotItemFactory == null) { continue; } // OK, try to consume a slot (the smallest one possible). var type = slotItemFactory.GetType().ToItemType(); var size = slotItemFactory.RequiredSlotSize; ItemFactory.ItemSlotInfo bestSlot = null; foreach (var availableSlot in availableSlots) { if (availableSlot.Type != type || availableSlot.Size < size) { continue; } if (bestSlot == null || availableSlot.Size < bestSlot.Size) { bestSlot = availableSlot; } } if (bestSlot == null) { AddIssue("Equipped item cannot be fit into any slot.", factory, prefix + "Slots[" + i + "]", IssueType.Error); } else { availableSlots.Remove(bestSlot); } } } }