expose appropriate *Inits, and make them work in editor

This commit is contained in:
Chris Forbes
2011-11-06 18:15:56 +13:00
parent 772734d032
commit 6cb8ee1f9f
17 changed files with 332 additions and 28 deletions

View File

@@ -0,0 +1,92 @@
namespace OpenRA.Editor
{
partial class ActorPropertiesDialog
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
this.SuspendLayout();
//
// button1
//
this.button1.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.button1.Location = new System.Drawing.Point(226, 333);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "Cancel";
this.button1.UseVisualStyleBackColor = true;
//
// button2
//
this.button2.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.button2.Enabled = false;
this.button2.Location = new System.Drawing.Point(145, 333);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(75, 23);
this.button2.TabIndex = 0;
this.button2.Text = "OK";
this.button2.UseVisualStyleBackColor = true;
//
// flowLayoutPanel1
//
this.flowLayoutPanel1.AutoScroll = true;
this.flowLayoutPanel1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.flowLayoutPanel1.Location = new System.Drawing.Point(13, 13);
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
this.flowLayoutPanel1.Size = new System.Drawing.Size(288, 314);
this.flowLayoutPanel1.TabIndex = 1;
//
// ActorPropertiesDialog
//
this.AcceptButton = this.button2;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.button1;
this.ClientSize = new System.Drawing.Size(313, 368);
this.Controls.Add(this.flowLayoutPanel1);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "ActorPropertiesDialog";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Actor Properties";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
}
}

View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using OpenRA.FileFormats;
namespace OpenRA.Editor
{
public partial class ActorPropertiesDialog : Form
{
public ActorPropertiesDialog()
{
InitializeComponent();
}
public void AddRow(string name, Control c)
{
flowLayoutPanel1.Controls.Add(new Label
{
Text = name,
Width = flowLayoutPanel1.Width * 3 / 10,
Height = 25,
TextAlign = ContentAlignment.MiddleLeft,
});
c.Width = flowLayoutPanel1.Width * 6 / 10 - 25;
c.Height = 25;
flowLayoutPanel1.Controls.Add(c);
}
public Control MakeEditorControl(Type t, Func<object> getter, Action<object> setter)
{
var r = new TextBox();
r.Text = FieldSaver.FormatValue(getter(), t);
r.LostFocus += (e,_) => setter(FieldLoader.GetValue("<editor internals>", t, r.Text));
r.Enabled = false;
return r;
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -10,13 +10,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using OpenRA.FileFormats; using OpenRA.FileFormats;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
using System.Drawing;
namespace OpenRA.Editor namespace OpenRA.Editor
{ {
@@ -57,6 +57,7 @@ namespace OpenRA.Editor
surface1.AfterChange += OnMapChanged; surface1.AfterChange += OnMapChanged;
surface1.MousePositionChanged += s => toolStripStatusLabelMousePosition.Text = s; surface1.MousePositionChanged += s => toolStripStatusLabelMousePosition.Text = s;
surface1.ActorDoubleClicked += ActorDoubleClicked;
if (args.Length >= 2) if (args.Length >= 2)
LoadMap(args[1]); LoadMap(args[1]);
@@ -68,7 +69,31 @@ namespace OpenRA.Editor
pmMiniMap.Image = Minimap.AddStaticResources(surface1.Map, Minimap.TerrainBitmap(surface1.Map, true)); pmMiniMap.Image = Minimap.AddStaticResources(surface1.Map, Minimap.TerrainBitmap(surface1.Map, true));
} }
void ActorDoubleClicked(KeyValuePair<string,ActorReference> kv)
{
using( var apd = new ActorPropertiesDialog() )
{
var name = kv.Key;
apd.AddRow("(Name)", apd.MakeEditorControl(typeof(string), () => name, v => name = (string)v));
apd.AddRow("(Type)", apd.MakeEditorControl(typeof(string), () => kv.Value.Type, v => kv.Value.Type = (string)v));
var objSaved = kv.Value.Save();
// TODO: make this work properly
foreach( var init in Rules.Info[kv.Value.Type].GetInitKeys() )
apd.AddRow(init.First,
apd.MakeEditorControl(init.Second,
() => objSaved.NodesDict.ContainsKey( init.First ) ? objSaved.NodesDict[init.First].Value : null,
_ => {}));
apd.ShowDialog();
// TODO: writeback
}
}
void MakeDirty() { dirty = true; } void MakeDirty() { dirty = true; }
string loadedMapName; string loadedMapName;
string currentMod = "ra"; string currentMod = "ra";
TileSet tileset; TileSet tileset;

View File

@@ -10,10 +10,9 @@
using System; using System;
using System.IO; using System.IO;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using System.Linq; using System.Linq;
using System.Windows.Forms;
using OpenRA.Graphics;
namespace OpenRA.Editor namespace OpenRA.Editor
{ {
@@ -79,6 +78,5 @@ namespace OpenRA.Editor
{ {
MapFolderPath = txtPathOut.Text; MapFolderPath = txtPathOut.Text;
} }
} }
} }

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -53,6 +53,12 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="ActorPropertiesDialog.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="ActorPropertiesDialog.Designer.cs">
<DependentUpon>ActorPropertiesDialog.cs</DependentUpon>
</Compile>
<Compile Include="ActorTemplate.cs" /> <Compile Include="ActorTemplate.cs" />
<Compile Include="ActorTool.cs" /> <Compile Include="ActorTool.cs" />
<Compile Include="BrushTool.cs" /> <Compile Include="BrushTool.cs" />
@@ -90,6 +96,9 @@
<DependentUpon>PropertiesDialog.cs</DependentUpon> <DependentUpon>PropertiesDialog.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="ActorPropertiesDialog.resx">
<DependentUpon>ActorPropertiesDialog.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Form1.resx"> <EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon> <DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource> </EmbeddedResource>

View File

@@ -42,6 +42,7 @@ namespace OpenRA.Editor
public event Action AfterChange = () => { }; public event Action AfterChange = () => { };
public event Action<string> MousePositionChanged = _ => { }; public event Action<string> MousePositionChanged = _ => { };
public event Action<KeyValuePair<string, ActorReference>> ActorDoubleClicked = _ => { };
Dictionary<string, ActorTemplate> ActorTemplates = new Dictionary<string, ActorTemplate>(); Dictionary<string, ActorTemplate> ActorTemplates = new Dictionary<string, ActorTemplate>();
Dictionary<int, ResourceTemplate> ResourceTemplates = new Dictionary<int, ResourceTemplate>(); Dictionary<int, ResourceTemplate> ResourceTemplates = new Dictionary<int, ResourceTemplate>();
@@ -91,6 +92,15 @@ namespace OpenRA.Editor
Invalidate(); Invalidate();
} }
protected override void OnDoubleClick(EventArgs e)
{
base.OnDoubleClick(e);
var x = Map.Actors.Value.FirstOrDefault(a => a.Value.Location() == GetBrushLocation());
if (x.Key != null)
ActorDoubleClicked(x);
}
protected override void OnMouseWheel(MouseEventArgs e) protected override void OnMouseWheel(MouseEventArgs e)
{ {
base.OnMouseWheel(e); base.OnMouseWheel(e);
@@ -294,7 +304,7 @@ namespace OpenRA.Editor
if (cp != null) bmp.Palette = restorePalette; if (cp != null) bmp.Palette = restorePalette;
} }
void DrawActorBorder(System.Drawing.Graphics g, int2 p, ActorTemplate t) void DrawActorBorder(SGraphics g, int2 p, ActorTemplate t)
{ {
var centered = t.Appearance == null || !t.Appearance.RelativeToTopLeft; var centered = t.Appearance == null || !t.Appearance.RelativeToTopLeft;
var drawPos = GetDrawPosition(p, t.Bitmap, centered); var drawPos = GetDrawPosition(p, t.Bitmap, centered);

View File

@@ -305,14 +305,13 @@ namespace OpenRA.FileFormats
return new MiniYamlNode(field, FieldSaver.FormatValue( o, o.GetType().GetField(field) )); return new MiniYamlNode(field, FieldSaver.FormatValue( o, o.GetType().GetField(field) ));
} }
public static string FormatValue(object o, FieldInfo f) public static string FormatValue(object v, Type t)
{ {
var v = f.GetValue(o);
if (v == null) if (v == null)
return ""; return "";
// Color.ToString() does the wrong thing; force it to format as an array // Color.ToString() does the wrong thing; force it to format as an array
if (f.FieldType == typeof(Color)) if (t == typeof(Color))
{ {
var c = (Color)v; var c = (Color)v;
return "{0},{1},{2},{3}".F(((int)c.A).Clamp(0, 255), return "{0},{1},{2},{3}".F(((int)c.A).Clamp(0, 255),
@@ -321,13 +320,13 @@ namespace OpenRA.FileFormats
((int)c.B).Clamp(0, 255)); ((int)c.B).Clamp(0, 255));
} }
if (f.FieldType == typeof(Rectangle)) if (t == typeof(Rectangle))
{ {
var r = (Rectangle)v; var r = (Rectangle)v;
return "{0},{1},{2},{3}".F(r.X, r.Y, r.Width, r.Height); return "{0},{1},{2},{3}".F(r.X, r.Y, r.Width, r.Height);
} }
if (f.FieldType.IsArray) if (t.IsArray)
{ {
var elems = ((Array)v).OfType<object>(); var elems = ((Array)v).OfType<object>();
return elems.JoinWith(","); return elems.JoinWith(",");
@@ -335,6 +334,11 @@ namespace OpenRA.FileFormats
return v.ToString(); return v.ToString();
} }
public static string FormatValue(object o, FieldInfo f)
{
return FormatValue(f.GetValue(o), f.FieldType);
}
} }
public class FieldFromYamlKeyAttribute : Attribute { } public class FieldFromYamlKeyAttribute : Attribute { }

View File

@@ -64,13 +64,18 @@ namespace OpenRA.FileFormats
public T GetOrDefault<T>() public T GetOrDefault<T>()
{ {
if( dataMultiple.ContainsKey( typeof( T ) ) ) return (T)GetOrDefault(typeof(T));
throw new InvalidOperationException( string.Format( "TypeDictionary contains multiple instance of type `{0}`", typeof( T ) ) ); }
public object GetOrDefault(Type t)
{
if( dataMultiple.ContainsKey(t) )
throw new InvalidOperationException( string.Format( "TypeDictionary contains multiple instance of type `{0}`", t ) );
object ret; object ret;
if( !dataSingular.TryGetValue( typeof( T ), out ret ) ) if( !dataSingular.TryGetValue(t, out ret ) )
return default( T ); return null;
return (T)ret; return ret;
} }
public IEnumerable<T> WithInterface<T>() public IEnumerable<T> WithInterface<T>()

View File

@@ -15,8 +15,8 @@ namespace OpenRA.FileFormats
{ {
public class ActorReference : IEnumerable public class ActorReference : IEnumerable
{ {
public readonly string Type; public string Type;
public readonly TypeDictionary InitDict; public TypeDictionary InitDict;
public ActorReference( string type ) : this( type, new Dictionary<string, MiniYaml>() ) { } public ActorReference( string type ) : this( type, new Dictionary<string, MiniYaml>() ) { }

View File

@@ -121,8 +121,7 @@ namespace OpenRA
return inits.Select( return inits.Select(
i => Pair.New( i => Pair.New(
i.GetType().Name.Replace( "Init", "" ), i.Name.Replace( "Init", "" ), i ));
i.GetType().GetInterfaces()[0].GetGenericArguments()[0] ) );
} }
} }
} }

View File

@@ -14,7 +14,7 @@ using OpenRA.GameRules;
namespace OpenRA.Traits namespace OpenRA.Traits
{ {
public class HealthInfo : ITraitInfo public class HealthInfo : ITraitInfo, UsesInit<HealthInit>
{ {
public readonly int HP = 0; public readonly int HP = 0;
public readonly float Radius = 10; public readonly float Radius = 10;

View File

@@ -10,8 +10,6 @@
using System.Linq; using System.Linq;
using OpenRA.FileFormats; using OpenRA.FileFormats;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Mods.RA.Render;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.RA.Activities namespace OpenRA.Mods.RA.Activities

View File

@@ -67,7 +67,7 @@ namespace OpenRA.Mods.RA.Air
[Sync] public int foo { get { return a.Altitude; } } [Sync] public int foo { get { return a.Altitude; } }
} }
public class AircraftInfo : ITraitInfo, IFacingInfo public class AircraftInfo : ITraitInfo, IFacingInfo, UsesInit<AltitudeInit>, UsesInit<LocationInit>, UsesInit<FacingInit>
{ {
public readonly int CruiseAltitude = 30; public readonly int CruiseAltitude = 30;
[ActorReference] [ActorReference]

View File

@@ -19,7 +19,7 @@ namespace OpenRA.Mods.RA.Buildings
public class GivesBuildableAreaInfo : TraitInfo<GivesBuildableArea> {} public class GivesBuildableAreaInfo : TraitInfo<GivesBuildableArea> {}
public class GivesBuildableArea {} public class GivesBuildableArea {}
public class BuildingInfo : ITraitInfo public class BuildingInfo : ITraitInfo, UsesInit<LocationInit>
{ {
public readonly int Power = 0; public readonly int Power = 0;
public readonly string[] TerrainTypes = {}; public readonly string[] TerrainTypes = {};

View File

@@ -18,7 +18,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA.Move namespace OpenRA.Mods.RA.Move
{ {
public class MobileInfo : ITraitInfo, IFacingInfo public class MobileInfo : ITraitInfo, IFacingInfo, UsesInit<FacingInit>, UsesInit<LocationInit>, UsesInit<SubCellInit>
{ {
[FieldLoader.LoadUsing("LoadSpeeds")] [FieldLoader.LoadUsing("LoadSpeeds")]
public readonly Dictionary<string, TerrainInfo> TerrainSpeeds; public readonly Dictionary<string, TerrainInfo> TerrainSpeeds;

View File

@@ -12,7 +12,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA namespace OpenRA.Mods.RA
{ {
public class TurretedInfo : ITraitInfo public class TurretedInfo : ITraitInfo, UsesInit<TurretFacingInit>
{ {
public readonly int ROT = 255; public readonly int ROT = 255;
public readonly int InitialFacing = 128; public readonly int InitialFacing = 128;