Update copyright header. Normalize line endings to LF.

This commit is contained in:
Paul Chote
2011-02-13 10:38:57 +13:00
parent ea5e2c0588
commit 094907c1a9
489 changed files with 43614 additions and 43613 deletions

206
INSTALL
View File

@@ -1,103 +1,103 @@
Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
This file is part of OpenRA, which is free software. It is made
available to you under the terms of the GNU General Public License
as published by the Free Software Foundation. For more information,
see LICENSE.
To run OpenRA, several files are needed from the original game disks.
The required files for the Red Alert mod are:
EITHER:
* conquer.mix
* temperat.mix
* interior.mix
* snow.mix
* sounds.mix
* allies.mix
* russian.mix
OR:
* main.mix
AND:
* redalert.mix
These need to be copied into the mods/ra/packages/ directory.
The required files for the Command and Conquer mod are:
* cclocal.mix
* speech.mix
* conquer.mix
* sounds.mix
* tempicnh.mix
* temperat.mix
* winter.mix
* desert.mix
These need to be copied into the mods/cnc/packages/ directory.
If you have a case-sensitive filesystem you must change the filenames to
lower case.
The files can be downloaded from:
http://open-ra.org/get-dependency.php?file=ra-packages for the Red Alert files and
http://open-ra.org/get-dependency.php?file=cnc-packages for the Command & Conquer files.
Alternatively:
Red Alert and C&C have been released by EA Games as freeware. They can be
downloaded from http://www.commandandconquer.com/classic
Unfortunately the installer is 16-bit and so wont run on 64-bit operating
systems. This can be worked around by using the Red Alert Setup Manager
(http://ra.afraid.org/html/downloads/utilities-3.html).
Make sure you apply the no-CD protection fix so all the files needed
are installed to the hard drive.
Dependencies - Make sure you have these installed, or you'll
have very strange errors.
WINDOWS:
* .NET Framework >= 3.5-SP1
(http://www.microsoft.com/downloads/details.aspx?FamilyID=AB99342F-5D1A-413D-8319-81DA479AB0D7&displaylang=en)
* Tao Framework >= 2.1.0
This is now bundled with OpenRA, copy the files in thirdparty/Tao to the game root directory.
* OpenAL >= 1.1
(http://connect.creativelabs.com/openal/Downloads/oalinst.zip)
* Cg Toolkit >= 2.2
(http://developer.download.nvidia.com/cg/Cg_2.2/Cg-2.2_October2009_Setup.exe)
To compile OpenRA, open the OpenRA.sln solution in the main folder,
or build it from the command-line with MSBuild.
Run the game with `OpenRA.Game.exe Game.Mods=ra` for Red Alert
or `OpenRA.Game.exe Game.Mods=cnc` for Command & Conquer
UBUNTU (substitute comparable packages for other linux distros):
* mono-gmcs
* freetype
* libmono-corlib1.0-cil
* libmono-winforms2.0-cil
* libopenal1
* libsdl1.2-dev
* nvidia-cg-toolkit (download the latest version from
http://developer.nvidia.com/object/cg_download.html)
OpenRA is incompatible with Compiz, please disable desktop effects when trying
to run OpenRA or the game will crash.
You will need to copy the third party dependencies (.dll and .config) from the
thirdparty and thirdparty/Tao directories into the game root, or install them permanently into
your GAC with the following script
#!/bin/sh
gacutil -i thirdparty/Tao/Tao.Cg.dll
gacutil -i thirdparty/Tao/Tao.OpenGl.dll
gacutil -i thirdparty/Tao/Tao.OpenAl.dll
gacutil -i thirdparty/Tao/Tao.Sdl.dll
gacutil -i thirdparty/Tao/Tao.FreeType.dll
gacutil -i thirdparty/ICSharpCode.SharpZipLib.dll
To compile OpenRA, run `make' from the command line.
Run the game with `mono OpenRA.Game.exe Game.Mods=ra` for Red Alert
or `mono OpenRA.Game.exe Game.Mods=cnc` for Command & Conquer
Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
This file is part of OpenRA, which is free software. It is made
available to you under the terms of the GNU General Public License
as published by the Free Software Foundation. For more information,
see COPYING.
To run OpenRA, several files are needed from the original game disks.
The required files for the Red Alert mod are:
EITHER:
* conquer.mix
* temperat.mix
* interior.mix
* snow.mix
* sounds.mix
* allies.mix
* russian.mix
OR:
* main.mix
AND:
* redalert.mix
These need to be copied into the mods/ra/packages/ directory.
The required files for the Command and Conquer mod are:
* cclocal.mix
* speech.mix
* conquer.mix
* sounds.mix
* tempicnh.mix
* temperat.mix
* winter.mix
* desert.mix
These need to be copied into the mods/cnc/packages/ directory.
If you have a case-sensitive filesystem you must change the filenames to
lower case.
The files can be downloaded from:
http://open-ra.org/get-dependency.php?file=ra-packages for the Red Alert files and
http://open-ra.org/get-dependency.php?file=cnc-packages for the Command & Conquer files.
Alternatively:
Red Alert and C&C have been released by EA Games as freeware. They can be
downloaded from http://www.commandandconquer.com/classic
Unfortunately the installer is 16-bit and so wont run on 64-bit operating
systems. This can be worked around by using the Red Alert Setup Manager
(http://ra.afraid.org/html/downloads/utilities-3.html).
Make sure you apply the no-CD protection fix so all the files needed
are installed to the hard drive.
Dependencies - Make sure you have these installed, or you'll
have very strange errors.
WINDOWS:
* .NET Framework >= 3.5-SP1
(http://www.microsoft.com/downloads/details.aspx?FamilyID=AB99342F-5D1A-413D-8319-81DA479AB0D7&displaylang=en)
* Tao Framework >= 2.1.0
This is now bundled with OpenRA, copy the files in thirdparty/Tao to the game root directory.
* OpenAL >= 1.1
(http://connect.creativelabs.com/openal/Downloads/oalinst.zip)
* Cg Toolkit >= 2.2
(http://developer.download.nvidia.com/cg/Cg_2.2/Cg-2.2_October2009_Setup.exe)
To compile OpenRA, open the OpenRA.sln solution in the main folder,
or build it from the command-line with MSBuild.
Run the game with `OpenRA.Game.exe Game.Mods=ra` for Red Alert
or `OpenRA.Game.exe Game.Mods=cnc` for Command & Conquer
UBUNTU (substitute comparable packages for other linux distros):
* mono-gmcs
* freetype
* libmono-corlib1.0-cil
* libmono-winforms2.0-cil
* libopenal1
* libsdl1.2-dev
* nvidia-cg-toolkit (download the latest version from
http://developer.nvidia.com/object/cg_download.html)
OpenRA is incompatible with Compiz, please disable desktop effects when trying
to run OpenRA or the game will crash.
You will need to copy the third party dependencies (.dll and .config) from the
thirdparty and thirdparty/Tao directories into the game root, or install them permanently into
your GAC with the following script
#!/bin/sh
gacutil -i thirdparty/Tao/Tao.Cg.dll
gacutil -i thirdparty/Tao/Tao.OpenGl.dll
gacutil -i thirdparty/Tao/Tao.OpenAl.dll
gacutil -i thirdparty/Tao/Tao.Sdl.dll
gacutil -i thirdparty/Tao/Tao.FreeType.dll
gacutil -i thirdparty/ICSharpCode.SharpZipLib.dll
To compile OpenRA, run `make' from the command line.
Run the game with `mono OpenRA.Game.exe Game.Mods=ra` for Red Alert
or `mono OpenRA.Game.exe Game.Mods=cnc` for Command & Conquer

View File

@@ -1,36 +1,36 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Drawing;
using OpenRA.GameRules;
using OpenRA.Traits;
namespace OpenRA.Editor
{
class ActorTemplate
{
public Bitmap Bitmap;
public ActorInfo Info;
public EditorAppearanceInfo Appearance;
}
class BrushTemplate
{
public Bitmap Bitmap;
public ushort N;
}
class ResourceTemplate
{
public Bitmap Bitmap;
public ResourceTypeInfo Info;
public int Value;
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Drawing;
using OpenRA.GameRules;
using OpenRA.Traits;
namespace OpenRA.Editor
{
class ActorTemplate
{
public Bitmap Bitmap;
public ActorInfo Info;
public EditorAppearanceInfo Appearance;
}
class BrushTemplate
{
public Bitmap Bitmap;
public ushort N;
}
class ResourceTemplate
{
public Bitmap Bitmap;
public ResourceTypeInfo Info;
public int Value;
}
}

View File

@@ -1,55 +1,55 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Linq;
using OpenRA.FileFormats;
using SGraphics = System.Drawing.Graphics;
namespace OpenRA.Editor
{
class ActorTool : ITool
{
ActorTemplate Actor;
public ActorTool(ActorTemplate actor) { this.Actor = actor; }
public void Preview(Surface surface, SGraphics g)
{
/* todo: include the player
* in the brush so we can color new buildings too */
surface.DrawActor(g, surface.GetBrushLocation(), Actor, null);
}
public void Apply(Surface surface)
{
if (surface.Map.Actors.Value.Any(a => a.Value.Location() == surface.GetBrushLocation()))
return;
var owner = "Neutral";
var id = NextActorName(surface);
surface.Map.Actors.Value[id] = new ActorReference(Actor.Info.Name.ToLowerInvariant())
{
new LocationInit( surface.GetBrushLocation() ),
new OwnerInit( owner)
};
}
string NextActorName(Surface surface)
{
var id = 0;
for (; ; )
{
var possible = "Actor{0}".F(id++);
if (!surface.Map.Actors.Value.ContainsKey(possible)) return possible;
}
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Linq;
using OpenRA.FileFormats;
using SGraphics = System.Drawing.Graphics;
namespace OpenRA.Editor
{
class ActorTool : ITool
{
ActorTemplate Actor;
public ActorTool(ActorTemplate actor) { this.Actor = actor; }
public void Preview(Surface surface, SGraphics g)
{
/* todo: include the player
* in the brush so we can color new buildings too */
surface.DrawActor(g, surface.GetBrushLocation(), Actor, null);
}
public void Apply(Surface surface)
{
if (surface.Map.Actors.Value.Any(a => a.Value.Location() == surface.GetBrushLocation()))
return;
var owner = "Neutral";
var id = NextActorName(surface);
surface.Map.Actors.Value[id] = new ActorReference(Actor.Info.Name.ToLowerInvariant())
{
new LocationInit( surface.GetBrushLocation() ),
new OwnerInit( owner)
};
}
string NextActorName(Surface surface)
{
var id = 0;
for (; ; )
{
var possible = "Actor{0}".F(id++);
if (!surface.Map.Actors.Value.ContainsKey(possible)) return possible;
}
}
}
}

View File

@@ -1,123 +1,123 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using OpenRA.FileFormats;
using SGraphics = System.Drawing.Graphics;
namespace OpenRA.Editor
{
class BrushTool : ITool
{
BrushTemplate Brush;
public BrushTool(BrushTemplate brush) { this.Brush = brush; }
public void Apply(Surface surface)
{
// change the bits in the map
var tile = surface.TileSet.Tiles[Brush.N];
var template = surface.TileSet.Templates[Brush.N];
var pos = surface.GetBrushLocation();
if (surface.GetModifiers() == Keys.Shift)
{
FloodFillWithBrush(surface, pos);
return;
}
for (var u = 0; u < template.Size.X; u++)
for (var v = 0; v < template.Size.Y; v++)
{
if (surface.Map.IsInMap(new int2(u, v) + pos))
{
var z = u + v * template.Size.X;
if (tile.TileBitmapBytes[z] != null)
surface.Map.MapTiles.Value[u + pos.X, v + pos.Y] =
new TileReference<ushort, byte>
{
type = Brush.N,
index = template.PickAny ? (byte)((u + pos.X) % 4 + ((v + pos.Y) % 4) * 4) : (byte)z,
};
var ch = new int2((pos.X + u) / Surface.ChunkSize, (pos.Y + v) / Surface.ChunkSize);
if (surface.Chunks.ContainsKey(ch))
{
surface.Chunks[ch].Dispose();
surface.Chunks.Remove(ch);
}
}
}
}
public void Preview(Surface surface, SGraphics g)
{
g.DrawImage(Brush.Bitmap,
surface.TileSet.TileSize * surface.GetBrushLocation().X * surface.Zoom + surface.GetOffset().X,
surface.TileSet.TileSize * surface.GetBrushLocation().Y * surface.Zoom + surface.GetOffset().Y,
Brush.Bitmap.Width * surface.Zoom,
Brush.Bitmap.Height * surface.Zoom);
}
void FloodFillWithBrush(Surface s, int2 pos)
{
var queue = new Queue<int2>();
var replace = s.Map.MapTiles.Value[pos.X, pos.Y];
var touched = new bool[s.Map.MapSize.X, s.Map.MapSize.Y];
Action<int, int> MaybeEnqueue = (x, y) =>
{
if (s.Map.IsInMap(x, y) && !touched[x, y])
{
queue.Enqueue(new int2(x, y));
touched[x, y] = true;
}
};
queue.Enqueue(pos);
while (queue.Count > 0)
{
var p = queue.Dequeue();
if (!s.Map.MapTiles.Value[p.X, p.Y].Equals(replace))
continue;
var a = FindEdge(s, p, new int2(-1, 0), replace);
var b = FindEdge(s, p, new int2(1, 0), replace);
for (var x = a.X; x <= b.X; x++)
{
s.Map.MapTiles.Value[x, p.Y] = new TileReference<ushort, byte> { type = Brush.N, index = (byte)0 };
if (s.Map.MapTiles.Value[x, p.Y - 1].Equals(replace))
MaybeEnqueue(x, p.Y - 1);
if (s.Map.MapTiles.Value[x, p.Y + 1].Equals(replace))
MaybeEnqueue(x, p.Y + 1);
}
}
/* todo: optimize */
foreach (var ch in s.Chunks.Values) ch.Dispose();
s.Chunks.Clear();
}
int2 FindEdge(Surface s, int2 p, int2 d, TileReference<ushort, byte> replace)
{
for (; ; )
{
var q = p + d;
if (!s.Map.IsInMap(q)) return p;
if (!s.Map.MapTiles.Value[q.X, q.Y].Equals(replace)) return p;
p = q;
}
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using OpenRA.FileFormats;
using SGraphics = System.Drawing.Graphics;
namespace OpenRA.Editor
{
class BrushTool : ITool
{
BrushTemplate Brush;
public BrushTool(BrushTemplate brush) { this.Brush = brush; }
public void Apply(Surface surface)
{
// change the bits in the map
var tile = surface.TileSet.Tiles[Brush.N];
var template = surface.TileSet.Templates[Brush.N];
var pos = surface.GetBrushLocation();
if (surface.GetModifiers() == Keys.Shift)
{
FloodFillWithBrush(surface, pos);
return;
}
for (var u = 0; u < template.Size.X; u++)
for (var v = 0; v < template.Size.Y; v++)
{
if (surface.Map.IsInMap(new int2(u, v) + pos))
{
var z = u + v * template.Size.X;
if (tile.TileBitmapBytes[z] != null)
surface.Map.MapTiles.Value[u + pos.X, v + pos.Y] =
new TileReference<ushort, byte>
{
type = Brush.N,
index = template.PickAny ? (byte)((u + pos.X) % 4 + ((v + pos.Y) % 4) * 4) : (byte)z,
};
var ch = new int2((pos.X + u) / Surface.ChunkSize, (pos.Y + v) / Surface.ChunkSize);
if (surface.Chunks.ContainsKey(ch))
{
surface.Chunks[ch].Dispose();
surface.Chunks.Remove(ch);
}
}
}
}
public void Preview(Surface surface, SGraphics g)
{
g.DrawImage(Brush.Bitmap,
surface.TileSet.TileSize * surface.GetBrushLocation().X * surface.Zoom + surface.GetOffset().X,
surface.TileSet.TileSize * surface.GetBrushLocation().Y * surface.Zoom + surface.GetOffset().Y,
Brush.Bitmap.Width * surface.Zoom,
Brush.Bitmap.Height * surface.Zoom);
}
void FloodFillWithBrush(Surface s, int2 pos)
{
var queue = new Queue<int2>();
var replace = s.Map.MapTiles.Value[pos.X, pos.Y];
var touched = new bool[s.Map.MapSize.X, s.Map.MapSize.Y];
Action<int, int> MaybeEnqueue = (x, y) =>
{
if (s.Map.IsInMap(x, y) && !touched[x, y])
{
queue.Enqueue(new int2(x, y));
touched[x, y] = true;
}
};
queue.Enqueue(pos);
while (queue.Count > 0)
{
var p = queue.Dequeue();
if (!s.Map.MapTiles.Value[p.X, p.Y].Equals(replace))
continue;
var a = FindEdge(s, p, new int2(-1, 0), replace);
var b = FindEdge(s, p, new int2(1, 0), replace);
for (var x = a.X; x <= b.X; x++)
{
s.Map.MapTiles.Value[x, p.Y] = new TileReference<ushort, byte> { type = Brush.N, index = (byte)0 };
if (s.Map.MapTiles.Value[x, p.Y - 1].Equals(replace))
MaybeEnqueue(x, p.Y - 1);
if (s.Map.MapTiles.Value[x, p.Y + 1].Equals(replace))
MaybeEnqueue(x, p.Y + 1);
}
}
/* todo: optimize */
foreach (var ch in s.Chunks.Values) ch.Dispose();
s.Chunks.Clear();
}
int2 FindEdge(Surface s, int2 p, int2 d, TileReference<ushort, byte> replace)
{
for (; ; )
{
var q = p + d;
if (!s.Map.IsInMap(q)) return p;
if (!s.Map.MapTiles.Value[q.X, q.Y].Equals(replace)) return p;
p = q;
}
}
}
}

View File

@@ -1,415 +1,415 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Editor
{
public partial class Form1 : Form
{
public Form1(string[] mods)
{
InitializeComponent();
AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly;
currentMod = mods.FirstOrDefault() ?? "ra";
toolStripComboBox1.Items.AddRange(Mod.AllMods.Keys.ToArray());
toolStripComboBox1.SelectedIndexChanged += (_, e) =>
{
tilePalette.SuspendLayout();
actorPalette.SuspendLayout();
resourcePalette.SuspendLayout();
tilePalette.Controls.Clear();
actorPalette.Controls.Clear();
resourcePalette.Controls.Clear();
tilePalette.ResumeLayout();
actorPalette.ResumeLayout();
resourcePalette.ResumeLayout();
surface1.Bind(null, null, null);
pmMiniMap.Image = null;
currentMod = toolStripComboBox1.SelectedItem as string;
Text = "OpenRA Editor (mod:{0})".F(currentMod);
Game.modData = new ModData(currentMod);
FileSystem.LoadFromManifest(Game.modData.Manifest);
Rules.LoadRules(Game.modData.Manifest, new Map());
loadedMapName = null;
};
toolStripComboBox1.SelectedItem = currentMod;
surface1.AfterChange += OnMapChanged;
surface1.MousePositionChanged += s => toolStripStatusLabelMousePosition.Text = s;
}
void OnMapChanged()
{
MakeDirty();
pmMiniMap.Image = Minimap.AddStaticResources(surface1.Map, Minimap.TerrainBitmap(surface1.Map, true));
}
void MakeDirty() { dirty = true; }
string loadedMapName;
string currentMod = "ra";
TileSet tileset;
bool dirty = false;
void LoadMap(string mapname)
{
tilePalette.Controls.Clear();
actorPalette.Controls.Clear();
resourcePalette.Controls.Clear();
loadedMapName = mapname;
// load the map
var map = new Map(mapname);
// upgrade maps that have no player definitions. editor doesnt care,
// but this breaks the game pretty badly.
if (map.Players.Count == 0)
map.Players.Add("Neutral", new PlayerReference("Neutral",
Rules.Info["world"].Traits.WithInterface<CountryInfo>().First().Race, true, true));
PrepareMapResources(Game.modData.Manifest, map);
dirty = false;
}
void NewMap(Map map)
{
tilePalette.Controls.Clear();
actorPalette.Controls.Clear();
resourcePalette.Controls.Clear();
loadedMapName = null;
PrepareMapResources(Game.modData.Manifest, map);
MakeDirty();
}
// this code is insanely stupid, and mostly my fault -- chrisf
void PrepareMapResources(Manifest manifest, Map map)
{
Rules.LoadRules(manifest, map);
tileset = Rules.TileSets[map.Tileset];
tileset.LoadTiles();
var palette = new Palette(FileSystem.Open(tileset.Palette), true);
surface1.Bind(map, tileset, palette);
// construct the palette of tiles
var palettes = new[] { tilePalette, actorPalette, resourcePalette };
foreach (var p in palettes) { p.Visible = false; p.SuspendLayout(); }
foreach (var t in tileset.Templates)
{
try
{
var bitmap = RenderUtils.RenderTemplate(tileset, (ushort)t.Key, palette);
var ibox = new PictureBox
{
Image = bitmap,
Width = bitmap.Width / 2,
Height = bitmap.Height / 2,
SizeMode = PictureBoxSizeMode.StretchImage
};
var brushTemplate = new BrushTemplate { Bitmap = bitmap, N = t.Key };
ibox.Click += (_, e) => surface1.SetTool(new BrushTool(brushTemplate));
var template = t.Value;
tilePalette.Controls.Add(ibox);
tt.SetToolTip(ibox,
"{1}:{0} ({2}x{3})".F(
template.Image,
template.Id,
template.Size.X,
template.Size.Y));
}
catch { }
}
var actorTemplates = new List<ActorTemplate>();
foreach (var a in Rules.Info.Keys)
{
try
{
var info = Rules.Info[a];
if (!info.Traits.Contains<RenderSimpleInfo>()) continue;
var template = RenderUtils.RenderActor(info, tileset, palette);
var ibox = new PictureBox
{
Image = template.Bitmap,
Width = 32,
Height = 32,
SizeMode = PictureBoxSizeMode.Zoom,
BorderStyle = BorderStyle.FixedSingle
};
ibox.Click += (_, e) => surface1.SetTool(new ActorTool(template));
actorPalette.Controls.Add(ibox);
tt.SetToolTip(ibox,
"{0}".F(
info.Name));
actorTemplates.Add(template);
}
catch { }
}
surface1.BindActorTemplates(actorTemplates);
var resourceTemplates = new List<ResourceTemplate>();
foreach (var a in Rules.Info["world"].Traits.WithInterface<ResourceTypeInfo>())
{
try
{
var template = RenderUtils.RenderResourceType(a, tileset.Extensions, palette);
var ibox = new PictureBox
{
Image = template.Bitmap,
Width = 32,
Height = 32,
SizeMode = PictureBoxSizeMode.Zoom,
BorderStyle = BorderStyle.FixedSingle
};
ibox.Click += (_, e) => surface1.SetTool(new ResourceTool(template));
resourcePalette.Controls.Add(ibox);
tt.SetToolTip(ibox,
"{0}:{1}cr".F(
template.Info.Name,
template.Info.ValuePerUnit));
resourceTemplates.Add(template);
}
catch { }
}
surface1.BindResourceTemplates(resourceTemplates);
foreach (var p in palettes)
{
p.Visible = true;
p.ResumeLayout();
}
pmMiniMap.Image = Minimap.AddStaticResources(surface1.Map, Minimap.TerrainBitmap(surface1.Map, true));
propertiesToolStripMenuItem.Enabled = true;
resizeToolStripMenuItem.Enabled = true;
spawnpointsToolStripMenuItem.Enabled = true;
saveToolStripMenuItem.Enabled = true;
saveAsToolStripMenuItem.Enabled = true;
mnuMinimapToPNG.Enabled = true; // todo: what is this VB naming bullshit doing here?
}
void ResizeClicked(object sender, EventArgs e)
{
using (var rd = new ResizeDialog())
{
rd.width.Value = surface1.Map.MapSize.X;
rd.height.Value = surface1.Map.MapSize.Y;
rd.cordonLeft.Value = surface1.Map.Bounds.Left;
rd.cordonTop.Value = surface1.Map.Bounds.Top;
rd.cordonRight.Value = surface1.Map.Bounds.Right;
rd.cordonBottom.Value = surface1.Map.Bounds.Bottom;
if (DialogResult.OK != rd.ShowDialog())
return;
surface1.Map.ResizeCordon((int)rd.cordonLeft.Value,
(int)rd.cordonTop.Value,
(int)rd.cordonRight.Value,
(int)rd.cordonBottom.Value);
if ((int)rd.width.Value != surface1.Map.MapSize.X || (int)rd.height.Value != surface1.Map.MapSize.Y)
{
surface1.Map.Resize((int)rd.width.Value, (int)rd.height.Value);
surface1.Bind(surface1.Map, surface1.TileSet, surface1.Palette); // rebind it to invalidate all caches
}
surface1.Invalidate();
}
}
void SaveClicked(object sender, EventArgs e)
{
if (loadedMapName == null)
SaveAsClicked(sender, e);
else
{
surface1.Map.Save(loadedMapName);
dirty = false;
}
}
void SaveAsClicked(object sender, EventArgs e)
{
using (var nms = new MapSelect(currentMod))
{
nms.txtNew.ReadOnly = false;
nms.btnOk.Text = "Save";
nms.txtNew.Text = "unnamed";
nms.txtPathOut.ReadOnly = false;
if (DialogResult.OK == nms.ShowDialog())
{
if (nms.txtNew.Text == "")
nms.txtNew.Text = "unnamed";
// TODO: Allow the user to choose map format (directory vs oramap)
loadedMapName = Path.Combine(nms.MapFolderPath, nms.txtNew.Text + ".oramap");
SaveClicked(sender, e);
}
}
}
void OpenClicked(object sender, EventArgs e)
{
using (var nms = new MapSelect(currentMod))
{
nms.txtNew.ReadOnly = true;
nms.txtPathOut.ReadOnly = true;
nms.btnOk.Text = "Open";
if (DialogResult.OK == nms.ShowDialog())
LoadMap(nms.txtNew.Tag as string);
}
}
void NewClicked(object sender, EventArgs e)
{
using (var nmd = new NewMapDialog())
{
nmd.theater.Items.Clear();
nmd.theater.Items.AddRange(Rules.TileSets.Select(a => a.Value.Id).ToArray());
nmd.theater.SelectedIndex = 0;
if (DialogResult.OK == nmd.ShowDialog())
{
var map = Map.FromTileset(nmd.theater.SelectedItem as string);
map.Resize((int)nmd.width.Value, (int)nmd.height.Value);
map.ResizeCordon((int)nmd.cordonLeft.Value, (int)nmd.cordonTop.Value,
(int)nmd.cordonRight.Value, (int)nmd.cordonBottom.Value);
map.Players.Add("Neutral", new PlayerReference("Neutral", Rules.Info["world"].Traits.WithInterface<CountryInfo>().First().Race, true, true));
map.Players.Add("Creeps", new PlayerReference("Creeps", Rules.Info["world"].Traits.WithInterface<CountryInfo>().First().Race, true, true));
NewMap(map);
}
}
}
void PropertiesClicked(object sender, EventArgs e)
{
using (var pd = new PropertiesDialog())
{
pd.title.Text = surface1.Map.Title;
pd.desc.Text = surface1.Map.Description;
pd.author.Text = surface1.Map.Author;
pd.selectable.Checked = surface1.Map.Selectable;
pd.useAsShellmap.Checked = surface1.Map.UseAsShellmap;
if (DialogResult.OK != pd.ShowDialog())
return;
surface1.Map.Title = pd.title.Text;
surface1.Map.Description = pd.desc.Text;
surface1.Map.Author = pd.author.Text;
surface1.Map.Selectable = pd.selectable.Checked;
surface1.Map.UseAsShellmap = pd.useAsShellmap.Checked;
}
}
void Form1_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Space) surface1.IsPanning = true; }
void Form1_KeyUp(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Space) surface1.IsPanning = false; }
void CloseClicked(object sender, EventArgs e)
{
Close();
}
void ImportLegacyMapClicked(object sender, EventArgs e)
{
var currentDirectory = Directory.GetCurrentDirectory();
using (var ofd = new OpenFileDialog { Filter = "Legacy maps (*.ini;*.mpr)|*.ini;*.mpr" })
if (DialogResult.OK == ofd.ShowDialog())
{
Directory.SetCurrentDirectory(currentDirectory);
/* massive hack: we should be able to call NewMap() with the imported Map object,
* but something's not right internally in it, unless loaded via the real maploader */
var savePath = Path.Combine(Path.GetTempPath(), "OpenRA.Import");
Directory.CreateDirectory(savePath);
var map = LegacyMapImporter.Import(ofd.FileName);
map.Players.Add("Neutral", new PlayerReference("Neutral",
Rules.Info["world"].Traits.WithInterface<CountryInfo>().First().Race, true, true));
map.Players.Add("Creeps", new PlayerReference("Creeps",
Rules.Info["world"].Traits.WithInterface<CountryInfo>().First().Race, true, true));
map.Save(savePath);
LoadMap(savePath);
loadedMapName = null; /* editor needs to think this hasnt been saved */
Directory.Delete(savePath, true);
MakeDirty();
}
}
void OnFormClosing(object sender, FormClosingEventArgs e)
{
if (!dirty) return;
switch (MessageBox.Show("The map has been modified since it was last saved. " + "\r\n" + "Save changes now?",
"Unsaved Changes", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Exclamation))
{
case DialogResult.Yes: SaveClicked(null, EventArgs.Empty); break;
case DialogResult.No: break;
case DialogResult.Cancel: e.Cancel = true; break;
}
}
private void layersFloaterToolStripMenuItem_Click(object sender, EventArgs e)
{
var pb = new PaletteBox();
pb.Show();
}
void ExportMinimap(object sender, EventArgs e)
{
saveFileDialog.InitialDirectory = Path.Combine(Environment.CurrentDirectory, "maps");
saveFileDialog.FileName = Path.ChangeExtension(loadedMapName, ".png");
if (DialogResult.OK == saveFileDialog.ShowDialog())
pmMiniMap.Image.Save(saveFileDialog.FileName);
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Editor
{
public partial class Form1 : Form
{
public Form1(string[] mods)
{
InitializeComponent();
AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly;
currentMod = mods.FirstOrDefault() ?? "ra";
toolStripComboBox1.Items.AddRange(Mod.AllMods.Keys.ToArray());
toolStripComboBox1.SelectedIndexChanged += (_, e) =>
{
tilePalette.SuspendLayout();
actorPalette.SuspendLayout();
resourcePalette.SuspendLayout();
tilePalette.Controls.Clear();
actorPalette.Controls.Clear();
resourcePalette.Controls.Clear();
tilePalette.ResumeLayout();
actorPalette.ResumeLayout();
resourcePalette.ResumeLayout();
surface1.Bind(null, null, null);
pmMiniMap.Image = null;
currentMod = toolStripComboBox1.SelectedItem as string;
Text = "OpenRA Editor (mod:{0})".F(currentMod);
Game.modData = new ModData(currentMod);
FileSystem.LoadFromManifest(Game.modData.Manifest);
Rules.LoadRules(Game.modData.Manifest, new Map());
loadedMapName = null;
};
toolStripComboBox1.SelectedItem = currentMod;
surface1.AfterChange += OnMapChanged;
surface1.MousePositionChanged += s => toolStripStatusLabelMousePosition.Text = s;
}
void OnMapChanged()
{
MakeDirty();
pmMiniMap.Image = Minimap.AddStaticResources(surface1.Map, Minimap.TerrainBitmap(surface1.Map, true));
}
void MakeDirty() { dirty = true; }
string loadedMapName;
string currentMod = "ra";
TileSet tileset;
bool dirty = false;
void LoadMap(string mapname)
{
tilePalette.Controls.Clear();
actorPalette.Controls.Clear();
resourcePalette.Controls.Clear();
loadedMapName = mapname;
// load the map
var map = new Map(mapname);
// upgrade maps that have no player definitions. editor doesnt care,
// but this breaks the game pretty badly.
if (map.Players.Count == 0)
map.Players.Add("Neutral", new PlayerReference("Neutral",
Rules.Info["world"].Traits.WithInterface<CountryInfo>().First().Race, true, true));
PrepareMapResources(Game.modData.Manifest, map);
dirty = false;
}
void NewMap(Map map)
{
tilePalette.Controls.Clear();
actorPalette.Controls.Clear();
resourcePalette.Controls.Clear();
loadedMapName = null;
PrepareMapResources(Game.modData.Manifest, map);
MakeDirty();
}
// this code is insanely stupid, and mostly my fault -- chrisf
void PrepareMapResources(Manifest manifest, Map map)
{
Rules.LoadRules(manifest, map);
tileset = Rules.TileSets[map.Tileset];
tileset.LoadTiles();
var palette = new Palette(FileSystem.Open(tileset.Palette), true);
surface1.Bind(map, tileset, palette);
// construct the palette of tiles
var palettes = new[] { tilePalette, actorPalette, resourcePalette };
foreach (var p in palettes) { p.Visible = false; p.SuspendLayout(); }
foreach (var t in tileset.Templates)
{
try
{
var bitmap = RenderUtils.RenderTemplate(tileset, (ushort)t.Key, palette);
var ibox = new PictureBox
{
Image = bitmap,
Width = bitmap.Width / 2,
Height = bitmap.Height / 2,
SizeMode = PictureBoxSizeMode.StretchImage
};
var brushTemplate = new BrushTemplate { Bitmap = bitmap, N = t.Key };
ibox.Click += (_, e) => surface1.SetTool(new BrushTool(brushTemplate));
var template = t.Value;
tilePalette.Controls.Add(ibox);
tt.SetToolTip(ibox,
"{1}:{0} ({2}x{3})".F(
template.Image,
template.Id,
template.Size.X,
template.Size.Y));
}
catch { }
}
var actorTemplates = new List<ActorTemplate>();
foreach (var a in Rules.Info.Keys)
{
try
{
var info = Rules.Info[a];
if (!info.Traits.Contains<RenderSimpleInfo>()) continue;
var template = RenderUtils.RenderActor(info, tileset, palette);
var ibox = new PictureBox
{
Image = template.Bitmap,
Width = 32,
Height = 32,
SizeMode = PictureBoxSizeMode.Zoom,
BorderStyle = BorderStyle.FixedSingle
};
ibox.Click += (_, e) => surface1.SetTool(new ActorTool(template));
actorPalette.Controls.Add(ibox);
tt.SetToolTip(ibox,
"{0}".F(
info.Name));
actorTemplates.Add(template);
}
catch { }
}
surface1.BindActorTemplates(actorTemplates);
var resourceTemplates = new List<ResourceTemplate>();
foreach (var a in Rules.Info["world"].Traits.WithInterface<ResourceTypeInfo>())
{
try
{
var template = RenderUtils.RenderResourceType(a, tileset.Extensions, palette);
var ibox = new PictureBox
{
Image = template.Bitmap,
Width = 32,
Height = 32,
SizeMode = PictureBoxSizeMode.Zoom,
BorderStyle = BorderStyle.FixedSingle
};
ibox.Click += (_, e) => surface1.SetTool(new ResourceTool(template));
resourcePalette.Controls.Add(ibox);
tt.SetToolTip(ibox,
"{0}:{1}cr".F(
template.Info.Name,
template.Info.ValuePerUnit));
resourceTemplates.Add(template);
}
catch { }
}
surface1.BindResourceTemplates(resourceTemplates);
foreach (var p in palettes)
{
p.Visible = true;
p.ResumeLayout();
}
pmMiniMap.Image = Minimap.AddStaticResources(surface1.Map, Minimap.TerrainBitmap(surface1.Map, true));
propertiesToolStripMenuItem.Enabled = true;
resizeToolStripMenuItem.Enabled = true;
spawnpointsToolStripMenuItem.Enabled = true;
saveToolStripMenuItem.Enabled = true;
saveAsToolStripMenuItem.Enabled = true;
mnuMinimapToPNG.Enabled = true; // todo: what is this VB naming bullshit doing here?
}
void ResizeClicked(object sender, EventArgs e)
{
using (var rd = new ResizeDialog())
{
rd.width.Value = surface1.Map.MapSize.X;
rd.height.Value = surface1.Map.MapSize.Y;
rd.cordonLeft.Value = surface1.Map.Bounds.Left;
rd.cordonTop.Value = surface1.Map.Bounds.Top;
rd.cordonRight.Value = surface1.Map.Bounds.Right;
rd.cordonBottom.Value = surface1.Map.Bounds.Bottom;
if (DialogResult.OK != rd.ShowDialog())
return;
surface1.Map.ResizeCordon((int)rd.cordonLeft.Value,
(int)rd.cordonTop.Value,
(int)rd.cordonRight.Value,
(int)rd.cordonBottom.Value);
if ((int)rd.width.Value != surface1.Map.MapSize.X || (int)rd.height.Value != surface1.Map.MapSize.Y)
{
surface1.Map.Resize((int)rd.width.Value, (int)rd.height.Value);
surface1.Bind(surface1.Map, surface1.TileSet, surface1.Palette); // rebind it to invalidate all caches
}
surface1.Invalidate();
}
}
void SaveClicked(object sender, EventArgs e)
{
if (loadedMapName == null)
SaveAsClicked(sender, e);
else
{
surface1.Map.Save(loadedMapName);
dirty = false;
}
}
void SaveAsClicked(object sender, EventArgs e)
{
using (var nms = new MapSelect(currentMod))
{
nms.txtNew.ReadOnly = false;
nms.btnOk.Text = "Save";
nms.txtNew.Text = "unnamed";
nms.txtPathOut.ReadOnly = false;
if (DialogResult.OK == nms.ShowDialog())
{
if (nms.txtNew.Text == "")
nms.txtNew.Text = "unnamed";
// TODO: Allow the user to choose map format (directory vs oramap)
loadedMapName = Path.Combine(nms.MapFolderPath, nms.txtNew.Text + ".oramap");
SaveClicked(sender, e);
}
}
}
void OpenClicked(object sender, EventArgs e)
{
using (var nms = new MapSelect(currentMod))
{
nms.txtNew.ReadOnly = true;
nms.txtPathOut.ReadOnly = true;
nms.btnOk.Text = "Open";
if (DialogResult.OK == nms.ShowDialog())
LoadMap(nms.txtNew.Tag as string);
}
}
void NewClicked(object sender, EventArgs e)
{
using (var nmd = new NewMapDialog())
{
nmd.theater.Items.Clear();
nmd.theater.Items.AddRange(Rules.TileSets.Select(a => a.Value.Id).ToArray());
nmd.theater.SelectedIndex = 0;
if (DialogResult.OK == nmd.ShowDialog())
{
var map = Map.FromTileset(nmd.theater.SelectedItem as string);
map.Resize((int)nmd.width.Value, (int)nmd.height.Value);
map.ResizeCordon((int)nmd.cordonLeft.Value, (int)nmd.cordonTop.Value,
(int)nmd.cordonRight.Value, (int)nmd.cordonBottom.Value);
map.Players.Add("Neutral", new PlayerReference("Neutral", Rules.Info["world"].Traits.WithInterface<CountryInfo>().First().Race, true, true));
map.Players.Add("Creeps", new PlayerReference("Creeps", Rules.Info["world"].Traits.WithInterface<CountryInfo>().First().Race, true, true));
NewMap(map);
}
}
}
void PropertiesClicked(object sender, EventArgs e)
{
using (var pd = new PropertiesDialog())
{
pd.title.Text = surface1.Map.Title;
pd.desc.Text = surface1.Map.Description;
pd.author.Text = surface1.Map.Author;
pd.selectable.Checked = surface1.Map.Selectable;
pd.useAsShellmap.Checked = surface1.Map.UseAsShellmap;
if (DialogResult.OK != pd.ShowDialog())
return;
surface1.Map.Title = pd.title.Text;
surface1.Map.Description = pd.desc.Text;
surface1.Map.Author = pd.author.Text;
surface1.Map.Selectable = pd.selectable.Checked;
surface1.Map.UseAsShellmap = pd.useAsShellmap.Checked;
}
}
void Form1_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Space) surface1.IsPanning = true; }
void Form1_KeyUp(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Space) surface1.IsPanning = false; }
void CloseClicked(object sender, EventArgs e)
{
Close();
}
void ImportLegacyMapClicked(object sender, EventArgs e)
{
var currentDirectory = Directory.GetCurrentDirectory();
using (var ofd = new OpenFileDialog { Filter = "Legacy maps (*.ini;*.mpr)|*.ini;*.mpr" })
if (DialogResult.OK == ofd.ShowDialog())
{
Directory.SetCurrentDirectory(currentDirectory);
/* massive hack: we should be able to call NewMap() with the imported Map object,
* but something's not right internally in it, unless loaded via the real maploader */
var savePath = Path.Combine(Path.GetTempPath(), "OpenRA.Import");
Directory.CreateDirectory(savePath);
var map = LegacyMapImporter.Import(ofd.FileName);
map.Players.Add("Neutral", new PlayerReference("Neutral",
Rules.Info["world"].Traits.WithInterface<CountryInfo>().First().Race, true, true));
map.Players.Add("Creeps", new PlayerReference("Creeps",
Rules.Info["world"].Traits.WithInterface<CountryInfo>().First().Race, true, true));
map.Save(savePath);
LoadMap(savePath);
loadedMapName = null; /* editor needs to think this hasnt been saved */
Directory.Delete(savePath, true);
MakeDirty();
}
}
void OnFormClosing(object sender, FormClosingEventArgs e)
{
if (!dirty) return;
switch (MessageBox.Show("The map has been modified since it was last saved. " + "\r\n" + "Save changes now?",
"Unsaved Changes", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Exclamation))
{
case DialogResult.Yes: SaveClicked(null, EventArgs.Empty); break;
case DialogResult.No: break;
case DialogResult.Cancel: e.Cancel = true; break;
}
}
private void layersFloaterToolStripMenuItem_Click(object sender, EventArgs e)
{
var pb = new PaletteBox();
pb.Show();
}
void ExportMinimap(object sender, EventArgs e)
{
saveFileDialog.InitialDirectory = Path.Combine(Environment.CurrentDirectory, "maps");
saveFileDialog.FileName = Path.ChangeExtension(loadedMapName, ".png");
if (DialogResult.OK == saveFileDialog.ShowDialog())
pmMiniMap.Image.Save(saveFileDialog.FileName);
}
}
}

View File

@@ -1,20 +1,20 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using SGraphics = System.Drawing.Graphics;
namespace OpenRA.Editor
{
interface ITool
{
void Apply(Surface surface);
void Preview(Surface surface, SGraphics g);
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using SGraphics = System.Drawing.Graphics;
namespace OpenRA.Editor
{
interface ITool
{
void Apply(Surface surface);
void Preview(Surface surface, SGraphics g);
}
}

View File

@@ -1,472 +1,472 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA.Editor
{
public class LegacyMapImporter
{
// Mapping from ra overlay index to type string
static string[] raOverlayNames =
{
"sbag", "cycl", "brik", "fenc", "wood",
"gold01", "gold02", "gold03", "gold04",
"gem01", "gem02", "gem03", "gem04",
"v12", "v13", "v14", "v15", "v16", "v17", "v18",
"fpls", "wcrate", "scrate", "barb", "sbag",
};
static Dictionary<string, Pair<byte, byte>> overlayResourceMapping = new Dictionary<string, Pair<byte, byte>>()
{
// RA Gems, Gold
{ "gold01", new Pair<byte,byte>(1,0) },
{ "gold02", new Pair<byte,byte>(1,1) },
{ "gold03", new Pair<byte,byte>(1,2) },
{ "gold04", new Pair<byte,byte>(1,3) },
{ "gem01", new Pair<byte,byte>(2,0) },
{ "gem02", new Pair<byte,byte>(2,1) },
{ "gem03", new Pair<byte,byte>(2,2) },
{ "gem04", new Pair<byte,byte>(2,3) },
// cnc tiberium
{ "ti1", new Pair<byte,byte>(1,0) },
{ "ti2", new Pair<byte,byte>(1,1) },
{ "ti3", new Pair<byte,byte>(1,2) },
{ "ti4", new Pair<byte,byte>(1,3) },
{ "ti5", new Pair<byte,byte>(1,4) },
{ "ti6", new Pair<byte,byte>(1,5) },
{ "ti7", new Pair<byte,byte>(1,6) },
{ "ti8", new Pair<byte,byte>(1,7) },
{ "ti9", new Pair<byte,byte>(1,8) },
{ "ti10", new Pair<byte,byte>(1,9) },
{ "ti11", new Pair<byte,byte>(1,10) },
{ "ti12", new Pair<byte,byte>(1,11) },
};
static Dictionary<string, string> overlayActorMapping = new Dictionary<string, string>() {
// Fences
{"sbag","sbag"},
{"cycl","cycl"},
{"brik","brik"},
{"fenc","fenc"},
{"wood","wood"},
// Fields
{"v12","v12"},
{"v13","v13"},
{"v14","v14"},
{"v15","v15"},
{"v16","v16"},
{"v17","v17"},
{"v18","v18"},
// Crates
// {"wcrate","crate"},
// {"scrate","crate"},
};
// todo: fix this -- will have bitrotted pretty badly.
static Dictionary<string,Pair<Color,Color>> namedColorMapping = new Dictionary<string, Pair<Color, Color>>()
{
{"gold",Pair.New(Color.FromArgb(246,214,121),Color.FromArgb(40,32,8))},
{"blue",Pair.New(Color.FromArgb(226,230,246),Color.FromArgb(8,20,52))},
{"red",Pair.New(Color.FromArgb(255,20,0),Color.FromArgb(56,0,0))},
{"neutral",Pair.New(Color.FromArgb(238,238,238),Color.FromArgb(44,28,24))},
{"orange",Pair.New(Color.FromArgb(255,230,149),Color.FromArgb(56,0,0))},
{"teal",Pair.New(Color.FromArgb(93,194,165),Color.FromArgb(0,32,32))},
{"salmon",Pair.New(Color.FromArgb(210,153,125),Color.FromArgb(56,0,0))},
{"green",Pair.New(Color.FromArgb(160,240,140),Color.FromArgb(20,20,20))},
{"white",Pair.New(Color.FromArgb(255,255,255),Color.FromArgb(75,75,75))},
{"black",Pair.New(Color.FromArgb(80,80,80),Color.FromArgb(5,5,5))},
};
int MapSize;
int ActorCount = 0;
Map Map = new Map();
List<string> Players = new List<string>();
LegacyMapImporter(string filename)
{
ConvertIniMap(filename);
}
public static Map Import(string filename)
{
var converter = new LegacyMapImporter(filename);
return converter.Map;
}
enum IniMapFormat { RedAlert = 3, /* otherwise, cnc (2 variants exist, we don't care to differentiate) */ };
public void ConvertIniMap(string iniFile)
{
var file = new IniFile(FileSystem.Open(iniFile));
var basic = file.GetSection("Basic");
var map = file.GetSection("Map");
var legacyMapFormat = (IniMapFormat)int.Parse(basic.GetValue("NewINIFormat", "0"));
var XOffset = int.Parse(map.GetValue("X", "0"));
var YOffset = int.Parse(map.GetValue("Y", "0"));
var Width = int.Parse(map.GetValue("Width", "0"));
var Height = int.Parse(map.GetValue("Height", "0"));
MapSize = (legacyMapFormat == IniMapFormat.RedAlert) ? 128 : 64;
Map.Title = basic.GetValue("Name", "(null)");
Map.Author = "Westwood Studios";
Map.Tileset = Truncate(map.GetValue("Theater", "TEMPERAT"), 8);
Map.MapSize.X = MapSize;
Map.MapSize.Y = MapSize;
Map.Bounds = Rectangle.FromLTRB(XOffset, YOffset, XOffset + Width, YOffset + Height);
Map.Selectable = true;
Map.Smudges = Lazy.New(() => new List<SmudgeReference>());
Map.Actors = Lazy.New(() => new Dictionary<string, ActorReference>());
Map.MapResources = Lazy.New(() => new TileReference<byte, byte>[MapSize, MapSize]);
Map.MapTiles = Lazy.New(() => new TileReference<ushort, byte>[MapSize, MapSize]);
if (legacyMapFormat == IniMapFormat.RedAlert)
{
UnpackRATileData(ReadPackedSection(file.GetSection("MapPack")));
UnpackRAOverlayData(ReadPackedSection(file.GetSection("OverlayPack")));
ReadRATrees(file);
}
else // CNC
{
UnpackCncTileData(FileSystem.Open(iniFile.Substring(0, iniFile.Length - 4) + ".bin"));
ReadCncOverlay(file);
ReadCncTrees(file);
}
LoadActors(file, "STRUCTURES");
LoadActors(file, "UNITS");
LoadActors(file, "INFANTRY");
LoadSmudges(file, "SMUDGE");
foreach (var p in Players)
LoadPlayer(file, p, (legacyMapFormat == IniMapFormat.RedAlert));
var wps = file.GetSection("Waypoints")
.Where(kv => int.Parse(kv.Value) > 0)
.Select(kv => Pair.New(int.Parse(kv.Key),
LocationFromMapOffset(int.Parse(kv.Value), MapSize)))
.ToArray();
// Add waypoint actors
foreach( var kv in wps )
{
var a = new ActorReference("mpspawn");
a.Add(new LocationInit(kv.Second));
Map.Actors.Value.Add("spawn" + kv.First, a);
}
}
static int2 LocationFromMapOffset(int offset, int mapSize)
{
return new int2(offset % mapSize, offset / mapSize);
}
static MemoryStream ReadPackedSection(IniSection mapPackSection)
{
StringBuilder sb = new StringBuilder();
for (int i = 1; ; i++)
{
string line = mapPackSection.GetValue(i.ToString(), null);
if (line == null)
break;
sb.Append(line.Trim());
}
byte[] data = Convert.FromBase64String(sb.ToString());
List<byte[]> chunks = new List<byte[]>();
BinaryReader reader = new BinaryReader(new MemoryStream(data));
try
{
while (true)
{
uint length = reader.ReadUInt32() & 0xdfffffff;
byte[] dest = new byte[8192];
byte[] src = reader.ReadBytes((int)length);
/*int actualLength =*/
Format80.DecodeInto(src, dest);
chunks.Add(dest);
}
}
catch (EndOfStreamException) { }
MemoryStream ms = new MemoryStream();
foreach (byte[] chunk in chunks)
ms.Write(chunk, 0, chunk.Length);
ms.Position = 0;
return ms;
}
static byte ReadByte(Stream s)
{
int ret = s.ReadByte();
if (ret == -1)
throw new NotImplementedException();
return (byte)ret;
}
static ushort ReadWord(Stream s)
{
ushort ret = ReadByte(s);
ret |= (ushort)(ReadByte(s) << 8);
return ret;
}
void UnpackRATileData(MemoryStream ms)
{
for (int i = 0; i < MapSize; i++)
for (int j = 0; j < MapSize; j++)
Map.MapTiles.Value[i, j] = new TileReference<ushort, byte>();
for (int j = 0; j < MapSize; j++)
for (int i = 0; i < MapSize; i++)
Map.MapTiles.Value[i, j].type = ReadWord(ms);
for (int j = 0; j < MapSize; j++)
for (int i = 0; i < MapSize; i++)
Map.MapTiles.Value[i, j].index = ReadByte(ms);
}
void UnpackRAOverlayData(MemoryStream ms)
{
for (int j = 0; j < MapSize; j++)
for (int i = 0; i < MapSize; i++)
{
byte o = ReadByte(ms);
var res = Pair.New((byte)0, (byte)0);
if (o != 255 && overlayResourceMapping.ContainsKey(raOverlayNames[o]))
res = overlayResourceMapping[raOverlayNames[o]];
Map.MapResources.Value[i, j] = new TileReference<byte, byte>(res.First, res.Second);
if (o != 255 && overlayActorMapping.ContainsKey(raOverlayNames[o]))
Map.Actors.Value.Add("Actor" + ActorCount++,
new ActorReference(overlayActorMapping[raOverlayNames[o]])
{
new LocationInit( new int2(i, j) ),
new OwnerInit( "Neutral" )
});
}
}
void ReadRATrees(IniFile file)
{
IniSection terrain = file.GetSection("TERRAIN", true);
if (terrain == null)
return;
foreach (KeyValuePair<string, string> kv in terrain)
{
var loc = int.Parse(kv.Key);
Map.Actors.Value.Add("Actor" + ActorCount++,
new ActorReference(kv.Value.ToLowerInvariant())
{
new LocationInit(new int2(loc % MapSize, loc / MapSize)),
new OwnerInit("Neutral")
});
}
}
void UnpackCncTileData(Stream ms)
{
for (int i = 0; i < MapSize; i++)
for (int j = 0; j < MapSize; j++)
Map.MapTiles.Value[i, j] = new TileReference<ushort, byte>();
for (int j = 0; j < MapSize; j++)
for (int i = 0; i < MapSize; i++)
{
Map.MapTiles.Value[i, j].type = ReadByte(ms);
Map.MapTiles.Value[i, j].index = ReadByte(ms);
}
}
void ReadCncOverlay(IniFile file)
{
IniSection overlay = file.GetSection("OVERLAY", true);
if (overlay == null)
return;
foreach (KeyValuePair<string, string> kv in overlay)
{
var loc = int.Parse(kv.Key);
int2 cell = new int2(loc % MapSize, loc / MapSize);
var res = Pair.New((byte)0, (byte)0);
if (overlayResourceMapping.ContainsKey(kv.Value.ToLower()))
res = overlayResourceMapping[kv.Value.ToLower()];
Map.MapResources.Value[cell.X, cell.Y] = new TileReference<byte, byte>(res.First, res.Second);
if (overlayActorMapping.ContainsKey(kv.Value.ToLower()))
Map.Actors.Value.Add("Actor" + ActorCount++,
new ActorReference(overlayActorMapping[kv.Value.ToLower()])
{
new LocationInit(cell),
new OwnerInit("Neutral")
});
}
}
void ReadCncTrees(IniFile file)
{
IniSection terrain = file.GetSection("TERRAIN", true);
if (terrain == null)
return;
foreach (KeyValuePair<string, string> kv in terrain)
{
var loc = int.Parse(kv.Key);
Map.Actors.Value.Add("Actor" + ActorCount++,
new ActorReference(kv.Value.Split(',')[0].ToLowerInvariant())
{
new LocationInit(new int2(loc % MapSize, loc / MapSize)),
new OwnerInit("Neutral")
});
}
}
void LoadActors(IniFile file, string section)
{
foreach (var s in file.GetSection(section, true))
{
//Structures: num=owner,type,health,location,turret-facing,trigger
//Units: num=owner,type,health,location,facing,action,trigger
//Infantry: num=owner,type,health,location,subcell,action,facing,trigger
var parts = s.Value.Split(',');
var loc = int.Parse(parts[3]);
if (parts[0] == "")
parts[0] = "Neutral";
if (!Players.Contains(parts[0]))
Players.Add(parts[0]);
var stance = ActorStance.Stance.None;
switch(parts[5])
{
case "Area Guard":
case "Guard":
stance = ActorStance.Stance.Guard;
break;
case "Defend Base":
stance = ActorStance.Stance.Defend;
break;
case "Hunt":
case "Rampage":
case "Attack Base":
case "Attack Units":
case "Attack Civil.":
case "Attack Tarcom":
stance = ActorStance.Stance.Hunt;
break;
case "Retreat":
case "Return":
stance = ActorStance.Stance.Retreat;
break;
// do we care about `Harvest' and `Sticky'?
}
var actor = new ActorReference(parts[1].ToLowerInvariant())
{
new LocationInit(new int2(loc % MapSize, loc / MapSize)),
new OwnerInit(parts[0]),
new HealthInit(float.Parse(parts[2], NumberFormatInfo.InvariantInfo)/256),
new FacingInit((section == "INFANTRY") ? int.Parse(parts[6]) : int.Parse(parts[4])),
new ActorStanceInit(stance),
};
if (section == "INFANTRY")
actor.Add(new SubCellInit(int.Parse(parts[4])));
Map.Actors.Value.Add("Actor" + ActorCount++,actor);
}
}
void LoadSmudges(IniFile file, string section)
{
foreach (var s in file.GetSection(section, true))
{
//loc=type,loc,depth
var parts = s.Value.Split(',');
var loc = int.Parse(parts[1]);
Map.Smudges.Value.Add(new SmudgeReference(parts[0].ToLowerInvariant(), new int2(loc % MapSize, loc / MapSize), int.Parse(parts[2])));
}
}
void LoadPlayer(IniFile file, string section, bool isRA)
{
var c = (section == "BadGuy") ? "red" :
(isRA) ? "blue" : "gold";
var color = namedColorMapping[c];
var pr = new PlayerReference
{
Name = section,
OwnsWorld = (section == "Neutral"),
NonCombatant = (section == "Neutral"),
Race = (isRA) ? ((section == "BadGuy") ? "soviet" : "allies") : ((section == "BadGuy") ? "nod" : "gdi"),
ColorRamp = new ColorRamp(
(byte)((color.First.GetHue() / 360.0f) * 255),
(byte)(color.First.GetSaturation() * 255),
(byte)(color.First.GetBrightness() * 255),
(byte)(color.Second.GetBrightness() * 255))
};
var Neutral = new List<string>(){"Neutral"};
foreach (var s in file.GetSection(section, true))
{
Console.WriteLine(s.Key);
switch(s.Key)
{
case "Credits":
pr.InitialCash = int.Parse(s.Value);
break;
case "Allies":
pr.Allies = s.Value.Split(',').Intersect(Players).Except(Neutral).ToArray();
pr.Enemies = s.Value.Split(',').SymmetricDifference(Players).Except(Neutral).ToArray();
break;
}
}
Map.Players.Add(section, pr);
}
static string Truncate(string s, int maxLength)
{
return s.Length <= maxLength ? s : s.Substring(0, maxLength);
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA.Editor
{
public class LegacyMapImporter
{
// Mapping from ra overlay index to type string
static string[] raOverlayNames =
{
"sbag", "cycl", "brik", "fenc", "wood",
"gold01", "gold02", "gold03", "gold04",
"gem01", "gem02", "gem03", "gem04",
"v12", "v13", "v14", "v15", "v16", "v17", "v18",
"fpls", "wcrate", "scrate", "barb", "sbag",
};
static Dictionary<string, Pair<byte, byte>> overlayResourceMapping = new Dictionary<string, Pair<byte, byte>>()
{
// RA Gems, Gold
{ "gold01", new Pair<byte,byte>(1,0) },
{ "gold02", new Pair<byte,byte>(1,1) },
{ "gold03", new Pair<byte,byte>(1,2) },
{ "gold04", new Pair<byte,byte>(1,3) },
{ "gem01", new Pair<byte,byte>(2,0) },
{ "gem02", new Pair<byte,byte>(2,1) },
{ "gem03", new Pair<byte,byte>(2,2) },
{ "gem04", new Pair<byte,byte>(2,3) },
// cnc tiberium
{ "ti1", new Pair<byte,byte>(1,0) },
{ "ti2", new Pair<byte,byte>(1,1) },
{ "ti3", new Pair<byte,byte>(1,2) },
{ "ti4", new Pair<byte,byte>(1,3) },
{ "ti5", new Pair<byte,byte>(1,4) },
{ "ti6", new Pair<byte,byte>(1,5) },
{ "ti7", new Pair<byte,byte>(1,6) },
{ "ti8", new Pair<byte,byte>(1,7) },
{ "ti9", new Pair<byte,byte>(1,8) },
{ "ti10", new Pair<byte,byte>(1,9) },
{ "ti11", new Pair<byte,byte>(1,10) },
{ "ti12", new Pair<byte,byte>(1,11) },
};
static Dictionary<string, string> overlayActorMapping = new Dictionary<string, string>() {
// Fences
{"sbag","sbag"},
{"cycl","cycl"},
{"brik","brik"},
{"fenc","fenc"},
{"wood","wood"},
// Fields
{"v12","v12"},
{"v13","v13"},
{"v14","v14"},
{"v15","v15"},
{"v16","v16"},
{"v17","v17"},
{"v18","v18"},
// Crates
// {"wcrate","crate"},
// {"scrate","crate"},
};
// todo: fix this -- will have bitrotted pretty badly.
static Dictionary<string,Pair<Color,Color>> namedColorMapping = new Dictionary<string, Pair<Color, Color>>()
{
{"gold",Pair.New(Color.FromArgb(246,214,121),Color.FromArgb(40,32,8))},
{"blue",Pair.New(Color.FromArgb(226,230,246),Color.FromArgb(8,20,52))},
{"red",Pair.New(Color.FromArgb(255,20,0),Color.FromArgb(56,0,0))},
{"neutral",Pair.New(Color.FromArgb(238,238,238),Color.FromArgb(44,28,24))},
{"orange",Pair.New(Color.FromArgb(255,230,149),Color.FromArgb(56,0,0))},
{"teal",Pair.New(Color.FromArgb(93,194,165),Color.FromArgb(0,32,32))},
{"salmon",Pair.New(Color.FromArgb(210,153,125),Color.FromArgb(56,0,0))},
{"green",Pair.New(Color.FromArgb(160,240,140),Color.FromArgb(20,20,20))},
{"white",Pair.New(Color.FromArgb(255,255,255),Color.FromArgb(75,75,75))},
{"black",Pair.New(Color.FromArgb(80,80,80),Color.FromArgb(5,5,5))},
};
int MapSize;
int ActorCount = 0;
Map Map = new Map();
List<string> Players = new List<string>();
LegacyMapImporter(string filename)
{
ConvertIniMap(filename);
}
public static Map Import(string filename)
{
var converter = new LegacyMapImporter(filename);
return converter.Map;
}
enum IniMapFormat { RedAlert = 3, /* otherwise, cnc (2 variants exist, we don't care to differentiate) */ };
public void ConvertIniMap(string iniFile)
{
var file = new IniFile(FileSystem.Open(iniFile));
var basic = file.GetSection("Basic");
var map = file.GetSection("Map");
var legacyMapFormat = (IniMapFormat)int.Parse(basic.GetValue("NewINIFormat", "0"));
var XOffset = int.Parse(map.GetValue("X", "0"));
var YOffset = int.Parse(map.GetValue("Y", "0"));
var Width = int.Parse(map.GetValue("Width", "0"));
var Height = int.Parse(map.GetValue("Height", "0"));
MapSize = (legacyMapFormat == IniMapFormat.RedAlert) ? 128 : 64;
Map.Title = basic.GetValue("Name", "(null)");
Map.Author = "Westwood Studios";
Map.Tileset = Truncate(map.GetValue("Theater", "TEMPERAT"), 8);
Map.MapSize.X = MapSize;
Map.MapSize.Y = MapSize;
Map.Bounds = Rectangle.FromLTRB(XOffset, YOffset, XOffset + Width, YOffset + Height);
Map.Selectable = true;
Map.Smudges = Lazy.New(() => new List<SmudgeReference>());
Map.Actors = Lazy.New(() => new Dictionary<string, ActorReference>());
Map.MapResources = Lazy.New(() => new TileReference<byte, byte>[MapSize, MapSize]);
Map.MapTiles = Lazy.New(() => new TileReference<ushort, byte>[MapSize, MapSize]);
if (legacyMapFormat == IniMapFormat.RedAlert)
{
UnpackRATileData(ReadPackedSection(file.GetSection("MapPack")));
UnpackRAOverlayData(ReadPackedSection(file.GetSection("OverlayPack")));
ReadRATrees(file);
}
else // CNC
{
UnpackCncTileData(FileSystem.Open(iniFile.Substring(0, iniFile.Length - 4) + ".bin"));
ReadCncOverlay(file);
ReadCncTrees(file);
}
LoadActors(file, "STRUCTURES");
LoadActors(file, "UNITS");
LoadActors(file, "INFANTRY");
LoadSmudges(file, "SMUDGE");
foreach (var p in Players)
LoadPlayer(file, p, (legacyMapFormat == IniMapFormat.RedAlert));
var wps = file.GetSection("Waypoints")
.Where(kv => int.Parse(kv.Value) > 0)
.Select(kv => Pair.New(int.Parse(kv.Key),
LocationFromMapOffset(int.Parse(kv.Value), MapSize)))
.ToArray();
// Add waypoint actors
foreach( var kv in wps )
{
var a = new ActorReference("mpspawn");
a.Add(new LocationInit(kv.Second));
Map.Actors.Value.Add("spawn" + kv.First, a);
}
}
static int2 LocationFromMapOffset(int offset, int mapSize)
{
return new int2(offset % mapSize, offset / mapSize);
}
static MemoryStream ReadPackedSection(IniSection mapPackSection)
{
StringBuilder sb = new StringBuilder();
for (int i = 1; ; i++)
{
string line = mapPackSection.GetValue(i.ToString(), null);
if (line == null)
break;
sb.Append(line.Trim());
}
byte[] data = Convert.FromBase64String(sb.ToString());
List<byte[]> chunks = new List<byte[]>();
BinaryReader reader = new BinaryReader(new MemoryStream(data));
try
{
while (true)
{
uint length = reader.ReadUInt32() & 0xdfffffff;
byte[] dest = new byte[8192];
byte[] src = reader.ReadBytes((int)length);
/*int actualLength =*/
Format80.DecodeInto(src, dest);
chunks.Add(dest);
}
}
catch (EndOfStreamException) { }
MemoryStream ms = new MemoryStream();
foreach (byte[] chunk in chunks)
ms.Write(chunk, 0, chunk.Length);
ms.Position = 0;
return ms;
}
static byte ReadByte(Stream s)
{
int ret = s.ReadByte();
if (ret == -1)
throw new NotImplementedException();
return (byte)ret;
}
static ushort ReadWord(Stream s)
{
ushort ret = ReadByte(s);
ret |= (ushort)(ReadByte(s) << 8);
return ret;
}
void UnpackRATileData(MemoryStream ms)
{
for (int i = 0; i < MapSize; i++)
for (int j = 0; j < MapSize; j++)
Map.MapTiles.Value[i, j] = new TileReference<ushort, byte>();
for (int j = 0; j < MapSize; j++)
for (int i = 0; i < MapSize; i++)
Map.MapTiles.Value[i, j].type = ReadWord(ms);
for (int j = 0; j < MapSize; j++)
for (int i = 0; i < MapSize; i++)
Map.MapTiles.Value[i, j].index = ReadByte(ms);
}
void UnpackRAOverlayData(MemoryStream ms)
{
for (int j = 0; j < MapSize; j++)
for (int i = 0; i < MapSize; i++)
{
byte o = ReadByte(ms);
var res = Pair.New((byte)0, (byte)0);
if (o != 255 && overlayResourceMapping.ContainsKey(raOverlayNames[o]))
res = overlayResourceMapping[raOverlayNames[o]];
Map.MapResources.Value[i, j] = new TileReference<byte, byte>(res.First, res.Second);
if (o != 255 && overlayActorMapping.ContainsKey(raOverlayNames[o]))
Map.Actors.Value.Add("Actor" + ActorCount++,
new ActorReference(overlayActorMapping[raOverlayNames[o]])
{
new LocationInit( new int2(i, j) ),
new OwnerInit( "Neutral" )
});
}
}
void ReadRATrees(IniFile file)
{
IniSection terrain = file.GetSection("TERRAIN", true);
if (terrain == null)
return;
foreach (KeyValuePair<string, string> kv in terrain)
{
var loc = int.Parse(kv.Key);
Map.Actors.Value.Add("Actor" + ActorCount++,
new ActorReference(kv.Value.ToLowerInvariant())
{
new LocationInit(new int2(loc % MapSize, loc / MapSize)),
new OwnerInit("Neutral")
});
}
}
void UnpackCncTileData(Stream ms)
{
for (int i = 0; i < MapSize; i++)
for (int j = 0; j < MapSize; j++)
Map.MapTiles.Value[i, j] = new TileReference<ushort, byte>();
for (int j = 0; j < MapSize; j++)
for (int i = 0; i < MapSize; i++)
{
Map.MapTiles.Value[i, j].type = ReadByte(ms);
Map.MapTiles.Value[i, j].index = ReadByte(ms);
}
}
void ReadCncOverlay(IniFile file)
{
IniSection overlay = file.GetSection("OVERLAY", true);
if (overlay == null)
return;
foreach (KeyValuePair<string, string> kv in overlay)
{
var loc = int.Parse(kv.Key);
int2 cell = new int2(loc % MapSize, loc / MapSize);
var res = Pair.New((byte)0, (byte)0);
if (overlayResourceMapping.ContainsKey(kv.Value.ToLower()))
res = overlayResourceMapping[kv.Value.ToLower()];
Map.MapResources.Value[cell.X, cell.Y] = new TileReference<byte, byte>(res.First, res.Second);
if (overlayActorMapping.ContainsKey(kv.Value.ToLower()))
Map.Actors.Value.Add("Actor" + ActorCount++,
new ActorReference(overlayActorMapping[kv.Value.ToLower()])
{
new LocationInit(cell),
new OwnerInit("Neutral")
});
}
}
void ReadCncTrees(IniFile file)
{
IniSection terrain = file.GetSection("TERRAIN", true);
if (terrain == null)
return;
foreach (KeyValuePair<string, string> kv in terrain)
{
var loc = int.Parse(kv.Key);
Map.Actors.Value.Add("Actor" + ActorCount++,
new ActorReference(kv.Value.Split(',')[0].ToLowerInvariant())
{
new LocationInit(new int2(loc % MapSize, loc / MapSize)),
new OwnerInit("Neutral")
});
}
}
void LoadActors(IniFile file, string section)
{
foreach (var s in file.GetSection(section, true))
{
//Structures: num=owner,type,health,location,turret-facing,trigger
//Units: num=owner,type,health,location,facing,action,trigger
//Infantry: num=owner,type,health,location,subcell,action,facing,trigger
var parts = s.Value.Split(',');
var loc = int.Parse(parts[3]);
if (parts[0] == "")
parts[0] = "Neutral";
if (!Players.Contains(parts[0]))
Players.Add(parts[0]);
var stance = ActorStance.Stance.None;
switch(parts[5])
{
case "Area Guard":
case "Guard":
stance = ActorStance.Stance.Guard;
break;
case "Defend Base":
stance = ActorStance.Stance.Defend;
break;
case "Hunt":
case "Rampage":
case "Attack Base":
case "Attack Units":
case "Attack Civil.":
case "Attack Tarcom":
stance = ActorStance.Stance.Hunt;
break;
case "Retreat":
case "Return":
stance = ActorStance.Stance.Retreat;
break;
// do we care about `Harvest' and `Sticky'?
}
var actor = new ActorReference(parts[1].ToLowerInvariant())
{
new LocationInit(new int2(loc % MapSize, loc / MapSize)),
new OwnerInit(parts[0]),
new HealthInit(float.Parse(parts[2], NumberFormatInfo.InvariantInfo)/256),
new FacingInit((section == "INFANTRY") ? int.Parse(parts[6]) : int.Parse(parts[4])),
new ActorStanceInit(stance),
};
if (section == "INFANTRY")
actor.Add(new SubCellInit(int.Parse(parts[4])));
Map.Actors.Value.Add("Actor" + ActorCount++,actor);
}
}
void LoadSmudges(IniFile file, string section)
{
foreach (var s in file.GetSection(section, true))
{
//loc=type,loc,depth
var parts = s.Value.Split(',');
var loc = int.Parse(parts[1]);
Map.Smudges.Value.Add(new SmudgeReference(parts[0].ToLowerInvariant(), new int2(loc % MapSize, loc / MapSize), int.Parse(parts[2])));
}
}
void LoadPlayer(IniFile file, string section, bool isRA)
{
var c = (section == "BadGuy") ? "red" :
(isRA) ? "blue" : "gold";
var color = namedColorMapping[c];
var pr = new PlayerReference
{
Name = section,
OwnsWorld = (section == "Neutral"),
NonCombatant = (section == "Neutral"),
Race = (isRA) ? ((section == "BadGuy") ? "soviet" : "allies") : ((section == "BadGuy") ? "nod" : "gdi"),
ColorRamp = new ColorRamp(
(byte)((color.First.GetHue() / 360.0f) * 255),
(byte)(color.First.GetSaturation() * 255),
(byte)(color.First.GetBrightness() * 255),
(byte)(color.Second.GetBrightness() * 255))
};
var Neutral = new List<string>(){"Neutral"};
foreach (var s in file.GetSection(section, true))
{
Console.WriteLine(s.Key);
switch(s.Key)
{
case "Credits":
pr.InitialCash = int.Parse(s.Value);
break;
case "Allies":
pr.Allies = s.Value.Split(',').Intersect(Players).Except(Neutral).ToArray();
pr.Enemies = s.Value.Split(',').SymmetricDifference(Players).Except(Neutral).ToArray();
break;
}
}
Map.Players.Add(section, pr);
}
static string Truncate(string s, int maxLength)
{
return s.Length <= maxLength ? s : s.Substring(0, maxLength);
}
}
}

View File

@@ -1,27 +1,27 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Windows.Forms;
namespace OpenRA.Editor
{
public partial class NewMapDialog : Form
{
public NewMapDialog()
{
InitializeComponent();
}
private void SelectText(object sender, System.EventArgs e)
{
(sender as NumericUpDown).Select(0, (sender as NumericUpDown).ToString().Length);
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Windows.Forms;
namespace OpenRA.Editor
{
public partial class NewMapDialog : Form
{
public NewMapDialog()
{
InitializeComponent();
}
private void SelectText(object sender, System.EventArgs e)
{
(sender as NumericUpDown).Select(0, (sender as NumericUpDown).ToString().Length);
}
}
}

View File

@@ -1,54 +1,54 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Globalization;
using System.Windows.Forms;
using System.Linq;
using System.IO;
using OpenRA.FileFormats;
namespace OpenRA.Editor
{
static class Program
{
[STAThread]
static void Main( string[] args )
{
if (args.Length >= 2 && args[0] == "--convert")
{
Game.modData = new ModData(args[1]);
FileSystem.LoadFromManifest(Game.modData.Manifest);
Rules.LoadRules(Game.modData.Manifest, new Map());
UpgradeMaps(args[1]);
return;
}
Application.CurrentCulture = CultureInfo.InvariantCulture;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1(args));
}
static void UpgradeMaps(string mod)
{
var MapFolderPath = new string[] { Environment.CurrentDirectory, "mods", mod, "maps" }
.Aggregate(Path.Combine);
foreach (var path in ModData.FindMapsIn(MapFolderPath))
{
var map = new Map(path);
map.Save(path);
}
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Globalization;
using System.Windows.Forms;
using System.Linq;
using System.IO;
using OpenRA.FileFormats;
namespace OpenRA.Editor
{
static class Program
{
[STAThread]
static void Main( string[] args )
{
if (args.Length >= 2 && args[0] == "--convert")
{
Game.modData = new ModData(args[1]);
FileSystem.LoadFromManifest(Game.modData.Manifest);
Rules.LoadRules(Game.modData.Manifest, new Map());
UpgradeMaps(args[1]);
return;
}
Application.CurrentCulture = CultureInfo.InvariantCulture;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1(args));
}
static void UpgradeMaps(string mod)
{
var MapFolderPath = new string[] { Environment.CurrentDirectory, "mods", mod, "maps" }
.Aggregate(Path.Combine);
foreach (var path in ModData.FindMapsIn(MapFolderPath))
{
var map = new Map(path);
map.Save(path);
}
}
}
}

View File

@@ -1,22 +1,22 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Windows.Forms;
namespace OpenRA.Editor
{
public partial class PropertiesDialog : Form
{
public PropertiesDialog()
{
InitializeComponent();
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Windows.Forms;
namespace OpenRA.Editor
{
public partial class PropertiesDialog : Form
{
public PropertiesDialog()
{
InitializeComponent();
}
}
}

View File

@@ -1,156 +1,156 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Drawing;
using System.Drawing.Imaging;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA.Editor
{
static class RenderUtils
{
public static ColorPalette MakeSystemPalette(Palette p)
{
ColorPalette pal;
using (var b = new Bitmap(1, 1, PixelFormat.Format8bppIndexed))
pal = b.Palette;
for (var i = 0; i < 256; i++)
pal.Entries[i] = p.GetColor(i);
return pal;
}
public static Bitmap RenderTemplate(TileSet ts, ushort n, Palette p)
{
var template = ts.Templates[n];
var tile = ts.Tiles[n];
var bitmap = new Bitmap(ts.TileSize * template.Size.X, ts.TileSize * template.Size.Y,
PixelFormat.Format8bppIndexed);
bitmap.Palette = MakeSystemPalette(p);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
unsafe
{
byte* q = (byte*)data.Scan0.ToPointer();
var stride = data.Stride;
for (var u = 0; u < template.Size.X; u++)
for (var v = 0; v < template.Size.Y; v++)
if (tile.TileBitmapBytes[u + v * template.Size.X] != null)
{
var rawImage = tile.TileBitmapBytes[u + v * template.Size.X];
for (var i = 0; i < ts.TileSize; i++)
for (var j = 0; j < ts.TileSize; j++)
q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = rawImage[i + ts.TileSize * j];
}
else
{
for (var i = 0; i < ts.TileSize; i++)
for (var j = 0; j < ts.TileSize; j++)
q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = 0;
}
}
bitmap.UnlockBits(data);
return bitmap;
}
static Bitmap RenderShp(ShpReader shp, Palette p)
{
var frame = shp[0];
var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed);
bitmap.Palette = MakeSystemPalette(p);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
unsafe
{
byte* q = (byte*)data.Scan0.ToPointer();
var stride2 = data.Stride;
for (var i = 0; i < shp.Width; i++)
for (var j = 0; j < shp.Height; j++)
q[j * stride2 + i] = frame.Image[i + shp.Width * j];
}
bitmap.UnlockBits(data);
return bitmap;
}
public static ActorTemplate RenderActor(ActorInfo info, TileSet tileset, Palette p)
{
var ri = info.Traits.Get<RenderSimpleInfo>();
var image = RenderSimple.GetImage(info, tileset.Id);
using (var s = FileSystem.OpenWithExts(image, tileset.Extensions))
{
var shp = new ShpReader(s);
var bitmap = RenderShp(shp, p);
try
{
using (var s2 = FileSystem.OpenWithExts(image + "2", tileset.Extensions))
{
var shp2 = new ShpReader(s2);
var roofBitmap = RenderShp(shp2, p);
using (var g = System.Drawing.Graphics.FromImage(bitmap))
g.DrawImage(roofBitmap, 0, 0);
}
}
catch { }
return new ActorTemplate
{
Bitmap = bitmap,
Info = info,
Appearance = info.Traits.GetOrDefault<EditorAppearanceInfo>()
};
}
}
public static ResourceTemplate RenderResourceType(ResourceTypeInfo info, string[] exts, Palette p)
{
var image = info.SpriteNames[0];
using (var s = FileSystem.OpenWithExts(image, exts))
{
var shp = new ShpReader(s);
var frame = shp[shp.ImageCount - 1];
var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed);
bitmap.Palette = MakeSystemPalette(p);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
unsafe
{
byte* q = (byte*)data.Scan0.ToPointer();
var stride = data.Stride;
for (var i = 0; i < shp.Width; i++)
for (var j = 0; j < shp.Height; j++)
q[j * stride + i] = frame.Image[i + shp.Width * j];
}
bitmap.UnlockBits(data);
return new ResourceTemplate { Bitmap = bitmap, Info = info, Value = shp.ImageCount - 1 };
}
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Drawing;
using System.Drawing.Imaging;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA.Editor
{
static class RenderUtils
{
public static ColorPalette MakeSystemPalette(Palette p)
{
ColorPalette pal;
using (var b = new Bitmap(1, 1, PixelFormat.Format8bppIndexed))
pal = b.Palette;
for (var i = 0; i < 256; i++)
pal.Entries[i] = p.GetColor(i);
return pal;
}
public static Bitmap RenderTemplate(TileSet ts, ushort n, Palette p)
{
var template = ts.Templates[n];
var tile = ts.Tiles[n];
var bitmap = new Bitmap(ts.TileSize * template.Size.X, ts.TileSize * template.Size.Y,
PixelFormat.Format8bppIndexed);
bitmap.Palette = MakeSystemPalette(p);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
unsafe
{
byte* q = (byte*)data.Scan0.ToPointer();
var stride = data.Stride;
for (var u = 0; u < template.Size.X; u++)
for (var v = 0; v < template.Size.Y; v++)
if (tile.TileBitmapBytes[u + v * template.Size.X] != null)
{
var rawImage = tile.TileBitmapBytes[u + v * template.Size.X];
for (var i = 0; i < ts.TileSize; i++)
for (var j = 0; j < ts.TileSize; j++)
q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = rawImage[i + ts.TileSize * j];
}
else
{
for (var i = 0; i < ts.TileSize; i++)
for (var j = 0; j < ts.TileSize; j++)
q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = 0;
}
}
bitmap.UnlockBits(data);
return bitmap;
}
static Bitmap RenderShp(ShpReader shp, Palette p)
{
var frame = shp[0];
var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed);
bitmap.Palette = MakeSystemPalette(p);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
unsafe
{
byte* q = (byte*)data.Scan0.ToPointer();
var stride2 = data.Stride;
for (var i = 0; i < shp.Width; i++)
for (var j = 0; j < shp.Height; j++)
q[j * stride2 + i] = frame.Image[i + shp.Width * j];
}
bitmap.UnlockBits(data);
return bitmap;
}
public static ActorTemplate RenderActor(ActorInfo info, TileSet tileset, Palette p)
{
var ri = info.Traits.Get<RenderSimpleInfo>();
var image = RenderSimple.GetImage(info, tileset.Id);
using (var s = FileSystem.OpenWithExts(image, tileset.Extensions))
{
var shp = new ShpReader(s);
var bitmap = RenderShp(shp, p);
try
{
using (var s2 = FileSystem.OpenWithExts(image + "2", tileset.Extensions))
{
var shp2 = new ShpReader(s2);
var roofBitmap = RenderShp(shp2, p);
using (var g = System.Drawing.Graphics.FromImage(bitmap))
g.DrawImage(roofBitmap, 0, 0);
}
}
catch { }
return new ActorTemplate
{
Bitmap = bitmap,
Info = info,
Appearance = info.Traits.GetOrDefault<EditorAppearanceInfo>()
};
}
}
public static ResourceTemplate RenderResourceType(ResourceTypeInfo info, string[] exts, Palette p)
{
var image = info.SpriteNames[0];
using (var s = FileSystem.OpenWithExts(image, exts))
{
var shp = new ShpReader(s);
var frame = shp[shp.ImageCount - 1];
var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed);
bitmap.Palette = MakeSystemPalette(p);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
unsafe
{
byte* q = (byte*)data.Scan0.ToPointer();
var stride = data.Stride;
for (var i = 0; i < shp.Width; i++)
for (var j = 0; j < shp.Height; j++)
q[j * stride + i] = frame.Image[i + shp.Width * j];
}
bitmap.UnlockBits(data);
return new ResourceTemplate { Bitmap = bitmap, Info = info, Value = shp.ImageCount - 1 };
}
}
}
}

View File

@@ -1,22 +1,22 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Windows.Forms;
namespace OpenRA.Editor
{
public partial class ResizeDialog : Form
{
public ResizeDialog()
{
InitializeComponent();
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Windows.Forms;
namespace OpenRA.Editor
{
public partial class ResizeDialog : Form
{
public ResizeDialog()
{
InitializeComponent();
}
}
}

View File

@@ -1,50 +1,50 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using OpenRA.FileFormats;
using SGraphics = System.Drawing.Graphics;
namespace OpenRA.Editor
{
class ResourceTool : ITool
{
ResourceTemplate Resource;
public ResourceTool(ResourceTemplate resource) { Resource = resource; }
public void Apply(Surface surface)
{
surface.Map.MapResources.Value[surface.GetBrushLocation().X, surface.GetBrushLocation().Y]
= new TileReference<byte, byte>
{
type = (byte)Resource.Info.ResourceType,
index = (byte)random.Next(Resource.Info.SpriteNames.Length)
};
var ch = new int2((surface.GetBrushLocation().X) / Surface.ChunkSize,
(surface.GetBrushLocation().Y) / Surface.ChunkSize);
if (surface.Chunks.ContainsKey(ch))
{
surface.Chunks[ch].Dispose();
surface.Chunks.Remove(ch);
}
}
public void Preview(Surface surface, SGraphics g)
{
surface.DrawImage(g, Resource.Bitmap, surface.GetBrushLocation(), false, null);
}
Random random = new Random();
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using OpenRA.FileFormats;
using SGraphics = System.Drawing.Graphics;
namespace OpenRA.Editor
{
class ResourceTool : ITool
{
ResourceTemplate Resource;
public ResourceTool(ResourceTemplate resource) { Resource = resource; }
public void Apply(Surface surface)
{
surface.Map.MapResources.Value[surface.GetBrushLocation().X, surface.GetBrushLocation().Y]
= new TileReference<byte, byte>
{
type = (byte)Resource.Info.ResourceType,
index = (byte)random.Next(Resource.Info.SpriteNames.Length)
};
var ch = new int2((surface.GetBrushLocation().X) / Surface.ChunkSize,
(surface.GetBrushLocation().Y) / Surface.ChunkSize);
if (surface.Chunks.ContainsKey(ch))
{
surface.Chunks[ch].Dispose();
surface.Chunks.Remove(ch);
}
}
public void Preview(Surface surface, SGraphics g)
{
surface.DrawImage(g, Resource.Bitmap, surface.GetBrushLocation(), false, null);
}
Random random = new Random();
}
}

View File

@@ -1,364 +1,364 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.Traits;
using SGraphics = System.Drawing.Graphics;
namespace OpenRA.Editor
{
class Surface : Control
{
public Map Map { get; private set; }
public TileSet TileSet { get; private set; }
public Palette Palette { get; private set; }
public int2 Offset;
public int2 GetOffset() { return Offset; }
public float Zoom = 1.0f;
ITool Tool;
public bool IsPanning;
public event Action AfterChange = () => { };
public event Action<string> MousePositionChanged = _ => { };
Dictionary<string, ActorTemplate> ActorTemplates = new Dictionary<string, ActorTemplate>();
Dictionary<int, ResourceTemplate> ResourceTemplates = new Dictionary<int, ResourceTemplate>();
public Keys GetModifiers() { return ModifierKeys; }
public void Bind(Map m, TileSet ts, Palette p)
{
Map = m;
TileSet = ts;
Palette = p;
PlayerPalettes = null;
Chunks.Clear();
Tool = null;
}
public void SetTool(ITool tool) { Tool = tool; }
public void BindActorTemplates(IEnumerable<ActorTemplate> templates)
{
ActorTemplates = templates.ToDictionary(a => a.Info.Name.ToLowerInvariant());
}
public void BindResourceTemplates(IEnumerable<ResourceTemplate> templates)
{
ResourceTemplates = templates.ToDictionary(a => a.Info.ResourceType);
}
public Dictionary<int2, Bitmap> Chunks = new Dictionary<int2, Bitmap>();
public Surface()
: base()
{
BackColor = Color.Black;
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.ResizeRedraw, true);
UpdateStyles();
}
static readonly Pen CordonPen = new Pen(Color.Red);
int2 MousePos;
public void Scroll(int2 dx)
{
Offset -= dx;
Invalidate();
}
protected override void OnMouseWheel(MouseEventArgs e)
{
base.OnMouseWheel(e);
if (Map == null) return;
Zoom *= e.Delta > 0 ? 4.0f / 3.0f : .75f;
Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
this.Parent.Focus();
Invalidate();
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseLeave(e);
this.Focus();
Invalidate();
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (Map == null) return;
var oldMousePos = MousePos;
MousePos = new int2(e.Location);
MousePositionChanged(GetBrushLocation().ToString());
if (e.Button == MouseButtons.Middle || (e.Button != MouseButtons.None && IsPanning))
Scroll(oldMousePos - MousePos);
else
{
if (e.Button == MouseButtons.Right)
Erase();
if (e.Button == MouseButtons.Left)
Draw();
Invalidate();
}
}
void Erase()
{
// Crash preventing
var BrushLocation = GetBrushLocation();
if (Map == null || BrushLocation.X >= Map.MapSize.X ||
BrushLocation.Y >= Map.MapSize.Y ||
BrushLocation.X < 0 ||
BrushLocation.Y < 0)
return;
Tool = null;
var key = Map.Actors.Value.FirstOrDefault(a => a.Value.Location() == BrushLocation);
if (key.Key != null) Map.Actors.Value.Remove(key.Key);
if (Map.MapResources.Value[BrushLocation.X, BrushLocation.Y].type != 0)
{
Map.MapResources.Value[BrushLocation.X, BrushLocation.Y] = new TileReference<byte, byte>();
var ch = new int2((BrushLocation.X) / ChunkSize, (BrushLocation.Y) / ChunkSize);
if (Chunks.ContainsKey(ch))
{
Chunks[ch].Dispose();
Chunks.Remove(ch);
}
}
AfterChange();
}
void Draw()
{
if (Tool != null) Tool.Apply(this);
AfterChange();
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (Map == null) return;
if (!IsPanning)
{
if (e.Button == MouseButtons.Right) Erase();
if (e.Button == MouseButtons.Left) Draw();
}
Invalidate();
}
public const int ChunkSize = 8; // 8x8 chunks ==> 192x192 bitmaps.
Bitmap RenderChunk(int u, int v)
{
var bitmap = new Bitmap(ChunkSize * TileSet.TileSize, ChunkSize * TileSet.TileSize);
bitmap.SetPixel(0, 0, Color.Green);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
int* p = (int*)data.Scan0.ToPointer();
var stride = data.Stride >> 2;
for (var i = 0; i < ChunkSize; i++)
for (var j = 0; j < ChunkSize; j++)
{
var tr = Map.MapTiles.Value[u * ChunkSize + i, v * ChunkSize + j];
var tile = TileSet.Tiles[tr.type];
var index = (tr.index < tile.TileBitmapBytes.Count) ? tr.index : (byte)0;
var rawImage = tile.TileBitmapBytes[index];
for (var x = 0; x < TileSet.TileSize; x++)
for (var y = 0; y < TileSet.TileSize; y++)
p[(j * TileSet.TileSize + y) * stride + i * TileSet.TileSize + x] = Palette.GetColor(rawImage[x + TileSet.TileSize * y]).ToArgb();
if (Map.MapResources.Value[u * ChunkSize + i, v * ChunkSize + j].type != 0)
{
var resourceImage = ResourceTemplates[Map.MapResources.Value[u * ChunkSize + i, v * ChunkSize + j].type].Bitmap;
var srcdata = resourceImage.LockBits(new Rectangle(0, 0, resourceImage.Width, resourceImage.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
int* q = (int*)srcdata.Scan0.ToPointer();
var srcstride = srcdata.Stride >> 2;
for (var x = 0; x < TileSet.TileSize; x++)
for (var y = 0; y < TileSet.TileSize; y++)
{
var c = q[y * srcstride + x];
if ((c & 0xff000000) != 0) /* quick & dirty, i cbf doing real alpha */
p[(j * TileSet.TileSize + y) * stride + i * TileSet.TileSize + x] = c;
}
resourceImage.UnlockBits(srcdata);
}
}
}
bitmap.UnlockBits(data);
return bitmap;
}
public int2 GetBrushLocation()
{
var vX = (int)Math.Floor((MousePos.X - Offset.X) / Zoom);
var vY = (int)Math.Floor((MousePos.Y - Offset.Y) / Zoom);
return new int2(vX / TileSet.TileSize, vY / TileSet.TileSize);
}
public void DrawActor(SGraphics g, int2 p, ActorTemplate t, ColorPalette cp)
{
var centered = t.Appearance == null || !t.Appearance.RelativeToTopLeft;
DrawImage(g, t.Bitmap, p, centered, cp);
}
float2 GetDrawPosition(int2 location, Bitmap bmp, bool centered)
{
float OffsetX = centered ? bmp.Width / 2 - TileSet.TileSize / 2 : 0;
float DrawX = TileSet.TileSize * location.X * Zoom + Offset.X - OffsetX;
float OffsetY = centered ? bmp.Height / 2 - TileSet.TileSize / 2 : 0;
float DrawY = TileSet.TileSize * location.Y * Zoom + Offset.Y - OffsetY;
return new float2(DrawX, DrawY);
}
public void DrawImage(SGraphics g, Bitmap bmp, int2 location, bool centered, ColorPalette cp)
{
var drawPos = GetDrawPosition(location, bmp, centered);
var sourceRect = new RectangleF(0, 0, bmp.Width, bmp.Height);
var destRect = new RectangleF(drawPos.X, drawPos.Y, bmp.Width * Zoom, bmp.Height * Zoom);
var restorePalette = bmp.Palette;
if (cp != null) bmp.Palette = cp;
g.DrawImage(bmp, destRect, sourceRect, GraphicsUnit.Pixel);
if (cp != null) bmp.Palette = restorePalette;
}
void DrawActorBorder(System.Drawing.Graphics g, int2 p, ActorTemplate t)
{
var centered = t.Appearance == null || !t.Appearance.RelativeToTopLeft;
var drawPos = GetDrawPosition(p, t.Bitmap, centered);
g.DrawRectangle(CordonPen,
drawPos.X, drawPos.Y,
t.Bitmap.Width * Zoom, t.Bitmap.Height * Zoom);
}
ColorPalette GetPaletteForPlayer(string name)
{
var pr = Map.Players[name];
var pcpi = Rules.Info["player"].Traits.Get<PlayerColorPaletteInfo>();
var remap = new PlayerColorRemap(pr.ColorRamp, pcpi.PaletteFormat);
return RenderUtils.MakeSystemPalette(new Palette(Palette, remap));
}
Cache<string, ColorPalette> PlayerPalettes;
ColorPalette GetPaletteForActor(ActorReference ar)
{
if (PlayerPalettes == null)
PlayerPalettes = new Cache<string, ColorPalette>(GetPaletteForPlayer);
var ownerInit = ar.InitDict.GetOrDefault<OwnerInit>();
if (ownerInit == null)
return null;
return PlayerPalettes[ownerInit.PlayerName];
}
protected override void OnPaint(PaintEventArgs e)
{
if (Map == null) return;
if (TileSet == null) return;
for (var u = 0; u < Map.MapSize.X; u += ChunkSize)
for (var v = 0; v < Map.MapSize.Y; v += ChunkSize)
{
var x = new int2(u / ChunkSize, v / ChunkSize);
if (!Chunks.ContainsKey(x)) Chunks[x] = RenderChunk(u / ChunkSize, v / ChunkSize);
Bitmap bmp = Chunks[x];
float DrawX = TileSet.TileSize * (float)ChunkSize * (float)x.X * Zoom + Offset.X;
float DrawY = TileSet.TileSize * (float)ChunkSize * (float)x.Y * Zoom + Offset.Y;
RectangleF sourceRect = new RectangleF(0, 0, bmp.Width, bmp.Height);
RectangleF destRect = new RectangleF(DrawX, DrawY, bmp.Width * Zoom, bmp.Height * Zoom);
e.Graphics.DrawImage(bmp, destRect, sourceRect, GraphicsUnit.Pixel);
}
e.Graphics.DrawRectangle(CordonPen,
Map.Bounds.Left * TileSet.TileSize * Zoom + Offset.X,
Map.Bounds.Top * TileSet.TileSize * Zoom + Offset.Y,
Map.Bounds.Width * TileSet.TileSize * Zoom,
Map.Bounds.Height * TileSet.TileSize * Zoom);
foreach (var ar in Map.Actors.Value)
DrawActor(e.Graphics, ar.Value.Location(), ActorTemplates[ar.Value.Type],
GetPaletteForActor(ar.Value));
if (Tool != null)
Tool.Preview(this, e.Graphics);
if (Tool == null)
{
var x = Map.Actors.Value.FirstOrDefault(a => a.Value.Location() == GetBrushLocation());
if (x.Key != null)
DrawActorBorder(e.Graphics, x.Value.Location(), ActorTemplates[x.Value.Type]);
}
}
}
static class ActorReferenceExts
{
public static int2 Location(this ActorReference ar)
{
return ar.InitDict.Get<LocationInit>().value;
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.Traits;
using SGraphics = System.Drawing.Graphics;
namespace OpenRA.Editor
{
class Surface : Control
{
public Map Map { get; private set; }
public TileSet TileSet { get; private set; }
public Palette Palette { get; private set; }
public int2 Offset;
public int2 GetOffset() { return Offset; }
public float Zoom = 1.0f;
ITool Tool;
public bool IsPanning;
public event Action AfterChange = () => { };
public event Action<string> MousePositionChanged = _ => { };
Dictionary<string, ActorTemplate> ActorTemplates = new Dictionary<string, ActorTemplate>();
Dictionary<int, ResourceTemplate> ResourceTemplates = new Dictionary<int, ResourceTemplate>();
public Keys GetModifiers() { return ModifierKeys; }
public void Bind(Map m, TileSet ts, Palette p)
{
Map = m;
TileSet = ts;
Palette = p;
PlayerPalettes = null;
Chunks.Clear();
Tool = null;
}
public void SetTool(ITool tool) { Tool = tool; }
public void BindActorTemplates(IEnumerable<ActorTemplate> templates)
{
ActorTemplates = templates.ToDictionary(a => a.Info.Name.ToLowerInvariant());
}
public void BindResourceTemplates(IEnumerable<ResourceTemplate> templates)
{
ResourceTemplates = templates.ToDictionary(a => a.Info.ResourceType);
}
public Dictionary<int2, Bitmap> Chunks = new Dictionary<int2, Bitmap>();
public Surface()
: base()
{
BackColor = Color.Black;
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.ResizeRedraw, true);
UpdateStyles();
}
static readonly Pen CordonPen = new Pen(Color.Red);
int2 MousePos;
public void Scroll(int2 dx)
{
Offset -= dx;
Invalidate();
}
protected override void OnMouseWheel(MouseEventArgs e)
{
base.OnMouseWheel(e);
if (Map == null) return;
Zoom *= e.Delta > 0 ? 4.0f / 3.0f : .75f;
Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
this.Parent.Focus();
Invalidate();
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseLeave(e);
this.Focus();
Invalidate();
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (Map == null) return;
var oldMousePos = MousePos;
MousePos = new int2(e.Location);
MousePositionChanged(GetBrushLocation().ToString());
if (e.Button == MouseButtons.Middle || (e.Button != MouseButtons.None && IsPanning))
Scroll(oldMousePos - MousePos);
else
{
if (e.Button == MouseButtons.Right)
Erase();
if (e.Button == MouseButtons.Left)
Draw();
Invalidate();
}
}
void Erase()
{
// Crash preventing
var BrushLocation = GetBrushLocation();
if (Map == null || BrushLocation.X >= Map.MapSize.X ||
BrushLocation.Y >= Map.MapSize.Y ||
BrushLocation.X < 0 ||
BrushLocation.Y < 0)
return;
Tool = null;
var key = Map.Actors.Value.FirstOrDefault(a => a.Value.Location() == BrushLocation);
if (key.Key != null) Map.Actors.Value.Remove(key.Key);
if (Map.MapResources.Value[BrushLocation.X, BrushLocation.Y].type != 0)
{
Map.MapResources.Value[BrushLocation.X, BrushLocation.Y] = new TileReference<byte, byte>();
var ch = new int2((BrushLocation.X) / ChunkSize, (BrushLocation.Y) / ChunkSize);
if (Chunks.ContainsKey(ch))
{
Chunks[ch].Dispose();
Chunks.Remove(ch);
}
}
AfterChange();
}
void Draw()
{
if (Tool != null) Tool.Apply(this);
AfterChange();
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (Map == null) return;
if (!IsPanning)
{
if (e.Button == MouseButtons.Right) Erase();
if (e.Button == MouseButtons.Left) Draw();
}
Invalidate();
}
public const int ChunkSize = 8; // 8x8 chunks ==> 192x192 bitmaps.
Bitmap RenderChunk(int u, int v)
{
var bitmap = new Bitmap(ChunkSize * TileSet.TileSize, ChunkSize * TileSet.TileSize);
bitmap.SetPixel(0, 0, Color.Green);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
int* p = (int*)data.Scan0.ToPointer();
var stride = data.Stride >> 2;
for (var i = 0; i < ChunkSize; i++)
for (var j = 0; j < ChunkSize; j++)
{
var tr = Map.MapTiles.Value[u * ChunkSize + i, v * ChunkSize + j];
var tile = TileSet.Tiles[tr.type];
var index = (tr.index < tile.TileBitmapBytes.Count) ? tr.index : (byte)0;
var rawImage = tile.TileBitmapBytes[index];
for (var x = 0; x < TileSet.TileSize; x++)
for (var y = 0; y < TileSet.TileSize; y++)
p[(j * TileSet.TileSize + y) * stride + i * TileSet.TileSize + x] = Palette.GetColor(rawImage[x + TileSet.TileSize * y]).ToArgb();
if (Map.MapResources.Value[u * ChunkSize + i, v * ChunkSize + j].type != 0)
{
var resourceImage = ResourceTemplates[Map.MapResources.Value[u * ChunkSize + i, v * ChunkSize + j].type].Bitmap;
var srcdata = resourceImage.LockBits(new Rectangle(0, 0, resourceImage.Width, resourceImage.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
int* q = (int*)srcdata.Scan0.ToPointer();
var srcstride = srcdata.Stride >> 2;
for (var x = 0; x < TileSet.TileSize; x++)
for (var y = 0; y < TileSet.TileSize; y++)
{
var c = q[y * srcstride + x];
if ((c & 0xff000000) != 0) /* quick & dirty, i cbf doing real alpha */
p[(j * TileSet.TileSize + y) * stride + i * TileSet.TileSize + x] = c;
}
resourceImage.UnlockBits(srcdata);
}
}
}
bitmap.UnlockBits(data);
return bitmap;
}
public int2 GetBrushLocation()
{
var vX = (int)Math.Floor((MousePos.X - Offset.X) / Zoom);
var vY = (int)Math.Floor((MousePos.Y - Offset.Y) / Zoom);
return new int2(vX / TileSet.TileSize, vY / TileSet.TileSize);
}
public void DrawActor(SGraphics g, int2 p, ActorTemplate t, ColorPalette cp)
{
var centered = t.Appearance == null || !t.Appearance.RelativeToTopLeft;
DrawImage(g, t.Bitmap, p, centered, cp);
}
float2 GetDrawPosition(int2 location, Bitmap bmp, bool centered)
{
float OffsetX = centered ? bmp.Width / 2 - TileSet.TileSize / 2 : 0;
float DrawX = TileSet.TileSize * location.X * Zoom + Offset.X - OffsetX;
float OffsetY = centered ? bmp.Height / 2 - TileSet.TileSize / 2 : 0;
float DrawY = TileSet.TileSize * location.Y * Zoom + Offset.Y - OffsetY;
return new float2(DrawX, DrawY);
}
public void DrawImage(SGraphics g, Bitmap bmp, int2 location, bool centered, ColorPalette cp)
{
var drawPos = GetDrawPosition(location, bmp, centered);
var sourceRect = new RectangleF(0, 0, bmp.Width, bmp.Height);
var destRect = new RectangleF(drawPos.X, drawPos.Y, bmp.Width * Zoom, bmp.Height * Zoom);
var restorePalette = bmp.Palette;
if (cp != null) bmp.Palette = cp;
g.DrawImage(bmp, destRect, sourceRect, GraphicsUnit.Pixel);
if (cp != null) bmp.Palette = restorePalette;
}
void DrawActorBorder(System.Drawing.Graphics g, int2 p, ActorTemplate t)
{
var centered = t.Appearance == null || !t.Appearance.RelativeToTopLeft;
var drawPos = GetDrawPosition(p, t.Bitmap, centered);
g.DrawRectangle(CordonPen,
drawPos.X, drawPos.Y,
t.Bitmap.Width * Zoom, t.Bitmap.Height * Zoom);
}
ColorPalette GetPaletteForPlayer(string name)
{
var pr = Map.Players[name];
var pcpi = Rules.Info["player"].Traits.Get<PlayerColorPaletteInfo>();
var remap = new PlayerColorRemap(pr.ColorRamp, pcpi.PaletteFormat);
return RenderUtils.MakeSystemPalette(new Palette(Palette, remap));
}
Cache<string, ColorPalette> PlayerPalettes;
ColorPalette GetPaletteForActor(ActorReference ar)
{
if (PlayerPalettes == null)
PlayerPalettes = new Cache<string, ColorPalette>(GetPaletteForPlayer);
var ownerInit = ar.InitDict.GetOrDefault<OwnerInit>();
if (ownerInit == null)
return null;
return PlayerPalettes[ownerInit.PlayerName];
}
protected override void OnPaint(PaintEventArgs e)
{
if (Map == null) return;
if (TileSet == null) return;
for (var u = 0; u < Map.MapSize.X; u += ChunkSize)
for (var v = 0; v < Map.MapSize.Y; v += ChunkSize)
{
var x = new int2(u / ChunkSize, v / ChunkSize);
if (!Chunks.ContainsKey(x)) Chunks[x] = RenderChunk(u / ChunkSize, v / ChunkSize);
Bitmap bmp = Chunks[x];
float DrawX = TileSet.TileSize * (float)ChunkSize * (float)x.X * Zoom + Offset.X;
float DrawY = TileSet.TileSize * (float)ChunkSize * (float)x.Y * Zoom + Offset.Y;
RectangleF sourceRect = new RectangleF(0, 0, bmp.Width, bmp.Height);
RectangleF destRect = new RectangleF(DrawX, DrawY, bmp.Width * Zoom, bmp.Height * Zoom);
e.Graphics.DrawImage(bmp, destRect, sourceRect, GraphicsUnit.Pixel);
}
e.Graphics.DrawRectangle(CordonPen,
Map.Bounds.Left * TileSet.TileSize * Zoom + Offset.X,
Map.Bounds.Top * TileSet.TileSize * Zoom + Offset.Y,
Map.Bounds.Width * TileSet.TileSize * Zoom,
Map.Bounds.Height * TileSet.TileSize * Zoom);
foreach (var ar in Map.Actors.Value)
DrawActor(e.Graphics, ar.Value.Location(), ActorTemplates[ar.Value.Type],
GetPaletteForActor(ar.Value));
if (Tool != null)
Tool.Preview(this, e.Graphics);
if (Tool == null)
{
var x = Map.Actors.Value.FirstOrDefault(a => a.Value.Location() == GetBrushLocation());
if (x.Key != null)
DrawActorBorder(e.Graphics, x.Value.Location(), ActorTemplates[x.Value.Type]);
}
}
}
static class ActorReferenceExts
{
public static int2 Location(this ActorReference ar)
{
return ar.InitDict.Get<LocationInit>().value;
}
}
}

View File

@@ -1,64 +1,64 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Drawing;
namespace OpenRA.FileFormats
{
public struct ColorRamp
{
public byte H,S,L,R;
public ColorRamp(byte h, byte s, byte l, byte r)
{
H = h; S = s; L = l; R = r;
}
/* returns a color along the Lum ramp */
public Color GetColor( float t )
{
return ColorFromHSL( H / 255f, S / 255f, float2.Lerp( L / 255f, L*R / (255f * 255f), t ) );
}
public override string ToString()
{
return "{0},{1},{2},{3}".F(H, S, L, R);
}
// hk is hue in the range [0,1] instead of [0,360]
public static Color ColorFromHSL(float hk, float s, float l)
{
// Convert from HSL to RGB
var q = (l < 0.5f) ? l * (1 + s) : l + s - (l * s);
var p = 2 * l - q;
float[] trgb = { hk + 1 / 3.0f,
hk,
hk - 1/3.0f };
float[] rgb = { 0, 0, 0 };
for (int k = 0; k < 3; k++)
{
while (trgb[k] < 0) trgb[k] += 1.0f;
while (trgb[k] > 1) trgb[k] -= 1.0f;
}
for (int k = 0; k < 3; k++)
{
if (trgb[k] < 1 / 6.0f) { rgb[k] = (p + ((q - p) * 6 * trgb[k])); }
else if (trgb[k] >= 1 / 6.0f && trgb[k] < 0.5) { rgb[k] = q; }
else if (trgb[k] >= 0.5f && trgb[k] < 2.0f / 3) { rgb[k] = (p + ((q - p) * 6 * (2.0f / 3 - trgb[k]))); }
else { rgb[k] = p; }
}
return Color.FromArgb((int)(rgb[0] * 255), (int)(rgb[1] * 255), (int)(rgb[2] * 255));
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Drawing;
namespace OpenRA.FileFormats
{
public struct ColorRamp
{
public byte H,S,L,R;
public ColorRamp(byte h, byte s, byte l, byte r)
{
H = h; S = s; L = l; R = r;
}
/* returns a color along the Lum ramp */
public Color GetColor( float t )
{
return ColorFromHSL( H / 255f, S / 255f, float2.Lerp( L / 255f, L*R / (255f * 255f), t ) );
}
public override string ToString()
{
return "{0},{1},{2},{3}".F(H, S, L, R);
}
// hk is hue in the range [0,1] instead of [0,360]
public static Color ColorFromHSL(float hk, float s, float l)
{
// Convert from HSL to RGB
var q = (l < 0.5f) ? l * (1 + s) : l + s - (l * s);
var p = 2 * l - q;
float[] trgb = { hk + 1 / 3.0f,
hk,
hk - 1/3.0f };
float[] rgb = { 0, 0, 0 };
for (int k = 0; k < 3; k++)
{
while (trgb[k] < 0) trgb[k] += 1.0f;
while (trgb[k] > 1) trgb[k] -= 1.0f;
}
for (int k = 0; k < 3; k++)
{
if (trgb[k] < 1 / 6.0f) { rgb[k] = (p + ((q - p) * 6 * trgb[k])); }
else if (trgb[k] >= 1 / 6.0f && trgb[k] < 0.5) { rgb[k] = q; }
else if (trgb[k] >= 0.5f && trgb[k] < 2.0f / 3) { rgb[k] = (p + ((q - p) * 6 * (2.0f / 3 - trgb[k]))); }
else { rgb[k] = p; }
}
return Color.FromArgb((int)(rgb[0] * 255), (int)(rgb[1] * 255), (int)(rgb[2] * 255));
}
}
}

View File

@@ -1,107 +1,107 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
namespace OpenRA.FileFormats
{
public static class Evaluator
{
public static int Evaluate(string expr)
{
return Evaluate(expr, new Dictionary<string, int>());
}
public static int Evaluate(string expr, Dictionary<string, int> syms)
{
var toks = Tokens(expr, "+-*/()");
var postfix = ToPostfix(toks, syms);
var s = new Stack<int>();
foreach (var t in postfix)
{
switch (t[0])
{
case '+': ApplyBinop(s, (x, y) => y + x); break;
case '-': ApplyBinop(s, (x, y) => y - x); break;
case '*': ApplyBinop(s, (x, y) => y * x); break;
case '/': ApplyBinop(s, (x, y) => y / x); break;
default: s.Push(int.Parse(t)); break;
}
}
return s.Pop();
}
static void ApplyBinop( Stack<int> s, Func<int,int,int> f )
{
var x = s.Pop();
var y = s.Pop();
s.Push( f(x,y) );
}
static IEnumerable<string> ToPostfix(IEnumerable<string> toks, Dictionary<string, int> syms)
{
var s = new Stack<string>();
foreach (var t in toks)
{
if (t[0] == '(') s.Push(t);
else if (t[0] == ')')
{
var temp = "";
while ((temp = s.Pop()) != "(") yield return temp;
}
else if (char.IsNumber(t[0])) yield return t;
else if (char.IsLetter(t[0]))
{
if (!syms.ContainsKey(t))
throw new InvalidOperationException("Substitution `{0}` undefined".F(t));
yield return syms[t].ToString();;
}
else
{
while (s.Count > 0 && Prec[t] <= Prec[s.Peek()]) yield return s.Pop();
s.Push(t);
}
}
while (s.Count > 0) yield return s.Pop();
}
static readonly Dictionary<string, int> Prec
= new Dictionary<string, int> { { "+", 0 }, { "-", 0 }, { "*", 1 }, { "/", 1 }, { "(", -1 } };
static IEnumerable<string> Tokens(string expr, string ops)
{
var s = "";
foreach (var c in expr)
{
if (char.IsWhiteSpace(c))
{
if (s != "") yield return s;
s = "";
}
else if (ops.Contains(c))
{
if (s != "") yield return s;
s = "";
yield return "" + c;
}
else
s += c;
}
if (s != "") yield return s;
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
namespace OpenRA.FileFormats
{
public static class Evaluator
{
public static int Evaluate(string expr)
{
return Evaluate(expr, new Dictionary<string, int>());
}
public static int Evaluate(string expr, Dictionary<string, int> syms)
{
var toks = Tokens(expr, "+-*/()");
var postfix = ToPostfix(toks, syms);
var s = new Stack<int>();
foreach (var t in postfix)
{
switch (t[0])
{
case '+': ApplyBinop(s, (x, y) => y + x); break;
case '-': ApplyBinop(s, (x, y) => y - x); break;
case '*': ApplyBinop(s, (x, y) => y * x); break;
case '/': ApplyBinop(s, (x, y) => y / x); break;
default: s.Push(int.Parse(t)); break;
}
}
return s.Pop();
}
static void ApplyBinop( Stack<int> s, Func<int,int,int> f )
{
var x = s.Pop();
var y = s.Pop();
s.Push( f(x,y) );
}
static IEnumerable<string> ToPostfix(IEnumerable<string> toks, Dictionary<string, int> syms)
{
var s = new Stack<string>();
foreach (var t in toks)
{
if (t[0] == '(') s.Push(t);
else if (t[0] == ')')
{
var temp = "";
while ((temp = s.Pop()) != "(") yield return temp;
}
else if (char.IsNumber(t[0])) yield return t;
else if (char.IsLetter(t[0]))
{
if (!syms.ContainsKey(t))
throw new InvalidOperationException("Substitution `{0}` undefined".F(t));
yield return syms[t].ToString();;
}
else
{
while (s.Count > 0 && Prec[t] <= Prec[s.Peek()]) yield return s.Pop();
s.Push(t);
}
}
while (s.Count > 0) yield return s.Pop();
}
static readonly Dictionary<string, int> Prec
= new Dictionary<string, int> { { "+", 0 }, { "-", 0 }, { "*", 1 }, { "/", 1 }, { "(", -1 } };
static IEnumerable<string> Tokens(string expr, string ops)
{
var s = "";
foreach (var c in expr)
{
if (char.IsWhiteSpace(c))
{
if (s != "") yield return s;
s = "";
}
else if (ops.Contains(c))
{
if (s != "") yield return s;
s = "";
yield return "" + c;
}
else
s += c;
}
if (s != "") yield return s;
}
}
}

View File

@@ -1,110 +1,110 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
namespace OpenRA
{
public static class Exts
{
public static string F(this string fmt, params object[] args)
{
return string.Format(fmt, args);
}
public static void Do<T>(this IEnumerable<T> e, Action<T> fn)
{
foreach (var ee in e)
fn(ee);
}
public static IEnumerable<string> GetNamespaces(this Assembly a)
{
return a.GetTypes().Select(t => t.Namespace).Distinct().Where(n => n != null);
}
public static string ReadAllText(this Stream s)
{
using (s)
using (var sr = new StreamReader(s))
return sr.ReadToEnd();
}
public static byte[] ReadAllBytes(this Stream s)
{
using (s)
{
var data = new byte[s.Length - s.Position];
s.Read(data, 0, data.Length);
return data;
}
}
public static void Write(this Stream s, byte[] data)
{
s.Write(data, 0, data.Length);
}
public static IEnumerable<string> ReadAllLines(this Stream s)
{
using (var sr = new StreamReader(s))
for (; ; )
{
var line = sr.ReadLine();
if (line == null)
yield break;
else
yield return line;
}
}
public static bool HasAttribute<T>(this MemberInfo mi)
{
return mi.GetCustomAttributes(typeof(T), true).Length != 0;
}
public static T[] GetCustomAttributes<T>(this MemberInfo mi, bool inherit)
where T : class
{
return (T[])mi.GetCustomAttributes(typeof(T), inherit);
}
public static T[] GetCustomAttributes<T>(this ParameterInfo mi)
where T : class
{
return (T[])mi.GetCustomAttributes(typeof(T), true);
}
public static T Clamp<T>(this T val, T min, T max) where T : IComparable<T>
{
if (val.CompareTo(min) < 0)
return min;
else if (val.CompareTo(max) > 0)
return max;
else
return val;
}
public static bool Contains(this Rectangle r, int2 p)
{
return r.Contains(p.ToPoint());
}
public static bool Contains(this RectangleF r, int2 p)
{
return r.Contains(p.ToPointF());
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
namespace OpenRA
{
public static class Exts
{
public static string F(this string fmt, params object[] args)
{
return string.Format(fmt, args);
}
public static void Do<T>(this IEnumerable<T> e, Action<T> fn)
{
foreach (var ee in e)
fn(ee);
}
public static IEnumerable<string> GetNamespaces(this Assembly a)
{
return a.GetTypes().Select(t => t.Namespace).Distinct().Where(n => n != null);
}
public static string ReadAllText(this Stream s)
{
using (s)
using (var sr = new StreamReader(s))
return sr.ReadToEnd();
}
public static byte[] ReadAllBytes(this Stream s)
{
using (s)
{
var data = new byte[s.Length - s.Position];
s.Read(data, 0, data.Length);
return data;
}
}
public static void Write(this Stream s, byte[] data)
{
s.Write(data, 0, data.Length);
}
public static IEnumerable<string> ReadAllLines(this Stream s)
{
using (var sr = new StreamReader(s))
for (; ; )
{
var line = sr.ReadLine();
if (line == null)
yield break;
else
yield return line;
}
}
public static bool HasAttribute<T>(this MemberInfo mi)
{
return mi.GetCustomAttributes(typeof(T), true).Length != 0;
}
public static T[] GetCustomAttributes<T>(this MemberInfo mi, bool inherit)
where T : class
{
return (T[])mi.GetCustomAttributes(typeof(T), inherit);
}
public static T[] GetCustomAttributes<T>(this ParameterInfo mi)
where T : class
{
return (T[])mi.GetCustomAttributes(typeof(T), true);
}
public static T Clamp<T>(this T val, T min, T max) where T : IComparable<T>
{
if (val.CompareTo(min) < 0)
return min;
else if (val.CompareTo(max) > 0)
return max;
else
return val;
}
public static bool Contains(this Rectangle r, int2 p)
{
return r.Contains(p.ToPoint());
}
public static bool Contains(this RectangleF r, int2 p)
{
return r.Contains(p.ToPointF());
}
}
}

View File

@@ -1,316 +1,316 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Globalization;
namespace OpenRA.FileFormats
{
public static class FieldLoader
{
public static Func<string,Type,string,object> InvalidValueAction = (s,t,f) =>
{
throw new InvalidOperationException("FieldLoader: Cannot parse `{0}` into `{1}.{2}` ".F(s,f,t) );
};
public static Action<string,Type> UnknownFieldAction = (s,f) =>
{
throw new NotImplementedException( "FieldLoader: Missing field `{0}` on `{1}`".F( s, f.Name ) );
};
public static void Load( object self, MiniYaml my )
{
var loadDict = typeLoadInfo[ self.GetType() ];
foreach( var kv in loadDict )
{
object val;
if( kv.Value != null )
val = kv.Value( kv.Key.Name, kv.Key.FieldType, my );
else if( !TryGetValueFromYaml( kv.Key.Name, kv.Key.FieldType, my, out val ) )
continue;
kv.Key.SetValue( self, val );
}
}
static bool TryGetValueFromYaml( string fieldName, Type fieldType, MiniYaml yaml, out object ret )
{
ret = null;
var n = yaml.Nodes.Where( x=>x.Key == fieldName ).ToList();
if( n.Count == 0 )
return false;
if( n.Count == 1 && n[ 0 ].Value.Nodes.Count == 0 )
{
ret = GetValue( fieldName, fieldType, n[ 0 ].Value.Value );
return true;
}
throw new InvalidOperationException( "TryGetValueFromYaml: unable to load field {0} (of type {1})".F( fieldName, fieldType ) );
}
public static T Load<T>(MiniYaml y) where T : new()
{
var t = new T();
Load(t, y);
return t;
}
public static void LoadField( object self, string key, string value )
{
var field = self.GetType().GetField( key.Trim() );
if( field == null )
UnknownFieldAction( key.Trim(), self.GetType() );
else if( field.HasAttribute<FieldFromYamlKeyAttribute>() )
return;
else
field.SetValue( self, GetValue( field.Name, field.FieldType, value ) );
}
public static object GetValue( string field, Type fieldType, string x )
{
if (x != null) x = x.Trim();
if( fieldType == typeof( int ) )
{
int res;
if (int.TryParse(x,out res))
return res;
return InvalidValueAction(x,fieldType, field);
}
else if( fieldType == typeof( ushort ) )
{
ushort res;
if (ushort.TryParse(x,out res))
return res;
return InvalidValueAction(x,fieldType, field);
}
else if (fieldType == typeof(float))
{
float res;
if (float.TryParse(x.Replace("%",""), System.Globalization.NumberStyles.Any, NumberFormatInfo.InvariantInfo, out res))
return res * (x.Contains( '%' ) ? 0.01f : 1f);
return InvalidValueAction(x,fieldType, field);
}
else if (fieldType == typeof(decimal))
{
decimal res;
if (decimal.TryParse(x.Replace("%",""), System.Globalization.NumberStyles.Any, NumberFormatInfo.InvariantInfo, out res))
return res * (x.Contains( '%' ) ? 0.01m : 1m);
return InvalidValueAction(x,fieldType, field);
}
else if (fieldType == typeof(string))
return x;
else if (fieldType == typeof(Color))
{
var parts = x.Split(',');
if (parts.Length == 3)
return Color.FromArgb(int.Parse(parts[0]).Clamp(0, 255), int.Parse(parts[1]).Clamp(0, 255), int.Parse(parts[2]).Clamp(0, 255));
if (parts.Length == 4)
return Color.FromArgb(int.Parse(parts[0]).Clamp(0, 255), int.Parse(parts[1]).Clamp(0, 255), int.Parse(parts[2]).Clamp(0, 255), int.Parse(parts[3]).Clamp(0, 255));
return InvalidValueAction(x,fieldType, field);
}
else if (fieldType == typeof(ColorRamp))
{
var parts = x.Split(',');
if (parts.Length == 4)
return new ColorRamp(
(byte)int.Parse(parts[0]).Clamp(0, 255),
(byte)int.Parse(parts[1]).Clamp(0, 255),
(byte)int.Parse(parts[2]).Clamp(0, 255),
(byte)int.Parse(parts[3]).Clamp(0, 255));
return InvalidValueAction(x, fieldType, field);
}
else if (fieldType.IsEnum)
{
if (!Enum.GetNames(fieldType).Select(a => a.ToLower()).Contains(x.ToLower()))
return InvalidValueAction(x, fieldType, field);
return Enum.Parse(fieldType, x, true);
}
else if (fieldType == typeof(bool))
return ParseYesNo(x, fieldType, field);
else if (fieldType.IsArray)
{
if (x == null)
return Array.CreateInstance(fieldType.GetElementType(), 0);
var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
var ret = Array.CreateInstance(fieldType.GetElementType(), parts.Length);
for (int i = 0; i < parts.Length; i++)
ret.SetValue(GetValue(field, fieldType.GetElementType(), parts[i].Trim()), i);
return ret;
}
else if (fieldType == typeof(int2))
{
var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
return new int2(int.Parse(parts[0]), int.Parse(parts[1]));
}
else if (fieldType == typeof(float2))
{
var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
float xx = 0;
float yy = 0;
float res;
if (float.TryParse(parts[0].Replace("%", ""), out res))
xx = res * (parts[0].Contains('%') ? 0.01f : 1f);
if (float.TryParse(parts[1].Replace("%", ""), out res))
yy = res * (parts[1].Contains('%') ? 0.01f : 1f);
return new float2(xx, yy);
}
else if (fieldType == typeof(Rectangle))
{
var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
return new Rectangle(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3]));
}
UnknownFieldAction("[Type] {0}".F(x),fieldType);
return null;
}
static object ParseYesNo( string p, System.Type fieldType, string field )
{
p = p.ToLowerInvariant();
if( p == "yes" ) return true;
if( p == "true" ) return true;
if( p == "no" ) return false;
if( p == "false" ) return false;
return InvalidValueAction(p,fieldType, field);
}
static Cache<Type, Dictionary<FieldInfo, Func<string, Type, MiniYaml, object>>> typeLoadInfo = new Cache<Type, Dictionary<FieldInfo, Func<string, Type, MiniYaml, object>>>( GetTypeLoadInfo );
static Dictionary<FieldInfo, Func<string, Type, MiniYaml, object>> GetTypeLoadInfo( Type type )
{
var ret = new Dictionary<FieldInfo, Func<string, Type, MiniYaml, object>>();
foreach( var ff in type.GetFields() )
{
var field = ff;
var load = field.GetCustomAttributes<LoadAttribute>( false );
var loadUsing = field.GetCustomAttributes<LoadUsingAttribute>( false );
var fromYamlKey = field.GetCustomAttributes<FieldFromYamlKeyAttribute>( false );
if( loadUsing.Length != 0 )
ret[ field ] = ( _1, fieldType, yaml ) => loadUsing[ 0 ].LoaderFunc( field )( yaml );
else if( fromYamlKey.Length != 0 )
ret[ field ] = ( f, ft, yaml ) => GetValue( f, ft, yaml.Value );
else if( load.Length != 0 )
ret[ field ] = null;
}
if( ret.Count == 0 )
foreach( var f in type.GetFields() )
ret.Add( f, null );
return ret;
}
[AttributeUsage( AttributeTargets.Field )]
public class LoadAttribute : Attribute { }
[AttributeUsage( AttributeTargets.Field )]
public class LoadUsingAttribute : Attribute
{
Func<MiniYaml, object> loaderFuncCache;
public readonly string Loader;
public LoadUsingAttribute( string loader )
{
Loader = loader;
}
internal Func<MiniYaml, object> LoaderFunc( FieldInfo field )
{
const BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
if( loaderFuncCache == null )
loaderFuncCache = (Func<MiniYaml, object>)Delegate.CreateDelegate( typeof( Func<MiniYaml, object> ), field.DeclaringType.GetMethod( Loader, bf ) );
return loaderFuncCache;
}
}
}
public static class FieldSaver
{
public static MiniYaml Save(object o)
{
var nodes = new List<MiniYamlNode>();
string root = null;
foreach( var f in o.GetType().GetFields( BindingFlags.Public | BindingFlags.Instance ) )
{
if( f.HasAttribute<FieldFromYamlKeyAttribute>() )
root = FormatValue( o, f );
else
nodes.Add( new MiniYamlNode( f.Name, FormatValue( o, f ) ) );
}
return new MiniYaml( root, nodes );
}
public static MiniYaml SaveDifferences(object o, object from)
{
if (o.GetType() != from.GetType())
throw new InvalidOperationException("FieldLoader: can't diff objects of different types");
var fields = o.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance)
.Where(f => FormatValue(o,f) != FormatValue(from,f));
return new MiniYaml( null, fields.Select( f => new MiniYamlNode(
f.Name,
FormatValue( o, f ) ) ).ToList() );
}
public static MiniYamlNode SaveField(object o, string field)
{
return new MiniYamlNode(field, FieldSaver.FormatValue( o, o.GetType().GetField(field) ));
}
public static string FormatValue(object o, FieldInfo f)
{
var v = f.GetValue(o);
if (v == null)
return "";
// Color.ToString() does the wrong thing; force it to format as an array
if (f.FieldType == typeof(Color))
{
var c = (Color)v;
return "{0},{1},{2},{3}".F(((int)c.A).Clamp(0, 255),
((int)c.R).Clamp(0, 255),
((int)c.G).Clamp(0, 255),
((int)c.B).Clamp(0, 255));
}
else if (f.FieldType == typeof(Rectangle))
{
var r = (Rectangle)v;
return "{0},{1},{2},{3}".F(r.X, r.Y, r.Width, r.Height);
}
return f.FieldType.IsArray
? string.Join(",", ((Array)v).OfType<object>().Select(a => a.ToString()).ToArray())
: v.ToString();
}
}
public class FieldFromYamlKeyAttribute : Attribute { }
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Globalization;
namespace OpenRA.FileFormats
{
public static class FieldLoader
{
public static Func<string,Type,string,object> InvalidValueAction = (s,t,f) =>
{
throw new InvalidOperationException("FieldLoader: Cannot parse `{0}` into `{1}.{2}` ".F(s,f,t) );
};
public static Action<string,Type> UnknownFieldAction = (s,f) =>
{
throw new NotImplementedException( "FieldLoader: Missing field `{0}` on `{1}`".F( s, f.Name ) );
};
public static void Load( object self, MiniYaml my )
{
var loadDict = typeLoadInfo[ self.GetType() ];
foreach( var kv in loadDict )
{
object val;
if( kv.Value != null )
val = kv.Value( kv.Key.Name, kv.Key.FieldType, my );
else if( !TryGetValueFromYaml( kv.Key.Name, kv.Key.FieldType, my, out val ) )
continue;
kv.Key.SetValue( self, val );
}
}
static bool TryGetValueFromYaml( string fieldName, Type fieldType, MiniYaml yaml, out object ret )
{
ret = null;
var n = yaml.Nodes.Where( x=>x.Key == fieldName ).ToList();
if( n.Count == 0 )
return false;
if( n.Count == 1 && n[ 0 ].Value.Nodes.Count == 0 )
{
ret = GetValue( fieldName, fieldType, n[ 0 ].Value.Value );
return true;
}
throw new InvalidOperationException( "TryGetValueFromYaml: unable to load field {0} (of type {1})".F( fieldName, fieldType ) );
}
public static T Load<T>(MiniYaml y) where T : new()
{
var t = new T();
Load(t, y);
return t;
}
public static void LoadField( object self, string key, string value )
{
var field = self.GetType().GetField( key.Trim() );
if( field == null )
UnknownFieldAction( key.Trim(), self.GetType() );
else if( field.HasAttribute<FieldFromYamlKeyAttribute>() )
return;
else
field.SetValue( self, GetValue( field.Name, field.FieldType, value ) );
}
public static object GetValue( string field, Type fieldType, string x )
{
if (x != null) x = x.Trim();
if( fieldType == typeof( int ) )
{
int res;
if (int.TryParse(x,out res))
return res;
return InvalidValueAction(x,fieldType, field);
}
else if( fieldType == typeof( ushort ) )
{
ushort res;
if (ushort.TryParse(x,out res))
return res;
return InvalidValueAction(x,fieldType, field);
}
else if (fieldType == typeof(float))
{
float res;
if (float.TryParse(x.Replace("%",""), System.Globalization.NumberStyles.Any, NumberFormatInfo.InvariantInfo, out res))
return res * (x.Contains( '%' ) ? 0.01f : 1f);
return InvalidValueAction(x,fieldType, field);
}
else if (fieldType == typeof(decimal))
{
decimal res;
if (decimal.TryParse(x.Replace("%",""), System.Globalization.NumberStyles.Any, NumberFormatInfo.InvariantInfo, out res))
return res * (x.Contains( '%' ) ? 0.01m : 1m);
return InvalidValueAction(x,fieldType, field);
}
else if (fieldType == typeof(string))
return x;
else if (fieldType == typeof(Color))
{
var parts = x.Split(',');
if (parts.Length == 3)
return Color.FromArgb(int.Parse(parts[0]).Clamp(0, 255), int.Parse(parts[1]).Clamp(0, 255), int.Parse(parts[2]).Clamp(0, 255));
if (parts.Length == 4)
return Color.FromArgb(int.Parse(parts[0]).Clamp(0, 255), int.Parse(parts[1]).Clamp(0, 255), int.Parse(parts[2]).Clamp(0, 255), int.Parse(parts[3]).Clamp(0, 255));
return InvalidValueAction(x,fieldType, field);
}
else if (fieldType == typeof(ColorRamp))
{
var parts = x.Split(',');
if (parts.Length == 4)
return new ColorRamp(
(byte)int.Parse(parts[0]).Clamp(0, 255),
(byte)int.Parse(parts[1]).Clamp(0, 255),
(byte)int.Parse(parts[2]).Clamp(0, 255),
(byte)int.Parse(parts[3]).Clamp(0, 255));
return InvalidValueAction(x, fieldType, field);
}
else if (fieldType.IsEnum)
{
if (!Enum.GetNames(fieldType).Select(a => a.ToLower()).Contains(x.ToLower()))
return InvalidValueAction(x, fieldType, field);
return Enum.Parse(fieldType, x, true);
}
else if (fieldType == typeof(bool))
return ParseYesNo(x, fieldType, field);
else if (fieldType.IsArray)
{
if (x == null)
return Array.CreateInstance(fieldType.GetElementType(), 0);
var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
var ret = Array.CreateInstance(fieldType.GetElementType(), parts.Length);
for (int i = 0; i < parts.Length; i++)
ret.SetValue(GetValue(field, fieldType.GetElementType(), parts[i].Trim()), i);
return ret;
}
else if (fieldType == typeof(int2))
{
var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
return new int2(int.Parse(parts[0]), int.Parse(parts[1]));
}
else if (fieldType == typeof(float2))
{
var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
float xx = 0;
float yy = 0;
float res;
if (float.TryParse(parts[0].Replace("%", ""), out res))
xx = res * (parts[0].Contains('%') ? 0.01f : 1f);
if (float.TryParse(parts[1].Replace("%", ""), out res))
yy = res * (parts[1].Contains('%') ? 0.01f : 1f);
return new float2(xx, yy);
}
else if (fieldType == typeof(Rectangle))
{
var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
return new Rectangle(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3]));
}
UnknownFieldAction("[Type] {0}".F(x),fieldType);
return null;
}
static object ParseYesNo( string p, System.Type fieldType, string field )
{
p = p.ToLowerInvariant();
if( p == "yes" ) return true;
if( p == "true" ) return true;
if( p == "no" ) return false;
if( p == "false" ) return false;
return InvalidValueAction(p,fieldType, field);
}
static Cache<Type, Dictionary<FieldInfo, Func<string, Type, MiniYaml, object>>> typeLoadInfo = new Cache<Type, Dictionary<FieldInfo, Func<string, Type, MiniYaml, object>>>( GetTypeLoadInfo );
static Dictionary<FieldInfo, Func<string, Type, MiniYaml, object>> GetTypeLoadInfo( Type type )
{
var ret = new Dictionary<FieldInfo, Func<string, Type, MiniYaml, object>>();
foreach( var ff in type.GetFields() )
{
var field = ff;
var load = field.GetCustomAttributes<LoadAttribute>( false );
var loadUsing = field.GetCustomAttributes<LoadUsingAttribute>( false );
var fromYamlKey = field.GetCustomAttributes<FieldFromYamlKeyAttribute>( false );
if( loadUsing.Length != 0 )
ret[ field ] = ( _1, fieldType, yaml ) => loadUsing[ 0 ].LoaderFunc( field )( yaml );
else if( fromYamlKey.Length != 0 )
ret[ field ] = ( f, ft, yaml ) => GetValue( f, ft, yaml.Value );
else if( load.Length != 0 )
ret[ field ] = null;
}
if( ret.Count == 0 )
foreach( var f in type.GetFields() )
ret.Add( f, null );
return ret;
}
[AttributeUsage( AttributeTargets.Field )]
public class LoadAttribute : Attribute { }
[AttributeUsage( AttributeTargets.Field )]
public class LoadUsingAttribute : Attribute
{
Func<MiniYaml, object> loaderFuncCache;
public readonly string Loader;
public LoadUsingAttribute( string loader )
{
Loader = loader;
}
internal Func<MiniYaml, object> LoaderFunc( FieldInfo field )
{
const BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
if( loaderFuncCache == null )
loaderFuncCache = (Func<MiniYaml, object>)Delegate.CreateDelegate( typeof( Func<MiniYaml, object> ), field.DeclaringType.GetMethod( Loader, bf ) );
return loaderFuncCache;
}
}
}
public static class FieldSaver
{
public static MiniYaml Save(object o)
{
var nodes = new List<MiniYamlNode>();
string root = null;
foreach( var f in o.GetType().GetFields( BindingFlags.Public | BindingFlags.Instance ) )
{
if( f.HasAttribute<FieldFromYamlKeyAttribute>() )
root = FormatValue( o, f );
else
nodes.Add( new MiniYamlNode( f.Name, FormatValue( o, f ) ) );
}
return new MiniYaml( root, nodes );
}
public static MiniYaml SaveDifferences(object o, object from)
{
if (o.GetType() != from.GetType())
throw new InvalidOperationException("FieldLoader: can't diff objects of different types");
var fields = o.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance)
.Where(f => FormatValue(o,f) != FormatValue(from,f));
return new MiniYaml( null, fields.Select( f => new MiniYamlNode(
f.Name,
FormatValue( o, f ) ) ).ToList() );
}
public static MiniYamlNode SaveField(object o, string field)
{
return new MiniYamlNode(field, FieldSaver.FormatValue( o, o.GetType().GetField(field) ));
}
public static string FormatValue(object o, FieldInfo f)
{
var v = f.GetValue(o);
if (v == null)
return "";
// Color.ToString() does the wrong thing; force it to format as an array
if (f.FieldType == typeof(Color))
{
var c = (Color)v;
return "{0},{1},{2},{3}".F(((int)c.A).Clamp(0, 255),
((int)c.R).Clamp(0, 255),
((int)c.G).Clamp(0, 255),
((int)c.B).Clamp(0, 255));
}
else if (f.FieldType == typeof(Rectangle))
{
var r = (Rectangle)v;
return "{0},{1},{2},{3}".F(r.X, r.Y, r.Width, r.Height);
}
return f.FieldType.IsArray
? string.Join(",", ((Array)v).OfType<object>().Select(a => a.ToString()).ToArray())
: v.ToString();
}
}
public class FieldFromYamlKeyAttribute : Attribute { }
}

View File

@@ -1,155 +1,155 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.IO;
namespace OpenRA.FileFormats
{
[Flags]
enum SoundFlags
{
Stereo = 0x1,
_16Bit = 0x2,
}
enum SoundFormat
{
WestwoodCompressed = 1,
ImaAdpcm = 99,
}
struct Chunk
{
public int CompressedSize;
public int OutputSize;
public static Chunk Read(BinaryReader r)
{
Chunk c;
c.CompressedSize = r.ReadUInt16();
c.OutputSize = r.ReadUInt16();
if (0xdeaf != r.ReadUInt32())
throw new InvalidDataException("Chunk header is bogus");
return c;
}
}
public static class AudLoader
{
static int[] IndexAdjust = { -1, -1, -1, -1, 2, 4, 6, 8 };
static int[] StepTable = {
7, 8, 9, 10, 11, 12, 13, 14, 16,
17, 19, 21, 23, 25, 28, 31, 34, 37,
41, 45, 50, 55, 60, 66, 73, 80, 88,
97, 107, 118, 130, 143, 157, 173, 190, 209,
230, 253, 279, 307, 337, 371, 408, 449, 494,
544, 598, 658, 724, 796, 876, 963, 1060, 1166,
1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749,
3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289,
16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 };
static short DecodeSample(byte b, ref int index, ref int current)
{
var sb = (b & 8) != 0;
b &= 7;
var delta = (StepTable[index] * b) / 4 + StepTable[index] / 8;
if (sb) delta = -delta;
current += delta;
if (current > short.MaxValue) current = short.MaxValue;
if (current < short.MinValue) current = short.MinValue;
index += IndexAdjust[b];
if (index < 0) index = 0;
if (index > 88) index = 88;
return (short)current;
}
public static byte[] LoadSound(byte[] raw, ref int index)
{
var br = new BinaryReader(new MemoryStream(raw));
var dataSize = raw.Length;
var outputSize = raw.Length * 4;
var output = new byte[outputSize];
var offset = 0;
var currentSample = 0;
while (dataSize-- > 0)
{
var b = br.ReadByte();
var t = DecodeSample(b, ref index, ref currentSample);
output[offset++] = (byte)t;
output[offset++] = (byte)(t >> 8);
t = DecodeSample((byte)(b >> 4), ref index, ref currentSample);
output[offset++] = (byte)t;
output[offset++] = (byte)(t >> 8);
}
return output;
}
public static float SoundLength(Stream s)
{
var br = new BinaryReader(s);
var sampleRate = br.ReadUInt16();
/*var dataSize = */ br.ReadInt32();
var outputSize = br.ReadInt32();
var flags = (SoundFlags) br.ReadByte();
var samples = outputSize;
if (0 != (flags & SoundFlags.Stereo)) samples /= 2;
if (0 != (flags & SoundFlags._16Bit)) samples /= 2;
return samples / sampleRate;
}
public static byte[] LoadSound(Stream s)
{
var br = new BinaryReader(s);
/*var sampleRate =*/ br.ReadUInt16();
var dataSize = br.ReadInt32();
var outputSize = br.ReadInt32();
/*var flags = (SoundFlags)*/ br.ReadByte();
/*var format = (SoundFormat)*/ br.ReadByte();
var output = new byte[outputSize];
var offset = 0;
var index = 0;
var currentSample = 0;
while (dataSize > 0)
{
var chunk = Chunk.Read(br);
for (int n = 0; n < chunk.CompressedSize; n++)
{
var b = br.ReadByte();
var t = DecodeSample(b, ref index, ref currentSample);
output[offset++] = (byte)t;
output[offset++] = (byte)(t >> 8);
t = DecodeSample((byte)(b >> 4), ref index, ref currentSample);
output[offset++] = (byte)t;
output[offset++] = (byte)(t >> 8);
}
dataSize -= 8 + chunk.CompressedSize;
}
return output;
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.IO;
namespace OpenRA.FileFormats
{
[Flags]
enum SoundFlags
{
Stereo = 0x1,
_16Bit = 0x2,
}
enum SoundFormat
{
WestwoodCompressed = 1,
ImaAdpcm = 99,
}
struct Chunk
{
public int CompressedSize;
public int OutputSize;
public static Chunk Read(BinaryReader r)
{
Chunk c;
c.CompressedSize = r.ReadUInt16();
c.OutputSize = r.ReadUInt16();
if (0xdeaf != r.ReadUInt32())
throw new InvalidDataException("Chunk header is bogus");
return c;
}
}
public static class AudLoader
{
static int[] IndexAdjust = { -1, -1, -1, -1, 2, 4, 6, 8 };
static int[] StepTable = {
7, 8, 9, 10, 11, 12, 13, 14, 16,
17, 19, 21, 23, 25, 28, 31, 34, 37,
41, 45, 50, 55, 60, 66, 73, 80, 88,
97, 107, 118, 130, 143, 157, 173, 190, 209,
230, 253, 279, 307, 337, 371, 408, 449, 494,
544, 598, 658, 724, 796, 876, 963, 1060, 1166,
1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749,
3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289,
16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 };
static short DecodeSample(byte b, ref int index, ref int current)
{
var sb = (b & 8) != 0;
b &= 7;
var delta = (StepTable[index] * b) / 4 + StepTable[index] / 8;
if (sb) delta = -delta;
current += delta;
if (current > short.MaxValue) current = short.MaxValue;
if (current < short.MinValue) current = short.MinValue;
index += IndexAdjust[b];
if (index < 0) index = 0;
if (index > 88) index = 88;
return (short)current;
}
public static byte[] LoadSound(byte[] raw, ref int index)
{
var br = new BinaryReader(new MemoryStream(raw));
var dataSize = raw.Length;
var outputSize = raw.Length * 4;
var output = new byte[outputSize];
var offset = 0;
var currentSample = 0;
while (dataSize-- > 0)
{
var b = br.ReadByte();
var t = DecodeSample(b, ref index, ref currentSample);
output[offset++] = (byte)t;
output[offset++] = (byte)(t >> 8);
t = DecodeSample((byte)(b >> 4), ref index, ref currentSample);
output[offset++] = (byte)t;
output[offset++] = (byte)(t >> 8);
}
return output;
}
public static float SoundLength(Stream s)
{
var br = new BinaryReader(s);
var sampleRate = br.ReadUInt16();
/*var dataSize = */ br.ReadInt32();
var outputSize = br.ReadInt32();
var flags = (SoundFlags) br.ReadByte();
var samples = outputSize;
if (0 != (flags & SoundFlags.Stereo)) samples /= 2;
if (0 != (flags & SoundFlags._16Bit)) samples /= 2;
return samples / sampleRate;
}
public static byte[] LoadSound(Stream s)
{
var br = new BinaryReader(s);
/*var sampleRate =*/ br.ReadUInt16();
var dataSize = br.ReadInt32();
var outputSize = br.ReadInt32();
/*var flags = (SoundFlags)*/ br.ReadByte();
/*var format = (SoundFormat)*/ br.ReadByte();
var output = new byte[outputSize];
var offset = 0;
var index = 0;
var currentSample = 0;
while (dataSize > 0)
{
var chunk = Chunk.Read(br);
for (int n = 0; n < chunk.CompressedSize; n++)
{
var b = br.ReadByte();
var t = DecodeSample(b, ref index, ref currentSample);
output[offset++] = (byte)t;
output[offset++] = (byte)(t >> 8);
t = DecodeSample((byte)(b >> 4), ref index, ref currentSample);
output[offset++] = (byte)t;
output[offset++] = (byte)(t >> 8);
}
dataSize -= 8 + chunk.CompressedSize;
}
return output;
}
}
}

View File

@@ -1,274 +1,274 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*
* This file is based on the blast routines (version 1.1 by Mark Adler)
* included in zlib/contrib
*/
#endregion
using System;
using System.IO;
namespace OpenRA.FileFormats
{
public static class Blast
{
public static readonly int MAXBITS = 13; // maximum code length
public static readonly int MAXWIN = 4096; // maximum window size
static byte[] litlen = new byte[] {
11, 124, 8, 7, 28, 7, 188, 13, 76, 4,
10, 8, 12, 10, 12, 10, 8, 23, 8, 9,
7, 6, 7, 8, 7, 6, 55, 8, 23, 24,
12, 11, 7, 9, 11, 12, 6, 7, 22, 5,
7, 24, 6, 11, 9, 6, 7, 22, 7, 11,
38, 7, 9, 8, 25, 11, 8, 11, 9, 12,
8, 12, 5, 38, 5, 38, 5, 11, 7, 5,
6, 21, 6, 10, 53, 8, 7, 24, 10, 27,
44, 253, 253, 253, 252, 252, 252, 13, 12, 45,
12, 45, 12, 61, 12, 45, 44, 173
};
// bit lengths of length codes 0..15
static byte[] lenlen = new byte[] { 2, 35, 36, 53, 38, 23 };
// bit lengths of distance codes 0..63
static byte[] distlen = new byte[] { 2, 20, 53, 230, 247, 151, 248 };
// base for length codes
static short[] lengthbase = new short[] {
3, 2, 4, 5, 6, 7, 8, 9, 10, 12,
16, 24, 40, 72, 136, 264
};
// extra bits for length codes
static byte[] extra = new byte[] {
0, 0, 0, 0, 0, 0, 0, 0, 1, 2,
3, 4, 5, 6, 7, 8
};
static Huffman litcode = new Huffman(litlen, litlen.Length, 256);
static Huffman lencode = new Huffman(lenlen, lenlen.Length, 16);
static Huffman distcode = new Huffman(distlen, distlen.Length, 64);
// Decode PKWare Compression Library stream.
public static byte[] Decompress(byte[] src)
{
BitReader br = new BitReader(src);
// Are literals coded?
int coded = br.ReadBits(8);
if (coded < 0 || coded > 1)
throw new NotImplementedException("Invalid datastream");
bool EncodedLiterals = (coded == 1);
// log2(dictionary size) - 6
int dict = br.ReadBits(8);
if (dict < 4 || dict > 6)
throw new InvalidDataException("Invalid dictionary size");
// output state
ushort next = 0; // index of next write location in out[]
bool first = true; // true to check distances (for first 4K)
byte[] outBuffer = new byte[MAXWIN]; // output buffer and sliding window
var ms = new MemoryStream();
// decode literals and length/distance pairs
do
{
// length/distance pair
if (br.ReadBits(1) == 1)
{
// Length
int symbol = Decode(lencode, br);
int len = lengthbase[symbol] + br.ReadBits(extra[symbol]);
if (len == 519) // Magic number for "done"
{
for (int i = 0; i < next; i++)
ms.WriteByte(outBuffer[i]);
break;
}
// Distance
symbol = len == 2 ? 2 : dict;
int dist = Decode(distcode, br) << symbol;
dist += br.ReadBits(symbol);
dist++;
if (first && dist > next)
throw new InvalidDataException("Attempt to jump before data");
// copy length bytes from distance bytes back
do
{
int dest = next;
int source = dest - dist;
int copy = MAXWIN;
if (next < dist)
{
source += copy;
copy = dist;
}
copy -= next;
if (copy > len)
copy = len;
len -= copy;
next += (ushort)copy;
Array.Copy(outBuffer, source, outBuffer, dest, copy);
// Flush window to outstream
if (next == MAXWIN)
{
for (int i = 0; i < next; i++)
ms.WriteByte(outBuffer[i]);
next = 0;
first = false;
}
} while (len != 0);
}
else // literal value
{
int symbol = EncodedLiterals ? Decode(litcode, br) : br.ReadBits(8);
outBuffer[next++] = (byte)symbol;
if (next == MAXWIN)
{
for (int i = 0; i < next; i++)
ms.WriteByte(outBuffer[i]);
next = 0;
first = false;
}
}
} while (true);
return ms.ToArray();
}
// Decode a code using huffman table h.
private static int Decode(Huffman h, BitReader br)
{
int code = 0; // len bits being decoded
int first = 0; // first code of length len
int index = 0; // index of first code of length len in symbol table
short next = 1;
while (true)
{
code |= br.ReadBits(1) ^ 1; // invert code
int count = h.Count[next++];
if (code < first + count)
return h.Symbol[index + (code - first)];
index += count;
first += count;
first <<= 1;
code <<= 1;
}
}
}
class BitReader
{
readonly byte[] src;
int offset = 0;
int bitBuffer = 0;
int bitCount = 0;
public BitReader(byte[] src)
{
this.src = src;
}
public int ReadBits(int count)
{
int ret = 0;
int filled = 0;
while (filled < count)
{
if (bitCount == 0)
{
bitBuffer = src[offset++];
bitCount = 8;
}
ret |= (bitBuffer & 1) << filled;
bitBuffer >>= 1;
bitCount--;
filled++;
}
return ret;
}
}
/*
* Given a list of repeated code lengths rep[0..n-1], where each byte is a
* count (high four bits + 1) and a code length (low four bits), generate the
* list of code lengths. This compaction reduces the size of the object code.
* Then given the list of code lengths length[0..n-1] representing a canonical
* Huffman code for n symbols, construct the tables required to decode those
* codes. Those tables are the number of codes of each length, and the symbols
* sorted by length, retaining their original order within each length.
*/
class Huffman
{
public short[] Count; // number of symbols of each length
public short[] Symbol; // canonically ordered symbols
public Huffman(byte[] rep, int n, short SymbolCount)
{
short[] length = new short[256]; // code lengths
int s = 0; // current symbol
// convert compact repeat counts into symbol bit length list
foreach (byte code in rep)
{
int num = (code >> 4) + 1; // Number of codes (top four bits plus 1)
byte len = (byte)(code & 15); // Code length (low four bits)
do
{
length[s++] = len;
} while (--num > 0);
}
n = s;
// count number of codes of each length
Count = new short[Blast.MAXBITS + 1];
for (int i = 0; i < n; i++)
Count[length[i]]++;
// no codes!
if (Count[0] == n)
return;
// check for an over-subscribed or incomplete set of lengths
int left = 1; // one possible code of zero length
for (int len = 1; len <= Blast.MAXBITS; len++)
{
left <<= 1;
// one more bit, double codes left
left -= Count[len];
// deduct count from possible codes
if (left < 0)
throw new InvalidDataException ("over subscribed code set");
}
// generate offsets into symbol table for each length for sorting
short[] offs = new short[Blast.MAXBITS + 1];
for (int len = 1; len < Blast.MAXBITS; len++)
offs[len + 1] = (short)(offs[len] + Count[len]);
// put symbols in table sorted by length, by symbol order within each length
Symbol = new short[SymbolCount];
for (short i = 0; i < n; i++)
if (length[i] != 0)
Symbol[offs[length[i]]++] = i;
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*
* This file is based on the blast routines (version 1.1 by Mark Adler)
* included in zlib/contrib
*/
#endregion
using System;
using System.IO;
namespace OpenRA.FileFormats
{
public static class Blast
{
public static readonly int MAXBITS = 13; // maximum code length
public static readonly int MAXWIN = 4096; // maximum window size
static byte[] litlen = new byte[] {
11, 124, 8, 7, 28, 7, 188, 13, 76, 4,
10, 8, 12, 10, 12, 10, 8, 23, 8, 9,
7, 6, 7, 8, 7, 6, 55, 8, 23, 24,
12, 11, 7, 9, 11, 12, 6, 7, 22, 5,
7, 24, 6, 11, 9, 6, 7, 22, 7, 11,
38, 7, 9, 8, 25, 11, 8, 11, 9, 12,
8, 12, 5, 38, 5, 38, 5, 11, 7, 5,
6, 21, 6, 10, 53, 8, 7, 24, 10, 27,
44, 253, 253, 253, 252, 252, 252, 13, 12, 45,
12, 45, 12, 61, 12, 45, 44, 173
};
// bit lengths of length codes 0..15
static byte[] lenlen = new byte[] { 2, 35, 36, 53, 38, 23 };
// bit lengths of distance codes 0..63
static byte[] distlen = new byte[] { 2, 20, 53, 230, 247, 151, 248 };
// base for length codes
static short[] lengthbase = new short[] {
3, 2, 4, 5, 6, 7, 8, 9, 10, 12,
16, 24, 40, 72, 136, 264
};
// extra bits for length codes
static byte[] extra = new byte[] {
0, 0, 0, 0, 0, 0, 0, 0, 1, 2,
3, 4, 5, 6, 7, 8
};
static Huffman litcode = new Huffman(litlen, litlen.Length, 256);
static Huffman lencode = new Huffman(lenlen, lenlen.Length, 16);
static Huffman distcode = new Huffman(distlen, distlen.Length, 64);
// Decode PKWare Compression Library stream.
public static byte[] Decompress(byte[] src)
{
BitReader br = new BitReader(src);
// Are literals coded?
int coded = br.ReadBits(8);
if (coded < 0 || coded > 1)
throw new NotImplementedException("Invalid datastream");
bool EncodedLiterals = (coded == 1);
// log2(dictionary size) - 6
int dict = br.ReadBits(8);
if (dict < 4 || dict > 6)
throw new InvalidDataException("Invalid dictionary size");
// output state
ushort next = 0; // index of next write location in out[]
bool first = true; // true to check distances (for first 4K)
byte[] outBuffer = new byte[MAXWIN]; // output buffer and sliding window
var ms = new MemoryStream();
// decode literals and length/distance pairs
do
{
// length/distance pair
if (br.ReadBits(1) == 1)
{
// Length
int symbol = Decode(lencode, br);
int len = lengthbase[symbol] + br.ReadBits(extra[symbol]);
if (len == 519) // Magic number for "done"
{
for (int i = 0; i < next; i++)
ms.WriteByte(outBuffer[i]);
break;
}
// Distance
symbol = len == 2 ? 2 : dict;
int dist = Decode(distcode, br) << symbol;
dist += br.ReadBits(symbol);
dist++;
if (first && dist > next)
throw new InvalidDataException("Attempt to jump before data");
// copy length bytes from distance bytes back
do
{
int dest = next;
int source = dest - dist;
int copy = MAXWIN;
if (next < dist)
{
source += copy;
copy = dist;
}
copy -= next;
if (copy > len)
copy = len;
len -= copy;
next += (ushort)copy;
Array.Copy(outBuffer, source, outBuffer, dest, copy);
// Flush window to outstream
if (next == MAXWIN)
{
for (int i = 0; i < next; i++)
ms.WriteByte(outBuffer[i]);
next = 0;
first = false;
}
} while (len != 0);
}
else // literal value
{
int symbol = EncodedLiterals ? Decode(litcode, br) : br.ReadBits(8);
outBuffer[next++] = (byte)symbol;
if (next == MAXWIN)
{
for (int i = 0; i < next; i++)
ms.WriteByte(outBuffer[i]);
next = 0;
first = false;
}
}
} while (true);
return ms.ToArray();
}
// Decode a code using huffman table h.
private static int Decode(Huffman h, BitReader br)
{
int code = 0; // len bits being decoded
int first = 0; // first code of length len
int index = 0; // index of first code of length len in symbol table
short next = 1;
while (true)
{
code |= br.ReadBits(1) ^ 1; // invert code
int count = h.Count[next++];
if (code < first + count)
return h.Symbol[index + (code - first)];
index += count;
first += count;
first <<= 1;
code <<= 1;
}
}
}
class BitReader
{
readonly byte[] src;
int offset = 0;
int bitBuffer = 0;
int bitCount = 0;
public BitReader(byte[] src)
{
this.src = src;
}
public int ReadBits(int count)
{
int ret = 0;
int filled = 0;
while (filled < count)
{
if (bitCount == 0)
{
bitBuffer = src[offset++];
bitCount = 8;
}
ret |= (bitBuffer & 1) << filled;
bitBuffer >>= 1;
bitCount--;
filled++;
}
return ret;
}
}
/*
* Given a list of repeated code lengths rep[0..n-1], where each byte is a
* count (high four bits + 1) and a code length (low four bits), generate the
* list of code lengths. This compaction reduces the size of the object code.
* Then given the list of code lengths length[0..n-1] representing a canonical
* Huffman code for n symbols, construct the tables required to decode those
* codes. Those tables are the number of codes of each length, and the symbols
* sorted by length, retaining their original order within each length.
*/
class Huffman
{
public short[] Count; // number of symbols of each length
public short[] Symbol; // canonically ordered symbols
public Huffman(byte[] rep, int n, short SymbolCount)
{
short[] length = new short[256]; // code lengths
int s = 0; // current symbol
// convert compact repeat counts into symbol bit length list
foreach (byte code in rep)
{
int num = (code >> 4) + 1; // Number of codes (top four bits plus 1)
byte len = (byte)(code & 15); // Code length (low four bits)
do
{
length[s++] = len;
} while (--num > 0);
}
n = s;
// count number of codes of each length
Count = new short[Blast.MAXBITS + 1];
for (int i = 0; i < n; i++)
Count[length[i]]++;
// no codes!
if (Count[0] == n)
return;
// check for an over-subscribed or incomplete set of lengths
int left = 1; // one possible code of zero length
for (int len = 1; len <= Blast.MAXBITS; len++)
{
left <<= 1;
// one more bit, double codes left
left -= Count[len];
// deduct count from possible codes
if (left < 0)
throw new InvalidDataException ("over subscribed code set");
}
// generate offsets into symbol table for each length for sorting
short[] offs = new short[Blast.MAXBITS + 1];
for (int len = 1; len < Blast.MAXBITS; len++)
offs[len + 1] = (short)(offs[len] + Count[len]);
// put symbols in table sorted by length, by symbol order within each length
Symbol = new short[SymbolCount];
for (short i = 0; i < n; i++)
if (length[i] != 0)
Symbol[offs[length[i]]++] = i;
}
}
}

View File

@@ -1,406 +1,406 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
namespace OpenRA.FileFormats
{
class Blowfish
{
public Blowfish(byte[] key)
{
for (int i = 0, j = 0; i < 18; ++i)
{
uint a = key[j++ % key.Length];
uint b = key[j++ % key.Length];
uint c = key[j++ % key.Length];
uint d = key[j++ % key.Length];
m_p[i] ^= a << 24 | b << 16 | c << 8 | d;
}
uint l = 0, r = 0;
for (int i = 0; i < 18; )
{
Encrypt(ref l, ref r);
m_p[i++] = l;
m_p[i++] = r;
}
for (int i = 0; i < 4; ++i)
for (int j = 0; j < 256; )
{
Encrypt(ref l, ref r);
m_s[i, j++] = l;
m_s[i, j++] = r;
}
}
public uint[] Encrypt(uint[] data) { return RunCipher(data, Encrypt); }
public uint[] Decrypt(uint[] data) { return RunCipher(data, Decrypt); }
delegate void CipherFunc( ref uint a, ref uint b );
uint[] RunCipher(uint[] data, CipherFunc f)
{
uint[] result = new uint[data.Length];
int size = data.Length / 2;
int i = 0;
while (size-- > 0)
{
uint a = SwapBytes(data[i]);
uint b = SwapBytes(data[i+1]);
f(ref a, ref b);
result[i++] = SwapBytes(a);
result[i++] = SwapBytes(b);
}
return result;
}
void Encrypt(ref uint a, ref uint b)
{
uint _a = a, _b = b;
_a ^= m_p[0];
bool x = false;
for( int i = 1; i <= 16; i++, x ^= true)
{
if (x)
Round(ref _a, _b, i);
else
Round(ref _b, _a, i);
}
_b ^= m_p[17];
a = _b;
b = _a;
}
void Decrypt(ref uint a, ref uint b)
{
uint _a = a, _b = b;
_a ^= m_p[17];
bool x = false;
for (int i = 16; i >= 1; i--, x ^= true)
{
if (x)
Round(ref _a, _b, i);
else
Round(ref _b, _a, i);
}
_b ^= m_p[0];
a = _b;
b = _a;
}
uint S(uint x, int i)
{
return m_s[i, (x >> ((3 - i) << 3)) & 0xff];
}
uint bf_f(uint x)
{
return ((S(x, 0) + S(x, 1)) ^ S(x, 2)) + S(x, 3);
}
void Round(ref uint a, uint b, int n)
{
a ^= bf_f(b) ^ m_p[n];
}
uint SwapBytes(uint i)
{
i = (i << 16) | (i >> 16);
i = ((i << 8) & 0xff00ff00) | ((i >> 8) & 0x00ff00ff);
return i;
}
uint[] m_p = new uint[] {
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
0x9216d5d9, 0x8979fb1b
};
uint[,] m_s = new uint[,] {
{
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
},
{
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
},
{
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
},
{
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
}
};
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
namespace OpenRA.FileFormats
{
class Blowfish
{
public Blowfish(byte[] key)
{
for (int i = 0, j = 0; i < 18; ++i)
{
uint a = key[j++ % key.Length];
uint b = key[j++ % key.Length];
uint c = key[j++ % key.Length];
uint d = key[j++ % key.Length];
m_p[i] ^= a << 24 | b << 16 | c << 8 | d;
}
uint l = 0, r = 0;
for (int i = 0; i < 18; )
{
Encrypt(ref l, ref r);
m_p[i++] = l;
m_p[i++] = r;
}
for (int i = 0; i < 4; ++i)
for (int j = 0; j < 256; )
{
Encrypt(ref l, ref r);
m_s[i, j++] = l;
m_s[i, j++] = r;
}
}
public uint[] Encrypt(uint[] data) { return RunCipher(data, Encrypt); }
public uint[] Decrypt(uint[] data) { return RunCipher(data, Decrypt); }
delegate void CipherFunc( ref uint a, ref uint b );
uint[] RunCipher(uint[] data, CipherFunc f)
{
uint[] result = new uint[data.Length];
int size = data.Length / 2;
int i = 0;
while (size-- > 0)
{
uint a = SwapBytes(data[i]);
uint b = SwapBytes(data[i+1]);
f(ref a, ref b);
result[i++] = SwapBytes(a);
result[i++] = SwapBytes(b);
}
return result;
}
void Encrypt(ref uint a, ref uint b)
{
uint _a = a, _b = b;
_a ^= m_p[0];
bool x = false;
for( int i = 1; i <= 16; i++, x ^= true)
{
if (x)
Round(ref _a, _b, i);
else
Round(ref _b, _a, i);
}
_b ^= m_p[17];
a = _b;
b = _a;
}
void Decrypt(ref uint a, ref uint b)
{
uint _a = a, _b = b;
_a ^= m_p[17];
bool x = false;
for (int i = 16; i >= 1; i--, x ^= true)
{
if (x)
Round(ref _a, _b, i);
else
Round(ref _b, _a, i);
}
_b ^= m_p[0];
a = _b;
b = _a;
}
uint S(uint x, int i)
{
return m_s[i, (x >> ((3 - i) << 3)) & 0xff];
}
uint bf_f(uint x)
{
return ((S(x, 0) + S(x, 1)) ^ S(x, 2)) + S(x, 3);
}
void Round(ref uint a, uint b, int n)
{
a ^= bf_f(b) ^ m_p[n];
}
uint SwapBytes(uint i)
{
i = (i << 16) | (i >> 16);
i = ((i << 8) & 0xff00ff00) | ((i >> 8) & 0x00ff00ff);
return i;
}
uint[] m_p = new uint[] {
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
0x9216d5d9, 0x8979fb1b
};
uint[,] m_s = new uint[,] {
{
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
},
{
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
},
{
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
},
{
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
}
};
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,36 +1,36 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
namespace OpenRA.FileFormats
{
public static class Format2
{
public static int DecodeInto(byte[] src, byte[] dest)
{
FastByteReader r = new FastByteReader(src);
int i = 0;
while (!r.Done())
{
byte cmd = r.ReadByte();
if (cmd == 0)
{
byte count = r.ReadByte();
while (count-- > 0)
dest[i++] = 0;
}
else
dest[i++] = cmd;
}
return i;
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
namespace OpenRA.FileFormats
{
public static class Format2
{
public static int DecodeInto(byte[] src, byte[] dest)
{
FastByteReader r = new FastByteReader(src);
int i = 0;
while (!r.Done())
{
byte cmd = r.ReadByte();
if (cmd == 0)
{
byte count = r.ReadByte();
while (count-- > 0)
dest[i++] = 0;
}
else
dest[i++] = cmd;
}
return i;
}
}
}

View File

@@ -1,78 +1,78 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
namespace OpenRA.FileFormats
{
public static class Format40
{
public static int DecodeInto( byte[] src, byte[] dest )
{
var ctx = new FastByteReader(src);
int destIndex = 0;
while( true )
{
byte i = ctx.ReadByte();
if( ( i & 0x80 ) == 0 )
{
int count = i & 0x7F;
if( count == 0 )
{
// case 6
count = ctx.ReadByte();
byte value = ctx.ReadByte();
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
dest[ destIndex ] ^= value;
}
else
{
// case 5
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
dest[destIndex] ^= ctx.ReadByte();
}
}
else
{
int count = i & 0x7F;
if( count == 0 )
{
count = ctx.ReadWord();
if( count == 0 )
return destIndex;
if( ( count & 0x8000 ) == 0 )
{
// case 2
destIndex += ( count & 0x7FFF );
}
else if( ( count & 0x4000 ) == 0 )
{
// case 3
for( int end = destIndex + ( count & 0x3FFF ) ; destIndex < end ; destIndex++ )
dest[destIndex] ^= ctx.ReadByte();
}
else
{
// case 4
byte value = ctx.ReadByte();
for( int end = destIndex + ( count & 0x3FFF ) ; destIndex < end ; destIndex++ )
dest[ destIndex ] ^= value;
}
}
else
{
// case 1
destIndex += count;
}
}
}
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
namespace OpenRA.FileFormats
{
public static class Format40
{
public static int DecodeInto( byte[] src, byte[] dest )
{
var ctx = new FastByteReader(src);
int destIndex = 0;
while( true )
{
byte i = ctx.ReadByte();
if( ( i & 0x80 ) == 0 )
{
int count = i & 0x7F;
if( count == 0 )
{
// case 6
count = ctx.ReadByte();
byte value = ctx.ReadByte();
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
dest[ destIndex ] ^= value;
}
else
{
// case 5
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
dest[destIndex] ^= ctx.ReadByte();
}
}
else
{
int count = i & 0x7F;
if( count == 0 )
{
count = ctx.ReadWord();
if( count == 0 )
return destIndex;
if( ( count & 0x8000 ) == 0 )
{
// case 2
destIndex += ( count & 0x7FFF );
}
else if( ( count & 0x4000 ) == 0 )
{
// case 3
for( int end = destIndex + ( count & 0x3FFF ) ; destIndex < end ; destIndex++ )
dest[destIndex] ^= ctx.ReadByte();
}
else
{
// case 4
byte value = ctx.ReadByte();
for( int end = destIndex + ( count & 0x3FFF ) ; destIndex < end ; destIndex++ )
dest[ destIndex ] ^= value;
}
}
else
{
// case 1
destIndex += count;
}
}
}
}
}
}

View File

@@ -1,150 +1,150 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.IO;
namespace OpenRA.FileFormats
{
class FastByteReader
{
readonly byte[] src;
int offset = 0;
public FastByteReader(byte[] src)
{
this.src = src;
}
public bool Done() { return offset >= src.Length; }
public byte ReadByte() { return src[offset++]; }
public int ReadWord()
{
int x = ReadByte();
return x | (ReadByte() << 8);
}
public void CopyTo(byte[] dest, int offset, int count)
{
Array.Copy(src, this.offset, dest, offset, count);
this.offset += count;
}
public int Remaining() { return src.Length - offset; }
}
public static class Format80
{
static void ReplicatePrevious( byte[] dest, int destIndex, int srcIndex, int count )
{
if( srcIndex > destIndex )
throw new NotImplementedException( string.Format( "srcIndex > destIndex {0} {1}", srcIndex, destIndex ) );
if( destIndex - srcIndex == 1 )
{
for( int i = 0 ; i < count ; i++ )
dest[ destIndex + i ] = dest[ destIndex - 1 ];
}
else
{
for( int i = 0 ; i < count ; i++ )
dest[ destIndex + i ] = dest[ srcIndex + i ];
}
}
public static int DecodeInto( byte[] src, byte[] dest )
{
var ctx = new FastByteReader(src);
int destIndex = 0;
while( true )
{
byte i = ctx.ReadByte();
if( ( i & 0x80 ) == 0 )
{
// case 2
byte secondByte = ctx.ReadByte();
int count = ( ( i & 0x70 ) >> 4 ) + 3;
int rpos = ( ( i & 0xf ) << 8 ) + secondByte;
ReplicatePrevious( dest, destIndex, destIndex - rpos, count );
destIndex += count;
}
else if( ( i & 0x40 ) == 0 )
{
// case 1
int count = i & 0x3F;
if( count == 0 )
return destIndex;
ctx.CopyTo( dest, destIndex, count );
destIndex += count;
}
else
{
int count3 = i & 0x3F;
if( count3 == 0x3E )
{
// case 4
int count = ctx.ReadWord();
byte color = ctx.ReadByte();
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
dest[ destIndex ] = color;
}
else if( count3 == 0x3F )
{
// case 5
int count = ctx.ReadWord();
int srcIndex = ctx.ReadWord();
if( srcIndex >= destIndex )
throw new NotImplementedException( string.Format( "srcIndex >= destIndex {0} {1}", srcIndex, destIndex ) );
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
dest[ destIndex ] = dest[ srcIndex++ ];
}
else
{
// case 3
int count = count3 + 3;
int srcIndex = ctx.ReadWord();
if( srcIndex >= destIndex )
throw new NotImplementedException( string.Format( "srcIndex >= destIndex {0} {1}", srcIndex, destIndex ) );
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
dest[ destIndex ] = dest[ srcIndex++ ];
}
}
}
}
public static byte[] Encode(byte[] src)
{
/* quick & dirty format80 encoder -- only uses raw copy operator, terminated with a zero-run. */
/* this does not produce good compression, but it's valid format80 */
var ctx = new FastByteReader(src);
var ms = new MemoryStream();
do
{
var len = Math.Min(ctx.Remaining(), 0x3F);
ms.WriteByte((byte)(0x80 | len));
while (len-- > 0)
ms.WriteByte(ctx.ReadByte());
}
while (!ctx.Done());
ms.WriteByte(0x80); // terminator -- 0-length run.
return ms.ToArray();
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.IO;
namespace OpenRA.FileFormats
{
class FastByteReader
{
readonly byte[] src;
int offset = 0;
public FastByteReader(byte[] src)
{
this.src = src;
}
public bool Done() { return offset >= src.Length; }
public byte ReadByte() { return src[offset++]; }
public int ReadWord()
{
int x = ReadByte();
return x | (ReadByte() << 8);
}
public void CopyTo(byte[] dest, int offset, int count)
{
Array.Copy(src, this.offset, dest, offset, count);
this.offset += count;
}
public int Remaining() { return src.Length - offset; }
}
public static class Format80
{
static void ReplicatePrevious( byte[] dest, int destIndex, int srcIndex, int count )
{
if( srcIndex > destIndex )
throw new NotImplementedException( string.Format( "srcIndex > destIndex {0} {1}", srcIndex, destIndex ) );
if( destIndex - srcIndex == 1 )
{
for( int i = 0 ; i < count ; i++ )
dest[ destIndex + i ] = dest[ destIndex - 1 ];
}
else
{
for( int i = 0 ; i < count ; i++ )
dest[ destIndex + i ] = dest[ srcIndex + i ];
}
}
public static int DecodeInto( byte[] src, byte[] dest )
{
var ctx = new FastByteReader(src);
int destIndex = 0;
while( true )
{
byte i = ctx.ReadByte();
if( ( i & 0x80 ) == 0 )
{
// case 2
byte secondByte = ctx.ReadByte();
int count = ( ( i & 0x70 ) >> 4 ) + 3;
int rpos = ( ( i & 0xf ) << 8 ) + secondByte;
ReplicatePrevious( dest, destIndex, destIndex - rpos, count );
destIndex += count;
}
else if( ( i & 0x40 ) == 0 )
{
// case 1
int count = i & 0x3F;
if( count == 0 )
return destIndex;
ctx.CopyTo( dest, destIndex, count );
destIndex += count;
}
else
{
int count3 = i & 0x3F;
if( count3 == 0x3E )
{
// case 4
int count = ctx.ReadWord();
byte color = ctx.ReadByte();
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
dest[ destIndex ] = color;
}
else if( count3 == 0x3F )
{
// case 5
int count = ctx.ReadWord();
int srcIndex = ctx.ReadWord();
if( srcIndex >= destIndex )
throw new NotImplementedException( string.Format( "srcIndex >= destIndex {0} {1}", srcIndex, destIndex ) );
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
dest[ destIndex ] = dest[ srcIndex++ ];
}
else
{
// case 3
int count = count3 + 3;
int srcIndex = ctx.ReadWord();
if( srcIndex >= destIndex )
throw new NotImplementedException( string.Format( "srcIndex >= destIndex {0} {1}", srcIndex, destIndex ) );
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
dest[ destIndex ] = dest[ srcIndex++ ];
}
}
}
}
public static byte[] Encode(byte[] src)
{
/* quick & dirty format80 encoder -- only uses raw copy operator, terminated with a zero-run. */
/* this does not produce good compression, but it's valid format80 */
var ctx = new FastByteReader(src);
var ms = new MemoryStream();
do
{
var len = Math.Min(ctx.Remaining(), 0x3F);
ms.WriteByte((byte)(0x80 | len));
while (len-- > 0)
ms.WriteByte(ctx.ReadByte());
}
while (!ctx.Done());
ms.WriteByte(0x80); // terminator -- 0-length run.
return ms.ToArray();
}
}
}

View File

@@ -1,151 +1,151 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
namespace OpenRA.FileFormats
{
public class IniFile
{
Dictionary<string, IniSection> sections = new Dictionary<string, IniSection>();
public IniFile( Stream s )
{
Load( s );
}
public IniFile( params Stream[] streams )
{
foreach( var s in streams )
Load( s );
}
public void Load( Stream s )
{
StreamReader reader = new StreamReader( s );
IniSection currentSection = null;
while( !reader.EndOfStream )
{
string line = reader.ReadLine();
if( line.Length == 0 ) continue;
switch( line[ 0 ] )
{
case ';': break;
case '[': currentSection = ProcessSection( line ); break;
default: ProcessEntry( line, currentSection ); break;
}
}
}
Regex sectionPattern = new Regex( @"^\[([^]]*)\]" );
IniSection ProcessSection( string line )
{
Match m = sectionPattern.Match( line );
if( m == null || !m.Success )
return null;
string sectionName = m.Groups[ 1 ].Value.ToLowerInvariant();
IniSection ret;
if( !sections.TryGetValue( sectionName, out ret ) )
sections.Add( sectionName, ret = new IniSection( sectionName ) );
return ret;
}
bool ProcessEntry( string line, IniSection currentSection )
{
int comment = line.IndexOf( ';' );
if( comment >= 0 )
line = line.Substring( 0, comment );
line = line.Trim();
if( line.Length == 0 )
return false;
var key = line;
var value = "";
int eq = line.IndexOf( '=' );
if( eq >= 0 )
{
key = line.Substring( 0, eq );
value = line.Substring( eq + 1, line.Length - eq - 1 );
}
if( currentSection == null )
throw new InvalidOperationException( "No current INI section" );
if( !currentSection.Contains( key ) )
currentSection.Add( key, value );
return true;
}
public IniSection GetSection( string s )
{
return GetSection( s, false );
}
public IniSection GetSection( string s, bool allowFail )
{
IniSection section;
if( sections.TryGetValue( s.ToLowerInvariant(), out section ) )
return section;
if( allowFail )
return new IniSection( s );
throw new InvalidOperationException( "Section does not exist in map or rules: " + s );
}
public IEnumerable<IniSection> Sections { get { return sections.Values; } }
}
public class IniSection : IEnumerable<KeyValuePair<string, string>>
{
public string Name { get; private set; }
Dictionary<string, string> values = new Dictionary<string, string>();
public IniSection( string name )
{
Name = name;
}
public void Add( string key, string value )
{
values[key] = value;
}
public bool Contains( string key )
{
return values.ContainsKey( key );
}
public string GetValue( string key, string defaultValue )
{
string s;
return values.TryGetValue( key, out s ) ? s : defaultValue;
}
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
{
return values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
namespace OpenRA.FileFormats
{
public class IniFile
{
Dictionary<string, IniSection> sections = new Dictionary<string, IniSection>();
public IniFile( Stream s )
{
Load( s );
}
public IniFile( params Stream[] streams )
{
foreach( var s in streams )
Load( s );
}
public void Load( Stream s )
{
StreamReader reader = new StreamReader( s );
IniSection currentSection = null;
while( !reader.EndOfStream )
{
string line = reader.ReadLine();
if( line.Length == 0 ) continue;
switch( line[ 0 ] )
{
case ';': break;
case '[': currentSection = ProcessSection( line ); break;
default: ProcessEntry( line, currentSection ); break;
}
}
}
Regex sectionPattern = new Regex( @"^\[([^]]*)\]" );
IniSection ProcessSection( string line )
{
Match m = sectionPattern.Match( line );
if( m == null || !m.Success )
return null;
string sectionName = m.Groups[ 1 ].Value.ToLowerInvariant();
IniSection ret;
if( !sections.TryGetValue( sectionName, out ret ) )
sections.Add( sectionName, ret = new IniSection( sectionName ) );
return ret;
}
bool ProcessEntry( string line, IniSection currentSection )
{
int comment = line.IndexOf( ';' );
if( comment >= 0 )
line = line.Substring( 0, comment );
line = line.Trim();
if( line.Length == 0 )
return false;
var key = line;
var value = "";
int eq = line.IndexOf( '=' );
if( eq >= 0 )
{
key = line.Substring( 0, eq );
value = line.Substring( eq + 1, line.Length - eq - 1 );
}
if( currentSection == null )
throw new InvalidOperationException( "No current INI section" );
if( !currentSection.Contains( key ) )
currentSection.Add( key, value );
return true;
}
public IniSection GetSection( string s )
{
return GetSection( s, false );
}
public IniSection GetSection( string s, bool allowFail )
{
IniSection section;
if( sections.TryGetValue( s.ToLowerInvariant(), out section ) )
return section;
if( allowFail )
return new IniSection( s );
throw new InvalidOperationException( "Section does not exist in map or rules: " + s );
}
public IEnumerable<IniSection> Sections { get { return sections.Values; } }
}
public class IniSection : IEnumerable<KeyValuePair<string, string>>
{
public string Name { get; private set; }
Dictionary<string, string> values = new Dictionary<string, string>();
public IniSection( string name )
{
Name = name;
}
public void Add( string key, string value )
{
values[key] = value;
}
public bool Contains( string key )
{
return values.ContainsKey( key );
}
public string GetValue( string key, string defaultValue )
{
string s;
return values.TryGetValue( key, out s ) ? s : defaultValue;
}
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
{
return values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

View File

@@ -1,206 +1,206 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Linq;
namespace OpenRA.FileFormats
{
public static class FileSystem
{
static List<IFolder> mountedFolders = new List<IFolder>();
public static string SpecialPackageRoot = "";
static Cache<uint, List<IFolder>> allFiles = new Cache<uint, List<IFolder>>( _ => new List<IFolder>() );
static void MountInner(IFolder folder)
{
mountedFolders.Add(folder);
foreach( var hash in folder.AllFileHashes() )
{
var l = allFiles[hash];
if( !l.Contains( folder ) )
l.Add( folder );
}
}
static int order = 0;
static IFolder OpenPackage(string filename)
{
return OpenPackage(filename, order++);
}
public static IFolder CreatePackage(string filename, int order, Dictionary<string, byte[]> content)
{
if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
return new MixFile(filename, order, content);
else if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase))
return new ZipFile(filename, order, content);
else if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase))
return new ZipFile(filename, order, content);
else if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase))
throw new NotImplementedException("Creating .Z archives is unsupported");
else
return new Folder(filename, order, content);
}
public static IFolder OpenPackage(string filename, int order)
{
if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
return new MixFile(filename, order);
else if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase))
return new ZipFile(filename, order);
else if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase))
return new ZipFile(filename, order);
else if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase))
return new InstallShieldPackage(filename, order);
else
return new Folder(filename, order);
}
public static void Mount(string name)
{
var optional = name.StartsWith("~");
if (optional) name = name.Substring(1);
// paths starting with $ are relative to SpecialPackageRoot
if (name.StartsWith("$"))
name = SpecialPackageRoot+name.Substring(1);
var a = (Action)(() => FileSystem.MountInner(OpenPackage(name)));
if (optional)
try { a(); }
catch { }
else
a();
}
public static void UnmountAll()
{
mountedFolders.Clear();
allFiles = new Cache<uint, List<IFolder>>( _ => new List<IFolder>() );
}
public static bool Unmount(IFolder mount)
{
return (mountedFolders.RemoveAll(f => f == mount) > 0);
}
public static void Mount(IFolder mount)
{
if (!mountedFolders.Contains(mount)) mountedFolders.Add(mount);
}
public static void LoadFromManifest( Manifest manifest )
{
UnmountAll();
foreach (var dir in manifest.Folders) Mount(dir);
foreach (var pkg in manifest.Packages) Mount(pkg);
}
static Stream GetFromCache( Cache<uint, List<IFolder>> index, string filename )
{
var folder = index[PackageEntry.HashFilename(filename)]
.Where(x => x.Exists(filename))
.OrderBy(x => x.Priority)
.FirstOrDefault();
if (folder != null)
return folder.GetContent(filename);
return null;
}
public static Stream Open(string filename)
{
if( filename.IndexOfAny( new char[] { '/', '\\' } ) == -1 )
{
var ret = GetFromCache( allFiles, filename );
if( ret != null )
return ret;
}
var folder = mountedFolders
.Where(x => x.Exists(filename))
.OrderByDescending(x => x.Priority)
.FirstOrDefault();
if (folder != null)
return folder.GetContent(filename);
throw new FileNotFoundException( string.Format( "File not found: {0}", filename ), filename );
}
public static Stream OpenWithExts( string filename, params string[] exts )
{
if( filename.IndexOfAny( new char[] { '/', '\\' } ) == -1 )
{
foreach( var ext in exts )
{
var s = GetFromCache( allFiles, filename + ext );
if( s != null )
return s;
}
}
foreach( var ext in exts )
{
foreach( IFolder folder in mountedFolders )
if (folder.Exists(filename + ext))
return folder.GetContent( filename + ext );
}
throw new FileNotFoundException( string.Format( "File not found: {0}", filename ), filename );
}
public static bool Exists(string filename)
{
foreach (var folder in mountedFolders)
if (folder.Exists(filename))
return true;
return false;
}
static Dictionary<string, Assembly> assemblyCache = new Dictionary<string, Assembly>();
public static Assembly ResolveAssembly(object sender, ResolveEventArgs e)
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
if (assembly.FullName == e.Name)
return assembly;
}
string[] frags = e.Name.Split(',');
var filename = frags[0] + ".dll";
Assembly a;
if (assemblyCache.TryGetValue(filename, out a))
return a;
if (FileSystem.Exists(filename))
using (Stream s = FileSystem.Open(filename))
{
byte[] buf = new byte[s.Length];
s.Read(buf, 0, buf.Length);
a = Assembly.Load(buf);
assemblyCache.Add(filename, a);
return a;
}
return null;
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Linq;
namespace OpenRA.FileFormats
{
public static class FileSystem
{
static List<IFolder> mountedFolders = new List<IFolder>();
public static string SpecialPackageRoot = "";
static Cache<uint, List<IFolder>> allFiles = new Cache<uint, List<IFolder>>( _ => new List<IFolder>() );
static void MountInner(IFolder folder)
{
mountedFolders.Add(folder);
foreach( var hash in folder.AllFileHashes() )
{
var l = allFiles[hash];
if( !l.Contains( folder ) )
l.Add( folder );
}
}
static int order = 0;
static IFolder OpenPackage(string filename)
{
return OpenPackage(filename, order++);
}
public static IFolder CreatePackage(string filename, int order, Dictionary<string, byte[]> content)
{
if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
return new MixFile(filename, order, content);
else if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase))
return new ZipFile(filename, order, content);
else if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase))
return new ZipFile(filename, order, content);
else if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase))
throw new NotImplementedException("Creating .Z archives is unsupported");
else
return new Folder(filename, order, content);
}
public static IFolder OpenPackage(string filename, int order)
{
if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
return new MixFile(filename, order);
else if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase))
return new ZipFile(filename, order);
else if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase))
return new ZipFile(filename, order);
else if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase))
return new InstallShieldPackage(filename, order);
else
return new Folder(filename, order);
}
public static void Mount(string name)
{
var optional = name.StartsWith("~");
if (optional) name = name.Substring(1);
// paths starting with $ are relative to SpecialPackageRoot
if (name.StartsWith("$"))
name = SpecialPackageRoot+name.Substring(1);
var a = (Action)(() => FileSystem.MountInner(OpenPackage(name)));
if (optional)
try { a(); }
catch { }
else
a();
}
public static void UnmountAll()
{
mountedFolders.Clear();
allFiles = new Cache<uint, List<IFolder>>( _ => new List<IFolder>() );
}
public static bool Unmount(IFolder mount)
{
return (mountedFolders.RemoveAll(f => f == mount) > 0);
}
public static void Mount(IFolder mount)
{
if (!mountedFolders.Contains(mount)) mountedFolders.Add(mount);
}
public static void LoadFromManifest( Manifest manifest )
{
UnmountAll();
foreach (var dir in manifest.Folders) Mount(dir);
foreach (var pkg in manifest.Packages) Mount(pkg);
}
static Stream GetFromCache( Cache<uint, List<IFolder>> index, string filename )
{
var folder = index[PackageEntry.HashFilename(filename)]
.Where(x => x.Exists(filename))
.OrderBy(x => x.Priority)
.FirstOrDefault();
if (folder != null)
return folder.GetContent(filename);
return null;
}
public static Stream Open(string filename)
{
if( filename.IndexOfAny( new char[] { '/', '\\' } ) == -1 )
{
var ret = GetFromCache( allFiles, filename );
if( ret != null )
return ret;
}
var folder = mountedFolders
.Where(x => x.Exists(filename))
.OrderByDescending(x => x.Priority)
.FirstOrDefault();
if (folder != null)
return folder.GetContent(filename);
throw new FileNotFoundException( string.Format( "File not found: {0}", filename ), filename );
}
public static Stream OpenWithExts( string filename, params string[] exts )
{
if( filename.IndexOfAny( new char[] { '/', '\\' } ) == -1 )
{
foreach( var ext in exts )
{
var s = GetFromCache( allFiles, filename + ext );
if( s != null )
return s;
}
}
foreach( var ext in exts )
{
foreach( IFolder folder in mountedFolders )
if (folder.Exists(filename + ext))
return folder.GetContent( filename + ext );
}
throw new FileNotFoundException( string.Format( "File not found: {0}", filename ), filename );
}
public static bool Exists(string filename)
{
foreach (var folder in mountedFolders)
if (folder.Exists(filename))
return true;
return false;
}
static Dictionary<string, Assembly> assemblyCache = new Dictionary<string, Assembly>();
public static Assembly ResolveAssembly(object sender, ResolveEventArgs e)
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
if (assembly.FullName == e.Name)
return assembly;
}
string[] frags = e.Name.Split(',');
var filename = frags[0] + ".dll";
Assembly a;
if (assemblyCache.TryGetValue(filename, out a))
return a;
if (FileSystem.Exists(filename))
using (Stream s = FileSystem.Open(filename))
{
byte[] buf = new byte[s.Length];
s.Read(buf, 0, buf.Length);
a = Assembly.Load(buf);
assemblyCache.Add(filename, a);
return a;
}
return null;
}
}
}

View File

@@ -1,73 +1,73 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.IO;
using System;
namespace OpenRA.FileFormats
{
public class Folder : IFolder
{
readonly string path;
int priority;
// Create a new folder package
public Folder(string path, int priority, Dictionary<string, byte[]> contents)
{
this.path = path;
this.priority = priority;
if (Directory.Exists(path))
Directory.Delete(path);
Write(contents);
}
public Folder(string path, int priority)
{
this.path = path;
this.priority = priority;
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
}
public Stream GetContent(string filename)
{
try { return File.OpenRead( Path.Combine( path, filename ) ); }
catch { return null; }
}
public IEnumerable<uint> AllFileHashes()
{
foreach( var filename in Directory.GetFiles( path, "*", SearchOption.TopDirectoryOnly ) )
yield return PackageEntry.HashFilename( Path.GetFileName(filename) );
}
public bool Exists(string filename)
{
return File.Exists(Path.Combine(path,filename));
}
public int Priority
{
get { return priority; }
}
public void Write(Dictionary<string, byte[]> contents)
{
foreach (var file in contents)
using (var dataStream = File.Create(Path.Combine(path, file.Key)))
using (var writer = new BinaryWriter(dataStream))
writer.Write(file.Value);
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.IO;
using System;
namespace OpenRA.FileFormats
{
public class Folder : IFolder
{
readonly string path;
int priority;
// Create a new folder package
public Folder(string path, int priority, Dictionary<string, byte[]> contents)
{
this.path = path;
this.priority = priority;
if (Directory.Exists(path))
Directory.Delete(path);
Write(contents);
}
public Folder(string path, int priority)
{
this.path = path;
this.priority = priority;
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
}
public Stream GetContent(string filename)
{
try { return File.OpenRead( Path.Combine( path, filename ) ); }
catch { return null; }
}
public IEnumerable<uint> AllFileHashes()
{
foreach( var filename in Directory.GetFiles( path, "*", SearchOption.TopDirectoryOnly ) )
yield return PackageEntry.HashFilename( Path.GetFileName(filename) );
}
public bool Exists(string filename)
{
return File.Exists(Path.Combine(path,filename));
}
public int Priority
{
get { return priority; }
}
public void Write(Dictionary<string, byte[]> contents)
{
foreach (var file in contents)
using (var dataStream = File.Create(Path.Combine(path, file.Key)))
using (var writer = new BinaryWriter(dataStream))
writer.Write(file.Value);
}
}
}

View File

@@ -1,126 +1,126 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace OpenRA.FileFormats
{
public class InstallShieldPackage : IFolder
{
readonly Dictionary<uint, PackageEntry> index = new Dictionary<uint, PackageEntry>();
readonly Stream s;
readonly long dataStart = 255;
int priority;
public InstallShieldPackage(string filename, int priority)
{
this.priority = priority;
s = FileSystem.Open(filename);
// Parse package header
BinaryReader reader = new BinaryReader(s);
uint signature = reader.ReadUInt32();
if (signature != 0x8C655D13)
throw new InvalidDataException("Not an Installshield package");
reader.ReadBytes(8);
/*var FileCount = */reader.ReadUInt16();
reader.ReadBytes(4);
/*var ArchiveSize = */reader.ReadUInt32();
reader.ReadBytes(19);
var TOCAddress = reader.ReadInt32();
reader.ReadBytes(4);
var DirCount = reader.ReadUInt16();
// Parse the directory list
s.Seek(TOCAddress, SeekOrigin.Begin);
BinaryReader TOCreader = new BinaryReader(s);
for (var i = 0; i < DirCount; i++)
ParseDirectory(TOCreader);
}
void ParseDirectory(BinaryReader reader)
{
// Parse directory header
var FileCount = reader.ReadUInt16();
var ChunkSize = reader.ReadUInt16();
var NameLength = reader.ReadUInt16();
reader.ReadChars(NameLength); //var DirName = new String(reader.ReadChars(NameLength));
// Skip to the end of the chunk
reader.ReadBytes(ChunkSize - NameLength - 6);
// Parse files
for (var i = 0; i < FileCount; i++)
ParseFile(reader);
}
uint AccumulatedData = 0;
void ParseFile(BinaryReader reader)
{
reader.ReadBytes(7);
var CompressedSize = reader.ReadUInt32();
reader.ReadBytes(12);
var ChunkSize = reader.ReadUInt16();
reader.ReadBytes(4);
var NameLength = reader.ReadByte();
var FileName = new String(reader.ReadChars(NameLength));
var hash = PackageEntry.HashFilename(FileName);
index.Add(hash, new PackageEntry(hash,AccumulatedData, CompressedSize));
AccumulatedData += CompressedSize;
// Skip to the end of the chunk
reader.ReadBytes(ChunkSize - NameLength - 30);
}
public Stream GetContent(uint hash)
{
PackageEntry e;
if (!index.TryGetValue(hash, out e))
return null;
s.Seek( dataStart + e.Offset, SeekOrigin.Begin );
byte[] data = new byte[ e.Length ];
s.Read( data, 0, (int)e.Length );
return new MemoryStream(Blast.Decompress(data));
}
public Stream GetContent(string filename)
{
return GetContent(PackageEntry.HashFilename(filename));
}
public IEnumerable<uint> AllFileHashes()
{
return index.Keys;
}
public bool Exists(string filename)
{
return index.ContainsKey(PackageEntry.HashFilename(filename));
}
public int Priority
{
get { return 2000 + priority; }
}
public void Write(Dictionary<string, byte[]> contents)
{
throw new NotImplementedException("Cannot save InstallShieldPackages.");
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace OpenRA.FileFormats
{
public class InstallShieldPackage : IFolder
{
readonly Dictionary<uint, PackageEntry> index = new Dictionary<uint, PackageEntry>();
readonly Stream s;
readonly long dataStart = 255;
int priority;
public InstallShieldPackage(string filename, int priority)
{
this.priority = priority;
s = FileSystem.Open(filename);
// Parse package header
BinaryReader reader = new BinaryReader(s);
uint signature = reader.ReadUInt32();
if (signature != 0x8C655D13)
throw new InvalidDataException("Not an Installshield package");
reader.ReadBytes(8);
/*var FileCount = */reader.ReadUInt16();
reader.ReadBytes(4);
/*var ArchiveSize = */reader.ReadUInt32();
reader.ReadBytes(19);
var TOCAddress = reader.ReadInt32();
reader.ReadBytes(4);
var DirCount = reader.ReadUInt16();
// Parse the directory list
s.Seek(TOCAddress, SeekOrigin.Begin);
BinaryReader TOCreader = new BinaryReader(s);
for (var i = 0; i < DirCount; i++)
ParseDirectory(TOCreader);
}
void ParseDirectory(BinaryReader reader)
{
// Parse directory header
var FileCount = reader.ReadUInt16();
var ChunkSize = reader.ReadUInt16();
var NameLength = reader.ReadUInt16();
reader.ReadChars(NameLength); //var DirName = new String(reader.ReadChars(NameLength));
// Skip to the end of the chunk
reader.ReadBytes(ChunkSize - NameLength - 6);
// Parse files
for (var i = 0; i < FileCount; i++)
ParseFile(reader);
}
uint AccumulatedData = 0;
void ParseFile(BinaryReader reader)
{
reader.ReadBytes(7);
var CompressedSize = reader.ReadUInt32();
reader.ReadBytes(12);
var ChunkSize = reader.ReadUInt16();
reader.ReadBytes(4);
var NameLength = reader.ReadByte();
var FileName = new String(reader.ReadChars(NameLength));
var hash = PackageEntry.HashFilename(FileName);
index.Add(hash, new PackageEntry(hash,AccumulatedData, CompressedSize));
AccumulatedData += CompressedSize;
// Skip to the end of the chunk
reader.ReadBytes(ChunkSize - NameLength - 30);
}
public Stream GetContent(uint hash)
{
PackageEntry e;
if (!index.TryGetValue(hash, out e))
return null;
s.Seek( dataStart + e.Offset, SeekOrigin.Begin );
byte[] data = new byte[ e.Length ];
s.Read( data, 0, (int)e.Length );
return new MemoryStream(Blast.Decompress(data));
}
public Stream GetContent(string filename)
{
return GetContent(PackageEntry.HashFilename(filename));
}
public IEnumerable<uint> AllFileHashes()
{
return index.Keys;
}
public bool Exists(string filename)
{
return index.ContainsKey(PackageEntry.HashFilename(filename));
}
public int Priority
{
get { return 2000 + priority; }
}
public void Write(Dictionary<string, byte[]> contents)
{
throw new NotImplementedException("Cannot save InstallShieldPackages.");
}
}
}

View File

@@ -1,220 +1,220 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace OpenRA.FileFormats
{
public interface IFolder
{
Stream GetContent(string filename);
bool Exists(string filename);
IEnumerable<uint> AllFileHashes();
void Write(Dictionary<string, byte[]> contents);
int Priority { get; }
}
public class MixFile : IFolder
{
readonly Dictionary<uint, PackageEntry> index;
readonly bool isRmix, isEncrypted;
readonly long dataStart;
readonly Stream s;
int priority;
// Create a new MixFile
public MixFile(string filename, int priority, Dictionary<string, byte[]> contents)
{
this.priority = priority;
if (File.Exists(filename))
File.Delete(filename);
s = File.Create(filename);
Write(contents);
}
public MixFile(string filename, int priority)
{
this.priority = priority;
s = FileSystem.Open(filename);
BinaryReader reader = new BinaryReader(s);
uint signature = reader.ReadUInt32();
isRmix = 0 == (signature & ~(uint)(MixFileFlags.Checksum | MixFileFlags.Encrypted));
if (isRmix)
{
isEncrypted = 0 != (signature & (uint)MixFileFlags.Encrypted);
if( isEncrypted )
{
index = ParseRaHeader( s, out dataStart ).ToDictionary(x => x.Hash);
return;
}
}
else
s.Seek( 0, SeekOrigin.Begin );
isEncrypted = false;
index = ParseTdHeader(s, out dataStart).ToDictionary(x => x.Hash);
}
const long headerStart = 84;
List<PackageEntry> ParseRaHeader(Stream s, out long dataStart)
{
BinaryReader reader = new BinaryReader(s);
byte[] keyblock = reader.ReadBytes(80);
byte[] blowfishKey = new BlowfishKeyProvider().DecryptKey(keyblock);
uint[] h = ReadUints(reader, 2);
Blowfish fish = new Blowfish(blowfishKey);
MemoryStream ms = Decrypt( h, fish );
BinaryReader reader2 = new BinaryReader(ms);
ushort numFiles = reader2.ReadUInt16();
reader2.ReadUInt32(); /*datasize*/
s.Position = headerStart;
reader = new BinaryReader(s);
int byteCount = 6 + numFiles * PackageEntry.Size;
h = ReadUints( reader, ( byteCount + 3 ) / 4 );
ms = Decrypt( h, fish );
dataStart = headerStart + byteCount + ( ( ~byteCount + 1 ) & 7 );
long ds;
return ParseTdHeader( ms, out ds );
}
static MemoryStream Decrypt( uint[] h, Blowfish fish )
{
uint[] decrypted = fish.Decrypt( h );
MemoryStream ms = new MemoryStream();
BinaryWriter writer = new BinaryWriter( ms );
foreach( uint t in decrypted )
writer.Write( t );
writer.Flush();
ms.Position = 0;
return ms;
}
uint[] ReadUints(BinaryReader r, int count)
{
uint[] ret = new uint[count];
for (int i = 0; i < ret.Length; i++)
ret[i] = r.ReadUInt32();
return ret;
}
List<PackageEntry> ParseTdHeader(Stream s, out long dataStart)
{
List<PackageEntry> items = new List<PackageEntry>();
BinaryReader reader = new BinaryReader(s);
ushort numFiles = reader.ReadUInt16();
/*uint dataSize = */reader.ReadUInt32();
for (int i = 0; i < numFiles; i++)
items.Add(new PackageEntry(reader));
dataStart = s.Position;
return items;
}
public Stream GetContent(uint hash)
{
PackageEntry e;
if (!index.TryGetValue(hash, out e))
return null;
s.Seek( dataStart + e.Offset, SeekOrigin.Begin );
byte[] data = new byte[ e.Length ];
s.Read( data, 0, (int)e.Length );
return new MemoryStream(data);
}
public Stream GetContent(string filename)
{
return GetContent(PackageEntry.HashFilename(filename));
}
public IEnumerable<uint> AllFileHashes()
{
return index.Keys;
}
public bool Exists(string filename)
{
return index.ContainsKey(PackageEntry.HashFilename(filename));
}
public int Priority
{
get { return 1000 + priority; }
}
public void Write(Dictionary<string, byte[]> contents)
{
// Cannot modify existing mixfile - rename existing file and
// create a new one with original content plus modifications
FileSystem.Unmount(this);
// TODO: Add existing data to the contents list
if (index.Count > 0)
throw new NotImplementedException("Updating mix files unfinished");
// Construct a list of entries for the file header
uint dataSize = 0;
var items = new List<PackageEntry>();
foreach (var kv in contents)
{
uint length = (uint)kv.Value.Length;
uint hash = PackageEntry.HashFilename(Path.GetFileName(kv.Key));
items.Add(new PackageEntry(hash, dataSize, length));
dataSize += length;
}
// Write the new file
s.Seek(0,SeekOrigin.Begin);
using (var writer = new BinaryWriter(s))
{
// Write file header
writer.Write((ushort)items.Count);
writer.Write(dataSize);
foreach (var item in items)
item.Write(writer);
writer.Flush();
// Copy file data
foreach (var file in contents)
s.Write(file.Value);
}
}
}
[Flags]
enum MixFileFlags : uint
{
Checksum = 0x10000,
Encrypted = 0x20000,
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace OpenRA.FileFormats
{
public interface IFolder
{
Stream GetContent(string filename);
bool Exists(string filename);
IEnumerable<uint> AllFileHashes();
void Write(Dictionary<string, byte[]> contents);
int Priority { get; }
}
public class MixFile : IFolder
{
readonly Dictionary<uint, PackageEntry> index;
readonly bool isRmix, isEncrypted;
readonly long dataStart;
readonly Stream s;
int priority;
// Create a new MixFile
public MixFile(string filename, int priority, Dictionary<string, byte[]> contents)
{
this.priority = priority;
if (File.Exists(filename))
File.Delete(filename);
s = File.Create(filename);
Write(contents);
}
public MixFile(string filename, int priority)
{
this.priority = priority;
s = FileSystem.Open(filename);
BinaryReader reader = new BinaryReader(s);
uint signature = reader.ReadUInt32();
isRmix = 0 == (signature & ~(uint)(MixFileFlags.Checksum | MixFileFlags.Encrypted));
if (isRmix)
{
isEncrypted = 0 != (signature & (uint)MixFileFlags.Encrypted);
if( isEncrypted )
{
index = ParseRaHeader( s, out dataStart ).ToDictionary(x => x.Hash);
return;
}
}
else
s.Seek( 0, SeekOrigin.Begin );
isEncrypted = false;
index = ParseTdHeader(s, out dataStart).ToDictionary(x => x.Hash);
}
const long headerStart = 84;
List<PackageEntry> ParseRaHeader(Stream s, out long dataStart)
{
BinaryReader reader = new BinaryReader(s);
byte[] keyblock = reader.ReadBytes(80);
byte[] blowfishKey = new BlowfishKeyProvider().DecryptKey(keyblock);
uint[] h = ReadUints(reader, 2);
Blowfish fish = new Blowfish(blowfishKey);
MemoryStream ms = Decrypt( h, fish );
BinaryReader reader2 = new BinaryReader(ms);
ushort numFiles = reader2.ReadUInt16();
reader2.ReadUInt32(); /*datasize*/
s.Position = headerStart;
reader = new BinaryReader(s);
int byteCount = 6 + numFiles * PackageEntry.Size;
h = ReadUints( reader, ( byteCount + 3 ) / 4 );
ms = Decrypt( h, fish );
dataStart = headerStart + byteCount + ( ( ~byteCount + 1 ) & 7 );
long ds;
return ParseTdHeader( ms, out ds );
}
static MemoryStream Decrypt( uint[] h, Blowfish fish )
{
uint[] decrypted = fish.Decrypt( h );
MemoryStream ms = new MemoryStream();
BinaryWriter writer = new BinaryWriter( ms );
foreach( uint t in decrypted )
writer.Write( t );
writer.Flush();
ms.Position = 0;
return ms;
}
uint[] ReadUints(BinaryReader r, int count)
{
uint[] ret = new uint[count];
for (int i = 0; i < ret.Length; i++)
ret[i] = r.ReadUInt32();
return ret;
}
List<PackageEntry> ParseTdHeader(Stream s, out long dataStart)
{
List<PackageEntry> items = new List<PackageEntry>();
BinaryReader reader = new BinaryReader(s);
ushort numFiles = reader.ReadUInt16();
/*uint dataSize = */reader.ReadUInt32();
for (int i = 0; i < numFiles; i++)
items.Add(new PackageEntry(reader));
dataStart = s.Position;
return items;
}
public Stream GetContent(uint hash)
{
PackageEntry e;
if (!index.TryGetValue(hash, out e))
return null;
s.Seek( dataStart + e.Offset, SeekOrigin.Begin );
byte[] data = new byte[ e.Length ];
s.Read( data, 0, (int)e.Length );
return new MemoryStream(data);
}
public Stream GetContent(string filename)
{
return GetContent(PackageEntry.HashFilename(filename));
}
public IEnumerable<uint> AllFileHashes()
{
return index.Keys;
}
public bool Exists(string filename)
{
return index.ContainsKey(PackageEntry.HashFilename(filename));
}
public int Priority
{
get { return 1000 + priority; }
}
public void Write(Dictionary<string, byte[]> contents)
{
// Cannot modify existing mixfile - rename existing file and
// create a new one with original content plus modifications
FileSystem.Unmount(this);
// TODO: Add existing data to the contents list
if (index.Count > 0)
throw new NotImplementedException("Updating mix files unfinished");
// Construct a list of entries for the file header
uint dataSize = 0;
var items = new List<PackageEntry>();
foreach (var kv in contents)
{
uint length = (uint)kv.Value.Length;
uint hash = PackageEntry.HashFilename(Path.GetFileName(kv.Key));
items.Add(new PackageEntry(hash, dataSize, length));
dataSize += length;
}
// Write the new file
s.Seek(0,SeekOrigin.Begin);
using (var writer = new BinaryWriter(s))
{
// Write file header
writer.Write((ushort)items.Count);
writer.Write(dataSize);
foreach (var item in items)
item.Write(writer);
writer.Flush();
// Copy file data
foreach (var file in contents)
s.Write(file.Value);
}
}
}
[Flags]
enum MixFileFlags : uint
{
Checksum = 0x10000,
Encrypted = 0x20000,
}
}

View File

@@ -1,117 +1,117 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;
using SZipFile = ICSharpCode.SharpZipLib.Zip.ZipFile;
namespace OpenRA.FileFormats
{
public class ZipFile : IFolder
{
string filename;
SZipFile pkg;
int priority;
public ZipFile(string filename, int priority)
{
this.filename = filename;
this.priority = priority;
try
{
// pull the file into memory, dont keep it open.
pkg = new SZipFile(new MemoryStream(File.ReadAllBytes(filename)));
}
catch (ZipException e)
{
Log.Write("debug", "Couldn't load zip file: {0}", e.Message);
}
}
// Create a new zip with the specified contents
public ZipFile(string filename, int priority, Dictionary<string, byte[]> contents)
{
this.priority = priority;
this.filename = filename;
if (File.Exists(filename))
File.Delete(filename);
pkg = SZipFile.Create(filename);
Write(contents);
}
public Stream GetContent(string filename)
{
using (var z = pkg.GetInputStream(pkg.GetEntry(filename)))
{
var ms = new MemoryStream();
int bufSize = 2048;
byte[] buf = new byte[bufSize];
while ((bufSize = z.Read(buf, 0, buf.Length)) > 0)
ms.Write(buf, 0, bufSize);
ms.Seek(0, SeekOrigin.Begin);
return ms;
}
}
public IEnumerable<uint> AllFileHashes()
{
foreach(ZipEntry entry in pkg)
yield return PackageEntry.HashFilename(entry.Name);
}
public bool Exists(string filename)
{
return pkg.GetEntry(filename) != null;
}
public int Priority
{
get { return 500 + priority; }
}
public void Write(Dictionary<string, byte[]> contents)
{
pkg.Close();
pkg = SZipFile.Create(filename);
pkg.BeginUpdate();
// TODO: Clear existing content?
foreach (var kvp in contents)
pkg.Add(new StaticMemoryDataSource(kvp.Value), kvp.Key);
pkg.CommitUpdate();
pkg.Close();
pkg = new SZipFile(new MemoryStream(File.ReadAllBytes(filename)));
}
}
class StaticMemoryDataSource : IStaticDataSource
{
byte[] data;
public StaticMemoryDataSource (byte[] data)
{
this.data = data;
}
public Stream GetSource()
{
return new MemoryStream(data);
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;
using SZipFile = ICSharpCode.SharpZipLib.Zip.ZipFile;
namespace OpenRA.FileFormats
{
public class ZipFile : IFolder
{
string filename;
SZipFile pkg;
int priority;
public ZipFile(string filename, int priority)
{
this.filename = filename;
this.priority = priority;
try
{
// pull the file into memory, dont keep it open.
pkg = new SZipFile(new MemoryStream(File.ReadAllBytes(filename)));
}
catch (ZipException e)
{
Log.Write("debug", "Couldn't load zip file: {0}", e.Message);
}
}
// Create a new zip with the specified contents
public ZipFile(string filename, int priority, Dictionary<string, byte[]> contents)
{
this.priority = priority;
this.filename = filename;
if (File.Exists(filename))
File.Delete(filename);
pkg = SZipFile.Create(filename);
Write(contents);
}
public Stream GetContent(string filename)
{
using (var z = pkg.GetInputStream(pkg.GetEntry(filename)))
{
var ms = new MemoryStream();
int bufSize = 2048;
byte[] buf = new byte[bufSize];
while ((bufSize = z.Read(buf, 0, buf.Length)) > 0)
ms.Write(buf, 0, bufSize);
ms.Seek(0, SeekOrigin.Begin);
return ms;
}
}
public IEnumerable<uint> AllFileHashes()
{
foreach(ZipEntry entry in pkg)
yield return PackageEntry.HashFilename(entry.Name);
}
public bool Exists(string filename)
{
return pkg.GetEntry(filename) != null;
}
public int Priority
{
get { return 500 + priority; }
}
public void Write(Dictionary<string, byte[]> contents)
{
pkg.Close();
pkg = SZipFile.Create(filename);
pkg.BeginUpdate();
// TODO: Clear existing content?
foreach (var kvp in contents)
pkg.Add(new StaticMemoryDataSource(kvp.Value), kvp.Key);
pkg.CommitUpdate();
pkg.Close();
pkg = new SZipFile(new MemoryStream(File.ReadAllBytes(filename)));
}
}
class StaticMemoryDataSource : IStaticDataSource
{
byte[] data;
public StaticMemoryDataSource (byte[] data)
{
this.data = data;
}
public Stream GetSource()
{
return new MemoryStream(data);
}
}
}

View File

@@ -1,146 +1,146 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
namespace OpenRA.FileFormats
{
public enum Dune2ImageFlags : int
{
F80_F2 = 0,
F2 = 2,
L16_F80_F2_1 = 1,
L16_F80_F2_2 = 3,
Ln_F80_F2 = 5
}
public class Dune2ImageHeader
{
public readonly Dune2ImageFlags Flags;
public readonly int Width;
public readonly int Height;
public readonly int Slices;
public readonly int FileSize;
public readonly int DataSize;
public readonly byte[] LookupTable;
public byte[] Image;
public Dune2ImageHeader(BinaryReader reader)
{
Flags = (Dune2ImageFlags)reader.ReadUInt16();
Slices = reader.ReadByte();
Width = reader.ReadUInt16();
Height = reader.ReadByte();
FileSize = reader.ReadUInt16();
DataSize = reader.ReadUInt16();
if (Flags == Dune2ImageFlags.L16_F80_F2_1 ||
Flags == Dune2ImageFlags.L16_F80_F2_2 ||
Flags == Dune2ImageFlags.Ln_F80_F2)
{
int n = Flags == Dune2ImageFlags.Ln_F80_F2 ? reader.ReadByte() : (byte)16;
LookupTable = new byte[n];
for (int i = 0; i < n; i++)
LookupTable[i] = reader.ReadByte();
}
else
{
LookupTable = new byte[256];
for (int i = 0; i < 256; i++)
LookupTable[i] = (byte)i;
LookupTable[1] = 0x7f;
LookupTable[2] = 0x7e;
LookupTable[3] = 0x7d;
LookupTable[4] = 0x7c;
}
}
public Size Size
{
get { return new Size(Width, Height); }
}
}
public class Dune2ShpReader : IEnumerable<Dune2ImageHeader>
{
public readonly int ImageCount;
List<Dune2ImageHeader> headers = new List<Dune2ImageHeader>();
public Dune2ShpReader(Stream stream)
{
BinaryReader reader = new BinaryReader(stream);
ImageCount = reader.ReadUInt16();
//Last offset is pointer to end of file.
uint[] offsets = new uint[ImageCount + 1];
uint temp = reader.ReadUInt32();
//If fourth byte in file is non-zero, the offsets are two bytes each.
bool twoByteOffsets = (temp & 0xFF0000) > 0;
if (twoByteOffsets)
{
offsets[0] = ((temp & 0xFFFF0000) >> 16) + 2; //Offset does not account for image count bytes
offsets[1] = (temp & 0xFFFF) + 2;
}
else
offsets[0] = temp + 2;
for (int i = twoByteOffsets ? 2 : 1; i < ImageCount + 1; i++)
offsets[i] = (twoByteOffsets ? reader.ReadUInt16() : reader.ReadUInt32()) + 2;
for (int i = 0; i < ImageCount; i++)
{
reader.BaseStream.Seek(offsets[i], SeekOrigin.Begin);
Dune2ImageHeader header = new Dune2ImageHeader(reader);
byte[] imgData = reader.ReadBytes(header.FileSize);
header.Image = new byte[header.Height * header.Width];
//Decode image data
if (header.Flags != Dune2ImageFlags.F2)
{
byte[] tempData = new byte[header.DataSize];
Format80.DecodeInto(imgData, tempData);
Format2.DecodeInto(tempData, header.Image);
}
else
Format2.DecodeInto(imgData, header.Image);
//Lookup values in lookup table
if (header.LookupTable != null)
for (int j = 0; j < header.Image.Length; j++)
header.Image[j] = header.LookupTable[header.Image[j]];
headers.Add(header);
}
}
public Dune2ImageHeader this[int index]
{
get { return headers[index]; }
}
public IEnumerator<Dune2ImageHeader> GetEnumerator()
{
return headers.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
namespace OpenRA.FileFormats
{
public enum Dune2ImageFlags : int
{
F80_F2 = 0,
F2 = 2,
L16_F80_F2_1 = 1,
L16_F80_F2_2 = 3,
Ln_F80_F2 = 5
}
public class Dune2ImageHeader
{
public readonly Dune2ImageFlags Flags;
public readonly int Width;
public readonly int Height;
public readonly int Slices;
public readonly int FileSize;
public readonly int DataSize;
public readonly byte[] LookupTable;
public byte[] Image;
public Dune2ImageHeader(BinaryReader reader)
{
Flags = (Dune2ImageFlags)reader.ReadUInt16();
Slices = reader.ReadByte();
Width = reader.ReadUInt16();
Height = reader.ReadByte();
FileSize = reader.ReadUInt16();
DataSize = reader.ReadUInt16();
if (Flags == Dune2ImageFlags.L16_F80_F2_1 ||
Flags == Dune2ImageFlags.L16_F80_F2_2 ||
Flags == Dune2ImageFlags.Ln_F80_F2)
{
int n = Flags == Dune2ImageFlags.Ln_F80_F2 ? reader.ReadByte() : (byte)16;
LookupTable = new byte[n];
for (int i = 0; i < n; i++)
LookupTable[i] = reader.ReadByte();
}
else
{
LookupTable = new byte[256];
for (int i = 0; i < 256; i++)
LookupTable[i] = (byte)i;
LookupTable[1] = 0x7f;
LookupTable[2] = 0x7e;
LookupTable[3] = 0x7d;
LookupTable[4] = 0x7c;
}
}
public Size Size
{
get { return new Size(Width, Height); }
}
}
public class Dune2ShpReader : IEnumerable<Dune2ImageHeader>
{
public readonly int ImageCount;
List<Dune2ImageHeader> headers = new List<Dune2ImageHeader>();
public Dune2ShpReader(Stream stream)
{
BinaryReader reader = new BinaryReader(stream);
ImageCount = reader.ReadUInt16();
//Last offset is pointer to end of file.
uint[] offsets = new uint[ImageCount + 1];
uint temp = reader.ReadUInt32();
//If fourth byte in file is non-zero, the offsets are two bytes each.
bool twoByteOffsets = (temp & 0xFF0000) > 0;
if (twoByteOffsets)
{
offsets[0] = ((temp & 0xFFFF0000) >> 16) + 2; //Offset does not account for image count bytes
offsets[1] = (temp & 0xFFFF) + 2;
}
else
offsets[0] = temp + 2;
for (int i = twoByteOffsets ? 2 : 1; i < ImageCount + 1; i++)
offsets[i] = (twoByteOffsets ? reader.ReadUInt16() : reader.ReadUInt32()) + 2;
for (int i = 0; i < ImageCount; i++)
{
reader.BaseStream.Seek(offsets[i], SeekOrigin.Begin);
Dune2ImageHeader header = new Dune2ImageHeader(reader);
byte[] imgData = reader.ReadBytes(header.FileSize);
header.Image = new byte[header.Height * header.Width];
//Decode image data
if (header.Flags != Dune2ImageFlags.F2)
{
byte[] tempData = new byte[header.DataSize];
Format80.DecodeInto(imgData, tempData);
Format2.DecodeInto(tempData, header.Image);
}
else
Format2.DecodeInto(imgData, header.Image);
//Lookup values in lookup table
if (header.LookupTable != null)
for (int j = 0; j < header.Image.Length; j++)
header.Image[j] = header.LookupTable[header.Image[j]];
headers.Add(header);
}
}
public Dune2ImageHeader this[int index]
{
get { return headers[index]; }
}
public IEnumerator<Dune2ImageHeader> GetEnumerator()
{
return headers.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

View File

@@ -1,96 +1,96 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Drawing;
using System.IO;
namespace OpenRA.FileFormats.Graphics
{
[AttributeUsage( AttributeTargets.Assembly )]
public class RendererAttribute : Attribute
{
public readonly Type Type;
public RendererAttribute( Type graphicsDeviceType )
{
if( !typeof( IGraphicsDevice ).IsAssignableFrom( graphicsDeviceType ) )
throw new InvalidOperationException( "Incorrect type in RendererAttribute" );
Type = graphicsDeviceType;
}
}
public interface IGraphicsDevice
{
IVertexBuffer<Vertex> CreateVertexBuffer( int length );
IIndexBuffer CreateIndexBuffer( int length );
ITexture CreateTexture( Bitmap bitmap );
ITexture CreateTexture();
IShader CreateShader( string name );
Size WindowSize { get; }
void Clear( Color color );
void Present( IInputHandler inputHandler );
void DrawIndexedPrimitives( PrimitiveType type, Range<int> vertexRange, Range<int> indexRange );
void DrawIndexedPrimitives( PrimitiveType type, int vertexPool, int numPrimitives );
void EnableScissor( int left, int top, int width, int height );
void DisableScissor();
}
public interface IVertexBuffer<T>
{
void Bind();
void SetData( T[] vertices, int length );
}
public interface IIndexBuffer
{
void Bind();
void SetData( ushort[] indices, int length );
}
public interface IShader
{
void SetValue( string name, float x, float y );
void SetValue( string param, ITexture texture );
void Commit();
void Render( Action a );
}
public interface ITexture
{
void SetData(Bitmap bitmap);
void SetData(uint[,] colors);
void SetData(byte[] colors, int width, int height);
}
public enum PrimitiveType
{
PointList,
LineList,
TriangleList,
}
public struct Range<T>
{
public readonly T Start, End;
public Range( T start, T end ) { Start = start; End = end; }
}
public enum WindowMode
{
Windowed,
Fullscreen,
PseudoFullscreen,
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Drawing;
using System.IO;
namespace OpenRA.FileFormats.Graphics
{
[AttributeUsage( AttributeTargets.Assembly )]
public class RendererAttribute : Attribute
{
public readonly Type Type;
public RendererAttribute( Type graphicsDeviceType )
{
if( !typeof( IGraphicsDevice ).IsAssignableFrom( graphicsDeviceType ) )
throw new InvalidOperationException( "Incorrect type in RendererAttribute" );
Type = graphicsDeviceType;
}
}
public interface IGraphicsDevice
{
IVertexBuffer<Vertex> CreateVertexBuffer( int length );
IIndexBuffer CreateIndexBuffer( int length );
ITexture CreateTexture( Bitmap bitmap );
ITexture CreateTexture();
IShader CreateShader( string name );
Size WindowSize { get; }
void Clear( Color color );
void Present( IInputHandler inputHandler );
void DrawIndexedPrimitives( PrimitiveType type, Range<int> vertexRange, Range<int> indexRange );
void DrawIndexedPrimitives( PrimitiveType type, int vertexPool, int numPrimitives );
void EnableScissor( int left, int top, int width, int height );
void DisableScissor();
}
public interface IVertexBuffer<T>
{
void Bind();
void SetData( T[] vertices, int length );
}
public interface IIndexBuffer
{
void Bind();
void SetData( ushort[] indices, int length );
}
public interface IShader
{
void SetValue( string name, float x, float y );
void SetValue( string param, ITexture texture );
void Commit();
void Render( Action a );
}
public interface ITexture
{
void SetData(Bitmap bitmap);
void SetData(uint[,] colors);
void SetData(byte[] colors, int width, int height);
}
public enum PrimitiveType
{
PointList,
LineList,
TriangleList,
}
public struct Range<T>
{
public readonly T Start, End;
public Range( T start, T end ) { Start = start; End = end; }
}
public enum WindowMode
{
Windowed,
Fullscreen,
PseudoFullscreen,
}
}

View File

@@ -1,71 +1,71 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
namespace OpenRA
{
public interface IInputHandler
{
void ModifierKeys( Modifiers mods );
void OnKeyInput( KeyInput input );
void OnMouseInput( MouseInput input );
}
public struct MouseInput
{
public MouseInputEvent Event;
public MouseButton Button;
public int2 Location;
public Modifiers Modifiers;
public MouseInput( MouseInputEvent ev, MouseButton button, int2 location, Modifiers mods )
{
this.Event = ev;
this.Button = button;
this.Location = location;
this.Modifiers = mods;
}
}
public enum MouseInputEvent { Down, Move, Up };
[Flags]
public enum MouseButton
{
None = 0,
Left = 1,
Right = 2,
Middle = 4,
WheelDown = 8,
WheelUp = 16
}
[Flags]
public enum Modifiers
{
None = 0,
Shift = 1,
Alt = 2,
Ctrl = 4,
}
public enum KeyInputEvent { Down, Up };
public struct KeyInput
{
public KeyInputEvent Event;
public char KeyChar;
public string KeyName;
public Modifiers Modifiers;
public int VirtKey;
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
namespace OpenRA
{
public interface IInputHandler
{
void ModifierKeys( Modifiers mods );
void OnKeyInput( KeyInput input );
void OnMouseInput( MouseInput input );
}
public struct MouseInput
{
public MouseInputEvent Event;
public MouseButton Button;
public int2 Location;
public Modifiers Modifiers;
public MouseInput( MouseInputEvent ev, MouseButton button, int2 location, Modifiers mods )
{
this.Event = ev;
this.Button = button;
this.Location = location;
this.Modifiers = mods;
}
}
public enum MouseInputEvent { Down, Move, Up };
[Flags]
public enum MouseButton
{
None = 0,
Left = 1,
Right = 2,
Middle = 4,
WheelDown = 8,
WheelUp = 16
}
[Flags]
public enum Modifiers
{
None = 0,
Shift = 1,
Alt = 2,
Ctrl = 4,
}
public enum KeyInputEvent { Down, Up };
public struct KeyInput
{
public KeyInputEvent Event;
public char KeyChar;
public string KeyName;
public Modifiers Modifiers;
public int VirtKey;
}
}

View File

@@ -1,178 +1,178 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
namespace OpenRA.FileFormats
{
public class ImageHeader
{
public uint Offset;
public Format Format;
public uint RefOffset;
public Format RefFormat;
public ImageHeader RefImage;
public byte[] Image;
public ImageHeader() { }
public ImageHeader( BinaryReader reader )
{
Offset = reader.ReadUInt32();
Format = (Format)( Offset >> 24 );
Offset &= 0xFFFFFF;
RefOffset = reader.ReadUInt16();
RefFormat = (Format)reader.ReadUInt16();
}
public static readonly int SizeOnDisk = 8;
public void WriteTo(BinaryWriter writer)
{
writer.Write(Offset | ((uint)Format << 24));
writer.Write((ushort)RefOffset);
writer.Write((ushort)RefFormat);
}
}
public enum Format
{
Format20 = 0x20,
Format40 = 0x40,
Format80 = 0x80,
}
public class ShpReader : IEnumerable<ImageHeader>
{
public readonly int ImageCount;
public readonly ushort Width;
public readonly ushort Height;
public Size Size { get { return new Size(Width, Height); } }
private readonly List<ImageHeader> headers = new List<ImageHeader>();
int recurseDepth = 0;
public ShpReader( Stream stream )
{
BinaryReader reader = new BinaryReader( stream );
ImageCount = reader.ReadUInt16();
reader.ReadUInt16();
reader.ReadUInt16();
Width = reader.ReadUInt16();
Height = reader.ReadUInt16();
reader.ReadUInt32();
for( int i = 0 ; i < ImageCount ; i++ )
headers.Add( new ImageHeader( reader ) );
new ImageHeader( reader ); // end-of-file header
new ImageHeader( reader ); // all-zeroes header
Dictionary<uint, ImageHeader> offsets = new Dictionary<uint, ImageHeader>();
foreach( ImageHeader h in headers )
offsets.Add( h.Offset, h );
for( int i = 0 ; i < ImageCount ; i++ )
{
ImageHeader h = headers[ i ];
if( h.Format == Format.Format20 )
h.RefImage = headers[ i - 1 ];
else if( h.Format == Format.Format40 )
{
if( !offsets.TryGetValue( h.RefOffset, out h.RefImage ) )
throw new InvalidDataException( string.Format( "Reference doesnt point to image data {0}->{1}", h.Offset, h.RefOffset ) );
}
}
foreach( ImageHeader h in headers )
Decompress( stream, h );
}
public ImageHeader this[ int index ]
{
get { return headers[ index ]; }
}
void Decompress( Stream stream, ImageHeader h )
{
if( recurseDepth > ImageCount )
throw new InvalidDataException( "Format20/40 headers contain infinite loop" );
switch( h.Format )
{
case Format.Format20:
case Format.Format40:
{
if( h.RefImage.Image == null )
{
++recurseDepth;
Decompress( stream, h.RefImage );
--recurseDepth;
}
h.Image = CopyImageData( h.RefImage.Image );
Format40.DecodeInto(ReadCompressedData(stream, h), h.Image);
break;
}
case Format.Format80:
{
byte[] imageBytes = new byte[ Width * Height ];
Format80.DecodeInto( ReadCompressedData( stream, h ), imageBytes );
h.Image = imageBytes;
break;
}
default:
throw new InvalidDataException();
}
}
static byte[] ReadCompressedData( Stream stream, ImageHeader h )
{
stream.Position = h.Offset;
// Actually, far too big. There's no length field with the correct length though :(
int compressedLength = (int)( stream.Length - stream.Position );
byte[] compressedBytes = new byte[ compressedLength ];
stream.Read( compressedBytes, 0, compressedLength );
//MemoryStream ms = new MemoryStream( compressedBytes );
return compressedBytes;
}
private byte[] CopyImageData( byte[] baseImage )
{
byte[] imageData = new byte[ Width * Height ];
for( int i = 0 ; i < Width * Height ; i++ )
imageData[ i ] = baseImage[ i ];
return imageData;
}
public IEnumerator<ImageHeader> GetEnumerator()
{
return headers.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
namespace OpenRA.FileFormats
{
public class ImageHeader
{
public uint Offset;
public Format Format;
public uint RefOffset;
public Format RefFormat;
public ImageHeader RefImage;
public byte[] Image;
public ImageHeader() { }
public ImageHeader( BinaryReader reader )
{
Offset = reader.ReadUInt32();
Format = (Format)( Offset >> 24 );
Offset &= 0xFFFFFF;
RefOffset = reader.ReadUInt16();
RefFormat = (Format)reader.ReadUInt16();
}
public static readonly int SizeOnDisk = 8;
public void WriteTo(BinaryWriter writer)
{
writer.Write(Offset | ((uint)Format << 24));
writer.Write((ushort)RefOffset);
writer.Write((ushort)RefFormat);
}
}
public enum Format
{
Format20 = 0x20,
Format40 = 0x40,
Format80 = 0x80,
}
public class ShpReader : IEnumerable<ImageHeader>
{
public readonly int ImageCount;
public readonly ushort Width;
public readonly ushort Height;
public Size Size { get { return new Size(Width, Height); } }
private readonly List<ImageHeader> headers = new List<ImageHeader>();
int recurseDepth = 0;
public ShpReader( Stream stream )
{
BinaryReader reader = new BinaryReader( stream );
ImageCount = reader.ReadUInt16();
reader.ReadUInt16();
reader.ReadUInt16();
Width = reader.ReadUInt16();
Height = reader.ReadUInt16();
reader.ReadUInt32();
for( int i = 0 ; i < ImageCount ; i++ )
headers.Add( new ImageHeader( reader ) );
new ImageHeader( reader ); // end-of-file header
new ImageHeader( reader ); // all-zeroes header
Dictionary<uint, ImageHeader> offsets = new Dictionary<uint, ImageHeader>();
foreach( ImageHeader h in headers )
offsets.Add( h.Offset, h );
for( int i = 0 ; i < ImageCount ; i++ )
{
ImageHeader h = headers[ i ];
if( h.Format == Format.Format20 )
h.RefImage = headers[ i - 1 ];
else if( h.Format == Format.Format40 )
{
if( !offsets.TryGetValue( h.RefOffset, out h.RefImage ) )
throw new InvalidDataException( string.Format( "Reference doesnt point to image data {0}->{1}", h.Offset, h.RefOffset ) );
}
}
foreach( ImageHeader h in headers )
Decompress( stream, h );
}
public ImageHeader this[ int index ]
{
get { return headers[ index ]; }
}
void Decompress( Stream stream, ImageHeader h )
{
if( recurseDepth > ImageCount )
throw new InvalidDataException( "Format20/40 headers contain infinite loop" );
switch( h.Format )
{
case Format.Format20:
case Format.Format40:
{
if( h.RefImage.Image == null )
{
++recurseDepth;
Decompress( stream, h.RefImage );
--recurseDepth;
}
h.Image = CopyImageData( h.RefImage.Image );
Format40.DecodeInto(ReadCompressedData(stream, h), h.Image);
break;
}
case Format.Format80:
{
byte[] imageBytes = new byte[ Width * Height ];
Format80.DecodeInto( ReadCompressedData( stream, h ), imageBytes );
h.Image = imageBytes;
break;
}
default:
throw new InvalidDataException();
}
}
static byte[] ReadCompressedData( Stream stream, ImageHeader h )
{
stream.Position = h.Offset;
// Actually, far too big. There's no length field with the correct length though :(
int compressedLength = (int)( stream.Length - stream.Position );
byte[] compressedBytes = new byte[ compressedLength ];
stream.Read( compressedBytes, 0, compressedLength );
//MemoryStream ms = new MemoryStream( compressedBytes );
return compressedBytes;
}
private byte[] CopyImageData( byte[] baseImage )
{
byte[] imageData = new byte[ Width * Height ];
for( int i = 0 ; i < Width * Height ; i++ )
imageData[ i ] = baseImage[ i ];
return imageData;
}
public IEnumerator<ImageHeader> GetEnumerator()
{
return headers.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

View File

@@ -1,28 +1,28 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Runtime.InteropServices;
namespace OpenRA.FileFormats.Graphics
{
[StructLayout(LayoutKind.Sequential)]
public struct Vertex
{
public float x, y, z, u, v;
public float p, c;
public Vertex(float2 xy, float2 uv, float2 pc)
{
this.x = xy.X; this.y = xy.Y; this.z = 0;
this.u = uv.X; this.v = uv.Y;
this.p = pc.X; this.c = pc.Y;
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Runtime.InteropServices;
namespace OpenRA.FileFormats.Graphics
{
[StructLayout(LayoutKind.Sequential)]
public struct Vertex
{
public float x, y, z, u, v;
public float p, c;
public Vertex(float2 xy, float2 uv, float2 pc)
{
this.x = xy.X; this.y = xy.Y; this.z = 0;
this.u = uv.X; this.v = uv.Y;
this.p = pc.X; this.c = pc.Y;
}
}
}

View File

@@ -1,16 +1,16 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
* see COPYING.
*/
#endregion
using System;
using System.IO;
#endregion
using System;
using System.IO;
namespace OpenRA.FileFormats
{
public class VqaReader
@@ -40,10 +40,10 @@ namespace OpenRA.FileFormats
byte[] origData;
// Final frame output
uint[,] frameData;
byte[] audioData; // audio for this frame: 22050Hz 16bit mono pcm, uncompressed.
public byte[] AudioData { get { return audioData; } }
uint[,] frameData;
byte[] audioData; // audio for this frame: 22050Hz 16bit mono pcm, uncompressed.
public byte[] AudioData { get { return audioData; } }
public int CurrentFrame { get { return currentFrame; } }
public VqaReader( Stream stream )
@@ -108,62 +108,62 @@ namespace OpenRA.FileFormats
offsets[i] = reader.ReadUInt32();
if (offsets[i] > 0x40000000) offsets[i] -= 0x40000000;
offsets[i] <<= 1;
}
}
CollectAudioData();
Reset();
}
}
public void Reset()
{
currentFrame = cbOffset = cbChunk = 0;
LoadFrame();
}
void CollectAudioData()
{
var ms = new MemoryStream();
var adpcmIndex = 0;
void CollectAudioData()
{
var ms = new MemoryStream();
var adpcmIndex = 0;
bool compressed = false;
for (var i = 0; i < Frames; i++)
{
stream.Seek(offsets[i], SeekOrigin.Begin);
BinaryReader reader = new BinaryReader(stream);
var end = (i < Frames - 1) ? offsets[i + 1] : stream.Length;
while (reader.BaseStream.Position < end)
{
var type = new String(reader.ReadChars(4));
var length = int2.Swap(reader.ReadUInt32());
switch (type)
{
bool compressed = false;
for (var i = 0; i < Frames; i++)
{
stream.Seek(offsets[i], SeekOrigin.Begin);
BinaryReader reader = new BinaryReader(stream);
var end = (i < Frames - 1) ? offsets[i + 1] : stream.Length;
while (reader.BaseStream.Position < end)
{
var type = new String(reader.ReadChars(4));
var length = int2.Swap(reader.ReadUInt32());
switch (type)
{
case "SND0":
case "SND2":
var rawAudio = reader.ReadBytes((int)length);
ms.Write(rawAudio);
compressed = (type == "SND2");
break;
default:
reader.ReadBytes((int)length);
break;
}
if (reader.PeekChar() == 0) reader.ReadByte();
}
}
audioData = (compressed) ? AudLoader.LoadSound(ms.ToArray(), ref adpcmIndex) : ms.ToArray();
}
break;
default:
reader.ReadBytes((int)length);
break;
}
if (reader.PeekChar() == 0) reader.ReadByte();
}
}
audioData = (compressed) ? AudLoader.LoadSound(ms.ToArray(), ref adpcmIndex) : ms.ToArray();
}
public void AdvanceFrame()
{
currentFrame++;
LoadFrame();
}
void LoadFrame()
{
if (currentFrame >= Frames)
@@ -180,7 +180,7 @@ namespace OpenRA.FileFormats
var length = int2.Swap(reader.ReadUInt32());
switch(type)
{
{
case "VQFR":
DecodeVQFR(reader);
break;

View File

@@ -1,97 +1,97 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace OpenRA.FileFormats
{
public static class HttpUtil
{
public static byte[] DownloadData(string url, Action<int, int> f, int chunkSize)
{
var uri = new Uri(url);
var ip = Dns.GetHostEntry(uri.DnsSafeHost).AddressList[0];
using (var s = new TcpClient())
{
s.Connect(new IPEndPoint(ip, uri.Port));
var ns = s.GetStream();
var sw = new StreamWriter(ns);
sw.Write("GET {0} HTTP/1.0\r\nHost:{1}\r\n\r\n", uri.PathAndQuery, uri.Host);
sw.Flush();
var br = new BinaryReader(ns);
var contentLength = 0;
var offset = 0;
for (; ; )
{
var result = br.ReadLine();
var kv = result.Split(new string[] { ": " }, StringSplitOptions.RemoveEmptyEntries);
if (result == "")
{
/* data follows the blank line */
if (contentLength > 0)
{
if (f != null)
f(offset, contentLength);
var data = new byte[contentLength];
while (offset < contentLength)
{
var thisChunk = Math.Min(contentLength - offset, chunkSize);
br.Read(data, offset, thisChunk);
offset += thisChunk;
if (f != null)
f(offset, contentLength);
}
s.Close();
return data;
}
else
{
s.Close();
return new byte[] { };
}
}
else if (kv[0] == "Content-Length")
contentLength = int.Parse(kv[1]);
}
}
}
public static byte[] DownloadData(string url, Action<int, int> f)
{
return DownloadData(url, f, 4096);
}
public static byte[] DownloadData(string url)
{
return DownloadData(url, null);
}
static string ReadLine(this BinaryReader br)
{
var sb = new StringBuilder();
char c;
while ((c = br.ReadChar()) != '\n')
if (c != '\r' && c != '\n')
sb.Append(c);
return sb.ToString();
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace OpenRA.FileFormats
{
public static class HttpUtil
{
public static byte[] DownloadData(string url, Action<int, int> f, int chunkSize)
{
var uri = new Uri(url);
var ip = Dns.GetHostEntry(uri.DnsSafeHost).AddressList[0];
using (var s = new TcpClient())
{
s.Connect(new IPEndPoint(ip, uri.Port));
var ns = s.GetStream();
var sw = new StreamWriter(ns);
sw.Write("GET {0} HTTP/1.0\r\nHost:{1}\r\n\r\n", uri.PathAndQuery, uri.Host);
sw.Flush();
var br = new BinaryReader(ns);
var contentLength = 0;
var offset = 0;
for (; ; )
{
var result = br.ReadLine();
var kv = result.Split(new string[] { ": " }, StringSplitOptions.RemoveEmptyEntries);
if (result == "")
{
/* data follows the blank line */
if (contentLength > 0)
{
if (f != null)
f(offset, contentLength);
var data = new byte[contentLength];
while (offset < contentLength)
{
var thisChunk = Math.Min(contentLength - offset, chunkSize);
br.Read(data, offset, thisChunk);
offset += thisChunk;
if (f != null)
f(offset, contentLength);
}
s.Close();
return data;
}
else
{
s.Close();
return new byte[] { };
}
}
else if (kv[0] == "Content-Length")
contentLength = int.Parse(kv[1]);
}
}
}
public static byte[] DownloadData(string url, Action<int, int> f)
{
return DownloadData(url, f, 4096);
}
public static byte[] DownloadData(string url)
{
return DownloadData(url, null);
}
static string ReadLine(this BinaryReader br)
{
var sb = new StringBuilder();
char c;
while ((c = br.ReadChar()) != '\n')
if (c != '\r' && c != '\n')
sb.Append(c);
return sb.ToString();
}
}
}

View File

@@ -1,65 +1,65 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
namespace OpenRA.FileFormats
{
/* describes what is to be loaded in order to run a set of mods */
public class Manifest
{
public readonly string[]
Mods, Folders, Packages, Rules, ServerTraits,
Sequences, Cursors, Chrome, Assemblies, ChromeLayout,
Weapons, Voices, Music, Movies, TileSets;
public readonly string LoadScreen;
public readonly int TileSize = 24;
public Manifest(string[] mods)
{
Mods = mods;
var yaml = mods
.Select(m => MiniYaml.FromFile("mods/" + m + "/mod.yaml"))
.Aggregate(MiniYaml.Merge);
// Todo: Use fieldloader
Folders = YamlList(yaml, "Folders");
Packages = YamlList(yaml, "Packages");
Rules = YamlList(yaml, "Rules");
ServerTraits = YamlList(yaml, "ServerTraits");
Sequences = YamlList(yaml, "Sequences");
Cursors = YamlList(yaml, "Cursors");
Chrome = YamlList(yaml, "Chrome");
Assemblies = YamlList(yaml, "Assemblies");
ChromeLayout = YamlList(yaml, "ChromeLayout");
Weapons = YamlList(yaml, "Weapons");
Voices = YamlList(yaml, "Voices");
Music = YamlList(yaml, "Music");
Movies = YamlList(yaml, "Movies");
TileSets = YamlList(yaml, "TileSets");
LoadScreen = yaml.First( x => x.Key == "LoadScreen" ).Value.Value;
if (yaml.FirstOrDefault( x => x.Key == "TileSize" ) != null)
TileSize = int.Parse(yaml.First( x => x.Key == "TileSize" ).Value.Value);
}
static string[] YamlList(List<MiniYamlNode> ys, string key)
{
var y = ys.FirstOrDefault( x => x.Key == key );
if( y == null )
return new string[ 0 ];
return y.Value.NodesDict.Keys.ToArray();
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
namespace OpenRA.FileFormats
{
/* describes what is to be loaded in order to run a set of mods */
public class Manifest
{
public readonly string[]
Mods, Folders, Packages, Rules, ServerTraits,
Sequences, Cursors, Chrome, Assemblies, ChromeLayout,
Weapons, Voices, Music, Movies, TileSets;
public readonly string LoadScreen;
public readonly int TileSize = 24;
public Manifest(string[] mods)
{
Mods = mods;
var yaml = mods
.Select(m => MiniYaml.FromFile("mods/" + m + "/mod.yaml"))
.Aggregate(MiniYaml.Merge);
// Todo: Use fieldloader
Folders = YamlList(yaml, "Folders");
Packages = YamlList(yaml, "Packages");
Rules = YamlList(yaml, "Rules");
ServerTraits = YamlList(yaml, "ServerTraits");
Sequences = YamlList(yaml, "Sequences");
Cursors = YamlList(yaml, "Cursors");
Chrome = YamlList(yaml, "Chrome");
Assemblies = YamlList(yaml, "Assemblies");
ChromeLayout = YamlList(yaml, "ChromeLayout");
Weapons = YamlList(yaml, "Weapons");
Voices = YamlList(yaml, "Voices");
Music = YamlList(yaml, "Music");
Movies = YamlList(yaml, "Movies");
TileSets = YamlList(yaml, "TileSets");
LoadScreen = yaml.First( x => x.Key == "LoadScreen" ).Value.Value;
if (yaml.FirstOrDefault( x => x.Key == "TileSize" ) != null)
TileSize = int.Parse(yaml.First( x => x.Key == "TileSize" ).Value.Value);
}
static string[] YamlList(List<MiniYamlNode> ys, string key)
{
var y = ys.FirstOrDefault( x => x.Key == key );
if( y == null )
return new string[ 0 ];
return y.Value.NodesDict.Keys.ToArray();
}
}
}

View File

@@ -1,14 +1,14 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Drawing;
using System.Drawing;
using System;
namespace OpenRA.FileFormats
@@ -18,21 +18,21 @@ namespace OpenRA.FileFormats
public string Name;
public string Palette;
public bool OwnsWorld = false;
public bool NonCombatant = false;
public bool Playable = false;
public bool NonCombatant = false;
public bool Playable = false;
public bool DefaultStartingUnits = false;
public bool AllowBots = true;
public bool LockRace = false;
public string Race;
public bool LockColor = false;
public ColorRamp ColorRamp = new ColorRamp(75, 255, 180, 25);
public int InitialCash = 0;
public string[] Allies = {};
public bool AllowBots = true;
public bool LockRace = false;
public string Race;
public bool LockColor = false;
public ColorRamp ColorRamp = new ColorRamp(75, 255, 180, 25);
public int InitialCash = 0;
public string[] Allies = {};
public string[] Enemies = {};
public PlayerReference() {}
public PlayerReference(MiniYaml my)
{

View File

@@ -1,11 +1,11 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
namespace OpenRA.FileFormats

View File

@@ -1,76 +1,76 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.IO;
namespace OpenRA.FileFormats
{
public class Terrain
{
public readonly List<byte[]> TileBitmapBytes = new List<byte[]>();
public Terrain( Stream stream, int size )
{
// Try loading as a cnc .tem
BinaryReader reader = new BinaryReader( stream );
int Width = reader.ReadUInt16();
int Height = reader.ReadUInt16();
if( Width != size || Height != size )
throw new InvalidDataException( "{0}x{1} != {2}x{2}".F(Width, Height, size ) );
/*NumTiles = */reader.ReadUInt16();
/*Zero1 = */reader.ReadUInt16();
/*uint Size = */reader.ReadUInt32();
uint ImgStart = reader.ReadUInt32();
/*Zero2 = */reader.ReadUInt32();
int IndexEnd, IndexStart;
if (reader.ReadUInt16() == 65535) // ID1 = FFFFh for cnc
{
/*ID2 = */reader.ReadUInt16();
IndexEnd = reader.ReadInt32();
IndexStart = reader.ReadInt32();
}
else // Load as a ra .tem
{
stream.Position = 0;
reader = new BinaryReader( stream );
Width = reader.ReadUInt16();
Height = reader.ReadUInt16();
/*NumTiles = */reader.ReadUInt16();
reader.ReadUInt16();
/*XDim = */reader.ReadUInt16();
/*YDim = */reader.ReadUInt16();
/*uint FileSize = */reader.ReadUInt32();
ImgStart = reader.ReadUInt32();
reader.ReadUInt32();
reader.ReadUInt32();
IndexEnd = reader.ReadInt32();
reader.ReadUInt32();
IndexStart = reader.ReadInt32();
}
stream.Position = IndexStart;
foreach( byte b in new BinaryReader(stream).ReadBytes(IndexEnd - IndexStart) )
{
if (b != 255)
{
stream.Position = ImgStart + b * size * size;
TileBitmapBytes.Add(new BinaryReader(stream).ReadBytes(size * size));
}
else
TileBitmapBytes.Add(null);
}
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.IO;
namespace OpenRA.FileFormats
{
public class Terrain
{
public readonly List<byte[]> TileBitmapBytes = new List<byte[]>();
public Terrain( Stream stream, int size )
{
// Try loading as a cnc .tem
BinaryReader reader = new BinaryReader( stream );
int Width = reader.ReadUInt16();
int Height = reader.ReadUInt16();
if( Width != size || Height != size )
throw new InvalidDataException( "{0}x{1} != {2}x{2}".F(Width, Height, size ) );
/*NumTiles = */reader.ReadUInt16();
/*Zero1 = */reader.ReadUInt16();
/*uint Size = */reader.ReadUInt32();
uint ImgStart = reader.ReadUInt32();
/*Zero2 = */reader.ReadUInt32();
int IndexEnd, IndexStart;
if (reader.ReadUInt16() == 65535) // ID1 = FFFFh for cnc
{
/*ID2 = */reader.ReadUInt16();
IndexEnd = reader.ReadInt32();
IndexStart = reader.ReadInt32();
}
else // Load as a ra .tem
{
stream.Position = 0;
reader = new BinaryReader( stream );
Width = reader.ReadUInt16();
Height = reader.ReadUInt16();
/*NumTiles = */reader.ReadUInt16();
reader.ReadUInt16();
/*XDim = */reader.ReadUInt16();
/*YDim = */reader.ReadUInt16();
/*uint FileSize = */reader.ReadUInt32();
ImgStart = reader.ReadUInt32();
reader.ReadUInt32();
reader.ReadUInt32();
IndexEnd = reader.ReadInt32();
reader.ReadUInt32();
IndexStart = reader.ReadInt32();
}
stream.Position = IndexStart;
foreach( byte b in new BinaryReader(stream).ReadBytes(IndexEnd - IndexStart) )
{
if (b != 255)
{
stream.Position = ImgStart + b * size * size;
TileBitmapBytes.Add(new BinaryReader(stream).ReadBytes(size * size));
}
else
TileBitmapBytes.Add(null);
}
}
}
}

View File

@@ -1,11 +1,11 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
namespace OpenRA.FileFormats

View File

@@ -1,157 +1,157 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
namespace OpenRA.FileFormats
{
public class TerrainTypeInfo
{
public string Type;
public bool Buildable = true;
public bool AcceptSmudge = true;
public bool IsWater = false;
public Color Color;
public TerrainTypeInfo() {}
public TerrainTypeInfo(MiniYaml my) { FieldLoader.Load(this, my); }
public MiniYaml Save() { return FieldSaver.Save(this); }
}
public class TileTemplate
{
[FieldLoader.Load] public ushort Id;
[FieldLoader.Load] public string Image;
[FieldLoader.Load] public int2 Size;
[FieldLoader.Load] public bool PickAny;
[FieldLoader.LoadUsing( "LoadTiles" )]
public Dictionary<byte, string> Tiles = new Dictionary<byte, string>();
public TileTemplate() {}
public TileTemplate(MiniYaml my)
{
FieldLoader.Load( this, my );
}
static object LoadTiles( MiniYaml y )
{
return y.NodesDict["Tiles"].NodesDict.ToDictionary(
t => byte.Parse(t.Key),
t => t.Value.Value );
}
public MiniYaml Save()
{
var root = new List<MiniYamlNode>();
foreach (var field in new string[] {"Id", "Image", "Size", "PickAny"})
{
FieldInfo f = this.GetType().GetField(field);
if (f.GetValue(this) == null) continue;
root.Add( new MiniYamlNode( field, FieldSaver.FormatValue( this, f ) ) );
}
root.Add( new MiniYamlNode( "Tiles", null,
Tiles.Select( x => new MiniYamlNode( x.Key.ToString(), x.Value ) ).ToList() ) );
return new MiniYaml(null, root);
}
}
public class TileSet
{
public string Name;
public string Id;
public string Palette;
public int TileSize = 24;
public string[] Extensions;
public Dictionary<string, TerrainTypeInfo> Terrain = new Dictionary<string, TerrainTypeInfo>();
public Dictionary<ushort, Terrain> Tiles = new Dictionary<ushort, Terrain>();
public Dictionary<ushort, TileTemplate> Templates = new Dictionary<ushort, TileTemplate>();
static List<string> fields = new List<string>() {"Name", "TileSize", "Id", "Palette", "Extensions"};
public TileSet() {}
public TileSet( string filepath )
{
var yaml = MiniYaml.DictFromFile( filepath );
// General info
FieldLoader.Load(this, yaml["General"]);
// TerrainTypes
Terrain = yaml["Terrain"].NodesDict.Values
.Select(y => new TerrainTypeInfo(y)).ToDictionary(t => t.Type);
// Templates
Templates = yaml["Templates"].NodesDict.Values
.Select(y => new TileTemplate(y)).ToDictionary(t => t.Id);
}
public void LoadTiles()
{
foreach (var t in Templates)
using( Stream s = FileSystem.OpenWithExts(t.Value.Image, Extensions) )
{
if( !Tiles.ContainsKey( t.Key ) )
Tiles.Add( t.Key, new Terrain( s, TileSize ) );
}
}
public void Save(string filepath)
{
var root = new List<MiniYamlNode>();
var gen = new List<MiniYamlNode>();
foreach (var field in fields)
{
FieldInfo f = this.GetType().GetField(field);
if (f.GetValue(this) == null) continue;
gen.Add( new MiniYamlNode( field, FieldSaver.FormatValue( this, f ) ) );
}
root.Add( new MiniYamlNode( "General", null, gen ) );
root.Add( new MiniYamlNode( "Terrain", null,
Terrain.Select( t => new MiniYamlNode(
"TerrainType@{0}".F( t.Value.Type ),
t.Value.Save() ) ).ToList() ) );
root.Add( new MiniYamlNode( "Templates", null,
Templates.Select( t => new MiniYamlNode(
"Template@{0}".F( t.Value.Id ),
t.Value.Save() ) ).ToList() ) );
root.WriteToFile(filepath);
}
public byte[] GetBytes(TileReference<ushort,byte> r)
{
Terrain tile;
if( Tiles.TryGetValue( r.type, out tile ) )
return tile.TileBitmapBytes[ r.index ];
byte[] missingTile = new byte[ TileSize * TileSize ];
for( int i = 0 ; i < missingTile.Length ; i++ )
missingTile[ i ] = 0x36;
return missingTile;
}
public string GetTerrainType(TileReference<ushort, byte> r)
{
var tt = Templates[r.type].Tiles;
string ret;
if (!tt.TryGetValue(r.index, out ret))
return "Clear"; // Default walkable
return ret;
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
namespace OpenRA.FileFormats
{
public class TerrainTypeInfo
{
public string Type;
public bool Buildable = true;
public bool AcceptSmudge = true;
public bool IsWater = false;
public Color Color;
public TerrainTypeInfo() {}
public TerrainTypeInfo(MiniYaml my) { FieldLoader.Load(this, my); }
public MiniYaml Save() { return FieldSaver.Save(this); }
}
public class TileTemplate
{
[FieldLoader.Load] public ushort Id;
[FieldLoader.Load] public string Image;
[FieldLoader.Load] public int2 Size;
[FieldLoader.Load] public bool PickAny;
[FieldLoader.LoadUsing( "LoadTiles" )]
public Dictionary<byte, string> Tiles = new Dictionary<byte, string>();
public TileTemplate() {}
public TileTemplate(MiniYaml my)
{
FieldLoader.Load( this, my );
}
static object LoadTiles( MiniYaml y )
{
return y.NodesDict["Tiles"].NodesDict.ToDictionary(
t => byte.Parse(t.Key),
t => t.Value.Value );
}
public MiniYaml Save()
{
var root = new List<MiniYamlNode>();
foreach (var field in new string[] {"Id", "Image", "Size", "PickAny"})
{
FieldInfo f = this.GetType().GetField(field);
if (f.GetValue(this) == null) continue;
root.Add( new MiniYamlNode( field, FieldSaver.FormatValue( this, f ) ) );
}
root.Add( new MiniYamlNode( "Tiles", null,
Tiles.Select( x => new MiniYamlNode( x.Key.ToString(), x.Value ) ).ToList() ) );
return new MiniYaml(null, root);
}
}
public class TileSet
{
public string Name;
public string Id;
public string Palette;
public int TileSize = 24;
public string[] Extensions;
public Dictionary<string, TerrainTypeInfo> Terrain = new Dictionary<string, TerrainTypeInfo>();
public Dictionary<ushort, Terrain> Tiles = new Dictionary<ushort, Terrain>();
public Dictionary<ushort, TileTemplate> Templates = new Dictionary<ushort, TileTemplate>();
static List<string> fields = new List<string>() {"Name", "TileSize", "Id", "Palette", "Extensions"};
public TileSet() {}
public TileSet( string filepath )
{
var yaml = MiniYaml.DictFromFile( filepath );
// General info
FieldLoader.Load(this, yaml["General"]);
// TerrainTypes
Terrain = yaml["Terrain"].NodesDict.Values
.Select(y => new TerrainTypeInfo(y)).ToDictionary(t => t.Type);
// Templates
Templates = yaml["Templates"].NodesDict.Values
.Select(y => new TileTemplate(y)).ToDictionary(t => t.Id);
}
public void LoadTiles()
{
foreach (var t in Templates)
using( Stream s = FileSystem.OpenWithExts(t.Value.Image, Extensions) )
{
if( !Tiles.ContainsKey( t.Key ) )
Tiles.Add( t.Key, new Terrain( s, TileSize ) );
}
}
public void Save(string filepath)
{
var root = new List<MiniYamlNode>();
var gen = new List<MiniYamlNode>();
foreach (var field in fields)
{
FieldInfo f = this.GetType().GetField(field);
if (f.GetValue(this) == null) continue;
gen.Add( new MiniYamlNode( field, FieldSaver.FormatValue( this, f ) ) );
}
root.Add( new MiniYamlNode( "General", null, gen ) );
root.Add( new MiniYamlNode( "Terrain", null,
Terrain.Select( t => new MiniYamlNode(
"TerrainType@{0}".F( t.Value.Type ),
t.Value.Save() ) ).ToList() ) );
root.Add( new MiniYamlNode( "Templates", null,
Templates.Select( t => new MiniYamlNode(
"Template@{0}".F( t.Value.Id ),
t.Value.Save() ) ).ToList() ) );
root.WriteToFile(filepath);
}
public byte[] GetBytes(TileReference<ushort,byte> r)
{
Terrain tile;
if( Tiles.TryGetValue( r.type, out tile ) )
return tile.TileBitmapBytes[ r.index ];
byte[] missingTile = new byte[ TileSize * TileSize ];
for( int i = 0 ; i < missingTile.Length ; i++ )
missingTile[ i ] = 0x36;
return missingTile;
}
public string GetTerrainType(TileReference<ushort, byte> r)
{
var tt = Templates[r.type].Tiles;
string ret;
if (!tt.TryGetValue(r.index, out ret))
return "Clear"; // Default walkable
return ret;
}
}
}

View File

@@ -1,240 +1,240 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace OpenRA.FileFormats
{
using MiniYamlNodes = List<MiniYamlNode>;
public class MiniYamlNode
{
public struct SourceLocation
{
public string Filename; public int Line;
}
public SourceLocation Location;
public string Key;
public MiniYaml Value;
public MiniYamlNode( string k, MiniYaml v )
{
Key = k;
Value = v;
}
public MiniYamlNode( string k, MiniYaml v, SourceLocation loc )
: this( k, v )
{
Location = loc;
}
public MiniYamlNode( string k, string v )
: this( k, v, null )
{
}
public MiniYamlNode( string k, string v, List<MiniYamlNode> n )
: this( k, new MiniYaml( v, n ) )
{
}
public MiniYamlNode( string k, string v, List<MiniYamlNode> n, SourceLocation loc )
: this( k, new MiniYaml( v, n ), loc )
{
}
}
public class MiniYaml
{
public string Value;
public List<MiniYamlNode> Nodes;
public Dictionary<string, MiniYaml> NodesDict { get { return Nodes.ToDictionary( x => x.Key, x => x.Value ); } }
public MiniYaml( string value ) : this( value, null ) { }
public MiniYaml( string value, List<MiniYamlNode> nodes )
{
Value = value;
Nodes = nodes ?? new List<MiniYamlNode>();
}
public static MiniYaml FromDictionary<K, V>( Dictionary<K, V> dict )
{
return new MiniYaml( null, dict.Select( x => new MiniYamlNode( x.Key.ToString(), new MiniYaml( x.Value.ToString() ) ) ).ToList() );
}
public static MiniYaml FromList<T>( List<T> list )
{
return new MiniYaml( null, list.Select( x => new MiniYamlNode( x.ToString(), new MiniYaml( null ) ) ).ToList() );
}
static List<MiniYamlNode> FromLines(string[] lines, string filename)
{
var levels = new List<List<MiniYamlNode>>();
levels.Add(new List<MiniYamlNode>());
var lineNo = 0;
foreach (var line in lines)
{
++lineNo;
var t = line.TrimStart(' ', '\t');
if (t.Length == 0 || t[0] == '#')
continue;
var level = line.Length - t.Length;
if (levels.Count <= level)
throw new InvalidOperationException("Bad indent in miniyaml");
while (levels.Count > level + 1)
levels.RemoveAt(levels.Count - 1);
var d = new List<MiniYamlNode>();
var rhs = SplitAtColon( ref t );
levels[ level ].Add( new MiniYamlNode( t, rhs, d, new MiniYamlNode.SourceLocation { Filename = filename, Line = lineNo } ) );
levels.Add(d);
}
return levels[ 0 ];
}
static string SplitAtColon( ref string t )
{
var colon = t.IndexOf(':');
if( colon == -1 )
return null;
var ret = t.Substring( colon + 1 ).Trim();
if( ret.Length == 0 )
ret = null;
t = t.Substring( 0, colon ).Trim();
return ret;
}
public static List<MiniYamlNode> FromFileInPackage( string path )
{
StreamReader reader = new StreamReader( FileSystem.Open(path) );
List<string> lines = new List<string>();
while( !reader.EndOfStream )
lines.Add(reader.ReadLine());
reader.Close();
return FromLines(lines.ToArray(), path);
}
public static Dictionary<string, MiniYaml> DictFromFile( string path )
{
return FromFile( path ).ToDictionary( x => x.Key, x => x.Value );
}
public static Dictionary<string, MiniYaml> DictFromStream( Stream stream )
{
return FromStream( stream ).ToDictionary( x => x.Key, x => x.Value );
}
public static List<MiniYamlNode> FromFile( string path )
{
return FromLines(File.ReadAllLines( path ), path);
}
public static List<MiniYamlNode> FromStream(Stream s)
{
using (var reader = new StreamReader(s))
return FromString(reader.ReadToEnd());
}
public static List<MiniYamlNode> FromString(string text)
{
return FromLines(text.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries), "<no filename available>");
}
public static List<MiniYamlNode> Merge( List<MiniYamlNode> a, List<MiniYamlNode> b )
{
if( a.Count == 0 )
return b;
if( b.Count == 0 )
return a;
var ret = new List<MiniYamlNode>();
var aDict = a.ToDictionary( x => x.Key );
var bDict = b.ToDictionary( x => x.Key );
var keys = aDict.Keys.Union( bDict.Keys ).ToList();
var noInherit = keys.Where( x => x.Length > 0 && x[ 0 ] == '-' ).Select( x => x.Substring( 1 ) ).ToList();
foreach( var key in keys )
{
MiniYamlNode aa, bb;
aDict.TryGetValue( key, out aa );
bDict.TryGetValue( key, out bb );
if( noInherit.Contains( key ) )
{
if( aa != null )
ret.Add( aa );
}
else
{
var loc = aa == null ? default( MiniYamlNode.SourceLocation ) : aa.Location;
var merged = ( aa == null || bb == null ) ? aa ?? bb : new MiniYamlNode( key, Merge( aa.Value, bb.Value ), loc );
ret.Add( merged );
}
}
return ret;
}
public static MiniYaml Merge( MiniYaml a, MiniYaml b )
{
if( a == null )
return b;
if( b == null )
return a;
return new MiniYaml( a.Value ?? b.Value, Merge( a.Nodes, b.Nodes ) );
}
public IEnumerable<string> ToLines(string name)
{
yield return name + ": " + Value;
if (Nodes != null)
foreach (var line in Nodes.ToLines(false))
yield return "\t" + line;
}
}
public static class MiniYamlExts
{
public static void WriteToFile(this MiniYamlNodes y, string filename)
{
File.WriteAllLines(filename, y.ToLines(true).Select(x => x.TrimEnd()).ToArray());
}
public static string WriteToString(this MiniYamlNodes y)
{
return string.Join("\n", y.ToLines(true).Select(x => x.TrimEnd()).ToArray());
}
public static IEnumerable<string> ToLines(this MiniYamlNodes y, bool lowest)
{
foreach (var kv in y)
{
foreach (var line in kv.Value.ToLines(kv.Key))
yield return line;
if (lowest)
yield return "";
}
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace OpenRA.FileFormats
{
using MiniYamlNodes = List<MiniYamlNode>;
public class MiniYamlNode
{
public struct SourceLocation
{
public string Filename; public int Line;
}
public SourceLocation Location;
public string Key;
public MiniYaml Value;
public MiniYamlNode( string k, MiniYaml v )
{
Key = k;
Value = v;
}
public MiniYamlNode( string k, MiniYaml v, SourceLocation loc )
: this( k, v )
{
Location = loc;
}
public MiniYamlNode( string k, string v )
: this( k, v, null )
{
}
public MiniYamlNode( string k, string v, List<MiniYamlNode> n )
: this( k, new MiniYaml( v, n ) )
{
}
public MiniYamlNode( string k, string v, List<MiniYamlNode> n, SourceLocation loc )
: this( k, new MiniYaml( v, n ), loc )
{
}
}
public class MiniYaml
{
public string Value;
public List<MiniYamlNode> Nodes;
public Dictionary<string, MiniYaml> NodesDict { get { return Nodes.ToDictionary( x => x.Key, x => x.Value ); } }
public MiniYaml( string value ) : this( value, null ) { }
public MiniYaml( string value, List<MiniYamlNode> nodes )
{
Value = value;
Nodes = nodes ?? new List<MiniYamlNode>();
}
public static MiniYaml FromDictionary<K, V>( Dictionary<K, V> dict )
{
return new MiniYaml( null, dict.Select( x => new MiniYamlNode( x.Key.ToString(), new MiniYaml( x.Value.ToString() ) ) ).ToList() );
}
public static MiniYaml FromList<T>( List<T> list )
{
return new MiniYaml( null, list.Select( x => new MiniYamlNode( x.ToString(), new MiniYaml( null ) ) ).ToList() );
}
static List<MiniYamlNode> FromLines(string[] lines, string filename)
{
var levels = new List<List<MiniYamlNode>>();
levels.Add(new List<MiniYamlNode>());
var lineNo = 0;
foreach (var line in lines)
{
++lineNo;
var t = line.TrimStart(' ', '\t');
if (t.Length == 0 || t[0] == '#')
continue;
var level = line.Length - t.Length;
if (levels.Count <= level)
throw new InvalidOperationException("Bad indent in miniyaml");
while (levels.Count > level + 1)
levels.RemoveAt(levels.Count - 1);
var d = new List<MiniYamlNode>();
var rhs = SplitAtColon( ref t );
levels[ level ].Add( new MiniYamlNode( t, rhs, d, new MiniYamlNode.SourceLocation { Filename = filename, Line = lineNo } ) );
levels.Add(d);
}
return levels[ 0 ];
}
static string SplitAtColon( ref string t )
{
var colon = t.IndexOf(':');
if( colon == -1 )
return null;
var ret = t.Substring( colon + 1 ).Trim();
if( ret.Length == 0 )
ret = null;
t = t.Substring( 0, colon ).Trim();
return ret;
}
public static List<MiniYamlNode> FromFileInPackage( string path )
{
StreamReader reader = new StreamReader( FileSystem.Open(path) );
List<string> lines = new List<string>();
while( !reader.EndOfStream )
lines.Add(reader.ReadLine());
reader.Close();
return FromLines(lines.ToArray(), path);
}
public static Dictionary<string, MiniYaml> DictFromFile( string path )
{
return FromFile( path ).ToDictionary( x => x.Key, x => x.Value );
}
public static Dictionary<string, MiniYaml> DictFromStream( Stream stream )
{
return FromStream( stream ).ToDictionary( x => x.Key, x => x.Value );
}
public static List<MiniYamlNode> FromFile( string path )
{
return FromLines(File.ReadAllLines( path ), path);
}
public static List<MiniYamlNode> FromStream(Stream s)
{
using (var reader = new StreamReader(s))
return FromString(reader.ReadToEnd());
}
public static List<MiniYamlNode> FromString(string text)
{
return FromLines(text.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries), "<no filename available>");
}
public static List<MiniYamlNode> Merge( List<MiniYamlNode> a, List<MiniYamlNode> b )
{
if( a.Count == 0 )
return b;
if( b.Count == 0 )
return a;
var ret = new List<MiniYamlNode>();
var aDict = a.ToDictionary( x => x.Key );
var bDict = b.ToDictionary( x => x.Key );
var keys = aDict.Keys.Union( bDict.Keys ).ToList();
var noInherit = keys.Where( x => x.Length > 0 && x[ 0 ] == '-' ).Select( x => x.Substring( 1 ) ).ToList();
foreach( var key in keys )
{
MiniYamlNode aa, bb;
aDict.TryGetValue( key, out aa );
bDict.TryGetValue( key, out bb );
if( noInherit.Contains( key ) )
{
if( aa != null )
ret.Add( aa );
}
else
{
var loc = aa == null ? default( MiniYamlNode.SourceLocation ) : aa.Location;
var merged = ( aa == null || bb == null ) ? aa ?? bb : new MiniYamlNode( key, Merge( aa.Value, bb.Value ), loc );
ret.Add( merged );
}
}
return ret;
}
public static MiniYaml Merge( MiniYaml a, MiniYaml b )
{
if( a == null )
return b;
if( b == null )
return a;
return new MiniYaml( a.Value ?? b.Value, Merge( a.Nodes, b.Nodes ) );
}
public IEnumerable<string> ToLines(string name)
{
yield return name + ": " + Value;
if (Nodes != null)
foreach (var line in Nodes.ToLines(false))
yield return "\t" + line;
}
}
public static class MiniYamlExts
{
public static void WriteToFile(this MiniYamlNodes y, string filename)
{
File.WriteAllLines(filename, y.ToLines(true).Select(x => x.TrimEnd()).ToArray());
}
public static string WriteToString(this MiniYamlNodes y)
{
return string.Join("\n", y.ToLines(true).Select(x => x.TrimEnd()).ToArray());
}
public static IEnumerable<string> ToLines(this MiniYamlNodes y, bool lowest)
{
foreach (var kv in y)
{
foreach (var line in kv.Value.ToLines(kv.Key))
yield return line;
if (lowest)
yield return "";
}
}
}
}

View File

@@ -1,85 +1,85 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace OpenRA.FileFormats
{
public class PackageEntry
{
public readonly uint Hash;
public readonly uint Offset;
public readonly uint Length;
public PackageEntry(uint hash, uint offset, uint length)
{
Hash = hash;
Offset = offset;
Length = length;
}
public PackageEntry(BinaryReader r)
{
Hash = r.ReadUInt32();
Offset = r.ReadUInt32();
Length = r.ReadUInt32();
}
public void Write(BinaryWriter w)
{
w.Write(Hash);
w.Write(Offset);
w.Write(Length);
}
public override string ToString()
{
string filename;
if (Names.TryGetValue(Hash, out filename))
return string.Format("{0} - offset 0x{1:x8} - length 0x{2:x8}", filename, Offset, Length);
else
return string.Format("0x{0:x8} - offset 0x{1:x8} - length 0x{2:x8}", Hash, Offset, Length);
}
public static uint HashFilename(string name)
{
if (name.Length > 12)
name = name.Substring(0, 12);
name = name.ToUpperInvariant();
if (name.Length % 4 != 0)
name = name.PadRight(name.Length + (4 - name.Length % 4), '\0');
MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(name));
BinaryReader reader = new BinaryReader(ms);
int len = name.Length >> 2;
uint result = 0;
while (len-- != 0)
result = ((result << 1) | (result >> 31)) + reader.ReadUInt32();
return result;
}
static Dictionary<uint, string> Names = new Dictionary<uint,string>();
public static void AddStandardName(string s)
{
uint hash = HashFilename(s);
Names.Add(hash, s);
}
public const int Size = 12;
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace OpenRA.FileFormats
{
public class PackageEntry
{
public readonly uint Hash;
public readonly uint Offset;
public readonly uint Length;
public PackageEntry(uint hash, uint offset, uint length)
{
Hash = hash;
Offset = offset;
Length = length;
}
public PackageEntry(BinaryReader r)
{
Hash = r.ReadUInt32();
Offset = r.ReadUInt32();
Length = r.ReadUInt32();
}
public void Write(BinaryWriter w)
{
w.Write(Hash);
w.Write(Offset);
w.Write(Length);
}
public override string ToString()
{
string filename;
if (Names.TryGetValue(Hash, out filename))
return string.Format("{0} - offset 0x{1:x8} - length 0x{2:x8}", filename, Offset, Length);
else
return string.Format("0x{0:x8} - offset 0x{1:x8} - length 0x{2:x8}", Hash, Offset, Length);
}
public static uint HashFilename(string name)
{
if (name.Length > 12)
name = name.Substring(0, 12);
name = name.ToUpperInvariant();
if (name.Length % 4 != 0)
name = name.PadRight(name.Length + (4 - name.Length % 4), '\0');
MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(name));
BinaryReader reader = new BinaryReader(ms);
int len = name.Length >> 2;
uint result = 0;
while (len-- != 0)
result = ((result << 1) | (result >> 31)) + reader.ReadUInt32();
return result;
}
static Dictionary<uint, string> Names = new Dictionary<uint,string>();
public static void AddStandardName(string s)
{
uint hash = HashFilename(s);
Names.Add(hash, s);
}
public const int Size = 12;
}
}

View File

@@ -1,77 +1,77 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Drawing;
using System.IO;
namespace OpenRA.FileFormats
{
public class Palette
{
uint[] colors;
public Color GetColor(int index)
{
return Color.FromArgb((int)colors[index]);
}
public void SetColor(int index, Color color)
{
colors[index] = (uint)color.ToArgb();
}
public void SetColor(int index, uint color)
{
colors[index] = (uint)color;
}
public uint[] Values
{
get { return colors; }
}
public Palette(Stream s, bool remapTransparent)
{
colors = new uint[256];
using (BinaryReader reader = new BinaryReader(s))
{
for (int i = 0; i < 256; i++)
{
byte r = (byte)(reader.ReadByte() << 2);
byte g = (byte)(reader.ReadByte() << 2);
byte b = (byte)(reader.ReadByte() << 2);
colors[i] = (uint)((255 << 24) | (r << 16) | (g << 8) | b);
}
}
colors[0] = 0;
if (remapTransparent)
{
colors[1] = 178u << 24; // Hack for d2k; may have side effects
colors[3] = 178u << 24;
colors[4] = 140u << 24;
}
}
public Palette(Palette p, IPaletteRemap r)
{
colors = new uint[256];
for(int i = 0; i < 256; i++)
colors[i] = (uint)r.GetRemappedColor(Color.FromArgb((int)p.colors[i]),i).ToArgb();
}
public Palette(Palette p)
{
colors = (uint[])p.colors.Clone();
}
}
public interface IPaletteRemap { Color GetRemappedColor(Color original, int index); }
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Drawing;
using System.IO;
namespace OpenRA.FileFormats
{
public class Palette
{
uint[] colors;
public Color GetColor(int index)
{
return Color.FromArgb((int)colors[index]);
}
public void SetColor(int index, Color color)
{
colors[index] = (uint)color.ToArgb();
}
public void SetColor(int index, uint color)
{
colors[index] = (uint)color;
}
public uint[] Values
{
get { return colors; }
}
public Palette(Stream s, bool remapTransparent)
{
colors = new uint[256];
using (BinaryReader reader = new BinaryReader(s))
{
for (int i = 0; i < 256; i++)
{
byte r = (byte)(reader.ReadByte() << 2);
byte g = (byte)(reader.ReadByte() << 2);
byte b = (byte)(reader.ReadByte() << 2);
colors[i] = (uint)((255 << 24) | (r << 16) | (g << 8) | b);
}
}
colors[0] = 0;
if (remapTransparent)
{
colors[1] = 178u << 24; // Hack for d2k; may have side effects
colors[3] = 178u << 24;
colors[4] = 140u << 24;
}
}
public Palette(Palette p, IPaletteRemap r)
{
colors = new uint[256];
for(int i = 0; i < 256; i++)
colors[i] = (uint)r.GetRemappedColor(Color.FromArgb((int)p.colors[i]),i).ToArgb();
}
public Palette(Palette p)
{
colors = (uint[])p.colors.Clone();
}
}
public interface IPaletteRemap { Color GetRemappedColor(Color original, int index); }
}

View File

@@ -1,53 +1,53 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
namespace OpenRA.FileFormats
{
// TODO: ship this out of here.
public enum PaletteFormat { ra, cnc, d2k }
public class PlayerColorRemap : IPaletteRemap
{
Dictionary<int, Color> remapColors;
public PlayerColorRemap(ColorRamp c, PaletteFormat fmt)
{
var c1 = c.GetColor(0);
var c2 = c.GetColor(1); /* temptemp: this can be expressed better */
var baseIndex = (fmt == PaletteFormat.cnc) ? 0xb0 : (fmt == PaletteFormat.d2k) ? 240 : 80;
var ramp = (fmt == PaletteFormat.cnc)
? new[] { 0, 2, 4, 6, 8, 10, 13, 15, 1, 3, 5, 7, 9, 11, 12, 14 }
: new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
remapColors = ramp.Select((x, i) => Pair.New(baseIndex + i, ColorLerp(x / 16f, c1, c2)))
.ToDictionary(u => u.First, u => u.Second);
}
public static Color ColorLerp(float t, Color c1, Color c2)
{
return Color.FromArgb(255,
(int)(t * c2.R + (1 - t) * c1.R),
(int)(t * c2.G + (1 - t) * c1.G),
(int)(t * c2.B + (1 - t) * c1.B));
}
public Color GetRemappedColor(Color original, int index)
{
Color c;
return remapColors.TryGetValue(index, out c)
? c : original;
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
namespace OpenRA.FileFormats
{
// TODO: ship this out of here.
public enum PaletteFormat { ra, cnc, d2k }
public class PlayerColorRemap : IPaletteRemap
{
Dictionary<int, Color> remapColors;
public PlayerColorRemap(ColorRamp c, PaletteFormat fmt)
{
var c1 = c.GetColor(0);
var c2 = c.GetColor(1); /* temptemp: this can be expressed better */
var baseIndex = (fmt == PaletteFormat.cnc) ? 0xb0 : (fmt == PaletteFormat.d2k) ? 240 : 80;
var ramp = (fmt == PaletteFormat.cnc)
? new[] { 0, 2, 4, 6, 8, 10, 13, 15, 1, 3, 5, 7, 9, 11, 12, 14 }
: new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
remapColors = ramp.Select((x, i) => Pair.New(baseIndex + i, ColorLerp(x / 16f, c1, c2)))
.ToDictionary(u => u.First, u => u.Second);
}
public static Color ColorLerp(float t, Color c1, Color c2)
{
return Color.FromArgb(255,
(int)(t * c2.R + (1 - t) * c1.R),
(int)(t * c2.G + (1 - t) * c1.G),
(int)(t * c2.B + (1 - t) * c1.B));
}
public Color GetRemappedColor(Color original, int index)
{
Color c;
return remapColors.TryGetValue(index, out c)
? c : original;
}
}
}

View File

@@ -1,40 +1,40 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
namespace OpenRA.FileFormats
{
/// <summary>
/// A thread-safe action queue, suitable for passing units of work between threads.
/// </summary>
public class ActionQueue
{
object syncRoot = new object();
Action actions = () => { };
public void Add(Action a)
{
lock (syncRoot)
actions += a;
}
public void PerformActions()
{
Action a;
lock (syncRoot)
{
a = actions;
actions = () => { };
}
a();
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
namespace OpenRA.FileFormats
{
/// <summary>
/// A thread-safe action queue, suitable for passing units of work between threads.
/// </summary>
public class ActionQueue
{
object syncRoot = new object();
Action actions = () => { };
public void Add(Action a)
{
lock (syncRoot)
actions += a;
}
public void PerformActions()
{
Action a;
lock (syncRoot)
{
a = actions;
actions = () => { };
}
a();
}
}
}

View File

@@ -1,49 +1,49 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
namespace OpenRA.FileFormats
{
public class Cache<T, U> : IEnumerable<KeyValuePair<T, U>>
{
Dictionary<T, U> hax = new Dictionary<T, U>();
Func<T,U> loader;
public Cache(Func<T,U> loader)
{
if (loader == null)
throw new ArgumentNullException();
this.loader = loader;
}
public U this[T key]
{
get
{
U result;
if (!hax.TryGetValue(key, out result))
hax.Add(key, result = loader(key));
return result;
}
}
public IEnumerator<KeyValuePair<T, U>> GetEnumerator() { return hax.GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
public IEnumerable<T> Keys { get { return hax.Keys; } }
public IEnumerable<U> Values { get { return hax.Values; } }
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
namespace OpenRA.FileFormats
{
public class Cache<T, U> : IEnumerable<KeyValuePair<T, U>>
{
Dictionary<T, U> hax = new Dictionary<T, U>();
Func<T,U> loader;
public Cache(Func<T,U> loader)
{
if (loader == null)
throw new ArgumentNullException();
this.loader = loader;
}
public U this[T key]
{
get
{
U result;
if (!hax.TryGetValue(key, out result))
hax.Add(key, result = loader(key));
return result;
}
}
public IEnumerator<KeyValuePair<T, U>> GetEnumerator() { return hax.GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
public IEnumerable<T> Keys { get { return hax.Keys; } }
public IEnumerable<U> Values { get { return hax.Values; } }
}
}

View File

@@ -1,35 +1,35 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
namespace OpenRA
{
public class DisposableAction : IDisposable
{
public DisposableAction(Action a) { this.a = a; }
Action a;
bool disposed;
public void Dispose()
{
if (disposed) return;
disposed = true;
a();
GC.SuppressFinalize(this);
}
~DisposableAction()
{
Dispose();
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
namespace OpenRA
{
public class DisposableAction : IDisposable
{
public DisposableAction(Action a) { this.a = a; }
Action a;
bool disposed;
public void Dispose()
{
if (disposed) return;
disposed = true;
a();
GC.SuppressFinalize(this);
}
~DisposableAction()
{
Dispose();
}
}
}

View File

@@ -1,46 +1,46 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
namespace OpenRA.FileFormats
{
public class Lazy<T>
{
Func<T> p;
T value;
public Lazy(Func<T> p)
{
if (p == null)
throw new ArgumentNullException();
this.p = p;
}
public T Value
{
get
{
if (p == null)
return value;
value = p();
p = null;
return value;
}
}
}
public static class Lazy
{
public static Lazy<T> New<T>(Func<T> p) { return new Lazy<T>(p); }
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
namespace OpenRA.FileFormats
{
public class Lazy<T>
{
Func<T> p;
T value;
public Lazy(Func<T> p)
{
if (p == null)
throw new ArgumentNullException();
this.p = p;
}
public T Value
{
get
{
if (p == null)
return value;
value = p();
p = null;
return value;
}
}
}
public static class Lazy
{
public static Lazy<T> New<T>(Func<T> p) { return new Lazy<T>(p); }
}
}

View File

@@ -1,70 +1,70 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
namespace OpenRA.FileFormats
{
public struct Pair<T, U>
{
public T First;
public U Second;
public Pair(T first, U second)
{
First = first;
Second = second;
}
static IEqualityComparer<T> tc = EqualityComparer<T>.Default;
static IEqualityComparer<U> uc = EqualityComparer<U>.Default;
public static bool operator ==(Pair<T, U> a, Pair<T, U> b)
{
return tc.Equals(a.First, b.First) && uc.Equals(a.Second, b.Second);
}
public static bool operator !=(Pair<T, U> a, Pair<T, U> b)
{
return !(a == b);
}
public override bool Equals(object obj)
{
if (!(obj is Pair<T, U>))
return false;
return (Pair<T, U>)obj == this;
}
public override int GetHashCode()
{
return First.GetHashCode() ^ Second.GetHashCode();
}
public Pair<T, U> WithFirst(T t) { return new Pair<T, U>(t, Second); }
public Pair<T, U> WithSecond(U u) { return new Pair<T, U>(First, u); }
public static T AsFirst(Pair<T, U> p) { return p.First; }
public static U AsSecond(Pair<T, U> p) { return p.Second; }
public Pair<U, T> Swap() { return Pair.New(Second, First); }
public override string ToString()
{
return "({0},{1})".F(First, Second);
}
}
public static class Pair
{
public static Pair<T, U> New<T, U>(T t, U u) { return new Pair<T, U>(t, u); }
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
namespace OpenRA.FileFormats
{
public struct Pair<T, U>
{
public T First;
public U Second;
public Pair(T first, U second)
{
First = first;
Second = second;
}
static IEqualityComparer<T> tc = EqualityComparer<T>.Default;
static IEqualityComparer<U> uc = EqualityComparer<U>.Default;
public static bool operator ==(Pair<T, U> a, Pair<T, U> b)
{
return tc.Equals(a.First, b.First) && uc.Equals(a.Second, b.Second);
}
public static bool operator !=(Pair<T, U> a, Pair<T, U> b)
{
return !(a == b);
}
public override bool Equals(object obj)
{
if (!(obj is Pair<T, U>))
return false;
return (Pair<T, U>)obj == this;
}
public override int GetHashCode()
{
return First.GetHashCode() ^ Second.GetHashCode();
}
public Pair<T, U> WithFirst(T t) { return new Pair<T, U>(t, Second); }
public Pair<T, U> WithSecond(U u) { return new Pair<T, U>(First, u); }
public static T AsFirst(Pair<T, U> p) { return p.First; }
public static U AsSecond(Pair<T, U> p) { return p.Second; }
public Pair<U, T> Swap() { return Pair.New(Second, First); }
public override string ToString()
{
return "({0},{1})".F(First, Second);
}
}
public static class Pair
{
public static Pair<T, U> New<T, U>(T t, U u) { return new Pair<T, U>(t, u); }
}
}

View File

@@ -1,103 +1,103 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
namespace OpenRA.FileFormats
{
public class PriorityQueue<T>
where T : IComparable<T>
{
List<T[]> items = new List<T[]>();
int level, index;
public PriorityQueue()
{
items.Add(new T[1]);
}
public void Add(T item)
{
int addLevel = level;
int addIndex = index;
while (addLevel >= 1 && Above(addLevel, addIndex).CompareTo(item) > 0)
{
items[addLevel][addIndex] = Above(addLevel, addIndex);
--addLevel;
addIndex >>= 1;
}
items[addLevel][addIndex] = item;
if (++index >= (1 << level))
{
index = 0;
if (items.Count <= ++level)
items.Add(new T[1 << level]);
}
}
public bool Empty { get { return (level == 0); } }
T At(int level, int index) { return items[level][index]; }
T Above(int level, int index) { return items[level - 1][index >> 1]; }
T Last()
{
int lastLevel = level;
int lastIndex = index;
if (--lastIndex < 0)
lastIndex = (1 << --lastLevel) - 1;
return At(lastLevel, lastIndex);
}
public T Pop()
{
if (level == 0 && index == 0)
throw new InvalidOperationException("Attempting to pop empty PriorityQueue");
T ret = At(0, 0);
BubbleInto(0, 0, Last());
if (--index < 0)
index = (1 << --level) - 1;
return ret;
}
void BubbleInto(int intoLevel, int intoIndex, T val)
{
int downLevel = intoLevel + 1;
int downIndex = intoIndex << 1;
if (downLevel > level || (downLevel == level && downIndex >= index))
{
items[intoLevel][intoIndex] = val;
return;
}
if (downLevel <= level && downIndex < index - 1 &&
At(downLevel, downIndex).CompareTo(At(downLevel, downIndex + 1)) >= 0)
++downIndex;
if (val.CompareTo(At(downLevel, downIndex)) <= 0)
{
items[intoLevel][intoIndex] = val;
return;
}
items[intoLevel][intoIndex] = At(downLevel, downIndex);
BubbleInto(downLevel, downIndex, val);
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
namespace OpenRA.FileFormats
{
public class PriorityQueue<T>
where T : IComparable<T>
{
List<T[]> items = new List<T[]>();
int level, index;
public PriorityQueue()
{
items.Add(new T[1]);
}
public void Add(T item)
{
int addLevel = level;
int addIndex = index;
while (addLevel >= 1 && Above(addLevel, addIndex).CompareTo(item) > 0)
{
items[addLevel][addIndex] = Above(addLevel, addIndex);
--addLevel;
addIndex >>= 1;
}
items[addLevel][addIndex] = item;
if (++index >= (1 << level))
{
index = 0;
if (items.Count <= ++level)
items.Add(new T[1 << level]);
}
}
public bool Empty { get { return (level == 0); } }
T At(int level, int index) { return items[level][index]; }
T Above(int level, int index) { return items[level - 1][index >> 1]; }
T Last()
{
int lastLevel = level;
int lastIndex = index;
if (--lastIndex < 0)
lastIndex = (1 << --lastLevel) - 1;
return At(lastLevel, lastIndex);
}
public T Pop()
{
if (level == 0 && index == 0)
throw new InvalidOperationException("Attempting to pop empty PriorityQueue");
T ret = At(0, 0);
BubbleInto(0, 0, Last());
if (--index < 0)
index = (1 << --level) - 1;
return ret;
}
void BubbleInto(int intoLevel, int intoIndex, T val)
{
int downLevel = intoLevel + 1;
int downIndex = intoIndex << 1;
if (downLevel > level || (downLevel == level && downIndex >= index))
{
items[intoLevel][intoIndex] = val;
return;
}
if (downLevel <= level && downIndex < index - 1 &&
At(downLevel, downIndex).CompareTo(At(downLevel, downIndex + 1)) >= 0)
++downIndex;
if (val.CompareTo(At(downLevel, downIndex)) <= 0)
{
items[intoLevel][intoIndex] = val;
return;
}
items[intoLevel][intoIndex] = At(downLevel, downIndex);
BubbleInto(downLevel, downIndex, val);
}
}
}

View File

@@ -1,66 +1,66 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
namespace OpenRA.Collections
{
public class Set<T> : IEnumerable<T>
{
Dictionary<T, bool> data = new Dictionary<T, bool>();
public void Add( T obj )
{
data.Add( obj, false );
if( OnAdd != null )
OnAdd( obj );
}
public void Remove( T obj )
{
data.Remove( obj );
if( OnRemove != null )
OnRemove( obj );
}
public event Action<T> OnAdd;
public event Action<T> OnRemove;
public IEnumerator<T> GetEnumerator()
{
return data.Keys.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class CachedView<T,U> : Set<U>
{
public CachedView( Set<T> set, Func<T, bool> include, Func<T, U> store )
: this( set, include, x => new[] { store( x ) } )
{
}
public CachedView( Set<T> set, Func<T,bool> include, Func<T,IEnumerable<U>> store )
{
foreach( var t in set )
if( include( t ) )
store( t ).Do( x => Add( x ) );
set.OnAdd += obj => { if( include( obj ) ) store( obj ).Do( x => Add( x ) ); };
set.OnRemove += obj => { if( include( obj ) ) store( obj ).Do( x => Remove( x ) ); };
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
namespace OpenRA.Collections
{
public class Set<T> : IEnumerable<T>
{
Dictionary<T, bool> data = new Dictionary<T, bool>();
public void Add( T obj )
{
data.Add( obj, false );
if( OnAdd != null )
OnAdd( obj );
}
public void Remove( T obj )
{
data.Remove( obj );
if( OnRemove != null )
OnRemove( obj );
}
public event Action<T> OnAdd;
public event Action<T> OnRemove;
public IEnumerator<T> GetEnumerator()
{
return data.Keys.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class CachedView<T,U> : Set<U>
{
public CachedView( Set<T> set, Func<T, bool> include, Func<T, U> store )
: this( set, include, x => new[] { store( x ) } )
{
}
public CachedView( Set<T> set, Func<T,bool> include, Func<T,IEnumerable<U>> store )
{
foreach( var t in set )
if( include( t ) )
store( t ).Do( x => Add( x ) );
set.OnAdd += obj => { if( include( obj ) ) store( obj ).Do( x => Add( x ) ); };
set.OnRemove += obj => { if( include( obj ) ) store( obj ).Do( x => Remove( x ) ); };
}
}
}

View File

@@ -1,104 +1,104 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace OpenRA
{
[StructLayout(LayoutKind.Sequential)]
public struct float2
{
public float X, Y;
public float2(float x, float y) { X = x; Y = y; }
public float2(PointF p) { X = p.X; Y = p.Y; }
public float2(Point p) { X = p.X; Y = p.Y; }
public float2(Size p) { X = p.Width; Y = p.Height; }
public float2(SizeF p) { X = p.Width; Y = p.Height; }
public PointF ToPointF() { return new PointF(X, Y); }
public SizeF ToSizeF() { return new SizeF(X, Y); }
public static implicit operator float2(int2 src) { return new float2(src.X, src.Y); }
public static float2 operator +(float2 a, float2 b) { return new float2(a.X + b.X, a.Y + b.Y); }
public static float2 operator -(float2 a, float2 b) { return new float2(a.X - b.X, a.Y - b.Y); }
public static float2 operator -(float2 a) { return new float2(-a.X, -a.Y); }
public static float Lerp(float a, float b, float t) { return a + t * (b - a); }
public static float2 Lerp(float2 a, float2 b, float t)
{
return new float2(
Lerp(a.X, b.X, t),
Lerp(a.Y, b.Y, t));
}
public static float2 Lerp(float2 a, float2 b, float2 t)
{
return new float2(
Lerp(a.X, b.X, t.X),
Lerp(a.Y, b.Y, t.Y));
}
public static float2 FromAngle(float a) { return new float2((float)Math.Sin(a), (float)Math.Cos(a)); }
static float Constrain(float x, float a, float b) { return x < a ? a : x > b ? b : x; }
public float2 Constrain(float2 min, float2 max)
{
return new float2(
Constrain(X, min.X, max.X),
Constrain(Y, min.Y, max.Y));
}
public static float2 operator *(float a, float2 b) { return new float2(a * b.X, a * b.Y); }
public static float2 operator *(float2 b, float a) { return new float2(a * b.X, a * b.Y); }
public static float2 operator *( float2 a, float2 b ) { return new float2( a.X * b.X, a.Y * b.Y ); }
public static float2 operator /( float2 a, float2 b ) { return new float2( a.X / b.X, a.Y / b.Y ); }
public static bool operator ==(float2 me, float2 other) { return (me.X == other.X && me.Y == other.Y); }
public static bool operator !=(float2 me, float2 other) { return !(me == other); }
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); }
public override bool Equals(object obj)
{
if (obj == null)
return false;
float2 o = (float2)obj;
return o == this;
}
public static readonly float2 Zero = new float2(0, 0);
public static bool WithinEpsilon(float2 a, float2 b, float e)
{
float2 d = a - b;
return Math.Abs(d.X) < e && Math.Abs(d.Y) < e;
}
public float2 Sign() { return new float2(Math.Sign(X), Math.Sign(Y)); }
public static float Dot(float2 a, float2 b) { return a.X * b.X + a.Y * b.Y; }
public float2 Round() { return new float2((float)Math.Round(X), (float)Math.Round(Y)); }
public override string ToString() { return string.Format("({0},{1})", X, Y); }
public int2 ToInt2() { return new int2((int)X, (int)Y); }
public static float2 Max(float2 a, float2 b) { return new float2(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); }
public static float2 Min(float2 a, float2 b) { return new float2(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); }
public float LengthSquared { get { return X * X + Y * Y; } }
public float Length { get { return (float)Math.Sqrt(LengthSquared); } }
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace OpenRA
{
[StructLayout(LayoutKind.Sequential)]
public struct float2
{
public float X, Y;
public float2(float x, float y) { X = x; Y = y; }
public float2(PointF p) { X = p.X; Y = p.Y; }
public float2(Point p) { X = p.X; Y = p.Y; }
public float2(Size p) { X = p.Width; Y = p.Height; }
public float2(SizeF p) { X = p.Width; Y = p.Height; }
public PointF ToPointF() { return new PointF(X, Y); }
public SizeF ToSizeF() { return new SizeF(X, Y); }
public static implicit operator float2(int2 src) { return new float2(src.X, src.Y); }
public static float2 operator +(float2 a, float2 b) { return new float2(a.X + b.X, a.Y + b.Y); }
public static float2 operator -(float2 a, float2 b) { return new float2(a.X - b.X, a.Y - b.Y); }
public static float2 operator -(float2 a) { return new float2(-a.X, -a.Y); }
public static float Lerp(float a, float b, float t) { return a + t * (b - a); }
public static float2 Lerp(float2 a, float2 b, float t)
{
return new float2(
Lerp(a.X, b.X, t),
Lerp(a.Y, b.Y, t));
}
public static float2 Lerp(float2 a, float2 b, float2 t)
{
return new float2(
Lerp(a.X, b.X, t.X),
Lerp(a.Y, b.Y, t.Y));
}
public static float2 FromAngle(float a) { return new float2((float)Math.Sin(a), (float)Math.Cos(a)); }
static float Constrain(float x, float a, float b) { return x < a ? a : x > b ? b : x; }
public float2 Constrain(float2 min, float2 max)
{
return new float2(
Constrain(X, min.X, max.X),
Constrain(Y, min.Y, max.Y));
}
public static float2 operator *(float a, float2 b) { return new float2(a * b.X, a * b.Y); }
public static float2 operator *(float2 b, float a) { return new float2(a * b.X, a * b.Y); }
public static float2 operator *( float2 a, float2 b ) { return new float2( a.X * b.X, a.Y * b.Y ); }
public static float2 operator /( float2 a, float2 b ) { return new float2( a.X / b.X, a.Y / b.Y ); }
public static bool operator ==(float2 me, float2 other) { return (me.X == other.X && me.Y == other.Y); }
public static bool operator !=(float2 me, float2 other) { return !(me == other); }
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); }
public override bool Equals(object obj)
{
if (obj == null)
return false;
float2 o = (float2)obj;
return o == this;
}
public static readonly float2 Zero = new float2(0, 0);
public static bool WithinEpsilon(float2 a, float2 b, float e)
{
float2 d = a - b;
return Math.Abs(d.X) < e && Math.Abs(d.Y) < e;
}
public float2 Sign() { return new float2(Math.Sign(X), Math.Sign(Y)); }
public static float Dot(float2 a, float2 b) { return a.X * b.X + a.Y * b.Y; }
public float2 Round() { return new float2((float)Math.Round(X), (float)Math.Round(Y)); }
public override string ToString() { return string.Format("({0},{1})", X, Y); }
public int2 ToInt2() { return new int2((int)X, (int)Y); }
public static float2 Max(float2 a, float2 b) { return new float2(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); }
public static float2 Min(float2 a, float2 b) { return new float2(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); }
public float LengthSquared { get { return X * X + Y * Y; } }
public float Length { get { return (float)Math.Sqrt(LengthSquared); } }
}
}

View File

@@ -1,85 +1,85 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Drawing;
namespace OpenRA
{
public struct int2
{
public int X,Y;
public int2( int x, int y ) { this.X = x; this.Y = y; }
public int2( Point p ) { X = p.X; Y = p.Y; }
public int2( Size p ) { X = p.Width; Y = p.Height; }
public static int2 operator +(int2 a, int2 b) { return new int2(a.X + b.X, a.Y + b.Y); }
public static int2 operator -(int2 a, int2 b) { return new int2(a.X - b.X, a.Y - b.Y); }
public static int2 operator *(int a, int2 b) { return new int2(a * b.X, a * b.Y); }
public static int2 operator *(int2 b, int a) { return new int2(a * b.X, a * b.Y); }
public static int2 operator /(int2 a, int b) { return new int2(a.X / b, a.Y / b); }
public static int2 operator -(int2 a) { return new int2(-a.X, -a.Y); }
public static bool operator ==(int2 me, int2 other) { return (me.X == other.X && me.Y == other.Y); }
public static bool operator !=(int2 me, int2 other) { return !(me == other); }
public int2 Sign() { return new int2(Math.Sign(X), Math.Sign(Y)); }
public int2 Abs() { return new int2( Math.Abs( X ), Math.Abs( Y ) ); }
public int LengthSquared { get { return X * X + Y * Y; } }
public int Length { get { return (int)Math.Sqrt(LengthSquared); } }
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); }
public static int2 Max(int2 a, int2 b) { return new int2(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); }
public static int2 Min(int2 a, int2 b) { return new int2(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); }
public override bool Equals(object obj)
{
if (obj == null)
return false;
int2 o = (int2)obj;
return o == this;
}
public static readonly int2 Zero = new int2(0, 0);
public Point ToPoint() { return new Point(X, Y); }
public PointF ToPointF() { return new PointF(X, Y); }
public float2 ToFloat2() { return new float2(X, Y); }
public override string ToString() { return string.Format("{0},{1}", X, Y); }
// Change endianness of a uint32
public static uint Swap(uint orig)
{
return (uint)((orig & 0xff000000) >> 24) | ((orig & 0x00ff0000) >> 8) | ((orig & 0x0000ff00) << 8) | ((orig & 0x000000ff) << 24);
}
public static int Lerp( int a, int b, int mul, int div )
{
return a + ( b - a ) * mul / div;
}
public static int2 Lerp( int2 a, int2 b, int mul, int div )
{
return a + ( b - a ) * mul / div;
}
public int2 Clamp(Rectangle r)
{
return new int2(Math.Min(r.Right, Math.Max(X, r.Left)),
Math.Min(r.Bottom, Math.Max(Y, r.Top)));
}
public static int Dot(int2 a, int2 b) { return a.X * b.X + a.Y * b.Y; }
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Drawing;
namespace OpenRA
{
public struct int2
{
public int X,Y;
public int2( int x, int y ) { this.X = x; this.Y = y; }
public int2( Point p ) { X = p.X; Y = p.Y; }
public int2( Size p ) { X = p.Width; Y = p.Height; }
public static int2 operator +(int2 a, int2 b) { return new int2(a.X + b.X, a.Y + b.Y); }
public static int2 operator -(int2 a, int2 b) { return new int2(a.X - b.X, a.Y - b.Y); }
public static int2 operator *(int a, int2 b) { return new int2(a * b.X, a * b.Y); }
public static int2 operator *(int2 b, int a) { return new int2(a * b.X, a * b.Y); }
public static int2 operator /(int2 a, int b) { return new int2(a.X / b, a.Y / b); }
public static int2 operator -(int2 a) { return new int2(-a.X, -a.Y); }
public static bool operator ==(int2 me, int2 other) { return (me.X == other.X && me.Y == other.Y); }
public static bool operator !=(int2 me, int2 other) { return !(me == other); }
public int2 Sign() { return new int2(Math.Sign(X), Math.Sign(Y)); }
public int2 Abs() { return new int2( Math.Abs( X ), Math.Abs( Y ) ); }
public int LengthSquared { get { return X * X + Y * Y; } }
public int Length { get { return (int)Math.Sqrt(LengthSquared); } }
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); }
public static int2 Max(int2 a, int2 b) { return new int2(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); }
public static int2 Min(int2 a, int2 b) { return new int2(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); }
public override bool Equals(object obj)
{
if (obj == null)
return false;
int2 o = (int2)obj;
return o == this;
}
public static readonly int2 Zero = new int2(0, 0);
public Point ToPoint() { return new Point(X, Y); }
public PointF ToPointF() { return new PointF(X, Y); }
public float2 ToFloat2() { return new float2(X, Y); }
public override string ToString() { return string.Format("{0},{1}", X, Y); }
// Change endianness of a uint32
public static uint Swap(uint orig)
{
return (uint)((orig & 0xff000000) >> 24) | ((orig & 0x00ff0000) >> 8) | ((orig & 0x0000ff00) << 8) | ((orig & 0x000000ff) << 24);
}
public static int Lerp( int a, int b, int mul, int div )
{
return a + ( b - a ) * mul / div;
}
public static int2 Lerp( int2 a, int2 b, int mul, int div )
{
return a + ( b - a ) * mul / div;
}
public int2 Clamp(Rectangle r)
{
return new int2(Math.Min(r.Right, Math.Max(X, r.Left)),
Math.Min(r.Bottom, Math.Max(Y, r.Top)));
}
public static int Dot(int2 a, int2 b) { return a.X * b.X + a.Y * b.Y; }
}
}

View File

@@ -1,74 +1,74 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
namespace OpenRA
{
public struct ChannelInfo
{
public string Filename;
public StreamWriter Writer;
}
public static class Log
{
static string LogPathPrefix = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + Path.DirectorySeparatorChar;
static Dictionary<string, ChannelInfo> channels = new Dictionary<string,ChannelInfo>();
public static string LogPath
{
get { return LogPathPrefix; }
set
{
LogPathPrefix = value;
if (!Directory.Exists(LogPathPrefix))
Directory.CreateDirectory(LogPathPrefix);
}
}
public static void AddChannel(string channelName, string filename)
{
if (channels.ContainsKey(channelName)) return;
var i = 0;
var f = filename;
while (File.Exists(LogPathPrefix + filename))
try
{
StreamWriter writer = File.CreateText(LogPathPrefix + filename);
writer.AutoFlush = true;
channels.Add(channelName, new ChannelInfo() { Filename = filename, Writer = writer });
return;
}
catch (IOException) { filename = f + ".{0}".F(++i); }
//if no logs exist, just make it
StreamWriter w = File.CreateText(LogPathPrefix + filename);
w.AutoFlush = true;
channels.Add(channelName, new ChannelInfo() { Filename = filename, Writer = w });
}
public static void Write(string channel, string format, params object[] args)
{
ChannelInfo info;
if (!channels.TryGetValue(channel, out info))
throw new Exception("Tried logging to non-existant channel " + channel);
info.Writer.WriteLine(format, args);
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
namespace OpenRA
{
public struct ChannelInfo
{
public string Filename;
public StreamWriter Writer;
}
public static class Log
{
static string LogPathPrefix = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + Path.DirectorySeparatorChar;
static Dictionary<string, ChannelInfo> channels = new Dictionary<string,ChannelInfo>();
public static string LogPath
{
get { return LogPathPrefix; }
set
{
LogPathPrefix = value;
if (!Directory.Exists(LogPathPrefix))
Directory.CreateDirectory(LogPathPrefix);
}
}
public static void AddChannel(string channelName, string filename)
{
if (channels.ContainsKey(channelName)) return;
var i = 0;
var f = filename;
while (File.Exists(LogPathPrefix + filename))
try
{
StreamWriter writer = File.CreateText(LogPathPrefix + filename);
writer.AutoFlush = true;
channels.Add(channelName, new ChannelInfo() { Filename = filename, Writer = writer });
return;
}
catch (IOException) { filename = f + ".{0}".F(++i); }
//if no logs exist, just make it
StreamWriter w = File.CreateText(LogPathPrefix + filename);
w.AutoFlush = true;
channels.Add(channelName, new ChannelInfo() { Filename = filename, Writer = w });
}
public static void Write(string channel, string format, params object[] args)
{
ChannelInfo info;
if (!channels.TryGetValue(channel, out info))
throw new Exception("Tried logging to non-existant channel " + channel);
info.Writer.WriteLine(format, args);
}
}
}

View File

@@ -1,31 +1,31 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
namespace OpenRA.Support
{
public class Stopwatch
{
System.Diagnostics.Stopwatch sw;
public Stopwatch ()
{
Reset();
}
public double ElapsedTime()
{
return sw.Elapsed.TotalMilliseconds / 1000.0;
}
public void Reset()
{
sw = System.Diagnostics.Stopwatch.StartNew();
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
namespace OpenRA.Support
{
public class Stopwatch
{
System.Diagnostics.Stopwatch sw;
public Stopwatch ()
{
Reset();
}
public double ElapsedTime()
{
return sw.Elapsed.TotalMilliseconds / 1000.0;
}
public void Reset()
{
sw = System.Diagnostics.Stopwatch.StartNew();
}
}
}

View File

@@ -1,27 +1,27 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
namespace OpenRA.Support
{
public static class Timer
{
static Stopwatch sw = new Stopwatch();
static double lastTime = 0;
public static void Time( string message )
{
var time = sw.ElapsedTime();
var dt = time - lastTime;
if( dt > 0.0001 )
Log.Write("perf", message, dt );
lastTime = time;
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
namespace OpenRA.Support
{
public static class Timer
{
static Stopwatch sw = new Stopwatch();
static double lastTime = 0;
public static void Time( string message )
{
var time = sw.ElapsedTime();
var dt = time - lastTime;
if( dt > 0.0001 )
Log.Write("perf", message, dt );
lastTime = time;
}
}
}

View File

@@ -1,66 +1,66 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
namespace OpenRA.Thirdparty
{
// quick & dirty Mersenne Twister [MT19937] implementation
public class Random
{
uint[] mt = new uint[624];
int index = 0;
public int Last;
public Random() : this(Environment.TickCount) { }
public Random(int seed)
{
mt[0] = (uint)seed;
for (var i = 1u; i < mt.Length; i++)
mt[i] = 1812433253u * (mt[i - 1] ^ (mt[i - 1] >> 30)) + i;
}
public int Next()
{
if (index == 0) Generate();
var y = mt[index];
y ^= (y >> 11);
y ^= ((y << 7) & 2636928640);
y ^= ((y << 15) & 4022730752);
y ^= y >> 18;
index = (index + 1) % 624;
Last = (int)(y % int.MaxValue);
return Last;
}
public int Next(int low, int high) { return low + Next() % (high - low); }
public int Next(int high) { return Next() % high; }
public double NextDouble() { return Math.Abs(Next() / (double)0x7fffffff); }
void Generate()
{
unchecked
{
for (var i = 0u; i < mt.Length; i++)
{
var y = (mt[i] & 0x80000000) | (mt[(i + 1) % 624] & 0x7fffffff);
mt[i] = mt[(i + 397u) % 624u] ^ (y >> 1);
if ((y & 1) == 1)
mt[i] = (mt[i] ^ 2567483615);
}
}
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
namespace OpenRA.Thirdparty
{
// quick & dirty Mersenne Twister [MT19937] implementation
public class Random
{
uint[] mt = new uint[624];
int index = 0;
public int Last;
public Random() : this(Environment.TickCount) { }
public Random(int seed)
{
mt[0] = (uint)seed;
for (var i = 1u; i < mt.Length; i++)
mt[i] = 1812433253u * (mt[i - 1] ^ (mt[i - 1] >> 30)) + i;
}
public int Next()
{
if (index == 0) Generate();
var y = mt[index];
y ^= (y >> 11);
y ^= ((y << 7) & 2636928640);
y ^= ((y << 15) & 4022730752);
y ^= y >> 18;
index = (index + 1) % 624;
Last = (int)(y % int.MaxValue);
return Last;
}
public int Next(int low, int high) { return low + Next() % (high - low); }
public int Next(int high) { return Next() % high; }
public double NextDouble() { return Math.Abs(Next() / (double)0x7fffffff); }
void Generate()
{
unchecked
{
for (var i = 0u; i < mt.Length; i++)
{
var y = (mt[i] & 0x80000000) | (mt[(i + 1) % 624] & 0x7fffffff);
mt[i] = mt[(i + 397u) % 624u] ^ (y >> 1);
if ((y & 1) == 1)
mt[i] = (mt[i] ^ 2567483615);
}
}
}
}
}

View File

@@ -1,106 +1,106 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace OpenRA.FileFormats
{
public class TypeDictionary : IEnumerable
{
Dictionary<Type, object> dataSingular = new Dictionary<Type, object>();
Dictionary<Type, List<object>> dataMultiple = new Dictionary<Type, List<object>>();
public void Add( object val )
{
var t = val.GetType();
foreach( var i in t.GetInterfaces() )
InnerAdd( i, val );
foreach( var tt in t.BaseTypes() )
InnerAdd( tt, val );
}
void InnerAdd( Type t, object val )
{
List<object> objs;
object obj;
if( dataMultiple.TryGetValue( t, out objs ) )
objs.Add( val );
else if( dataSingular.TryGetValue( t, out obj ) )
{
dataSingular.Remove( t );
dataMultiple.Add( t, new List<object> { obj, val } );
}
else
dataSingular.Add( t, val );
}
public bool Contains<T>()
{
return dataSingular.ContainsKey( typeof( T ) ) || dataMultiple.ContainsKey( typeof( T ) );
}
public T Get<T>()
{
if( dataMultiple.ContainsKey( typeof( T ) ) )
throw new InvalidOperationException( string.Format( "TypeDictionary contains multiple instance of type `{0}`", typeof( T ) ) );
object ret;
if( !dataSingular.TryGetValue( typeof( T ), out ret ) )
throw new InvalidOperationException(string.Format("TypeDictionary does not contain instance of type `{0}`", typeof(T)));
return (T)ret;
}
public T GetOrDefault<T>()
{
if( dataMultiple.ContainsKey( typeof( T ) ) )
throw new InvalidOperationException( string.Format( "TypeDictionary contains multiple instance of type `{0}`", typeof( T ) ) );
object ret;
if( !dataSingular.TryGetValue( typeof( T ), out ret ) )
return default( T );
return (T)ret;
}
public IEnumerable<T> WithInterface<T>()
{
List<object> objs;
object obj;
if( dataMultiple.TryGetValue( typeof( T ), out objs ) )
return objs.Cast<T>();
else if( dataSingular.TryGetValue( typeof( T ), out obj ) )
return new T[] { (T)obj };
else
return new T[ 0 ];
}
public IEnumerator GetEnumerator()
{
return WithInterface<object>().GetEnumerator();
}
}
public static class TypeExts
{
public static IEnumerable<Type> BaseTypes( this Type t )
{
while( t != null )
{
yield return t;
t = t.BaseType;
}
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace OpenRA.FileFormats
{
public class TypeDictionary : IEnumerable
{
Dictionary<Type, object> dataSingular = new Dictionary<Type, object>();
Dictionary<Type, List<object>> dataMultiple = new Dictionary<Type, List<object>>();
public void Add( object val )
{
var t = val.GetType();
foreach( var i in t.GetInterfaces() )
InnerAdd( i, val );
foreach( var tt in t.BaseTypes() )
InnerAdd( tt, val );
}
void InnerAdd( Type t, object val )
{
List<object> objs;
object obj;
if( dataMultiple.TryGetValue( t, out objs ) )
objs.Add( val );
else if( dataSingular.TryGetValue( t, out obj ) )
{
dataSingular.Remove( t );
dataMultiple.Add( t, new List<object> { obj, val } );
}
else
dataSingular.Add( t, val );
}
public bool Contains<T>()
{
return dataSingular.ContainsKey( typeof( T ) ) || dataMultiple.ContainsKey( typeof( T ) );
}
public T Get<T>()
{
if( dataMultiple.ContainsKey( typeof( T ) ) )
throw new InvalidOperationException( string.Format( "TypeDictionary contains multiple instance of type `{0}`", typeof( T ) ) );
object ret;
if( !dataSingular.TryGetValue( typeof( T ), out ret ) )
throw new InvalidOperationException(string.Format("TypeDictionary does not contain instance of type `{0}`", typeof(T)));
return (T)ret;
}
public T GetOrDefault<T>()
{
if( dataMultiple.ContainsKey( typeof( T ) ) )
throw new InvalidOperationException( string.Format( "TypeDictionary contains multiple instance of type `{0}`", typeof( T ) ) );
object ret;
if( !dataSingular.TryGetValue( typeof( T ), out ret ) )
return default( T );
return (T)ret;
}
public IEnumerable<T> WithInterface<T>()
{
List<object> objs;
object obj;
if( dataMultiple.TryGetValue( typeof( T ), out objs ) )
return objs.Cast<T>();
else if( dataSingular.TryGetValue( typeof( T ), out obj ) )
return new T[] { (T)obj };
else
return new T[ 0 ];
}
public IEnumerator GetEnumerator()
{
return WithInterface<object>().GetEnumerator();
}
}
public static class TypeExts
{
public static IEnumerable<Type> BaseTypes( this Type t )
{
while( t != null )
{
yield return t;
t = t.BaseType;
}
}
}
}

View File

@@ -1,20 +1,20 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Support;
using OpenRA.Traits;
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Support;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA
@@ -24,23 +24,23 @@ namespace OpenRA
public readonly ActorInfo Info;
public readonly World World;
public readonly uint ActorID;
public int2 Location { get { return Trait<IOccupySpace>().TopLeft; } }
public readonly uint ActorID;
public int2 Location { get { return Trait<IOccupySpace>().TopLeft; } }
public int2 CenterLocation { get { return Trait<IHasLocation>().PxPosition; } }
[Sync]
public Player Owner;
private IActivity currentActivity;
public Group Group;
private IActivity currentActivity;
public Group Group;
internal Actor(World world, string name, TypeDictionary initDict )
{
{
var init = new ActorInitializer( this, initDict );
World = world;
ActorID = world.NextAID();
if( initDict.Contains<OwnerInit>() )
ActorID = world.NextAID();
if( initDict.Contains<OwnerInit>() )
Owner = init.Get<OwnerInit,Player>();
if (name != null)
@@ -51,8 +51,8 @@ namespace OpenRA
Info = Rules.Info[name.ToLowerInvariant()];
foreach (var trait in Info.TraitsInConstructOrder())
AddTrait(trait.Create(init));
}
}
Size = Lazy.New(() =>
{
var si = Info.Traits.GetOrDefault<SelectableInfo>();
@@ -61,13 +61,13 @@ namespace OpenRA
// auto size from render
var firstSprite = TraitsImplementing<IRender>().SelectMany(x => x.Render(this)).FirstOrDefault();
if (firstSprite.Sprite == null) return float2.Zero;
if (firstSprite.Sprite == null) return float2.Zero;
return firstSprite.Sprite.size * firstSprite.Scale;
});
}
public void Tick()
{
{
if (currentActivity == null)
foreach (var ni in TraitsImplementing<INotifyIdle>())
ni.TickIdle(this);
@@ -88,38 +88,38 @@ namespace OpenRA
var sprites = TraitsImplementing<IRender>().SelectMany(x => x.Render(this));
return mods.Aggregate(sprites, (m, p) => p.ModifyRender(this, m));
}
// When useAltitude = true, the bounding box is extended
// vertically to altitude = 0 to support FindUnitsInCircle queries
// When false, the bounding box is given for the actor
// When useAltitude = true, the bounding box is extended
// vertically to altitude = 0 to support FindUnitsInCircle queries
// When false, the bounding box is given for the actor
// at its current altitude
public RectangleF GetBounds(bool useAltitude)
{
var size = Size.Value;
var loc = CenterLocation - 0.5f * size;
var loc = CenterLocation - 0.5f * size;
var si = Info.Traits.GetOrDefault<SelectableInfo>();
if (si != null && si.Bounds != null && si.Bounds.Length > 2)
loc += new float2(si.Bounds[2], si.Bounds[3]);
var move = TraitOrDefault<IMove>();
if (move != null)
{
loc -= new float2(0, move.Altitude);
if (useAltitude)
size = new float2(size.X, size.Y + move.Altitude);
if (move != null)
{
loc -= new float2(0, move.Altitude);
if (useAltitude)
size = new float2(size.X, size.Y + move.Altitude);
}
return new RectangleF(loc.X, loc.Y, size.X, size.Y);
}
public bool IsInWorld { get; internal set; }
public void QueueActivity( bool queued, IActivity nextActivity )
{
if( !queued )
CancelActivity();
QueueActivity( nextActivity );
public bool IsInWorld { get; internal set; }
public void QueueActivity( bool queued, IActivity nextActivity )
{
if( !queued )
CancelActivity();
QueueActivity( nextActivity );
}
public void QueueActivity( IActivity nextActivity )
@@ -152,60 +152,60 @@ namespace OpenRA
return ( o != null && o.ActorID == ActorID );
}
public override string ToString()
{
return "{0} {1}{2}".F( Info.Name, ActorID, IsInWorld ? "" : " (not in world)" );
public override string ToString()
{
return "{0} {1}{2}".F( Info.Name, ActorID, IsInWorld ? "" : " (not in world)" );
}
public T Trait<T>()
{
return World.traitDict.Get<T>( this );
}
public T TraitOrDefault<T>()
{
return World.traitDict.GetOrDefault<T>( this );
}
public IEnumerable<T> TraitsImplementing<T>()
{
return World.traitDict.WithInterface<T>( this );
}
public bool HasTrait<T>()
{
return World.traitDict.Contains<T>( this );
}
public void AddTrait( object trait )
{
World.traitDict.AddTrait( this, trait );
}
public bool Destroyed { get; private set; }
public void Destroy()
{
World.AddFrameEndTask( w =>
{
if (Destroyed) return;
World.Remove( this );
World.traitDict.RemoveActor( this );
Destroyed = true;
} );
}
// todo: move elsewhere.
public void ChangeOwner(Player newOwner)
{
World.AddFrameEndTask(w =>
{
// momentarily remove from world so the ownership queries don't get confused
w.Remove(this);
Owner = newOwner;
w.Add(this);
});
}
}
public T Trait<T>()
{
return World.traitDict.Get<T>( this );
}
public T TraitOrDefault<T>()
{
return World.traitDict.GetOrDefault<T>( this );
}
public IEnumerable<T> TraitsImplementing<T>()
{
return World.traitDict.WithInterface<T>( this );
}
public bool HasTrait<T>()
{
return World.traitDict.Contains<T>( this );
}
public void AddTrait( object trait )
{
World.traitDict.AddTrait( this, trait );
}
public bool Destroyed { get; private set; }
public void Destroy()
{
World.AddFrameEndTask( w =>
{
if (Destroyed) return;
World.Remove( this );
World.traitDict.RemoveActor( this );
Destroyed = true;
} );
}
// todo: move elsewhere.
public void ChangeOwner(Player newOwner)
{
World.AddFrameEndTask(w =>
{
// momentarily remove from world so the ownership queries don't get confused
w.Remove(this);
Owner = newOwner;
w.Add(this);
});
}
}
}

View File

@@ -1,134 +1,134 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Linq;
using OpenRA.FileFormats;
namespace OpenRA
{
public class ActorInitializer
{
public readonly Actor self;
public World world { get { return self.World; } }
internal TypeDictionary dict;
public ActorInitializer( Actor actor, TypeDictionary dict )
{
this.self = actor;
this.dict = dict;
}
public T Get<T>()
where T : IActorInit
{
return dict.Get<T>();
}
public U Get<T,U>()
where T : IActorInit<U>
{
return dict.Get<T>().Value( world );
}
public bool Contains<T>()
where T : IActorInit
{
return dict.Contains<T>();
}
}
public interface IActorInit {}
public interface IActorInit<T> : IActorInit
{
T Value( World world );
}
public class FacingInit : IActorInit<int>
{
[FieldFromYamlKey]
public readonly int value = 128;
public FacingInit() { }
public FacingInit( int init )
{
value = init;
}
public int Value( World world )
{
return value;
}
}
public class AltitudeInit : IActorInit<int>
{
[FieldFromYamlKey]
public readonly int value = 0;
public AltitudeInit() { }
public AltitudeInit( int init )
{
value = init;
}
public int Value( World world )
{
return value;
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Linq;
using OpenRA.FileFormats;
namespace OpenRA
{
public class ActorInitializer
{
public readonly Actor self;
public World world { get { return self.World; } }
internal TypeDictionary dict;
public ActorInitializer( Actor actor, TypeDictionary dict )
{
this.self = actor;
this.dict = dict;
}
public T Get<T>()
where T : IActorInit
{
return dict.Get<T>();
}
public U Get<T,U>()
where T : IActorInit<U>
{
return dict.Get<T>().Value( world );
}
public bool Contains<T>()
where T : IActorInit
{
return dict.Contains<T>();
}
}
public class LocationInit : IActorInit<int2>
{
[FieldFromYamlKey]
public readonly int2 value = int2.Zero;
public LocationInit() { }
public LocationInit( int2 init )
{
value = init;
}
public int2 Value( World world )
{
return value;
}
}
public class OwnerInit : IActorInit<Player>
{
[FieldFromYamlKey]
public readonly string PlayerName = "Neutral";
Player player;
public OwnerInit() { }
public OwnerInit( string playerName )
{
this.PlayerName = playerName;
}
public OwnerInit( Player player )
{
this.player = player;
this.PlayerName = player.InternalName;
}
public Player Value( World world )
{
if( player != null )
return player;
return world.players.Values.First( x => x.InternalName == PlayerName );
}
}
}
public interface IActorInit {}
public interface IActorInit<T> : IActorInit
{
T Value( World world );
}
public class FacingInit : IActorInit<int>
{
[FieldFromYamlKey]
public readonly int value = 128;
public FacingInit() { }
public FacingInit( int init )
{
value = init;
}
public int Value( World world )
{
return value;
}
}
public class AltitudeInit : IActorInit<int>
{
[FieldFromYamlKey]
public readonly int value = 0;
public AltitudeInit() { }
public AltitudeInit( int init )
{
value = init;
}
public int Value( World world )
{
return value;
}
}
public class LocationInit : IActorInit<int2>
{
[FieldFromYamlKey]
public readonly int2 value = int2.Zero;
public LocationInit() { }
public LocationInit( int2 init )
{
value = init;
}
public int2 Value( World world )
{
return value;
}
}
public class OwnerInit : IActorInit<Player>
{
[FieldFromYamlKey]
public readonly string PlayerName = "Neutral";
Player player;
public OwnerInit() { }
public OwnerInit( string playerName )
{
this.PlayerName = playerName;
}
public OwnerInit( Player player )
{
this.player = player;
this.PlayerName = player.InternalName;
}
public Player Value( World world )
{
if( player != null )
return player;
return world.players.Values.First( x => x.InternalName == PlayerName );
}
}
}

View File

@@ -1,54 +1,54 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections;
using System.Collections.Generic;
using System.IO;
namespace OpenRA.FileFormats
{
public class ActorReference : IEnumerable
{
public readonly string Type;
public readonly TypeDictionary InitDict;
public ActorReference( string type ) : this( type, new Dictionary<string, MiniYaml>() ) { }
public ActorReference( string type, Dictionary<string, MiniYaml> inits )
{
Type = type;
InitDict = new TypeDictionary();
foreach( var i in inits )
InitDict.Add( LoadInit( i.Key, i.Value ) );
}
static IActorInit LoadInit(string traitName, MiniYaml my)
{
var info = Game.CreateObject<IActorInit>(traitName + "Init");
FieldLoader.Load(info, my);
return info;
}
public MiniYaml Save()
{
var ret = new MiniYaml( Type );
foreach( var init in InitDict )
{
var initName = init.GetType().Name;
ret.Nodes.Add( new MiniYamlNode( initName.Substring( 0, initName.Length - 4 ), FieldSaver.Save( init ) ) );
}
return ret;
}
// for initialization syntax
public void Add( object o ) { InitDict.Add( o ); }
public IEnumerator GetEnumerator() { return InitDict.GetEnumerator(); }
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections;
using System.Collections.Generic;
using System.IO;
namespace OpenRA.FileFormats
{
public class ActorReference : IEnumerable
{
public readonly string Type;
public readonly TypeDictionary InitDict;
public ActorReference( string type ) : this( type, new Dictionary<string, MiniYaml>() ) { }
public ActorReference( string type, Dictionary<string, MiniYaml> inits )
{
Type = type;
InitDict = new TypeDictionary();
foreach( var i in inits )
InitDict.Add( LoadInit( i.Key, i.Value ) );
}
static IActorInit LoadInit(string traitName, MiniYaml my)
{
var info = Game.CreateObject<IActorInit>(traitName + "Init");
FieldLoader.Load(info, my);
return info;
}
public MiniYaml Save()
{
var ret = new MiniYaml( Type );
foreach( var init in InitDict )
{
var initName = init.GetType().Name;
ret.Nodes.Add( new MiniYamlNode( initName.Substring( 0, initName.Length - 4 ), FieldSaver.Save( init ) ) );
}
return ret;
}
// for initialization syntax
public void Add( object o ) { InitDict.Add( o ); }
public IEnumerator GetEnumerator() { return InitDict.GetEnumerator(); }
}
}

View File

@@ -1,28 +1,28 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using OpenRA.Graphics;
namespace OpenRA
{
public class Cursor
{
CursorSequence sequence;
public Cursor(string cursor)
{
sequence = CursorProvider.GetCursorSequence(cursor);
}
public void Draw(int frame, float2 pos)
{
sequence.GetSprite(frame).DrawAt(pos - sequence.Hotspot, Game.modData.Palette.GetPaletteIndex(sequence.Palette));
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using OpenRA.Graphics;
namespace OpenRA
{
public class Cursor
{
CursorSequence sequence;
public Cursor(string cursor)
{
sequence = CursorProvider.GetCursorSequence(cursor);
}
public void Draw(int frame, float2 pos)
{
sequence.GetSprite(frame).DrawAt(pos - sequence.Hotspot, Game.modData.Palette.GetPaletteIndex(sequence.Palette));
}
}
}

View File

@@ -1,36 +1,36 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Traits;
namespace OpenRA.Effects
{
public class DelayedAction : IEffect
{
Action a;
int delay;
public DelayedAction(int delay, Action a)
{
this.a = a;
this.delay = delay;
}
public void Tick( World world )
{
if (--delay <= 0)
world.AddFrameEndTask(w => { w.Remove(this); a(); });
}
public IEnumerable<Renderable> Render() { yield break; }
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Traits;
namespace OpenRA.Effects
{
public class DelayedAction : IEffect
{
Action a;
int delay;
public DelayedAction(int delay, Action a)
{
this.a = a;
this.delay = delay;
}
public void Tick( World world )
{
if (--delay <= 0)
world.AddFrameEndTask(w => { w.Remove(this); a(); });
}
public IEnumerable<Renderable> Render() { yield break; }
}
}

View File

@@ -1,45 +1,45 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Traits;
namespace OpenRA.Effects
{
public class FlashTarget : IEffect
{
Actor target;
int remainingTicks = 4;
public FlashTarget(Actor target)
{
this.target = target;
foreach (var e in target.World.Effects.OfType<FlashTarget>().Where(a => a.target == target).ToArray())
target.World.Remove(e);
}
public void Tick( World world )
{
if (--remainingTicks == 0 || !target.IsInWorld)
world.AddFrameEndTask(w => w.Remove(this));
}
public IEnumerable<Renderable> Render()
{
if (!target.IsInWorld)
yield break;
if (remainingTicks % 2 == 0)
foreach (var r in target.Render())
yield return r.WithPalette("highlight");
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Traits;
namespace OpenRA.Effects
{
public class FlashTarget : IEffect
{
Actor target;
int remainingTicks = 4;
public FlashTarget(Actor target)
{
this.target = target;
foreach (var e in target.World.Effects.OfType<FlashTarget>().Where(a => a.target == target).ToArray())
target.World.Remove(e);
}
public void Tick( World world )
{
if (--remainingTicks == 0 || !target.IsInWorld)
world.AddFrameEndTask(w => w.Remove(this));
}
public IEnumerable<Renderable> Render()
{
if (!target.IsInWorld)
yield break;
if (remainingTicks % 2 == 0)
foreach (var r in target.Render())
yield return r.WithPalette("highlight");
}
}
}

View File

@@ -1,21 +1,21 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using OpenRA.Traits;
namespace OpenRA.Effects
{
public interface IEffect
{
void Tick( World world );
IEnumerable<Renderable> Render();
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using OpenRA.Traits;
namespace OpenRA.Effects
{
public interface IEffect
{
void Tick( World world );
IEnumerable<Renderable> Render();
}
}

View File

@@ -1,70 +1,70 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Support;
namespace OpenRA
{
public static class Exts
{
public static bool HasModifier(this Modifiers k, Modifiers mod)
{
return (k & mod) == mod;
}
public static IEnumerable<T> SymmetricDifference<T>(this IEnumerable<T> xs, IEnumerable<T> ys)
{
// this is probably a shockingly-slow way to do this, but it's concise.
return xs.Except(ys).Concat(ys.Except(xs));
}
public static float Product(this IEnumerable<float> xs)
{
return xs.Aggregate(1f, (a, x) => a * x);
}
public static V GetOrAdd<K, V>(this Dictionary<K, V> d, K k)
where V : new()
{
return d.GetOrAdd(k, _ => new V());
}
public static V GetOrAdd<K, V>(this Dictionary<K, V> d, K k, Func<K, V> createFn)
{
V ret;
if (!d.TryGetValue(k, out ret))
d.Add(k, ret = createFn(k));
return ret;
}
public static T Random<T>(this IEnumerable<T> ts, Thirdparty.Random r)
{
var xs = ts.ToArray();
return xs[r.Next(xs.Length)];
}
public static void DoTimed<T>(this IEnumerable<T> e, Action<T> a, string text, double time)
{
var sw = new Stopwatch();
e.Do(x =>
{
var t = sw.ElapsedTime();
a(x);
var dt = sw.ElapsedTime() - t;
if (dt > time)
Log.Write("perf", text, x, dt * 1000, Game.LocalTick);
});
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Support;
namespace OpenRA
{
public static class Exts
{
public static bool HasModifier(this Modifiers k, Modifiers mod)
{
return (k & mod) == mod;
}
public static IEnumerable<T> SymmetricDifference<T>(this IEnumerable<T> xs, IEnumerable<T> ys)
{
// this is probably a shockingly-slow way to do this, but it's concise.
return xs.Except(ys).Concat(ys.Except(xs));
}
public static float Product(this IEnumerable<float> xs)
{
return xs.Aggregate(1f, (a, x) => a * x);
}
public static V GetOrAdd<K, V>(this Dictionary<K, V> d, K k)
where V : new()
{
return d.GetOrAdd(k, _ => new V());
}
public static V GetOrAdd<K, V>(this Dictionary<K, V> d, K k, Func<K, V> createFn)
{
V ret;
if (!d.TryGetValue(k, out ret))
d.Add(k, ret = createFn(k));
return ret;
}
public static T Random<T>(this IEnumerable<T> ts, Thirdparty.Random r)
{
var xs = ts.ToArray();
return xs[r.Next(xs.Length)];
}
public static void DoTimed<T>(this IEnumerable<T> e, Action<T> a, string text, double time)
{
var sw = new Stopwatch();
e.Do(x =>
{
var t = sw.ElapsedTime();
a(x);
var dt = sw.ElapsedTime() - t;
if (dt > time)
Log.Write("perf", text, x, dt * 1000, Game.LocalTick);
});
}
}
}

View File

@@ -1,369 +1,369 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Network;
using OpenRA.Server;
using OpenRA.Support;
using OpenRA.Widgets;
using XRandom = OpenRA.Thirdparty.Random;
namespace OpenRA
{
public static class Game
{
public static Utilities Utilities;
public static int CellSize { get { return modData.Manifest.TileSize; } }
public static ModData modData;
private static WorldRenderer worldRenderer;
public static Viewport viewport;
public static Settings Settings;
internal static OrderManager orderManager;
static Server.Server server;
public static XRandom CosmeticRandom = new XRandom(); // not synced
public static Renderer Renderer;
public static bool HasInputFocus = false;
public static void MoveViewport(float2 loc)
{
viewport.Center(loc);
}
public static void JoinServer(string host, int port)
{
var replayFilename = ChooseReplayFilename();
string path = Path.Combine( Game.SupportDir, "Replays" );
if( !Directory.Exists( path ) ) Directory.CreateDirectory( path );
var replayFile = File.Create( Path.Combine( path, replayFilename ) );
JoinInner(new OrderManager(host, port,
new ReplayRecorderConnection(new NetworkConnection(host, port), replayFile)));
}
static string ChooseReplayFilename()
{
return DateTime.UtcNow.ToString("OpenRA-yyyy-MM-ddTHHmmssZ.rep");
}
static void JoinInner(OrderManager om)
{
if (orderManager != null) orderManager.Dispose();
orderManager = om;
lastConnectionState = ConnectionState.PreConnecting;
ConnectionStateChanged(orderManager);
}
public static void JoinReplay(string replayFile)
{
JoinInner(new OrderManager("<no server>", -1, new ReplayConnection(replayFile)));
}
static void JoinLocal()
{
JoinInner(new OrderManager("<no server>", -1, new EchoConnection()));
}
public static int RenderFrame = 0;
public static int NetFrameNumber { get { return orderManager.NetFrameNumber; } }
public static int LocalTick { get { return orderManager.LocalFrameNumber; } }
const int NetTickScale = 3; // 120ms net tick for 40ms local tick
public static event Action<OrderManager> ConnectionStateChanged = _ => { };
static ConnectionState lastConnectionState = ConnectionState.PreConnecting;
public static int LocalClientId { get { return orderManager.Connection.LocalClientId; } }
// Hacky workaround for orderManager visibility
public static Widget OpenWindow(World world, string widget)
{
return Widget.OpenWindow(widget, new Dictionary<string,object>{{ "world", world }, { "orderManager", orderManager }, { "worldRenderer", worldRenderer }});
}
static ActionQueue afterTickActions = new ActionQueue();
public static void RunAfterTick(Action a) { afterTickActions.Add(a); }
static void Tick( OrderManager orderManager, Viewport viewPort )
{
if (orderManager.Connection.ConnectionState != lastConnectionState)
{
lastConnectionState = orderManager.Connection.ConnectionState;
ConnectionStateChanged( orderManager );
}
Tick( orderManager );
if( worldRenderer != null && orderManager.world != worldRenderer.world )
Tick( worldRenderer.world.orderManager );
using (new PerfSample("render"))
{
++RenderFrame;
viewport.DrawRegions(worldRenderer, new DefaultInputHandler( orderManager.world ));
Sound.SetListenerPosition(viewport.Location + .5f * new float2(viewport.Width, viewport.Height));
}
PerfHistory.items["render"].Tick();
PerfHistory.items["batches"].Tick();
MasterServerQuery.Tick();
afterTickActions.PerformActions();
}
private static void Tick( OrderManager orderManager )
{
int t = Environment.TickCount;
int dt = t - orderManager.LastTickTime;
if (dt >= Settings.Game.Timestep)
using( new PerfSample( "tick_time" ) )
{
orderManager.LastTickTime += Settings.Game.Timestep;
Widget.DoTick();
var world = orderManager.world;
if( orderManager.GameStarted && world.LocalPlayer != null )
++Viewport.TicksSinceLastMove;
Sound.Tick();
Sync.CheckSyncUnchanged( world, () => { orderManager.TickImmediate(); } );
if (world != null)
{
var isNetTick = LocalTick % NetTickScale == 0;
if (!isNetTick || orderManager.IsReadyForNextFrame)
{
++orderManager.LocalFrameNumber;
Log.Write("debug", "--Tick: {0} ({1})", LocalTick, isNetTick ? "net" : "local");
if (isNetTick) orderManager.Tick();
Sync.CheckSyncUnchanged(world, () =>
{
world.OrderGenerator.Tick(world);
world.Selection.Tick(world);
});
world.Tick();
PerfHistory.Tick();
}
else
if (orderManager.NetFrameNumber == 0)
orderManager.LastTickTime = Environment.TickCount;
}
}
}
public static event Action LobbyInfoChanged = () => { };
internal static void SyncLobbyInfo()
{
LobbyInfoChanged();
}
public static event Action<World> AfterGameStart = _ => {};
public static event Action BeforeGameStart = () => {};
internal static void StartGame(string mapUID)
{
BeforeGameStart();
var map = modData.PrepareMap(mapUID);
viewport = new Viewport(new int2(Renderer.Resolution), map.Bounds, Renderer);
orderManager.world = new World(modData.Manifest, map, orderManager);
worldRenderer = new WorldRenderer(orderManager.world);
if (orderManager.GameStarted) return;
Widget.SelectedWidget = null;
orderManager.LocalFrameNumber = 0;
orderManager.StartGame();
worldRenderer.RefreshPalette();
AfterGameStart( orderManager.world );
}
public static bool IsHost
{
get { return orderManager.Connection.LocalClientId == 0; }
}
public static Dictionary<String, Mod> CurrentMods
{
get { return Mod.AllMods.Where( k => modData.Manifest.Mods.Contains( k.Key )).ToDictionary( k => k.Key, k => k.Value ); }
}
static Modifiers modifiers;
public static Modifiers GetModifierKeys() { return modifiers; }
internal static void HandleModifierKeys(Modifiers mods) { modifiers = mods; }
internal static void Initialize(Arguments args)
{
AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly;
var defaultSupport = Environment.GetFolderPath(Environment.SpecialFolder.Personal)
+ Path.DirectorySeparatorChar + "OpenRA";
SupportDir = args.GetValue("SupportDir", defaultSupport);
FileSystem.SpecialPackageRoot = args.GetValue("SpecialPackageRoot", "");
Utilities = new Utilities(args.GetValue("UtilityPath", "OpenRA.Utility.exe"));
Settings = new Settings(SupportDir + "settings.yaml", args);
Settings.Save();
Log.LogPath = SupportDir + "Logs" + Path.DirectorySeparatorChar;
Log.AddChannel("perf", "perf.log");
Log.AddChannel("debug", "debug.log");
Log.AddChannel("sync", "syncreport.log");
FileSystem.Mount("."); // Needed to access shaders
Renderer.Initialize( Game.Settings.Graphics.Mode );
Renderer.SheetSize = Settings.Game.SheetSize;
Renderer = new Renderer();
Console.WriteLine("Available mods:");
foreach(var mod in Mod.AllMods)
Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Title, mod.Value.Version);
Sound.Create();
InitializeWithMods(Settings.Game.Mods);
}
public static void InitializeWithMods(string[] mods)
{
// Clear static state if we have switched mods
LobbyInfoChanged = () => {};
AddChatLine = (a,b,c) => {};
worldRenderer = null;
if (server != null)
server.Shutdown();
if (orderManager != null)
orderManager.Dispose();
// Discard any invalid mods
var mm = mods.Where( m => Mod.AllMods.ContainsKey( m ) ).ToArray();
Console.WriteLine("Loading mods: {0}",string.Join(",",mm));
Settings.Game.Mods = mm;
Settings.Save();
Sound.Initialize();
modData = new ModData( mm );
modData.LoadInitialAssets();
PerfHistory.items["render"].hasNormalTick = false;
PerfHistory.items["batches"].hasNormalTick = false;
JoinLocal();
viewport = new Viewport(new int2(Renderer.Resolution), Rectangle.Empty, Renderer);
Widget.RootWidget.RemoveChildren();
modData.WidgetLoader.LoadWidget( new Dictionary<string,object>(), Widget.RootWidget, "INIT_SETUP" );
}
public static void LoadShellMap()
{
StartGame(ChooseShellmap());
Game.orderManager.LastTickTime = Environment.TickCount;
}
static string ChooseShellmap()
{
var shellmaps = modData.AvailableMaps
.Where(m => m.Value.UseAsShellmap);
if (shellmaps.Count() == 0)
throw new InvalidDataException("No valid shellmaps available");
return shellmaps.Random(CosmeticRandom).Key;
}
static bool quit;
public static event Action OnQuit = () => {};
internal static void Run()
{
while (!quit)
{
Tick( orderManager, viewport );
Application.DoEvents();
}
OnQuit();
}
public static void Exit() { quit = true; }
public static Action<Color,string,string> AddChatLine = (c,n,s) => {};
public static void Debug(string s, params object[] args)
{
AddChatLine(Color.White, "Debug", String.Format(s,args));
}
public static void Disconnect()
{
if (IsHost && server != null)
server.Shutdown();
orderManager.Dispose();
var shellmap = ChooseShellmap();
JoinLocal();
StartGame(shellmap);
Widget.CloseWindow();
Widget.OpenWindow("MAINMENU_BG");
}
static string baseSupportDir = null;
public static string SupportDir
{
set
{
var dir = value;
// Expand paths relative to the personal directory
if (dir.ElementAt(0) == '~')
dir = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + dir.Substring(1);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
baseSupportDir = dir + Path.DirectorySeparatorChar;
}
get { return baseSupportDir; }
}
public static T CreateObject<T>( string name )
{
return modData.ObjectCreator.CreateObject<T>( name );
}
public static void CreateAndJoinServer(Settings settings, string map)
{
server = new Server.Server(modData, settings, map);
JoinServer(IPAddress.Loopback.ToString(), settings.Server.ListenPort);
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Network;
using OpenRA.Server;
using OpenRA.Support;
using OpenRA.Widgets;
using XRandom = OpenRA.Thirdparty.Random;
namespace OpenRA
{
public static class Game
{
public static Utilities Utilities;
public static int CellSize { get { return modData.Manifest.TileSize; } }
public static ModData modData;
private static WorldRenderer worldRenderer;
public static Viewport viewport;
public static Settings Settings;
internal static OrderManager orderManager;
static Server.Server server;
public static XRandom CosmeticRandom = new XRandom(); // not synced
public static Renderer Renderer;
public static bool HasInputFocus = false;
public static void MoveViewport(float2 loc)
{
viewport.Center(loc);
}
public static void JoinServer(string host, int port)
{
var replayFilename = ChooseReplayFilename();
string path = Path.Combine( Game.SupportDir, "Replays" );
if( !Directory.Exists( path ) ) Directory.CreateDirectory( path );
var replayFile = File.Create( Path.Combine( path, replayFilename ) );
JoinInner(new OrderManager(host, port,
new ReplayRecorderConnection(new NetworkConnection(host, port), replayFile)));
}
static string ChooseReplayFilename()
{
return DateTime.UtcNow.ToString("OpenRA-yyyy-MM-ddTHHmmssZ.rep");
}
static void JoinInner(OrderManager om)
{
if (orderManager != null) orderManager.Dispose();
orderManager = om;
lastConnectionState = ConnectionState.PreConnecting;
ConnectionStateChanged(orderManager);
}
public static void JoinReplay(string replayFile)
{
JoinInner(new OrderManager("<no server>", -1, new ReplayConnection(replayFile)));
}
static void JoinLocal()
{
JoinInner(new OrderManager("<no server>", -1, new EchoConnection()));
}
public static int RenderFrame = 0;
public static int NetFrameNumber { get { return orderManager.NetFrameNumber; } }
public static int LocalTick { get { return orderManager.LocalFrameNumber; } }
const int NetTickScale = 3; // 120ms net tick for 40ms local tick
public static event Action<OrderManager> ConnectionStateChanged = _ => { };
static ConnectionState lastConnectionState = ConnectionState.PreConnecting;
public static int LocalClientId { get { return orderManager.Connection.LocalClientId; } }
// Hacky workaround for orderManager visibility
public static Widget OpenWindow(World world, string widget)
{
return Widget.OpenWindow(widget, new Dictionary<string,object>{{ "world", world }, { "orderManager", orderManager }, { "worldRenderer", worldRenderer }});
}
static ActionQueue afterTickActions = new ActionQueue();
public static void RunAfterTick(Action a) { afterTickActions.Add(a); }
static void Tick( OrderManager orderManager, Viewport viewPort )
{
if (orderManager.Connection.ConnectionState != lastConnectionState)
{
lastConnectionState = orderManager.Connection.ConnectionState;
ConnectionStateChanged( orderManager );
}
Tick( orderManager );
if( worldRenderer != null && orderManager.world != worldRenderer.world )
Tick( worldRenderer.world.orderManager );
using (new PerfSample("render"))
{
++RenderFrame;
viewport.DrawRegions(worldRenderer, new DefaultInputHandler( orderManager.world ));
Sound.SetListenerPosition(viewport.Location + .5f * new float2(viewport.Width, viewport.Height));
}
PerfHistory.items["render"].Tick();
PerfHistory.items["batches"].Tick();
MasterServerQuery.Tick();
afterTickActions.PerformActions();
}
private static void Tick( OrderManager orderManager )
{
int t = Environment.TickCount;
int dt = t - orderManager.LastTickTime;
if (dt >= Settings.Game.Timestep)
using( new PerfSample( "tick_time" ) )
{
orderManager.LastTickTime += Settings.Game.Timestep;
Widget.DoTick();
var world = orderManager.world;
if( orderManager.GameStarted && world.LocalPlayer != null )
++Viewport.TicksSinceLastMove;
Sound.Tick();
Sync.CheckSyncUnchanged( world, () => { orderManager.TickImmediate(); } );
if (world != null)
{
var isNetTick = LocalTick % NetTickScale == 0;
if (!isNetTick || orderManager.IsReadyForNextFrame)
{
++orderManager.LocalFrameNumber;
Log.Write("debug", "--Tick: {0} ({1})", LocalTick, isNetTick ? "net" : "local");
if (isNetTick) orderManager.Tick();
Sync.CheckSyncUnchanged(world, () =>
{
world.OrderGenerator.Tick(world);
world.Selection.Tick(world);
});
world.Tick();
PerfHistory.Tick();
}
else
if (orderManager.NetFrameNumber == 0)
orderManager.LastTickTime = Environment.TickCount;
}
}
}
public static event Action LobbyInfoChanged = () => { };
internal static void SyncLobbyInfo()
{
LobbyInfoChanged();
}
public static event Action<World> AfterGameStart = _ => {};
public static event Action BeforeGameStart = () => {};
internal static void StartGame(string mapUID)
{
BeforeGameStart();
var map = modData.PrepareMap(mapUID);
viewport = new Viewport(new int2(Renderer.Resolution), map.Bounds, Renderer);
orderManager.world = new World(modData.Manifest, map, orderManager);
worldRenderer = new WorldRenderer(orderManager.world);
if (orderManager.GameStarted) return;
Widget.SelectedWidget = null;
orderManager.LocalFrameNumber = 0;
orderManager.StartGame();
worldRenderer.RefreshPalette();
AfterGameStart( orderManager.world );
}
public static bool IsHost
{
get { return orderManager.Connection.LocalClientId == 0; }
}
public static Dictionary<String, Mod> CurrentMods
{
get { return Mod.AllMods.Where( k => modData.Manifest.Mods.Contains( k.Key )).ToDictionary( k => k.Key, k => k.Value ); }
}
static Modifiers modifiers;
public static Modifiers GetModifierKeys() { return modifiers; }
internal static void HandleModifierKeys(Modifiers mods) { modifiers = mods; }
internal static void Initialize(Arguments args)
{
AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly;
var defaultSupport = Environment.GetFolderPath(Environment.SpecialFolder.Personal)
+ Path.DirectorySeparatorChar + "OpenRA";
SupportDir = args.GetValue("SupportDir", defaultSupport);
FileSystem.SpecialPackageRoot = args.GetValue("SpecialPackageRoot", "");
Utilities = new Utilities(args.GetValue("UtilityPath", "OpenRA.Utility.exe"));
Settings = new Settings(SupportDir + "settings.yaml", args);
Settings.Save();
Log.LogPath = SupportDir + "Logs" + Path.DirectorySeparatorChar;
Log.AddChannel("perf", "perf.log");
Log.AddChannel("debug", "debug.log");
Log.AddChannel("sync", "syncreport.log");
FileSystem.Mount("."); // Needed to access shaders
Renderer.Initialize( Game.Settings.Graphics.Mode );
Renderer.SheetSize = Settings.Game.SheetSize;
Renderer = new Renderer();
Console.WriteLine("Available mods:");
foreach(var mod in Mod.AllMods)
Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Title, mod.Value.Version);
Sound.Create();
InitializeWithMods(Settings.Game.Mods);
}
public static void InitializeWithMods(string[] mods)
{
// Clear static state if we have switched mods
LobbyInfoChanged = () => {};
AddChatLine = (a,b,c) => {};
worldRenderer = null;
if (server != null)
server.Shutdown();
if (orderManager != null)
orderManager.Dispose();
// Discard any invalid mods
var mm = mods.Where( m => Mod.AllMods.ContainsKey( m ) ).ToArray();
Console.WriteLine("Loading mods: {0}",string.Join(",",mm));
Settings.Game.Mods = mm;
Settings.Save();
Sound.Initialize();
modData = new ModData( mm );
modData.LoadInitialAssets();
PerfHistory.items["render"].hasNormalTick = false;
PerfHistory.items["batches"].hasNormalTick = false;
JoinLocal();
viewport = new Viewport(new int2(Renderer.Resolution), Rectangle.Empty, Renderer);
Widget.RootWidget.RemoveChildren();
modData.WidgetLoader.LoadWidget( new Dictionary<string,object>(), Widget.RootWidget, "INIT_SETUP" );
}
public static void LoadShellMap()
{
StartGame(ChooseShellmap());
Game.orderManager.LastTickTime = Environment.TickCount;
}
static string ChooseShellmap()
{
var shellmaps = modData.AvailableMaps
.Where(m => m.Value.UseAsShellmap);
if (shellmaps.Count() == 0)
throw new InvalidDataException("No valid shellmaps available");
return shellmaps.Random(CosmeticRandom).Key;
}
static bool quit;
public static event Action OnQuit = () => {};
internal static void Run()
{
while (!quit)
{
Tick( orderManager, viewport );
Application.DoEvents();
}
OnQuit();
}
public static void Exit() { quit = true; }
public static Action<Color,string,string> AddChatLine = (c,n,s) => {};
public static void Debug(string s, params object[] args)
{
AddChatLine(Color.White, "Debug", String.Format(s,args));
}
public static void Disconnect()
{
if (IsHost && server != null)
server.Shutdown();
orderManager.Dispose();
var shellmap = ChooseShellmap();
JoinLocal();
StartGame(shellmap);
Widget.CloseWindow();
Widget.OpenWindow("MAINMENU_BG");
}
static string baseSupportDir = null;
public static string SupportDir
{
set
{
var dir = value;
// Expand paths relative to the personal directory
if (dir.ElementAt(0) == '~')
dir = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + dir.Substring(1);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
baseSupportDir = dir + Path.DirectorySeparatorChar;
}
get { return baseSupportDir; }
}
public static T CreateObject<T>( string name )
{
return modData.ObjectCreator.CreateObject<T>( name );
}
public static void CreateAndJoinServer(Settings settings, string map)
{
server = new Server.Server(modData, settings, map);
JoinServer(IPAddress.Loopback.ToString(), settings.Server.ListenPort);
}
}
}

View File

@@ -1,99 +1,99 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA
{
public class ActorInfo
{
public readonly string Name;
public readonly TypeDictionary Traits = new TypeDictionary();
public ActorInfo( string name, MiniYaml node, Dictionary<string, MiniYaml> allUnits )
{
var mergedNode = MergeWithParent( node, allUnits ).NodesDict;
Name = name;
foreach( var t in mergedNode )
if( t.Key != "Inherits" && !t.Key.StartsWith("-") )
Traits.Add( LoadTraitInfo( t.Key.Split('@')[0], t.Value ) );
}
static MiniYaml GetParent( MiniYaml node, Dictionary<string, MiniYaml> allUnits )
{
MiniYaml inherits;
node.NodesDict.TryGetValue( "Inherits", out inherits );
if( inherits == null || string.IsNullOrEmpty( inherits.Value ) )
return null;
MiniYaml parent;
allUnits.TryGetValue( inherits.Value, out parent );
if( parent == null )
return null;
return parent;
}
static MiniYaml MergeWithParent( MiniYaml node, Dictionary<string, MiniYaml> allUnits )
{
var parent = GetParent( node, allUnits );
if( parent != null )
return MiniYaml.Merge( node, MergeWithParent( parent, allUnits ) );
return node;
}
static ITraitInfo LoadTraitInfo(string traitName, MiniYaml my)
{
var info = Game.CreateObject<ITraitInfo>(traitName + "Info");
FieldLoader.Load(info, my);
return info;
}
public IEnumerable<ITraitInfo> TraitsInConstructOrder()
{
var ret = new List<ITraitInfo>();
var t = Traits.WithInterface<ITraitInfo>().ToList();
int index = 0;
while (t.Count != 0)
{
var prereqs = PrerequisitesOf(t[index]);
var unsatisfied = prereqs.Where(n => !ret.Any(x => x.GetType() == n || x.GetType().IsSubclassOf(n)));
if (!unsatisfied.Any())
{
ret.Add(t[index]);
t.RemoveAt(index);
index = 0;
}
else if (++index >= t.Count)
throw new InvalidOperationException("Trait prerequisites not satisfied (or prerequisite loop) Actor={0} Unresolved={1} Missing={2}".F(
Name,
string.Join(",", t.Select(x => x.GetType().Name).ToArray()),
string.Join(",", unsatisfied.Select(x => x.Name).ToArray())));
}
return ret;
}
static List<Type> PrerequisitesOf( ITraitInfo info )
{
return info
.GetType()
.GetInterfaces()
.Where( t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof( ITraitPrerequisite<> ) )
.Select( t => t.GetGenericArguments()[ 0 ] )
.ToList();
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA
{
public class ActorInfo
{
public readonly string Name;
public readonly TypeDictionary Traits = new TypeDictionary();
public ActorInfo( string name, MiniYaml node, Dictionary<string, MiniYaml> allUnits )
{
var mergedNode = MergeWithParent( node, allUnits ).NodesDict;
Name = name;
foreach( var t in mergedNode )
if( t.Key != "Inherits" && !t.Key.StartsWith("-") )
Traits.Add( LoadTraitInfo( t.Key.Split('@')[0], t.Value ) );
}
static MiniYaml GetParent( MiniYaml node, Dictionary<string, MiniYaml> allUnits )
{
MiniYaml inherits;
node.NodesDict.TryGetValue( "Inherits", out inherits );
if( inherits == null || string.IsNullOrEmpty( inherits.Value ) )
return null;
MiniYaml parent;
allUnits.TryGetValue( inherits.Value, out parent );
if( parent == null )
return null;
return parent;
}
static MiniYaml MergeWithParent( MiniYaml node, Dictionary<string, MiniYaml> allUnits )
{
var parent = GetParent( node, allUnits );
if( parent != null )
return MiniYaml.Merge( node, MergeWithParent( parent, allUnits ) );
return node;
}
static ITraitInfo LoadTraitInfo(string traitName, MiniYaml my)
{
var info = Game.CreateObject<ITraitInfo>(traitName + "Info");
FieldLoader.Load(info, my);
return info;
}
public IEnumerable<ITraitInfo> TraitsInConstructOrder()
{
var ret = new List<ITraitInfo>();
var t = Traits.WithInterface<ITraitInfo>().ToList();
int index = 0;
while (t.Count != 0)
{
var prereqs = PrerequisitesOf(t[index]);
var unsatisfied = prereqs.Where(n => !ret.Any(x => x.GetType() == n || x.GetType().IsSubclassOf(n)));
if (!unsatisfied.Any())
{
ret.Add(t[index]);
t.RemoveAt(index);
index = 0;
}
else if (++index >= t.Count)
throw new InvalidOperationException("Trait prerequisites not satisfied (or prerequisite loop) Actor={0} Unresolved={1} Missing={2}".F(
Name,
string.Join(",", t.Select(x => x.GetType().Name).ToArray()),
string.Join(",", unsatisfied.Select(x => x.Name).ToArray())));
}
return ret;
}
static List<Type> PrerequisitesOf( ITraitInfo info )
{
return info
.GetType()
.GetInterfaces()
.Where( t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof( ITraitPrerequisite<> ) )
.Select( t => t.GetGenericArguments()[ 0 ] )
.ToList();
}
}
}

View File

@@ -1,34 +1,34 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using OpenRA.FileFormats;
namespace OpenRA.GameRules
{
public class MusicInfo
{
public readonly string Filename = null;
public readonly string Title = null;
public readonly int Length = 0; // seconds
{
public readonly string Filename = null;
public readonly string Title = null;
public readonly int Length = 0; // seconds
public readonly bool Exists = false;
public MusicInfo( string key, MiniYaml value )
{
Filename = key+".aud";
Title = value.Value;
if (!FileSystem.Exists(Filename))
return;
Exists = true;
Length = (int)AudLoader.SoundLength(FileSystem.Open(Filename));
Filename = key+".aud";
Title = value.Value;
if (!FileSystem.Exists(Filename))
return;
Exists = true;
Length = (int)AudLoader.SoundLength(FileSystem.Open(Filename));
}
}
}

View File

@@ -1,52 +1,52 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.GameRules;
namespace OpenRA
{
public static class Rules
{
public static Dictionary<string, ActorInfo> Info;
public static Dictionary<string, WeaponInfo> Weapons;
public static Dictionary<string, VoiceInfo> Voices;
public static Dictionary<string, MusicInfo> Music;
public static Dictionary<string, string> Movies;
public static Dictionary<string, TileSet> TileSets;
public static void LoadRules(Manifest m, Map map)
{
// Added support to extend the list of rules (add it to m.LocalRules)
Info = LoadYamlRules(m.Rules, map.Rules, (k, y) => new ActorInfo(k.Key.ToLowerInvariant(), k.Value, y));
Weapons = LoadYamlRules(m.Weapons, map.Weapons, (k, _) => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value));
Voices = LoadYamlRules(m.Voices, map.Voices, (k, _) => new VoiceInfo(k.Value));
Music = LoadYamlRules(m.Music, new List<MiniYamlNode>(), (k, _) => new MusicInfo(k.Key, k.Value));
Movies = LoadYamlRules(m.Movies, new List<MiniYamlNode>(), (k, v) => k.Value.Value);
TileSets = new Dictionary<string, TileSet>();
foreach (var file in m.TileSets)
{
var t = new TileSet(file);
TileSets.Add(t.Id,t);
}
}
static Dictionary<string, T> LoadYamlRules<T>(string[] files, List<MiniYamlNode> dict, Func<MiniYamlNode, Dictionary<string, MiniYaml>, T> f)
{
var y = files.Select(a => MiniYaml.FromFile(a)).Aggregate(dict,MiniYaml.Merge);
var yy = y.ToDictionary( x => x.Key, x => x.Value );
return y.ToDictionary(kv => kv.Key.ToLowerInvariant(), kv => f(kv, yy));
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.GameRules;
namespace OpenRA
{
public static class Rules
{
public static Dictionary<string, ActorInfo> Info;
public static Dictionary<string, WeaponInfo> Weapons;
public static Dictionary<string, VoiceInfo> Voices;
public static Dictionary<string, MusicInfo> Music;
public static Dictionary<string, string> Movies;
public static Dictionary<string, TileSet> TileSets;
public static void LoadRules(Manifest m, Map map)
{
// Added support to extend the list of rules (add it to m.LocalRules)
Info = LoadYamlRules(m.Rules, map.Rules, (k, y) => new ActorInfo(k.Key.ToLowerInvariant(), k.Value, y));
Weapons = LoadYamlRules(m.Weapons, map.Weapons, (k, _) => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value));
Voices = LoadYamlRules(m.Voices, map.Voices, (k, _) => new VoiceInfo(k.Value));
Music = LoadYamlRules(m.Music, new List<MiniYamlNode>(), (k, _) => new MusicInfo(k.Key, k.Value));
Movies = LoadYamlRules(m.Movies, new List<MiniYamlNode>(), (k, v) => k.Value.Value);
TileSets = new Dictionary<string, TileSet>();
foreach (var file in m.TileSets)
{
var t = new TileSet(file);
TileSets.Add(t.Id,t);
}
}
static Dictionary<string, T> LoadYamlRules<T>(string[] files, List<MiniYamlNode> dict, Func<MiniYamlNode, Dictionary<string, MiniYaml>, T> f)
{
var y = files.Select(a => MiniYaml.FromFile(a)).Aggregate(dict,MiniYaml.Merge);
var yy = y.ToDictionary( x => x.Key, x => x.Value );
return y.ToDictionary(kv => kv.Key.ToLowerInvariant(), kv => f(kv, yy));
}
}
}

View File

@@ -1,162 +1,162 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.FileFormats.Graphics;
using OpenRA.Server;
namespace OpenRA.GameRules
{
public class ServerSettings
{
public string Name = "OpenRA Game";
public int ListenPort = 1234;
public int ExternalPort = 1234;
public bool AdvertiseOnline = true;
public string MasterServer = "http://master.open-ra.org/";
public bool AllowCheats = false;
}
public class DebugSettings
{
public bool BotDebug = false;
public bool PerfGraph = false;
public float LongTickThreshold = 0.001f;
public bool SanityCheckUnsyncedCode = false;
}
public class GraphicSettings
{
public string Renderer = "Gl";
public WindowMode Mode = WindowMode.PseudoFullscreen;
public int2 FullscreenSize = new int2(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
public int2 WindowedSize = new int2(1024, 768);
public readonly int2 MinResolution = new int2(800, 600);
}
public class SoundSettings
{
public float SoundVolume = 0.5f;
public float MusicVolume = 0.5f;
public float VideoVolume = 0.5f;
public bool Shuffle = false;
public bool Repeat = false;
}
public class PlayerSettings
{
public string Name = "Newbie";
[Obsolete] public Color Color1 = Color.FromArgb(255,160,238);
[Obsolete] public Color Color2 = Color.FromArgb(68,0,56);
public ColorRamp ColorRamp = new ColorRamp(75, 255, 180, 25);
public string LastServer = "localhost:1234";
}
public class GameSettings
{
public string[] Mods = { "ra" };
public bool MatchTimer = true;
// Chat settings
public bool TeamChatToggle = false;
// Behaviour settings
public bool ViewportEdgeScroll = true;
public bool InverseDragScroll = false;
public float ViewportEdgeScrollStep = 10f;
// Internal game settings
public int Timestep = 40;
public int SheetSize = 2048;
}
public class Settings
{
string SettingsFile;
public PlayerSettings Player = new PlayerSettings();
public GameSettings Game = new GameSettings();
public SoundSettings Sound = new SoundSettings();
public GraphicSettings Graphics = new GraphicSettings();
public ServerSettings Server = new ServerSettings();
public DebugSettings Debug = new DebugSettings();
public Dictionary<string, object> Sections;
public Settings(string file, Arguments args)
{
SettingsFile = file;
Sections = new Dictionary<string, object>()
{
{"Player", Player},
{"Game", Game},
{"Sound", Sound},
{"Graphics", Graphics},
{"Server", Server},
{"Debug", Debug}
};
// Override fieldloader to ignore invalid entries
var err1 = FieldLoader.UnknownFieldAction;
var err2 = FieldLoader.InvalidValueAction;
FieldLoader.UnknownFieldAction = (s,f) =>
{
Console.WriteLine( "Ignoring unknown field `{0}` on `{1}`".F( s, f.Name ) );
};
if (File.Exists(SettingsFile))
{
//Console.WriteLine("Loading settings file {0}",SettingsFile);
var yaml = MiniYaml.DictFromFile(SettingsFile);
foreach (var kv in Sections)
if (yaml.ContainsKey(kv.Key))
LoadSectionYaml(yaml[kv.Key], kv.Value);
}
// Override with commandline args
foreach (var kv in Sections)
foreach (var f in kv.Value.GetType().GetFields())
if (args.Contains(kv.Key+"."+f.Name))
FieldLoader.LoadField( kv.Value, f.Name, args.GetValue(kv.Key+"."+f.Name, "") );
FieldLoader.UnknownFieldAction = err1;
FieldLoader.InvalidValueAction = err2;
}
public void Save()
{
var root = new List<MiniYamlNode>();
foreach( var kv in Sections )
root.Add( new MiniYamlNode( kv.Key, FieldSaver.SaveDifferences(kv.Value, Activator.CreateInstance(kv.Value.GetType())) ) );
root.WriteToFile(SettingsFile);
}
void LoadSectionYaml(MiniYaml yaml, object section)
{
object defaults = Activator.CreateInstance(section.GetType());
FieldLoader.InvalidValueAction = (s,t,f) =>
{
object ret = defaults.GetType().GetField(f).GetValue(defaults);
System.Console.WriteLine("FieldLoader: Cannot parse `{0}` into `{2}:{1}`; substituting default `{3}`".F(s,t.Name,f,ret) );
return ret;
};
FieldLoader.Load(section, yaml);
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.FileFormats.Graphics;
using OpenRA.Server;
namespace OpenRA.GameRules
{
public class ServerSettings
{
public string Name = "OpenRA Game";
public int ListenPort = 1234;
public int ExternalPort = 1234;
public bool AdvertiseOnline = true;
public string MasterServer = "http://master.open-ra.org/";
public bool AllowCheats = false;
}
public class DebugSettings
{
public bool BotDebug = false;
public bool PerfGraph = false;
public float LongTickThreshold = 0.001f;
public bool SanityCheckUnsyncedCode = false;
}
public class GraphicSettings
{
public string Renderer = "Gl";
public WindowMode Mode = WindowMode.PseudoFullscreen;
public int2 FullscreenSize = new int2(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
public int2 WindowedSize = new int2(1024, 768);
public readonly int2 MinResolution = new int2(800, 600);
}
public class SoundSettings
{
public float SoundVolume = 0.5f;
public float MusicVolume = 0.5f;
public float VideoVolume = 0.5f;
public bool Shuffle = false;
public bool Repeat = false;
}
public class PlayerSettings
{
public string Name = "Newbie";
[Obsolete] public Color Color1 = Color.FromArgb(255,160,238);
[Obsolete] public Color Color2 = Color.FromArgb(68,0,56);
public ColorRamp ColorRamp = new ColorRamp(75, 255, 180, 25);
public string LastServer = "localhost:1234";
}
public class GameSettings
{
public string[] Mods = { "ra" };
public bool MatchTimer = true;
// Chat settings
public bool TeamChatToggle = false;
// Behaviour settings
public bool ViewportEdgeScroll = true;
public bool InverseDragScroll = false;
public float ViewportEdgeScrollStep = 10f;
// Internal game settings
public int Timestep = 40;
public int SheetSize = 2048;
}
public class Settings
{
string SettingsFile;
public PlayerSettings Player = new PlayerSettings();
public GameSettings Game = new GameSettings();
public SoundSettings Sound = new SoundSettings();
public GraphicSettings Graphics = new GraphicSettings();
public ServerSettings Server = new ServerSettings();
public DebugSettings Debug = new DebugSettings();
public Dictionary<string, object> Sections;
public Settings(string file, Arguments args)
{
SettingsFile = file;
Sections = new Dictionary<string, object>()
{
{"Player", Player},
{"Game", Game},
{"Sound", Sound},
{"Graphics", Graphics},
{"Server", Server},
{"Debug", Debug}
};
// Override fieldloader to ignore invalid entries
var err1 = FieldLoader.UnknownFieldAction;
var err2 = FieldLoader.InvalidValueAction;
FieldLoader.UnknownFieldAction = (s,f) =>
{
Console.WriteLine( "Ignoring unknown field `{0}` on `{1}`".F( s, f.Name ) );
};
if (File.Exists(SettingsFile))
{
//Console.WriteLine("Loading settings file {0}",SettingsFile);
var yaml = MiniYaml.DictFromFile(SettingsFile);
foreach (var kv in Sections)
if (yaml.ContainsKey(kv.Key))
LoadSectionYaml(yaml[kv.Key], kv.Value);
}
// Override with commandline args
foreach (var kv in Sections)
foreach (var f in kv.Value.GetType().GetFields())
if (args.Contains(kv.Key+"."+f.Name))
FieldLoader.LoadField( kv.Value, f.Name, args.GetValue(kv.Key+"."+f.Name, "") );
FieldLoader.UnknownFieldAction = err1;
FieldLoader.InvalidValueAction = err2;
}
public void Save()
{
var root = new List<MiniYamlNode>();
foreach( var kv in Sections )
root.Add( new MiniYamlNode( kv.Key, FieldSaver.SaveDifferences(kv.Value, Activator.CreateInstance(kv.Value.GetType())) ) );
root.WriteToFile(SettingsFile);
}
void LoadSectionYaml(MiniYaml yaml, object section)
{
object defaults = Activator.CreateInstance(section.GetType());
FieldLoader.InvalidValueAction = (s,t,f) =>
{
object ret = defaults.GetType().GetField(f).GetValue(defaults);
System.Console.WriteLine("FieldLoader: Cannot parse `{0}` into `{2}:{1}`; substituting default `{3}`".F(s,t.Name,f,ret) );
return ret;
};
FieldLoader.Load(section, yaml);
}
}
}

View File

@@ -1,76 +1,76 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
using System;
namespace OpenRA.GameRules
{
public class VoiceInfo
{
public readonly Dictionary<string,string[]> Variants;
public readonly Dictionary<string,string[]> Voices;
public readonly string DefaultVariant = ".aud" ;
[FieldLoader.Load] public readonly string[] DisableVariants = { };
static Dictionary<string, string[]> Load( MiniYaml y, string name )
{
return y.NodesDict.ContainsKey( name )
? y.NodesDict[ name ].NodesDict.ToDictionary(
a => a.Key,
a => (string[])FieldLoader.GetValue( "(value)", typeof( string[] ), a.Value.Value ) )
: new Dictionary<string, string[]>();
}
public readonly OpenRA.FileFormats.Lazy<Dictionary<string, VoicePool>> Pools;
public VoiceInfo( MiniYaml y )
{
FieldLoader.Load( this, y );
Variants = Load(y, "Variants");
Voices = Load(y, "Voices");
if (!Voices.ContainsKey("Attack"))
Voices.Add("Attack", Voices["Move"]);
if (!Voices.ContainsKey("AttackMove"))
Voices.Add("AttackMove", Voices["Move"]);
Pools = Lazy.New(() => Voices.ToDictionary( a => a.Key, a => new VoicePool(a.Value) ));
}
}
public class VoicePool
{
readonly string[] clips;
readonly List<string> liveclips = new List<string>();
public VoicePool(params string[] clips)
{
this.clips = clips;
}
public string GetNext()
{
if (liveclips.Count == 0)
liveclips.AddRange(clips);
if (liveclips.Count == 0)
return null; /* avoid crashing if there's no clips at all */
var i = Game.CosmeticRandom.Next(liveclips.Count);
var s = liveclips[i];
liveclips.RemoveAt(i);
return s;
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
using System;
namespace OpenRA.GameRules
{
public class VoiceInfo
{
public readonly Dictionary<string,string[]> Variants;
public readonly Dictionary<string,string[]> Voices;
public readonly string DefaultVariant = ".aud" ;
[FieldLoader.Load] public readonly string[] DisableVariants = { };
static Dictionary<string, string[]> Load( MiniYaml y, string name )
{
return y.NodesDict.ContainsKey( name )
? y.NodesDict[ name ].NodesDict.ToDictionary(
a => a.Key,
a => (string[])FieldLoader.GetValue( "(value)", typeof( string[] ), a.Value.Value ) )
: new Dictionary<string, string[]>();
}
public readonly OpenRA.FileFormats.Lazy<Dictionary<string, VoicePool>> Pools;
public VoiceInfo( MiniYaml y )
{
FieldLoader.Load( this, y );
Variants = Load(y, "Variants");
Voices = Load(y, "Voices");
if (!Voices.ContainsKey("Attack"))
Voices.Add("Attack", Voices["Move"]);
if (!Voices.ContainsKey("AttackMove"))
Voices.Add("AttackMove", Voices["Move"]);
Pools = Lazy.New(() => Voices.ToDictionary( a => a.Key, a => new VoicePool(a.Value) ));
}
}
public class VoicePool
{
readonly string[] clips;
readonly List<string> liveclips = new List<string>();
public VoicePool(params string[] clips)
{
this.clips = clips;
}
public string GetNext()
{
if (liveclips.Count == 0)
liveclips.AddRange(clips);
if (liveclips.Count == 0)
return null; /* avoid crashing if there's no clips at all */
var i = Game.CosmeticRandom.Next(liveclips.Count);
var s = liveclips[i];
liveclips.RemoveAt(i);
return s;
}
}
}

View File

@@ -1,126 +1,126 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using OpenRA.Effects;
using OpenRA.FileFormats;
using OpenRA.Traits;
using System.Linq;
namespace OpenRA.GameRules
{
public class WarheadInfo
{
[FieldLoader.Load] public readonly int Spread = 1; // distance (in pixels) from the explosion center at which damage is 1/2.
[FieldLoader.LoadUsing( "LoadVersus" )]
public readonly Dictionary<string, float> Versus; // damage vs each armortype
[FieldLoader.Load] public readonly bool Ore = false; // can this damage ore?
[FieldLoader.Load] public readonly string Explosion = null; // explosion effect to use
[FieldLoader.Load] public readonly string WaterExplosion = null; // explosion effect on hitting water (usually a splash)
[FieldLoader.Load] public readonly string SmudgeType = null; // type of smudge to apply
[FieldLoader.Load] public readonly int[] Size = { 0, 0 }; // size of the explosion. provide 2 values for a ring effect (outer/inner)
[FieldLoader.Load] public readonly int InfDeath = 0; // infantry death animation to use
[FieldLoader.Load] public readonly string ImpactSound = null; // sound to play on impact
[FieldLoader.Load] public readonly string WaterImpactSound = null; // sound to play on impact with water
[FieldLoader.Load] public readonly int Damage = 0; // how much (raw) damage to deal
[FieldLoader.Load] public readonly int Delay = 0; // delay in ticks before dealing the damage. 0=instant (old model)
[FieldLoader.Load] public readonly DamageModel DamageModel = DamageModel.Normal; // which damage model to use
[FieldLoader.Load] public readonly bool PreventProne = false; // whether we should prevent prone response in infantry.
public float EffectivenessAgainst(Actor self)
{
var health = self.Info.Traits.GetOrDefault<HealthInfo>();
if (health == null) return 0f;
var armor = self.Info.Traits.GetOrDefault<ArmorInfo>();
if (armor == null || armor.Type == null) return 1;
float versus;
return Versus.TryGetValue(armor.Type, out versus) ? versus : 1;
}
public WarheadInfo( MiniYaml yaml )
{
FieldLoader.Load( this, yaml );
}
static object LoadVersus( MiniYaml y )
{
return y.NodesDict.ContainsKey( "Versus" )
? y.NodesDict[ "Versus" ].NodesDict.ToDictionary(
a => a.Key,
a => (float)FieldLoader.GetValue( "(value)", typeof( float ), a.Value.Value ) )
: new Dictionary<string, float>();
}
}
public enum DamageModel
{
Normal, // classic RA damage model: point actors, distance-based falloff
PerCell, // like RA's "nuke damage"
}
public class ProjectileArgs
{
public WeaponInfo weapon;
public Actor firedBy;
public int2 src;
public int srcAltitude;
public int facing;
public Target target;
public int2 dest;
public int destAltitude;
public float firepowerModifier = 1.0f;
}
public interface IProjectileInfo { IEffect Create(ProjectileArgs args); }
public class WeaponInfo
{
[FieldLoader.Load] public readonly float Range = 0;
[FieldLoader.Load] public readonly string Report = null;
[FieldLoader.Load] public readonly int ROF = 1;
[FieldLoader.Load] public readonly int Burst = 1;
[FieldLoader.Load] public readonly bool Charges = false;
[FieldLoader.Load] public readonly bool Underwater = false;
[FieldLoader.Load] public readonly string[] ValidTargets = { "Ground" };
[FieldLoader.Load] public readonly int BurstDelay = 5;
[FieldLoader.Load] public readonly float MinRange = 0;
[FieldLoader.LoadUsing( "LoadProjectile" )] public IProjectileInfo Projectile;
[FieldLoader.LoadUsing( "LoadWarheads" )] public List<WarheadInfo> Warheads;
public WeaponInfo(string name, MiniYaml content)
{
FieldLoader.Load( this, content );
}
static object LoadProjectile( MiniYaml yaml )
{
MiniYaml proj;
if( !yaml.NodesDict.TryGetValue( "Projectile", out proj ) )
return null;
var ret = Game.CreateObject<IProjectileInfo>( proj.Value + "Info" );
FieldLoader.Load( ret, proj );
return ret;
}
static object LoadWarheads( MiniYaml yaml )
{
var ret = new List<WarheadInfo>();
foreach( var w in yaml.Nodes )
if( w.Key.Split( '@' )[ 0 ] == "Warhead" )
ret.Add( new WarheadInfo( w.Value ) );
return ret;
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using OpenRA.Effects;
using OpenRA.FileFormats;
using OpenRA.Traits;
using System.Linq;
namespace OpenRA.GameRules
{
public class WarheadInfo
{
[FieldLoader.Load] public readonly int Spread = 1; // distance (in pixels) from the explosion center at which damage is 1/2.
[FieldLoader.LoadUsing( "LoadVersus" )]
public readonly Dictionary<string, float> Versus; // damage vs each armortype
[FieldLoader.Load] public readonly bool Ore = false; // can this damage ore?
[FieldLoader.Load] public readonly string Explosion = null; // explosion effect to use
[FieldLoader.Load] public readonly string WaterExplosion = null; // explosion effect on hitting water (usually a splash)
[FieldLoader.Load] public readonly string SmudgeType = null; // type of smudge to apply
[FieldLoader.Load] public readonly int[] Size = { 0, 0 }; // size of the explosion. provide 2 values for a ring effect (outer/inner)
[FieldLoader.Load] public readonly int InfDeath = 0; // infantry death animation to use
[FieldLoader.Load] public readonly string ImpactSound = null; // sound to play on impact
[FieldLoader.Load] public readonly string WaterImpactSound = null; // sound to play on impact with water
[FieldLoader.Load] public readonly int Damage = 0; // how much (raw) damage to deal
[FieldLoader.Load] public readonly int Delay = 0; // delay in ticks before dealing the damage. 0=instant (old model)
[FieldLoader.Load] public readonly DamageModel DamageModel = DamageModel.Normal; // which damage model to use
[FieldLoader.Load] public readonly bool PreventProne = false; // whether we should prevent prone response in infantry.
public float EffectivenessAgainst(Actor self)
{
var health = self.Info.Traits.GetOrDefault<HealthInfo>();
if (health == null) return 0f;
var armor = self.Info.Traits.GetOrDefault<ArmorInfo>();
if (armor == null || armor.Type == null) return 1;
float versus;
return Versus.TryGetValue(armor.Type, out versus) ? versus : 1;
}
public WarheadInfo( MiniYaml yaml )
{
FieldLoader.Load( this, yaml );
}
static object LoadVersus( MiniYaml y )
{
return y.NodesDict.ContainsKey( "Versus" )
? y.NodesDict[ "Versus" ].NodesDict.ToDictionary(
a => a.Key,
a => (float)FieldLoader.GetValue( "(value)", typeof( float ), a.Value.Value ) )
: new Dictionary<string, float>();
}
}
public enum DamageModel
{
Normal, // classic RA damage model: point actors, distance-based falloff
PerCell, // like RA's "nuke damage"
}
public class ProjectileArgs
{
public WeaponInfo weapon;
public Actor firedBy;
public int2 src;
public int srcAltitude;
public int facing;
public Target target;
public int2 dest;
public int destAltitude;
public float firepowerModifier = 1.0f;
}
public interface IProjectileInfo { IEffect Create(ProjectileArgs args); }
public class WeaponInfo
{
[FieldLoader.Load] public readonly float Range = 0;
[FieldLoader.Load] public readonly string Report = null;
[FieldLoader.Load] public readonly int ROF = 1;
[FieldLoader.Load] public readonly int Burst = 1;
[FieldLoader.Load] public readonly bool Charges = false;
[FieldLoader.Load] public readonly bool Underwater = false;
[FieldLoader.Load] public readonly string[] ValidTargets = { "Ground" };
[FieldLoader.Load] public readonly int BurstDelay = 5;
[FieldLoader.Load] public readonly float MinRange = 0;
[FieldLoader.LoadUsing( "LoadProjectile" )] public IProjectileInfo Projectile;
[FieldLoader.LoadUsing( "LoadWarheads" )] public List<WarheadInfo> Warheads;
public WeaponInfo(string name, MiniYaml content)
{
FieldLoader.Load( this, content );
}
static object LoadProjectile( MiniYaml yaml )
{
MiniYaml proj;
if( !yaml.NodesDict.TryGetValue( "Projectile", out proj ) )
return null;
var ret = Game.CreateObject<IProjectileInfo>( proj.Value + "Info" );
FieldLoader.Load( ret, proj );
return ret;
}
static object LoadWarheads( MiniYaml yaml )
{
var ret = new List<WarheadInfo>();
foreach( var w in yaml.Nodes )
if( w.Key.Split( '@' )[ 0 ] == "Warhead" )
ret.Add( new WarheadInfo( w.Value ) );
return ret;
}
}
}

View File

@@ -1,145 +1,145 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
namespace OpenRA.Graphics
{
public class Animation
{
string name;
public Sequence CurrentSequence { get; private set; }
int frame = 0;
bool backwards = false;
bool tickAlways;
Func<int> facingFunc;
public string Name { get { return name; } }
public Animation( string name )
: this( name, () => 0 )
{
}
public Animation( string name, Func<int> facingFunc )
{
this.name = name.ToLowerInvariant();
this.tickFunc = () => { };
this.facingFunc = facingFunc;
}
public Sprite Image
{
get
{
return backwards
? CurrentSequence.GetSprite(CurrentSequence.End - frame - 1, facingFunc())
: CurrentSequence.GetSprite(frame, facingFunc());
}
}
public void Play( string sequenceName )
{
PlayThen(sequenceName, () => { });
}
public void PlayRepeating( string sequenceName )
{
PlayThen( sequenceName, () => PlayRepeating( CurrentSequence.Name ) );
}
public bool ReplaceAnim(string sequenceName)
{
if (!HasSequence(sequenceName))
return false;
CurrentSequence = SequenceProvider.GetSequence(name, sequenceName);
frame %= CurrentSequence.Length;
return true;
}
public void PlayThen( string sequenceName, Action after )
{
after = after ?? ( () => { } );
backwards = false;
tickAlways = false;
CurrentSequence = SequenceProvider.GetSequence( name, sequenceName );
frame = 0;
tickFunc = () =>
{
++frame;
if( frame >= CurrentSequence.Length )
{
frame = CurrentSequence.Length - 1;
tickFunc = () => { };
after();
}
};
}
public void PlayBackwardsThen(string sequenceName, Action after)
{
PlayThen(sequenceName, after);
backwards = true;
}
public void PlayFetchIndex( string sequenceName, Func<int> func )
{
backwards = false;
tickAlways = true;
CurrentSequence = SequenceProvider.GetSequence( name, sequenceName );
frame = func();
tickFunc = () => frame = func();
}
int timeUntilNextFrame;
Action tickFunc;
public void Tick()
{
Tick( 40 ); // tick one frame
}
public bool HasSequence(string seq) { return SequenceProvider.HasSequence( name, seq ); }
public void Tick( int t )
{
if( tickAlways )
tickFunc();
else
{
timeUntilNextFrame -= t;
while( timeUntilNextFrame <= 0 )
{
tickFunc();
timeUntilNextFrame += CurrentSequence != null ? CurrentSequence.Tick : 40; // 25 fps == 40 ms
}
}
}
public void ChangeImage(string newImage, string newAnimIfMissing)
{
newImage = newImage.ToLowerInvariant();
if (name != newImage)
{
name = newImage.ToLowerInvariant();
if (!ReplaceAnim(CurrentSequence.Name))
ReplaceAnim(newAnimIfMissing);
}
}
public Sequence GetSequence( string sequenceName )
{
return SequenceProvider.GetSequence( name, sequenceName );
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
namespace OpenRA.Graphics
{
public class Animation
{
string name;
public Sequence CurrentSequence { get; private set; }
int frame = 0;
bool backwards = false;
bool tickAlways;
Func<int> facingFunc;
public string Name { get { return name; } }
public Animation( string name )
: this( name, () => 0 )
{
}
public Animation( string name, Func<int> facingFunc )
{
this.name = name.ToLowerInvariant();
this.tickFunc = () => { };
this.facingFunc = facingFunc;
}
public Sprite Image
{
get
{
return backwards
? CurrentSequence.GetSprite(CurrentSequence.End - frame - 1, facingFunc())
: CurrentSequence.GetSprite(frame, facingFunc());
}
}
public void Play( string sequenceName )
{
PlayThen(sequenceName, () => { });
}
public void PlayRepeating( string sequenceName )
{
PlayThen( sequenceName, () => PlayRepeating( CurrentSequence.Name ) );
}
public bool ReplaceAnim(string sequenceName)
{
if (!HasSequence(sequenceName))
return false;
CurrentSequence = SequenceProvider.GetSequence(name, sequenceName);
frame %= CurrentSequence.Length;
return true;
}
public void PlayThen( string sequenceName, Action after )
{
after = after ?? ( () => { } );
backwards = false;
tickAlways = false;
CurrentSequence = SequenceProvider.GetSequence( name, sequenceName );
frame = 0;
tickFunc = () =>
{
++frame;
if( frame >= CurrentSequence.Length )
{
frame = CurrentSequence.Length - 1;
tickFunc = () => { };
after();
}
};
}
public void PlayBackwardsThen(string sequenceName, Action after)
{
PlayThen(sequenceName, after);
backwards = true;
}
public void PlayFetchIndex( string sequenceName, Func<int> func )
{
backwards = false;
tickAlways = true;
CurrentSequence = SequenceProvider.GetSequence( name, sequenceName );
frame = func();
tickFunc = () => frame = func();
}
int timeUntilNextFrame;
Action tickFunc;
public void Tick()
{
Tick( 40 ); // tick one frame
}
public bool HasSequence(string seq) { return SequenceProvider.HasSequence( name, seq ); }
public void Tick( int t )
{
if( tickAlways )
tickFunc();
else
{
timeUntilNextFrame -= t;
while( timeUntilNextFrame <= 0 )
{
tickFunc();
timeUntilNextFrame += CurrentSequence != null ? CurrentSequence.Tick : 40; // 25 fps == 40 ms
}
}
}
public void ChangeImage(string newImage, string newAnimIfMissing)
{
newImage = newImage.ToLowerInvariant();
if (name != newImage)
{
name = newImage.ToLowerInvariant();
if (!ReplaceAnim(CurrentSequence.Name))
ReplaceAnim(newAnimIfMissing);
}
}
public Sequence GetSequence( string sequenceName )
{
return SequenceProvider.GetSequence( name, sequenceName );
}
}
}

View File

@@ -1,87 +1,87 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
public static class ChromeProvider
{
static Dictionary<string, Dictionary<string, MappedImage>> collections;
static Dictionary<string, Sheet> cachedSheets;
static Dictionary<string, Dictionary<string, Sprite>> cachedSprites;
public static void Initialize(params string[] chromeFiles)
{
collections = new Dictionary<string, Dictionary<string, MappedImage>>();
cachedSheets = new Dictionary<string, Sheet>();
cachedSprites = new Dictionary<string, Dictionary<string, Sprite>>();
foreach (var f in chromeFiles)
LoadChromeSource(f);
}
static void LoadChromeSource(string filename)
{
XmlDocument document = new XmlDocument();
document.Load(FileSystem.Open(filename));
foreach (XmlElement eCollection in document.SelectNodes("/chrome/collection"))
LoadChromeForCollection(eCollection);
}
static void LoadChromeForCollection(XmlElement eCollection)
{
string elementName = eCollection.GetAttribute("name");
string defaultSrc = (eCollection.HasAttribute("src") ? eCollection.GetAttribute("src") : null);
var images = eCollection.SelectNodes("./image").OfType<XmlElement>()
.Select(e => new MappedImage(defaultSrc, e))
.ToDictionary(s => s.Name);
collections.Add(elementName, images);
}
public static Sprite GetImage(string collection, string image)
{
// Cached sprite
if (cachedSprites.ContainsKey(collection) && cachedSprites[collection].ContainsKey(image))
return cachedSprites[collection][image];
MappedImage mi;
try { mi = collections[collection][image]; }
catch (KeyNotFoundException)
{
throw new InvalidOperationException(
"Collection `{0}` does not have an image `{1}`".F(collection, image));
}
// Cached sheet
Sheet sheet;
if (cachedSheets.ContainsKey(mi.Src))
sheet = cachedSheets[mi.Src];
else
{
sheet = new Sheet(mi.Src);
cachedSheets.Add(mi.Src, sheet);
}
// Cache the sprite
if (!cachedSprites.ContainsKey(collection))
cachedSprites.Add(collection, new Dictionary<string, Sprite>());
cachedSprites[collection].Add(image, mi.GetImage(sheet));
return cachedSprites[collection][image];
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
public static class ChromeProvider
{
static Dictionary<string, Dictionary<string, MappedImage>> collections;
static Dictionary<string, Sheet> cachedSheets;
static Dictionary<string, Dictionary<string, Sprite>> cachedSprites;
public static void Initialize(params string[] chromeFiles)
{
collections = new Dictionary<string, Dictionary<string, MappedImage>>();
cachedSheets = new Dictionary<string, Sheet>();
cachedSprites = new Dictionary<string, Dictionary<string, Sprite>>();
foreach (var f in chromeFiles)
LoadChromeSource(f);
}
static void LoadChromeSource(string filename)
{
XmlDocument document = new XmlDocument();
document.Load(FileSystem.Open(filename));
foreach (XmlElement eCollection in document.SelectNodes("/chrome/collection"))
LoadChromeForCollection(eCollection);
}
static void LoadChromeForCollection(XmlElement eCollection)
{
string elementName = eCollection.GetAttribute("name");
string defaultSrc = (eCollection.HasAttribute("src") ? eCollection.GetAttribute("src") : null);
var images = eCollection.SelectNodes("./image").OfType<XmlElement>()
.Select(e => new MappedImage(defaultSrc, e))
.ToDictionary(s => s.Name);
collections.Add(elementName, images);
}
public static Sprite GetImage(string collection, string image)
{
// Cached sprite
if (cachedSprites.ContainsKey(collection) && cachedSprites[collection].ContainsKey(image))
return cachedSprites[collection][image];
MappedImage mi;
try { mi = collections[collection][image]; }
catch (KeyNotFoundException)
{
throw new InvalidOperationException(
"Collection `{0}` does not have an image `{1}`".F(collection, image));
}
// Cached sheet
Sheet sheet;
if (cachedSheets.ContainsKey(mi.Src))
sheet = cachedSheets[mi.Src];
else
{
sheet = new Sheet(mi.Src);
cachedSheets.Add(mi.Src, sheet);
}
// Cache the sprite
if (!cachedSprites.ContainsKey(collection))
cachedSprites.Add(collection, new Dictionary<string, Sprite>());
cachedSprites[collection].Add(image, mi.GetImage(sheet));
return cachedSprites[collection][image];
}
}
}

View File

@@ -1,10 +1,10 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
* see COPYING.
*/
#endregion

View File

@@ -1,57 +1,57 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Xml;
using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
public class CursorSequence
{
readonly int start, length;
readonly string palette;
public int Start { get { return start; } }
public int End { get { return start + length; } }
public int Length { get { return length; } }
public string Palette { get { return palette; } }
public readonly int2 Hotspot;
Sprite[] sprites;
public CursorSequence(string cursorSrc, string palette, MiniYaml info)
{
sprites = Game.modData.CursorSheetBuilder.LoadAllSprites(cursorSrc);
var d = info.NodesDict;
start = int.Parse(d["start"].Value);
this.palette = palette;
if ((d.ContainsKey("length") && d["length"].Value == "*") || (d.ContainsKey("end") && d["end"].Value == "*"))
length = sprites.Length - start;
else if (d.ContainsKey("length"))
length = int.Parse(d["length"].Value);
else if (d.ContainsKey("end"))
length = int.Parse(d["end"].Value) - start;
else
length = 1;
if (d.ContainsKey("x"))
int.TryParse(d["x"].Value, out Hotspot.X );
if (d.ContainsKey("y"))
int.TryParse(d["y"].Value, out Hotspot.Y );
}
public Sprite GetSprite(int frame)
{
return sprites[(frame % length) + start];
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Xml;
using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
public class CursorSequence
{
readonly int start, length;
readonly string palette;
public int Start { get { return start; } }
public int End { get { return start + length; } }
public int Length { get { return length; } }
public string Palette { get { return palette; } }
public readonly int2 Hotspot;
Sprite[] sprites;
public CursorSequence(string cursorSrc, string palette, MiniYaml info)
{
sprites = Game.modData.CursorSheetBuilder.LoadAllSprites(cursorSrc);
var d = info.NodesDict;
start = int.Parse(d["start"].Value);
this.palette = palette;
if ((d.ContainsKey("length") && d["length"].Value == "*") || (d.ContainsKey("end") && d["end"].Value == "*"))
length = sprites.Length - start;
else if (d.ContainsKey("length"))
length = int.Parse(d["length"].Value);
else if (d.ContainsKey("end"))
length = int.Parse(d["end"].Value) - start;
else
length = 1;
if (d.ContainsKey("x"))
int.TryParse(d["x"].Value, out Hotspot.X );
if (d.ContainsKey("y"))
int.TryParse(d["y"].Value, out Hotspot.Y );
}
public Sprite GetSprite(int frame)
{
return sprites[(frame % length) + start];
}
}
}

View File

@@ -1,45 +1,45 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Linq;
using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
public class CursorSheetBuilder
{
ModData modData;
Cache<string, Sprite[]> cursors;
readonly string[] exts = { ".shp" };
public CursorSheetBuilder( ModData modData )
{
this.modData = modData;
this.cursors = new Cache<string, Sprite[]>( LoadCursors );
}
Sprite[] LoadCursors(string filename)
{
try
{
var shp = new Dune2ShpReader(FileSystem.OpenWithExts(filename, exts));
return shp.Select(a => modData.SheetBuilder.Add(a.Image, a.Size)).ToArray();
}
catch (IndexOutOfRangeException) // This will occur when loading a custom (RA-format) .shp
{
var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts));
return shp.Select(a => modData.SheetBuilder.Add(a.Image, shp.Size)).ToArray();
}
}
public Sprite[] LoadAllSprites(string filename) { return cursors[filename]; }
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Linq;
using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
public class CursorSheetBuilder
{
ModData modData;
Cache<string, Sprite[]> cursors;
readonly string[] exts = { ".shp" };
public CursorSheetBuilder( ModData modData )
{
this.modData = modData;
this.cursors = new Cache<string, Sprite[]>( LoadCursors );
}
Sprite[] LoadCursors(string filename)
{
try
{
var shp = new Dune2ShpReader(FileSystem.OpenWithExts(filename, exts));
return shp.Select(a => modData.SheetBuilder.Add(a.Image, a.Size)).ToArray();
}
catch (IndexOutOfRangeException) // This will occur when loading a custom (RA-format) .shp
{
var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts));
return shp.Select(a => modData.SheetBuilder.Add(a.Image, shp.Size)).ToArray();
}
}
public Sprite[] LoadAllSprites(string filename) { return cursors[filename]; }
}
}

View File

@@ -1,82 +1,82 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.FileFormats.Graphics;
using OpenRA.Traits;
namespace OpenRA.Graphics
{
public class HardwarePalette
{
public const int MaxPalettes = 64;
int allocated = 0;
ITexture texture;
Dictionary<string, Palette> palettes;
Dictionary<string, int> indices;
public HardwarePalette()
{
palettes = new Dictionary<string, Palette>();
indices = new Dictionary<string, int>();
texture = Game.Renderer.Device.CreateTexture();
}
public Palette GetPalette(string name)
{
Palette ret;
if (!palettes.TryGetValue(name,out ret))
throw new InvalidOperationException("Palette `{0}` does not exist".F(name));
return ret;
}
public int GetPaletteIndex(string name)
{
int ret;
if (!indices.TryGetValue(name,out ret))
throw new InvalidOperationException("Palette `{0}` does not exist".F(name));
return ret;
}
public void AddPalette(string name, Palette p)
{
if (palettes.ContainsKey(name))
throw new InvalidOperationException("Palette {0} has already been defined".F(name));
palettes.Add(name, p);
indices.Add(name, allocated++);
}
public void Update(IEnumerable<IPaletteModifier> paletteMods)
{
var copy = palettes.ToDictionary(p => p.Key, p => new Palette(p.Value));
foreach (var mod in paletteMods)
mod.AdjustPalette(copy);
var data = new uint[MaxPalettes,256];
foreach (var pal in copy)
{
var j = indices[pal.Key];
var c = pal.Value.Values;
for (var i = 0; i < 256; i++)
data[j,i] = c[i];
}
// Doesn't work
texture.SetData(data);
Game.Renderer.PaletteTexture = texture;
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.FileFormats.Graphics;
using OpenRA.Traits;
namespace OpenRA.Graphics
{
public class HardwarePalette
{
public const int MaxPalettes = 64;
int allocated = 0;
ITexture texture;
Dictionary<string, Palette> palettes;
Dictionary<string, int> indices;
public HardwarePalette()
{
palettes = new Dictionary<string, Palette>();
indices = new Dictionary<string, int>();
texture = Game.Renderer.Device.CreateTexture();
}
public Palette GetPalette(string name)
{
Palette ret;
if (!palettes.TryGetValue(name,out ret))
throw new InvalidOperationException("Palette `{0}` does not exist".F(name));
return ret;
}
public int GetPaletteIndex(string name)
{
int ret;
if (!indices.TryGetValue(name,out ret))
throw new InvalidOperationException("Palette `{0}` does not exist".F(name));
return ret;
}
public void AddPalette(string name, Palette p)
{
if (palettes.ContainsKey(name))
throw new InvalidOperationException("Palette {0} has already been defined".F(name));
palettes.Add(name, p);
indices.Add(name, allocated++);
}
public void Update(IEnumerable<IPaletteModifier> paletteMods)
{
var copy = palettes.ToDictionary(p => p.Key, p => new Palette(p.Value));
foreach (var mod in paletteMods)
mod.AdjustPalette(copy);
var data = new uint[MaxPalettes,256];
foreach (var pal in copy)
{
var j = indices[pal.Key];
var c = pal.Value.Values;
for (var i = 0; i < 256; i++)
data[j,i] = c[i];
}
// Doesn't work
texture.SetData(data);
Game.Renderer.PaletteTexture = texture;
}
}
}

View File

@@ -1,77 +1,77 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Drawing;
using OpenRA.FileFormats.Graphics;
namespace OpenRA.Graphics
{
public class LineRenderer : Renderer.IBatchRenderer
{
Renderer renderer;
Vertex[] vertices = new Vertex[ Renderer.TempBufferSize ];
ushort[] indices = new ushort[ Renderer.TempBufferSize ];
int nv = 0, ni = 0;
public LineRenderer( Renderer renderer )
{
this.renderer = renderer;
}
public void Flush()
{
if( ni > 0 )
{
renderer.LineShader.Render( () =>
{
var vb = renderer.GetTempVertexBuffer();
var ib = renderer.GetTempIndexBuffer();
vb.SetData( vertices, nv );
ib.SetData( indices, ni );
renderer.DrawBatch( vb, ib,
nv, ni / 2, PrimitiveType.LineList );
} );
nv = 0; ni = 0;
}
}
public void DrawLine( float2 start, float2 end, Color startColor, Color endColor )
{
Renderer.CurrentBatchRenderer = this;
if( ni + 2 > Renderer.TempBufferSize )
Flush();
if( nv + 2 > Renderer.TempBufferSize )
Flush();
indices[ ni++ ] = (ushort)nv;
vertices[ nv++ ] = new Vertex( start,
new float2( startColor.R / 255.0f, startColor.G / 255.0f ),
new float2( startColor.B / 255.0f, startColor.A / 255.0f ) );
indices[ ni++ ] = (ushort)nv;
vertices[ nv++ ] = new Vertex( end,
new float2( endColor.R / 255.0f, endColor.G / 255.0f ),
new float2( endColor.B / 255.0f, endColor.A / 255.0f ) );
}
public void FillRect( RectangleF r, Color color )
{
for (float y = r.Top; y < r.Bottom; y++)
{
DrawLine(new float2(r.Left, y), new float2(r.Right, y), color, color);
}
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Drawing;
using OpenRA.FileFormats.Graphics;
namespace OpenRA.Graphics
{
public class LineRenderer : Renderer.IBatchRenderer
{
Renderer renderer;
Vertex[] vertices = new Vertex[ Renderer.TempBufferSize ];
ushort[] indices = new ushort[ Renderer.TempBufferSize ];
int nv = 0, ni = 0;
public LineRenderer( Renderer renderer )
{
this.renderer = renderer;
}
public void Flush()
{
if( ni > 0 )
{
renderer.LineShader.Render( () =>
{
var vb = renderer.GetTempVertexBuffer();
var ib = renderer.GetTempIndexBuffer();
vb.SetData( vertices, nv );
ib.SetData( indices, ni );
renderer.DrawBatch( vb, ib,
nv, ni / 2, PrimitiveType.LineList );
} );
nv = 0; ni = 0;
}
}
public void DrawLine( float2 start, float2 end, Color startColor, Color endColor )
{
Renderer.CurrentBatchRenderer = this;
if( ni + 2 > Renderer.TempBufferSize )
Flush();
if( nv + 2 > Renderer.TempBufferSize )
Flush();
indices[ ni++ ] = (ushort)nv;
vertices[ nv++ ] = new Vertex( start,
new float2( startColor.R / 255.0f, startColor.G / 255.0f ),
new float2( startColor.B / 255.0f, startColor.A / 255.0f ) );
indices[ ni++ ] = (ushort)nv;
vertices[ nv++ ] = new Vertex( end,
new float2( endColor.R / 255.0f, endColor.G / 255.0f ),
new float2( endColor.B / 255.0f, endColor.A / 255.0f ) );
}
public void FillRect( RectangleF r, Color color )
{
for (float y = r.Top; y < r.Bottom; y++)
{
DrawLine(new float2(r.Left, y), new float2(r.Right, y), color, color);
}
}
}
}

View File

@@ -1,41 +1,41 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Drawing;
using System.IO;
using System.Xml;
namespace OpenRA.Graphics
{
class MappedImage
{
readonly Rectangle rect;
public readonly string Src;
public readonly string Name;
public MappedImage(string defaultSrc, XmlElement e)
{
Src = (e.HasAttribute("src")) ? e.GetAttribute("src") : defaultSrc;
Name = e.GetAttribute("name");
if (Src == null)
throw new InvalidDataException("Image src missing");
rect = new Rectangle(int.Parse(e.GetAttribute("x")),
int.Parse(e.GetAttribute("y")),
int.Parse(e.GetAttribute("width")),
int.Parse(e.GetAttribute("height")));
}
public Sprite GetImage(Sheet s)
{
return new Sprite(s, rect, TextureChannel.Alpha);
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Drawing;
using System.IO;
using System.Xml;
namespace OpenRA.Graphics
{
class MappedImage
{
readonly Rectangle rect;
public readonly string Src;
public readonly string Name;
public MappedImage(string defaultSrc, XmlElement e)
{
Src = (e.HasAttribute("src")) ? e.GetAttribute("src") : defaultSrc;
Name = e.GetAttribute("name");
if (Src == null)
throw new InvalidDataException("Image src missing");
rect = new Rectangle(int.Parse(e.GetAttribute("x")),
int.Parse(e.GetAttribute("y")),
int.Parse(e.GetAttribute("width")),
int.Parse(e.GetAttribute("height")));
}
public Sprite GetImage(Sheet s)
{
return new Sprite(s, rect, TextureChannel.Alpha);
}
}
}

View File

@@ -1,195 +1,195 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Traits;
using System.IO;
namespace OpenRA.Graphics
{
public class Minimap
{
public static Bitmap TerrainBitmap(Map map)
{
return TerrainBitmap(map, false);
}
public static Bitmap TerrainBitmap(Map map, bool actualSize)
{
var tileset = Rules.TileSets[map.Tileset];
var width = map.Bounds.Width;
var height = map.Bounds.Height;
if (!actualSize)
{
width = height = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
}
Bitmap terrain = new Bitmap(width, height);
var bitmapData = terrain.LockBits(new Rectangle(0, 0, terrain.Width, terrain.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
int* c = (int*)bitmapData.Scan0;
for (var x = 0; x < map.Bounds.Width; x++)
for (var y = 0; y < map.Bounds.Height; y++)
{
var mapX = x + map.Bounds.Left;
var mapY = y + map.Bounds.Top;
var type = tileset.GetTerrainType(map.MapTiles.Value[mapX, mapY]);
if (!tileset.Terrain.ContainsKey(type))
throw new InvalidDataException("Tileset {0} lacks terraintype {1}".F(tileset.Id, type));
*(c + (y * bitmapData.Stride >> 2) + x) = tileset.Terrain[type].Color.ToArgb();
}
}
terrain.UnlockBits(bitmapData);
return terrain;
}
// Add the static resources defined in the map; if the map lives
// in a world use AddCustomTerrain instead
public static Bitmap AddStaticResources(Map map, Bitmap terrainBitmap)
{
Bitmap terrain = new Bitmap(terrainBitmap);
var tileset = Rules.TileSets[map.Tileset];
var bitmapData = terrain.LockBits(new Rectangle(0, 0, terrain.Width, terrain.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
int* c = (int*)bitmapData.Scan0;
for (var x = 0; x < map.Bounds.Width; x++)
for (var y = 0; y < map.Bounds.Height; y++)
{
var mapX = x + map.Bounds.Left;
var mapY = y + map.Bounds.Top;
if (map.MapResources.Value[mapX, mapY].type == 0)
continue;
var res = Rules.Info["world"].Traits.WithInterface<ResourceTypeInfo>()
.Where(t => t.ResourceType == map.MapResources.Value[mapX, mapY].type)
.Select(t => t.TerrainType).FirstOrDefault();
if (res == null)
continue;
*(c + (y * bitmapData.Stride >> 2) + x) = tileset.Terrain[res].Color.ToArgb();
}
}
terrain.UnlockBits(bitmapData);
return terrain;
}
public static Bitmap CustomTerrainBitmap(World world)
{
var map = world.Map;
var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
Bitmap bitmap = new Bitmap(size, size);
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
int* c = (int*)bitmapData.Scan0;
for (var x = 0; x < map.Bounds.Width; x++)
for (var y = 0; y < map.Bounds.Height; y++)
{
var mapX = x + map.Bounds.Left;
var mapY = y + map.Bounds.Top;
var custom = map.CustomTerrain[mapX,mapY];
if (custom == null)
continue;
*(c + (y * bitmapData.Stride >> 2) + x) = world.TileSet.Terrain[custom].Color.ToArgb();
}
}
bitmap.UnlockBits(bitmapData);
return bitmap;
}
public static Bitmap ActorsBitmap(World world)
{
var map = world.Map;
var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
Bitmap bitmap = new Bitmap(size, size);
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
int* c = (int*)bitmapData.Scan0;
foreach (var t in world.Queries.WithTrait<IRadarSignature>())
{
if (!world.LocalShroud.IsVisible(t.Actor))
continue;
var color = t.Trait.RadarSignatureColor(t.Actor);
foreach (var cell in t.Trait.RadarSignatureCells(t.Actor))
if (world.Map.IsInMap(cell))
*(c + ((cell.Y - world.Map.Bounds.Top) * bitmapData.Stride >> 2) + cell.X - world.Map.Bounds.Left) = color.ToArgb();
}
}
bitmap.UnlockBits(bitmapData);
return bitmap;
}
public static Bitmap ShroudBitmap(World world)
{
var map = world.Map;
var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
Bitmap bitmap = new Bitmap(size, size);
if (world.LocalShroud.Disabled)
return bitmap;
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
var shroud = Color.Black.ToArgb();
var fog = Color.FromArgb(128, Color.Black).ToArgb();
unsafe
{
int* c = (int*)bitmapData.Scan0;
for (var x = 0; x < map.Bounds.Width; x++)
for (var y = 0; y < map.Bounds.Height; y++)
{
var mapX = x + map.Bounds.Left;
var mapY = y + map.Bounds.Top;
if (!world.LocalShroud.IsExplored(mapX, mapY))
*(c + (y * bitmapData.Stride >> 2) + x) = shroud;
else if (!world.LocalShroud.IsVisible(mapX,mapY))
*(c + (y * bitmapData.Stride >> 2) + x) = fog;
}
}
bitmap.UnlockBits(bitmapData);
return bitmap;
}
public static Bitmap RenderMapPreview(Map map)
{
Bitmap terrain = TerrainBitmap(map);
return AddStaticResources(map, terrain);
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Traits;
using System.IO;
namespace OpenRA.Graphics
{
public class Minimap
{
public static Bitmap TerrainBitmap(Map map)
{
return TerrainBitmap(map, false);
}
public static Bitmap TerrainBitmap(Map map, bool actualSize)
{
var tileset = Rules.TileSets[map.Tileset];
var width = map.Bounds.Width;
var height = map.Bounds.Height;
if (!actualSize)
{
width = height = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
}
Bitmap terrain = new Bitmap(width, height);
var bitmapData = terrain.LockBits(new Rectangle(0, 0, terrain.Width, terrain.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
int* c = (int*)bitmapData.Scan0;
for (var x = 0; x < map.Bounds.Width; x++)
for (var y = 0; y < map.Bounds.Height; y++)
{
var mapX = x + map.Bounds.Left;
var mapY = y + map.Bounds.Top;
var type = tileset.GetTerrainType(map.MapTiles.Value[mapX, mapY]);
if (!tileset.Terrain.ContainsKey(type))
throw new InvalidDataException("Tileset {0} lacks terraintype {1}".F(tileset.Id, type));
*(c + (y * bitmapData.Stride >> 2) + x) = tileset.Terrain[type].Color.ToArgb();
}
}
terrain.UnlockBits(bitmapData);
return terrain;
}
// Add the static resources defined in the map; if the map lives
// in a world use AddCustomTerrain instead
public static Bitmap AddStaticResources(Map map, Bitmap terrainBitmap)
{
Bitmap terrain = new Bitmap(terrainBitmap);
var tileset = Rules.TileSets[map.Tileset];
var bitmapData = terrain.LockBits(new Rectangle(0, 0, terrain.Width, terrain.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
int* c = (int*)bitmapData.Scan0;
for (var x = 0; x < map.Bounds.Width; x++)
for (var y = 0; y < map.Bounds.Height; y++)
{
var mapX = x + map.Bounds.Left;
var mapY = y + map.Bounds.Top;
if (map.MapResources.Value[mapX, mapY].type == 0)
continue;
var res = Rules.Info["world"].Traits.WithInterface<ResourceTypeInfo>()
.Where(t => t.ResourceType == map.MapResources.Value[mapX, mapY].type)
.Select(t => t.TerrainType).FirstOrDefault();
if (res == null)
continue;
*(c + (y * bitmapData.Stride >> 2) + x) = tileset.Terrain[res].Color.ToArgb();
}
}
terrain.UnlockBits(bitmapData);
return terrain;
}
public static Bitmap CustomTerrainBitmap(World world)
{
var map = world.Map;
var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
Bitmap bitmap = new Bitmap(size, size);
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
int* c = (int*)bitmapData.Scan0;
for (var x = 0; x < map.Bounds.Width; x++)
for (var y = 0; y < map.Bounds.Height; y++)
{
var mapX = x + map.Bounds.Left;
var mapY = y + map.Bounds.Top;
var custom = map.CustomTerrain[mapX,mapY];
if (custom == null)
continue;
*(c + (y * bitmapData.Stride >> 2) + x) = world.TileSet.Terrain[custom].Color.ToArgb();
}
}
bitmap.UnlockBits(bitmapData);
return bitmap;
}
public static Bitmap ActorsBitmap(World world)
{
var map = world.Map;
var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
Bitmap bitmap = new Bitmap(size, size);
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
int* c = (int*)bitmapData.Scan0;
foreach (var t in world.Queries.WithTrait<IRadarSignature>())
{
if (!world.LocalShroud.IsVisible(t.Actor))
continue;
var color = t.Trait.RadarSignatureColor(t.Actor);
foreach (var cell in t.Trait.RadarSignatureCells(t.Actor))
if (world.Map.IsInMap(cell))
*(c + ((cell.Y - world.Map.Bounds.Top) * bitmapData.Stride >> 2) + cell.X - world.Map.Bounds.Left) = color.ToArgb();
}
}
bitmap.UnlockBits(bitmapData);
return bitmap;
}
public static Bitmap ShroudBitmap(World world)
{
var map = world.Map;
var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
Bitmap bitmap = new Bitmap(size, size);
if (world.LocalShroud.Disabled)
return bitmap;
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
var shroud = Color.Black.ToArgb();
var fog = Color.FromArgb(128, Color.Black).ToArgb();
unsafe
{
int* c = (int*)bitmapData.Scan0;
for (var x = 0; x < map.Bounds.Width; x++)
for (var y = 0; y < map.Bounds.Height; y++)
{
var mapX = x + map.Bounds.Left;
var mapY = y + map.Bounds.Top;
if (!world.LocalShroud.IsExplored(mapX, mapY))
*(c + (y * bitmapData.Stride >> 2) + x) = shroud;
else if (!world.LocalShroud.IsVisible(mapX,mapY))
*(c + (y * bitmapData.Stride >> 2) + x) = fog;
}
}
bitmap.UnlockBits(bitmapData);
return bitmap;
}
public static Bitmap RenderMapPreview(Map map)
{
Bitmap terrain = TerrainBitmap(map);
return AddStaticResources(map, terrain);
}
}
}

View File

@@ -1,208 +1,208 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using OpenRA.FileFormats.Graphics;
using OpenRA.Support;
namespace OpenRA.Graphics
{
public class Renderer
{
internal static int SheetSize;
internal IShader SpriteShader { get; private set; } /* note: shared shader params */
internal IShader LineShader { get; private set; }
internal IShader RgbaSpriteShader { get; private set; }
internal IShader WorldSpriteShader { get; private set; }
public SpriteRenderer SpriteRenderer { get; private set; }
public SpriteRenderer RgbaSpriteRenderer { get; private set; }
public SpriteRenderer WorldSpriteRenderer { get; private set; }
public LineRenderer LineRenderer { get; private set; }
public ITexture PaletteTexture;
public readonly SpriteFont RegularFont, BoldFont, TitleFont, TinyFont;
internal const int TempBufferSize = 8192;
const int TempBufferCount = 8;
Queue<IVertexBuffer<Vertex>> tempBuffersV = new Queue<IVertexBuffer<Vertex>>();
Queue<IIndexBuffer> tempBuffersI = new Queue<IIndexBuffer>();
public Renderer()
{
SpriteShader = device.CreateShader("world-shp");
LineShader = device.CreateShader("world-line");
RgbaSpriteShader = device.CreateShader("chrome-rgba");
WorldSpriteShader = device.CreateShader("chrome-shp");
SpriteRenderer = new SpriteRenderer( this, SpriteShader );
RgbaSpriteRenderer = new SpriteRenderer( this, RgbaSpriteShader );
WorldSpriteRenderer = new SpriteRenderer( this, WorldSpriteShader );
LineRenderer = new LineRenderer(this);
RegularFont = new SpriteFont("FreeSans.ttf", 14);
BoldFont = new SpriteFont("FreeSansBold.ttf", 14);
TitleFont = new SpriteFont("titles.ttf", 48);
TinyFont = new SpriteFont("FreeSans.ttf", 10);
for( int i = 0 ; i < TempBufferCount ; i++ )
{
tempBuffersV.Enqueue( device.CreateVertexBuffer( TempBufferSize ) );
tempBuffersI.Enqueue( device.CreateIndexBuffer( TempBufferSize ) );
}
}
internal IGraphicsDevice Device { get { return device; } }
public void BeginFrame(float2 scroll)
{
device.Clear(Color.Black);
float2 r1 = new float2(2f/Resolution.Width, -2f/Resolution.Height);
float2 r2 = new float2(-1, 1);
SetShaderParams( SpriteShader, r1, r2, scroll );
SetShaderParams( LineShader, r1, r2, scroll );
SetShaderParams( RgbaSpriteShader, r1, r2, scroll );
SetShaderParams( WorldSpriteShader, r1, r2, scroll );
}
private void SetShaderParams( IShader s, float2 r1, float2 r2, float2 scroll )
{
s.SetValue( "Palette", PaletteTexture );
s.SetValue( "Scroll", (int) scroll.X, (int) scroll.Y );
s.SetValue( "r1", r1.X, r1.Y );
s.SetValue( "r2", r2.X, r2.Y );
s.Commit();
}
public void EndFrame( IInputHandler inputHandler )
{
Flush();
device.Present( inputHandler );
}
public void DrawBatch<T>(IVertexBuffer<T> vertices, IIndexBuffer indices,
Range<int> vertexRange, Range<int> indexRange, PrimitiveType type, IShader shader)
where T : struct
{
vertices.Bind();
indices.Bind();
device.DrawIndexedPrimitives(type, vertexRange, indexRange);
PerfHistory.Increment("batches", 1);
}
public void DrawBatch<T>(IVertexBuffer<T> vertices, IIndexBuffer indices,
int vertexPool, int numPrimitives, PrimitiveType type)
where T : struct
{
vertices.Bind();
indices.Bind();
device.DrawIndexedPrimitives(type, vertexPool, numPrimitives);
PerfHistory.Increment("batches", 1);
}
public void Flush()
{
CurrentBatchRenderer = null;
}
static IGraphicsDevice device;
public static Size Resolution { get { return device.WindowSize; } }
internal static void Initialize( OpenRA.FileFormats.Graphics.WindowMode windowMode )
{
var resolution = GetResolution( windowMode );
device = CreateDevice( Assembly.LoadFile( Path.GetFullPath( "OpenRA.Renderer.{0}.dll".F(Game.Settings.Graphics.Renderer) ) ), resolution.Width, resolution.Height, windowMode, false );
}
static Size GetResolution(WindowMode windowmode)
{
var desktopResolution = Screen.PrimaryScreen.Bounds.Size;
var customSize = (windowmode == WindowMode.Windowed) ? Game.Settings.Graphics.WindowedSize : Game.Settings.Graphics.FullscreenSize;
if (customSize.X > 0 && customSize.Y > 0)
{
desktopResolution.Width = customSize.X;
desktopResolution.Height = customSize.Y;
}
return new Size(
desktopResolution.Width,
desktopResolution.Height);
}
static IGraphicsDevice CreateDevice( Assembly rendererDll, int width, int height, WindowMode window, bool vsync )
{
foreach( RendererAttribute r in rendererDll.GetCustomAttributes( typeof( RendererAttribute ), false ) )
{
return (IGraphicsDevice)r.Type.GetConstructor( new Type[] { typeof( int ), typeof( int ), typeof( WindowMode ), typeof( bool ) } )
.Invoke( new object[] { width, height, window, vsync } );
}
throw new NotImplementedException();
}
internal IVertexBuffer<Vertex> GetTempVertexBuffer()
{
var ret = tempBuffersV.Dequeue();
tempBuffersV.Enqueue( ret );
return ret;
}
internal IIndexBuffer GetTempIndexBuffer()
{
var ret = tempBuffersI.Dequeue();
tempBuffersI.Enqueue( ret );
return ret;
}
public interface IBatchRenderer
{
void Flush();
}
static IBatchRenderer currentBatchRenderer;
public static IBatchRenderer CurrentBatchRenderer
{
get { return currentBatchRenderer; }
set
{
if( currentBatchRenderer == value ) return;
if( currentBatchRenderer != null )
currentBatchRenderer.Flush();
currentBatchRenderer = value;
}
}
public void EnableScissor(int left, int top, int width, int height)
{
Flush();
Device.EnableScissor( left, top, width, height );
}
public void DisableScissor()
{
Flush();
Device.DisableScissor();
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using OpenRA.FileFormats.Graphics;
using OpenRA.Support;
namespace OpenRA.Graphics
{
public class Renderer
{
internal static int SheetSize;
internal IShader SpriteShader { get; private set; } /* note: shared shader params */
internal IShader LineShader { get; private set; }
internal IShader RgbaSpriteShader { get; private set; }
internal IShader WorldSpriteShader { get; private set; }
public SpriteRenderer SpriteRenderer { get; private set; }
public SpriteRenderer RgbaSpriteRenderer { get; private set; }
public SpriteRenderer WorldSpriteRenderer { get; private set; }
public LineRenderer LineRenderer { get; private set; }
public ITexture PaletteTexture;
public readonly SpriteFont RegularFont, BoldFont, TitleFont, TinyFont;
internal const int TempBufferSize = 8192;
const int TempBufferCount = 8;
Queue<IVertexBuffer<Vertex>> tempBuffersV = new Queue<IVertexBuffer<Vertex>>();
Queue<IIndexBuffer> tempBuffersI = new Queue<IIndexBuffer>();
public Renderer()
{
SpriteShader = device.CreateShader("world-shp");
LineShader = device.CreateShader("world-line");
RgbaSpriteShader = device.CreateShader("chrome-rgba");
WorldSpriteShader = device.CreateShader("chrome-shp");
SpriteRenderer = new SpriteRenderer( this, SpriteShader );
RgbaSpriteRenderer = new SpriteRenderer( this, RgbaSpriteShader );
WorldSpriteRenderer = new SpriteRenderer( this, WorldSpriteShader );
LineRenderer = new LineRenderer(this);
RegularFont = new SpriteFont("FreeSans.ttf", 14);
BoldFont = new SpriteFont("FreeSansBold.ttf", 14);
TitleFont = new SpriteFont("titles.ttf", 48);
TinyFont = new SpriteFont("FreeSans.ttf", 10);
for( int i = 0 ; i < TempBufferCount ; i++ )
{
tempBuffersV.Enqueue( device.CreateVertexBuffer( TempBufferSize ) );
tempBuffersI.Enqueue( device.CreateIndexBuffer( TempBufferSize ) );
}
}
internal IGraphicsDevice Device { get { return device; } }
public void BeginFrame(float2 scroll)
{
device.Clear(Color.Black);
float2 r1 = new float2(2f/Resolution.Width, -2f/Resolution.Height);
float2 r2 = new float2(-1, 1);
SetShaderParams( SpriteShader, r1, r2, scroll );
SetShaderParams( LineShader, r1, r2, scroll );
SetShaderParams( RgbaSpriteShader, r1, r2, scroll );
SetShaderParams( WorldSpriteShader, r1, r2, scroll );
}
private void SetShaderParams( IShader s, float2 r1, float2 r2, float2 scroll )
{
s.SetValue( "Palette", PaletteTexture );
s.SetValue( "Scroll", (int) scroll.X, (int) scroll.Y );
s.SetValue( "r1", r1.X, r1.Y );
s.SetValue( "r2", r2.X, r2.Y );
s.Commit();
}
public void EndFrame( IInputHandler inputHandler )
{
Flush();
device.Present( inputHandler );
}
public void DrawBatch<T>(IVertexBuffer<T> vertices, IIndexBuffer indices,
Range<int> vertexRange, Range<int> indexRange, PrimitiveType type, IShader shader)
where T : struct
{
vertices.Bind();
indices.Bind();
device.DrawIndexedPrimitives(type, vertexRange, indexRange);
PerfHistory.Increment("batches", 1);
}
public void DrawBatch<T>(IVertexBuffer<T> vertices, IIndexBuffer indices,
int vertexPool, int numPrimitives, PrimitiveType type)
where T : struct
{
vertices.Bind();
indices.Bind();
device.DrawIndexedPrimitives(type, vertexPool, numPrimitives);
PerfHistory.Increment("batches", 1);
}
public void Flush()
{
CurrentBatchRenderer = null;
}
static IGraphicsDevice device;
public static Size Resolution { get { return device.WindowSize; } }
internal static void Initialize( OpenRA.FileFormats.Graphics.WindowMode windowMode )
{
var resolution = GetResolution( windowMode );
device = CreateDevice( Assembly.LoadFile( Path.GetFullPath( "OpenRA.Renderer.{0}.dll".F(Game.Settings.Graphics.Renderer) ) ), resolution.Width, resolution.Height, windowMode, false );
}
static Size GetResolution(WindowMode windowmode)
{
var desktopResolution = Screen.PrimaryScreen.Bounds.Size;
var customSize = (windowmode == WindowMode.Windowed) ? Game.Settings.Graphics.WindowedSize : Game.Settings.Graphics.FullscreenSize;
if (customSize.X > 0 && customSize.Y > 0)
{
desktopResolution.Width = customSize.X;
desktopResolution.Height = customSize.Y;
}
return new Size(
desktopResolution.Width,
desktopResolution.Height);
}
static IGraphicsDevice CreateDevice( Assembly rendererDll, int width, int height, WindowMode window, bool vsync )
{
foreach( RendererAttribute r in rendererDll.GetCustomAttributes( typeof( RendererAttribute ), false ) )
{
return (IGraphicsDevice)r.Type.GetConstructor( new Type[] { typeof( int ), typeof( int ), typeof( WindowMode ), typeof( bool ) } )
.Invoke( new object[] { width, height, window, vsync } );
}
throw new NotImplementedException();
}
internal IVertexBuffer<Vertex> GetTempVertexBuffer()
{
var ret = tempBuffersV.Dequeue();
tempBuffersV.Enqueue( ret );
return ret;
}
internal IIndexBuffer GetTempIndexBuffer()
{
var ret = tempBuffersI.Dequeue();
tempBuffersI.Enqueue( ret );
return ret;
}
public interface IBatchRenderer
{
void Flush();
}
static IBatchRenderer currentBatchRenderer;
public static IBatchRenderer CurrentBatchRenderer
{
get { return currentBatchRenderer; }
set
{
if( currentBatchRenderer == value ) return;
if( currentBatchRenderer != null )
currentBatchRenderer.Flush();
currentBatchRenderer = value;
}
}
public void EnableScissor(int left, int top, int width, int height)
{
Flush();
Device.EnableScissor( left, top, width, height );
}
public void DisableScissor()
{
Flush();
Device.DisableScissor();
}
}
}

View File

@@ -1,89 +1,89 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Xml;
using OpenRA.FileFormats;
using System.Collections.Generic;
namespace OpenRA.Graphics
{
public class Sequence
{
readonly Sprite[] sprites;
readonly int start, length, facings, tick;
public readonly string Name;
public int Start { get { return start; } }
public int End { get { return start + length; } }
public int Length { get { return length; } }
public int Facings { get { return facings; } }
public int Tick { get { return tick; } }
string srcOverride;
public Sequence(string unit, string name, MiniYaml info)
{
srcOverride = info.Value;
Name = name;
var d = info.NodesDict;
sprites = Game.modData.SpriteLoader.LoadAllSprites(string.IsNullOrEmpty(srcOverride) ? unit : srcOverride );
start = int.Parse(d["Start"].Value);
if (!d.ContainsKey("Length"))
length = 1;
else if (d["Length"].Value == "*")
length = sprites.Length - Start;
else
length = int.Parse(d["Length"].Value);
if(d.ContainsKey("Facings"))
facings = int.Parse(d["Facings"].Value);
else
facings = 1;
if(d.ContainsKey("Tick"))
tick = int.Parse(d["Tick"].Value);
else
tick = 40;
}
public MiniYaml Save()
{
var root = new List<MiniYamlNode>();
root.Add(new MiniYamlNode("Start", start.ToString()));
if (length > 1 && (start != 0 || length != sprites.Length - start))
root.Add(new MiniYamlNode("Length", length.ToString()));
else if (length > 1 && length == sprites.Length - start)
root.Add(new MiniYamlNode("Length", "*"));
if (facings > 1)
root.Add(new MiniYamlNode("Facings", facings.ToString()));
if (tick != 40)
root.Add(new MiniYamlNode("Tick", tick.ToString()));
return new MiniYaml(srcOverride, root);
}
public Sprite GetSprite( int frame )
{
return GetSprite( frame, 0 );
}
public Sprite GetSprite(int frame, int facing)
{
var f = Traits.Util.QuantizeFacing( facing, facings );
return sprites[ (f * length) + ( frame % length ) + start ];
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Xml;
using OpenRA.FileFormats;
using System.Collections.Generic;
namespace OpenRA.Graphics
{
public class Sequence
{
readonly Sprite[] sprites;
readonly int start, length, facings, tick;
public readonly string Name;
public int Start { get { return start; } }
public int End { get { return start + length; } }
public int Length { get { return length; } }
public int Facings { get { return facings; } }
public int Tick { get { return tick; } }
string srcOverride;
public Sequence(string unit, string name, MiniYaml info)
{
srcOverride = info.Value;
Name = name;
var d = info.NodesDict;
sprites = Game.modData.SpriteLoader.LoadAllSprites(string.IsNullOrEmpty(srcOverride) ? unit : srcOverride );
start = int.Parse(d["Start"].Value);
if (!d.ContainsKey("Length"))
length = 1;
else if (d["Length"].Value == "*")
length = sprites.Length - Start;
else
length = int.Parse(d["Length"].Value);
if(d.ContainsKey("Facings"))
facings = int.Parse(d["Facings"].Value);
else
facings = 1;
if(d.ContainsKey("Tick"))
tick = int.Parse(d["Tick"].Value);
else
tick = 40;
}
public MiniYaml Save()
{
var root = new List<MiniYamlNode>();
root.Add(new MiniYamlNode("Start", start.ToString()));
if (length > 1 && (start != 0 || length != sprites.Length - start))
root.Add(new MiniYamlNode("Length", length.ToString()));
else if (length > 1 && length == sprites.Length - start)
root.Add(new MiniYamlNode("Length", "*"));
if (facings > 1)
root.Add(new MiniYamlNode("Facings", facings.ToString()));
if (tick != 40)
root.Add(new MiniYamlNode("Tick", tick.ToString()));
return new MiniYaml(srcOverride, root);
}
public Sprite GetSprite( int frame )
{
return GetSprite( frame, 0 );
}
public Sprite GetSprite(int frame, int facing)
{
var f = Traits.Util.QuantizeFacing( facing, facings );
return sprites[ (f * length) + ( frame % length ) + start ];
}
}
}

View File

@@ -1,72 +1,72 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
public static class SequenceProvider
{
static Dictionary<string, Dictionary<string, Sequence>> units;
public static void Initialize(string[] sequenceFiles, List<MiniYamlNode> sequenceNodes)
{
units = new Dictionary<string, Dictionary<string, Sequence>>();
if (sequenceFiles.Length == 0)
return;
var sequences = sequenceFiles.Select(s => MiniYaml.FromFile(s)).Aggregate(sequenceNodes, MiniYaml.Merge);
foreach (var s in sequences)
LoadSequencesForUnit(s.Key, s.Value);
}
static void LoadSequencesForUnit(string unit, MiniYaml sequences)
{
Game.modData.LoadScreen.Display();
try {
var seq = sequences.NodesDict.ToDictionary(x => x.Key, x => new Sequence(unit,x.Key,x.Value));
units.Add(unit, seq);
} catch (FileNotFoundException) {} // Do nothing; we can crash later if we actually wanted art
}
public static MiniYaml SaveSequencesForUnit(string unitname)
{
var ret = new List<MiniYamlNode>();
foreach (var s in units[unitname])
ret.Add(new MiniYamlNode(s.Key, s.Value.Save()));
return new MiniYaml(null, ret);
}
public static Sequence GetSequence(string unitName, string sequenceName)
{
try { return units[unitName][sequenceName]; }
catch (KeyNotFoundException)
{
if (units.ContainsKey(unitName))
throw new InvalidOperationException(
"Unit `{0}` does not have a sequence `{1}`".F(unitName, sequenceName));
else
throw new InvalidOperationException(
"Unit `{0}` does not have any sequences defined.".F(unitName));
}
}
public static bool HasSequence(string unit, string seq)
{
return units[unit].ContainsKey(seq);
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
public static class SequenceProvider
{
static Dictionary<string, Dictionary<string, Sequence>> units;
public static void Initialize(string[] sequenceFiles, List<MiniYamlNode> sequenceNodes)
{
units = new Dictionary<string, Dictionary<string, Sequence>>();
if (sequenceFiles.Length == 0)
return;
var sequences = sequenceFiles.Select(s => MiniYaml.FromFile(s)).Aggregate(sequenceNodes, MiniYaml.Merge);
foreach (var s in sequences)
LoadSequencesForUnit(s.Key, s.Value);
}
static void LoadSequencesForUnit(string unit, MiniYaml sequences)
{
Game.modData.LoadScreen.Display();
try {
var seq = sequences.NodesDict.ToDictionary(x => x.Key, x => new Sequence(unit,x.Key,x.Value));
units.Add(unit, seq);
} catch (FileNotFoundException) {} // Do nothing; we can crash later if we actually wanted art
}
public static MiniYaml SaveSequencesForUnit(string unitname)
{
var ret = new List<MiniYamlNode>();
foreach (var s in units[unitname])
ret.Add(new MiniYamlNode(s.Key, s.Value.Save()));
return new MiniYaml(null, ret);
}
public static Sequence GetSequence(string unitName, string sequenceName)
{
try { return units[unitName][sequenceName]; }
catch (KeyNotFoundException)
{
if (units.ContainsKey(unitName))
throw new InvalidOperationException(
"Unit `{0}` does not have a sequence `{1}`".F(unitName, sequenceName));
else
throw new InvalidOperationException(
"Unit `{0}` does not have any sequences defined.".F(unitName));
}
}
public static bool HasSequence(string unit, string seq)
{
return units[unit].ContainsKey(seq);
}
}
}

View File

@@ -1,67 +1,67 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Drawing;
using OpenRA.FileFormats;
using OpenRA.FileFormats.Graphics;
namespace OpenRA.Graphics
{
public class Sheet
{
Bitmap bitmap;
ITexture texture;
bool dirty;
byte[] data;
public readonly Size Size;
public Sheet(Size size)
{
Size = size;
}
public Sheet(string filename)
{
bitmap = (Bitmap)Image.FromStream(FileSystem.Open(filename));
Size = bitmap.Size;
}
public ITexture Texture
{
get
{
if (texture == null)
{
texture = Game.Renderer.Device.CreateTexture();
dirty = true;
}
if (dirty)
{
if (data != null)
{
texture.SetData(data, Size.Width, Size.Height);
dirty = false;
}
else if (bitmap != null)
{
texture.SetData(bitmap);
dirty = false;
}
}
return texture;
}
}
public byte[] Data { get { if (data == null) data = new byte[4 * Size.Width * Size.Height]; return data; } }
public void MakeDirty() { dirty = true; }
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Drawing;
using OpenRA.FileFormats;
using OpenRA.FileFormats.Graphics;
namespace OpenRA.Graphics
{
public class Sheet
{
Bitmap bitmap;
ITexture texture;
bool dirty;
byte[] data;
public readonly Size Size;
public Sheet(Size size)
{
Size = size;
}
public Sheet(string filename)
{
bitmap = (Bitmap)Image.FromStream(FileSystem.Open(filename));
Size = bitmap.Size;
}
public ITexture Texture
{
get
{
if (texture == null)
{
texture = Game.Renderer.Device.CreateTexture();
dirty = true;
}
if (dirty)
{
if (data != null)
{
texture.SetData(data, Size.Width, Size.Height);
dirty = false;
}
else if (bitmap != null)
{
texture.SetData(bitmap);
dirty = false;
}
}
return texture;
}
}
public byte[] Data { get { if (data == null) data = new byte[4 * Size.Width * Size.Height]; return data; } }
public void MakeDirty() { dirty = true; }
}
}

View File

@@ -1,102 +1,102 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Drawing;
namespace OpenRA.Graphics
{
public class SheetBuilder
{
internal SheetBuilder(TextureChannel ch)
{
current = null;
rowHeight = 0;
channel = null;
initialChannel = ch;
}
public Sprite Add(byte[] src, Size size)
{
Sprite rect = Allocate(size);
Util.FastCopyIntoChannel(rect, src);
return rect;
}
public Sprite Add(Size size, byte paletteIndex)
{
byte[] data = new byte[size.Width * size.Height];
for (int i = 0; i < data.Length; i++)
data[i] = paletteIndex;
return Add(data, size);
}
Sheet NewSheet() { return new Sheet(new Size( Renderer.SheetSize, Renderer.SheetSize ) ); }
Sheet current = null;
int rowHeight = 0;
Point p;
TextureChannel? channel = null;
TextureChannel initialChannel;
TextureChannel? NextChannel(TextureChannel? t)
{
if (t == null)
return initialChannel;
switch (t.Value)
{
case TextureChannel.Red: return TextureChannel.Green;
case TextureChannel.Green: return TextureChannel.Blue;
case TextureChannel.Blue: return TextureChannel.Alpha;
case TextureChannel.Alpha: return null;
default: return null;
}
}
public Sprite Allocate(Size imageSize)
{
if (current == null)
{
current = NewSheet();
channel = NextChannel(null);
}
if (imageSize.Width + p.X > current.Size.Width)
{
p = new Point(0, p.Y + rowHeight);
rowHeight = imageSize.Height;
}
if (imageSize.Height > rowHeight)
rowHeight = imageSize.Height;
if (p.Y + imageSize.Height > current.Size.Height)
{
if (null == (channel = NextChannel(channel)))
{
current = NewSheet();
channel = NextChannel(channel);
}
rowHeight = imageSize.Height;
p = new Point(0,0);
}
Sprite rect = new Sprite(current, new Rectangle(p, imageSize), channel.Value);
current.MakeDirty();
p.X += imageSize.Width;
return rect;
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Drawing;
namespace OpenRA.Graphics
{
public class SheetBuilder
{
internal SheetBuilder(TextureChannel ch)
{
current = null;
rowHeight = 0;
channel = null;
initialChannel = ch;
}
public Sprite Add(byte[] src, Size size)
{
Sprite rect = Allocate(size);
Util.FastCopyIntoChannel(rect, src);
return rect;
}
public Sprite Add(Size size, byte paletteIndex)
{
byte[] data = new byte[size.Width * size.Height];
for (int i = 0; i < data.Length; i++)
data[i] = paletteIndex;
return Add(data, size);
}
Sheet NewSheet() { return new Sheet(new Size( Renderer.SheetSize, Renderer.SheetSize ) ); }
Sheet current = null;
int rowHeight = 0;
Point p;
TextureChannel? channel = null;
TextureChannel initialChannel;
TextureChannel? NextChannel(TextureChannel? t)
{
if (t == null)
return initialChannel;
switch (t.Value)
{
case TextureChannel.Red: return TextureChannel.Green;
case TextureChannel.Green: return TextureChannel.Blue;
case TextureChannel.Blue: return TextureChannel.Alpha;
case TextureChannel.Alpha: return null;
default: return null;
}
}
public Sprite Allocate(Size imageSize)
{
if (current == null)
{
current = NewSheet();
channel = NextChannel(null);
}
if (imageSize.Width + p.X > current.Size.Width)
{
p = new Point(0, p.Y + rowHeight);
rowHeight = imageSize.Height;
}
if (imageSize.Height > rowHeight)
rowHeight = imageSize.Height;
if (p.Y + imageSize.Height > current.Size.Height)
{
if (null == (channel = NextChannel(channel)))
{
current = NewSheet();
channel = NextChannel(channel);
}
rowHeight = imageSize.Height;
p = new Point(0,0);
}
Sprite rect = new Sprite(current, new Rectangle(p, imageSize), channel.Value);
current.MakeDirty();
p.X += imageSize.Width;
return rect;
}
}
}

View File

@@ -1,161 +1,161 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Drawing;
using OpenRA.Traits;
namespace OpenRA.Graphics
{
public class ShroudRenderer
{
Traits.Shroud shroud;
Sprite[] shadowBits = Game.modData.SpriteLoader.LoadAllSprites("shadow");
Sprite[,] sprites, fogSprites;
bool dirty = true;
Map map;
public ShroudRenderer(World world)
{
this.shroud = world.LocalShroud;
this.map = world.Map;
sprites = new Sprite[map.MapSize.X, map.MapSize.Y];
fogSprites = new Sprite[map.MapSize.X, map.MapSize.Y];
shroud.Dirty += () => dirty = true;
}
static readonly byte[][] SpecialShroudTiles =
{
new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
new byte[] { 32, 32, 25, 25, 19, 19, 20, 20 },
new byte[] { 33, 33, 33, 33, 26, 26, 26, 26, 21, 21, 21, 21, 23, 23, 23, 23 },
new byte[] { 36, 36, 36, 36, 30, 30, 30, 30 },
new byte[] { 34, 16, 34, 16, 34, 16, 34, 16, 27, 22, 27, 22, 27, 22, 27, 22 },
new byte[] { 44 },
new byte[] { 37, 37, 37, 37, 37, 37, 37, 37, 31, 31, 31, 31, 31, 31, 31, 31 },
new byte[] { 40 },
new byte[] { 35, 24, 17, 18 },
new byte[] { 39, 39, 29, 29 },
new byte[] { 45 },
new byte[] { 43 },
new byte[] { 38, 28 },
new byte[] { 42 },
new byte[] { 41 },
new byte[] { 46 },
};
Sprite ChooseShroud(int i, int j)
{
if( !shroud.IsExplored( i, j ) ) return shadowBits[ 0xf ];
// bits are for unexploredness: up, right, down, left
var v = 0;
// bits are for unexploredness: TL, TR, BR, BL
var u = 0;
if( !shroud.IsExplored( i, j - 1 ) ) { v |= 1; u |= 3; }
if( !shroud.IsExplored( i + 1, j ) ) { v |= 2; u |= 6; }
if( !shroud.IsExplored( i, j + 1 ) ) { v |= 4; u |= 12; }
if( !shroud.IsExplored( i - 1, j ) ) { v |= 8; u |= 9; }
var uSides = u;
if( !shroud.IsExplored( i - 1, j - 1 ) ) u |= 1;
if( !shroud.IsExplored( i + 1, j - 1 ) ) u |= 2;
if( !shroud.IsExplored( i + 1, j + 1 ) ) u |= 4;
if( !shroud.IsExplored( i - 1, j + 1 ) ) u |= 8;
return shadowBits[ SpecialShroudTiles[ u ^ uSides ][ v ] ];
}
Sprite ChooseFog(int i, int j)
{
if (!shroud.IsVisible(i,j)) return shadowBits[0xf];
if (!shroud.IsExplored(i, j)) return shadowBits[0xf];
// bits are for unexploredness: up, right, down, left
var v = 0;
// bits are for unexploredness: TL, TR, BR, BL
var u = 0;
if (!shroud.IsVisible(i, j - 1)) { v |= 1; u |= 3; }
if (!shroud.IsVisible(i + 1, j)) { v |= 2; u |= 6; }
if (!shroud.IsVisible(i, j + 1)) { v |= 4; u |= 12; }
if (!shroud.IsVisible(i - 1, j)) { v |= 8; u |= 9; }
var uSides = u;
if (!shroud.IsVisible(i - 1, j - 1)) u |= 1;
if (!shroud.IsVisible(i + 1, j - 1)) u |= 2;
if (!shroud.IsVisible(i + 1, j + 1)) u |= 4;
if (!shroud.IsVisible(i - 1, j + 1)) u |= 8;
return shadowBits[SpecialShroudTiles[u ^ uSides][v]];
}
internal void Draw( WorldRenderer wr )
{
if (dirty)
{
dirty = false;
for (int i = map.Bounds.Left; i < map.Bounds.Right; i++)
for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++)
sprites[i, j] = ChooseShroud(i, j);
for (int i = map.Bounds.Left; i < map.Bounds.Right; i++)
for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++)
fogSprites[i, j] = ChooseFog(i, j);
}
var clipRect = Game.viewport.WorldBounds(wr.world);
DrawShroud( wr, clipRect, fogSprites, "fog" );
DrawShroud( wr, clipRect, sprites, "shroud" );
}
void DrawShroud( WorldRenderer wr, Rectangle clip, Sprite[,] s, string pal )
{
var shroudPalette = wr.GetPaletteIndex(pal);
for (var j = clip.Top; j < clip.Bottom; j++)
{
var starti = clip.Left;
var last = shadowBits[0x0f];
for (var i = clip.Left; i < clip.Right; i++)
{
if ((s[i, j] == shadowBits[0x0f] && last == shadowBits[0x0f])
|| (s[i, j] == shadowBits[0] && last == shadowBits[0]))
continue;
if (starti != i)
{
s[starti, j].DrawAt(
Game.CellSize * new float2(starti, j),
shroudPalette,
new float2(Game.CellSize * (i - starti), Game.CellSize));
starti = i + 1;
}
s[i, j].DrawAt(
Game.CellSize * new float2(i, j),
shroudPalette);
starti = i + 1;
last = s[i, j];
}
if (starti < clip.Right)
s[starti, j].DrawAt(
Game.CellSize * new float2(starti, j),
shroudPalette,
new float2(Game.CellSize * (clip.Right - starti), Game.CellSize));
}
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Drawing;
using OpenRA.Traits;
namespace OpenRA.Graphics
{
public class ShroudRenderer
{
Traits.Shroud shroud;
Sprite[] shadowBits = Game.modData.SpriteLoader.LoadAllSprites("shadow");
Sprite[,] sprites, fogSprites;
bool dirty = true;
Map map;
public ShroudRenderer(World world)
{
this.shroud = world.LocalShroud;
this.map = world.Map;
sprites = new Sprite[map.MapSize.X, map.MapSize.Y];
fogSprites = new Sprite[map.MapSize.X, map.MapSize.Y];
shroud.Dirty += () => dirty = true;
}
static readonly byte[][] SpecialShroudTiles =
{
new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
new byte[] { 32, 32, 25, 25, 19, 19, 20, 20 },
new byte[] { 33, 33, 33, 33, 26, 26, 26, 26, 21, 21, 21, 21, 23, 23, 23, 23 },
new byte[] { 36, 36, 36, 36, 30, 30, 30, 30 },
new byte[] { 34, 16, 34, 16, 34, 16, 34, 16, 27, 22, 27, 22, 27, 22, 27, 22 },
new byte[] { 44 },
new byte[] { 37, 37, 37, 37, 37, 37, 37, 37, 31, 31, 31, 31, 31, 31, 31, 31 },
new byte[] { 40 },
new byte[] { 35, 24, 17, 18 },
new byte[] { 39, 39, 29, 29 },
new byte[] { 45 },
new byte[] { 43 },
new byte[] { 38, 28 },
new byte[] { 42 },
new byte[] { 41 },
new byte[] { 46 },
};
Sprite ChooseShroud(int i, int j)
{
if( !shroud.IsExplored( i, j ) ) return shadowBits[ 0xf ];
// bits are for unexploredness: up, right, down, left
var v = 0;
// bits are for unexploredness: TL, TR, BR, BL
var u = 0;
if( !shroud.IsExplored( i, j - 1 ) ) { v |= 1; u |= 3; }
if( !shroud.IsExplored( i + 1, j ) ) { v |= 2; u |= 6; }
if( !shroud.IsExplored( i, j + 1 ) ) { v |= 4; u |= 12; }
if( !shroud.IsExplored( i - 1, j ) ) { v |= 8; u |= 9; }
var uSides = u;
if( !shroud.IsExplored( i - 1, j - 1 ) ) u |= 1;
if( !shroud.IsExplored( i + 1, j - 1 ) ) u |= 2;
if( !shroud.IsExplored( i + 1, j + 1 ) ) u |= 4;
if( !shroud.IsExplored( i - 1, j + 1 ) ) u |= 8;
return shadowBits[ SpecialShroudTiles[ u ^ uSides ][ v ] ];
}
Sprite ChooseFog(int i, int j)
{
if (!shroud.IsVisible(i,j)) return shadowBits[0xf];
if (!shroud.IsExplored(i, j)) return shadowBits[0xf];
// bits are for unexploredness: up, right, down, left
var v = 0;
// bits are for unexploredness: TL, TR, BR, BL
var u = 0;
if (!shroud.IsVisible(i, j - 1)) { v |= 1; u |= 3; }
if (!shroud.IsVisible(i + 1, j)) { v |= 2; u |= 6; }
if (!shroud.IsVisible(i, j + 1)) { v |= 4; u |= 12; }
if (!shroud.IsVisible(i - 1, j)) { v |= 8; u |= 9; }
var uSides = u;
if (!shroud.IsVisible(i - 1, j - 1)) u |= 1;
if (!shroud.IsVisible(i + 1, j - 1)) u |= 2;
if (!shroud.IsVisible(i + 1, j + 1)) u |= 4;
if (!shroud.IsVisible(i - 1, j + 1)) u |= 8;
return shadowBits[SpecialShroudTiles[u ^ uSides][v]];
}
internal void Draw( WorldRenderer wr )
{
if (dirty)
{
dirty = false;
for (int i = map.Bounds.Left; i < map.Bounds.Right; i++)
for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++)
sprites[i, j] = ChooseShroud(i, j);
for (int i = map.Bounds.Left; i < map.Bounds.Right; i++)
for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++)
fogSprites[i, j] = ChooseFog(i, j);
}
var clipRect = Game.viewport.WorldBounds(wr.world);
DrawShroud( wr, clipRect, fogSprites, "fog" );
DrawShroud( wr, clipRect, sprites, "shroud" );
}
void DrawShroud( WorldRenderer wr, Rectangle clip, Sprite[,] s, string pal )
{
var shroudPalette = wr.GetPaletteIndex(pal);
for (var j = clip.Top; j < clip.Bottom; j++)
{
var starti = clip.Left;
var last = shadowBits[0x0f];
for (var i = clip.Left; i < clip.Right; i++)
{
if ((s[i, j] == shadowBits[0x0f] && last == shadowBits[0x0f])
|| (s[i, j] == shadowBits[0] && last == shadowBits[0]))
continue;
if (starti != i)
{
s[starti, j].DrawAt(
Game.CellSize * new float2(starti, j),
shroudPalette,
new float2(Game.CellSize * (i - starti), Game.CellSize));
starti = i + 1;
}
s[i, j].DrawAt(
Game.CellSize * new float2(i, j),
shroudPalette);
starti = i + 1;
last = s[i, j];
}
if (starti < clip.Right)
s[starti, j].DrawAt(
Game.CellSize * new float2(starti, j),
shroudPalette,
new float2(Game.CellSize * (clip.Right - starti), Game.CellSize));
}
}
}
}

View File

@@ -1,81 +1,81 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Drawing;
namespace OpenRA.Graphics
{
public class Sprite
{
public readonly Rectangle bounds;
public readonly Sheet sheet;
public readonly TextureChannel channel;
public readonly RectangleF uv;
public readonly float2 size;
readonly float2[] uvhax;
public Sprite(Sheet sheet, Rectangle bounds, TextureChannel channel)
{
this.bounds = bounds;
this.sheet = sheet;
this.channel = channel;
uv = new RectangleF(
(float)(bounds.Left) / sheet.Size.Width,
(float)(bounds.Top) / sheet.Size.Height,
(float)(bounds.Width) / sheet.Size.Width,
(float)(bounds.Height) / sheet.Size.Height);
uvhax = new float2[]
{
new float2( uv.Left, uv.Top ),
new float2( uv.Right, uv.Top ),
new float2( uv.Left, uv.Bottom ),
new float2( uv.Right, uv.Bottom ),
};
this.size = new float2(bounds.Size);
}
public float2 FastMapTextureCoords( int k )
{
return uvhax[ k ];
}
public void DrawAt( WorldRenderer wr, float2 location, string palette )
{
Game.Renderer.SpriteRenderer.DrawSprite( this, location, wr, palette, this.size );
}
public void DrawAt( float2 location, int paletteIndex )
{
Game.Renderer.SpriteRenderer.DrawSprite( this, location, paletteIndex, this.size );
}
public void DrawAt(float2 location, int paletteIndex, float scale)
{
Game.Renderer.SpriteRenderer.DrawSprite(this, location, paletteIndex, this.size * scale);
}
public void DrawAt( float2 location, int paletteIndex, float2 size )
{
Game.Renderer.SpriteRenderer.DrawSprite( this, location, paletteIndex, size );
}
}
public enum TextureChannel
{
Red = 0,
Green = 1,
Blue = 2,
Alpha = 3,
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Drawing;
namespace OpenRA.Graphics
{
public class Sprite
{
public readonly Rectangle bounds;
public readonly Sheet sheet;
public readonly TextureChannel channel;
public readonly RectangleF uv;
public readonly float2 size;
readonly float2[] uvhax;
public Sprite(Sheet sheet, Rectangle bounds, TextureChannel channel)
{
this.bounds = bounds;
this.sheet = sheet;
this.channel = channel;
uv = new RectangleF(
(float)(bounds.Left) / sheet.Size.Width,
(float)(bounds.Top) / sheet.Size.Height,
(float)(bounds.Width) / sheet.Size.Width,
(float)(bounds.Height) / sheet.Size.Height);
uvhax = new float2[]
{
new float2( uv.Left, uv.Top ),
new float2( uv.Right, uv.Top ),
new float2( uv.Left, uv.Bottom ),
new float2( uv.Right, uv.Bottom ),
};
this.size = new float2(bounds.Size);
}
public float2 FastMapTextureCoords( int k )
{
return uvhax[ k ];
}
public void DrawAt( WorldRenderer wr, float2 location, string palette )
{
Game.Renderer.SpriteRenderer.DrawSprite( this, location, wr, palette, this.size );
}
public void DrawAt( float2 location, int paletteIndex )
{
Game.Renderer.SpriteRenderer.DrawSprite( this, location, paletteIndex, this.size );
}
public void DrawAt(float2 location, int paletteIndex, float scale)
{
Game.Renderer.SpriteRenderer.DrawSprite(this, location, paletteIndex, this.size * scale);
}
public void DrawAt( float2 location, int paletteIndex, float2 size )
{
Game.Renderer.SpriteRenderer.DrawSprite( this, location, paletteIndex, size );
}
}
public enum TextureChannel
{
Red = 0,
Green = 1,
Blue = 2,
Alpha = 3,
}
}

View File

@@ -1,153 +1,153 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using OpenRA.FileFormats;
using Tao.FreeType;
namespace OpenRA.Graphics
{
public class SpriteFont
{
int size;
public SpriteFont(string name, int size)
{
this.size = size;
if (0 != FT.FT_New_Face(library, name, 0, out face))
throw new InvalidOperationException("FT_New_Face failed");
FT.FT_Set_Pixel_Sizes(face, 0, (uint)size);
glyphs = new Cache<Pair<char, Color>, GlyphInfo>(CreateGlyph);
// setup a 1-channel SheetBuilder for our private use
if (builder == null) builder = new SheetBuilder(TextureChannel.Alpha);
PrecacheColor(Color.White);
PrecacheColor(Color.Red);
}
void PrecacheColor(Color c)
{
// precache glyphs for U+0020 - U+007f
for (var n = (char)0x20; n < (char)0x7f; n++)
if (glyphs[Pair.New(n, c)] == null)
throw new InvalidOperationException();
}
public void DrawText( string text, float2 location, Color c )
{
location.Y += size; // baseline vs top
var p = location;
foreach (var s in text)
{
if (s == '\n')
{
location.Y += size;
p = location;
continue;
}
var g = glyphs[Pair.New(s, c)];
Game.Renderer.RgbaSpriteRenderer.DrawSprite(g.Sprite,
new float2(
(int)Math.Round(p.X + g.Offset.X, 0),
p.Y + g.Offset.Y));
p.X += g.Advance;
}
}
public void DrawTextWithContrast(string text, float2 location, Color fg, Color bg, int offset)
{
if (offset > 0)
{
DrawText(text, location + new float2(-offset, 0), bg);
DrawText(text, location + new float2(offset, 0), bg);
DrawText(text, location + new float2(0, -offset), bg);
DrawText(text, location + new float2(0, offset), bg);
}
DrawText(text, location, fg);
}
public int2 Measure(string text)
{
return new int2((int)text.Split( '\n' ).Max( s => s.Sum(a => glyphs[Pair.New(a, Color.White)].Advance)), text.Split('\n').Count()*size);
}
Cache<Pair<char,Color>, GlyphInfo> glyphs;
IntPtr face;
GlyphInfo CreateGlyph(Pair<char,Color> c)
{
var index = FT.FT_Get_Char_Index(face, (uint)c.First);
if (0 != FT.FT_Load_Glyph(face, index, FT.FT_LOAD_RENDER))
throw new InvalidOperationException( "FT_Load_Glyph failed." );
var _face = (FT_FaceRec)Marshal.PtrToStructure(face, typeof(FT_FaceRec));
var _glyph = (FT_GlyphSlotRec)Marshal.PtrToStructure(_face.glyph, typeof(FT_GlyphSlotRec));
var s = builder.Allocate(
new Size(_glyph.metrics.width.ToInt32() >> 6,
_glyph.metrics.height.ToInt32() >> 6));
var g = new GlyphInfo
{
Sprite = s,
Advance = _glyph.metrics.horiAdvance.ToInt32() / 64f,
Offset = { X = _glyph.bitmap_left, Y = -_glyph.bitmap_top }
};
unsafe
{
var p = (byte*)_glyph.bitmap.buffer;
var dest = s.sheet.Data;
var destStride = s.sheet.Size.Width * 4;
for (var j = 0; j < s.size.Y; j++)
{
for (var i = 0; i < s.size.X; i++)
if (p[i] != 0)
{
var q = destStride * (j + s.bounds.Top) + 4 * (i + s.bounds.Left);
dest[q] = c.Second.B;
dest[q + 1] = c.Second.G;
dest[q + 2] = c.Second.R;
dest[q + 3] = p[i];
}
p += _glyph.bitmap.pitch;
}
}
return g;
}
static SpriteFont()
{
FT.FT_Init_FreeType(out library);
}
static IntPtr library;
static SheetBuilder builder;
}
class GlyphInfo
{
public float Advance;
public int2 Offset;
public Sprite Sprite;
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using OpenRA.FileFormats;
using Tao.FreeType;
namespace OpenRA.Graphics
{
public class SpriteFont
{
int size;
public SpriteFont(string name, int size)
{
this.size = size;
if (0 != FT.FT_New_Face(library, name, 0, out face))
throw new InvalidOperationException("FT_New_Face failed");
FT.FT_Set_Pixel_Sizes(face, 0, (uint)size);
glyphs = new Cache<Pair<char, Color>, GlyphInfo>(CreateGlyph);
// setup a 1-channel SheetBuilder for our private use
if (builder == null) builder = new SheetBuilder(TextureChannel.Alpha);
PrecacheColor(Color.White);
PrecacheColor(Color.Red);
}
void PrecacheColor(Color c)
{
// precache glyphs for U+0020 - U+007f
for (var n = (char)0x20; n < (char)0x7f; n++)
if (glyphs[Pair.New(n, c)] == null)
throw new InvalidOperationException();
}
public void DrawText( string text, float2 location, Color c )
{
location.Y += size; // baseline vs top
var p = location;
foreach (var s in text)
{
if (s == '\n')
{
location.Y += size;
p = location;
continue;
}
var g = glyphs[Pair.New(s, c)];
Game.Renderer.RgbaSpriteRenderer.DrawSprite(g.Sprite,
new float2(
(int)Math.Round(p.X + g.Offset.X, 0),
p.Y + g.Offset.Y));
p.X += g.Advance;
}
}
public void DrawTextWithContrast(string text, float2 location, Color fg, Color bg, int offset)
{
if (offset > 0)
{
DrawText(text, location + new float2(-offset, 0), bg);
DrawText(text, location + new float2(offset, 0), bg);
DrawText(text, location + new float2(0, -offset), bg);
DrawText(text, location + new float2(0, offset), bg);
}
DrawText(text, location, fg);
}
public int2 Measure(string text)
{
return new int2((int)text.Split( '\n' ).Max( s => s.Sum(a => glyphs[Pair.New(a, Color.White)].Advance)), text.Split('\n').Count()*size);
}
Cache<Pair<char,Color>, GlyphInfo> glyphs;
IntPtr face;
GlyphInfo CreateGlyph(Pair<char,Color> c)
{
var index = FT.FT_Get_Char_Index(face, (uint)c.First);
if (0 != FT.FT_Load_Glyph(face, index, FT.FT_LOAD_RENDER))
throw new InvalidOperationException( "FT_Load_Glyph failed." );
var _face = (FT_FaceRec)Marshal.PtrToStructure(face, typeof(FT_FaceRec));
var _glyph = (FT_GlyphSlotRec)Marshal.PtrToStructure(_face.glyph, typeof(FT_GlyphSlotRec));
var s = builder.Allocate(
new Size(_glyph.metrics.width.ToInt32() >> 6,
_glyph.metrics.height.ToInt32() >> 6));
var g = new GlyphInfo
{
Sprite = s,
Advance = _glyph.metrics.horiAdvance.ToInt32() / 64f,
Offset = { X = _glyph.bitmap_left, Y = -_glyph.bitmap_top }
};
unsafe
{
var p = (byte*)_glyph.bitmap.buffer;
var dest = s.sheet.Data;
var destStride = s.sheet.Size.Width * 4;
for (var j = 0; j < s.size.Y; j++)
{
for (var i = 0; i < s.size.X; i++)
if (p[i] != 0)
{
var q = destStride * (j + s.bounds.Top) + 4 * (i + s.bounds.Left);
dest[q] = c.Second.B;
dest[q + 1] = c.Second.G;
dest[q + 2] = c.Second.R;
dest[q + 3] = p[i];
}
p += _glyph.bitmap.pitch;
}
}
return g;
}
static SpriteFont()
{
FT.FT_Init_FreeType(out library);
}
static IntPtr library;
static SheetBuilder builder;
}
class GlyphInfo
{
public float Advance;
public int2 Offset;
public Sprite Sprite;
}
}

View File

@@ -1,37 +1,37 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Linq;
using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
public class SpriteLoader
{
public SpriteLoader( string[] exts, SheetBuilder sheetBuilder )
{
SheetBuilder = sheetBuilder;
this.exts = exts;
sprites = new Cache<string, Sprite[]>( LoadSprites );
}
readonly SheetBuilder SheetBuilder;
readonly Cache<string, Sprite[]> sprites;
readonly string[] exts;
Sprite[] LoadSprites(string filename)
{
var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts));
return shp.Select(a => SheetBuilder.Add(a.Image, shp.Size)).ToArray();
}
public Sprite[] LoadAllSprites(string filename) { return sprites[filename]; }
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Linq;
using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
public class SpriteLoader
{
public SpriteLoader( string[] exts, SheetBuilder sheetBuilder )
{
SheetBuilder = sheetBuilder;
this.exts = exts;
sprites = new Cache<string, Sprite[]>( LoadSprites );
}
readonly SheetBuilder SheetBuilder;
readonly Cache<string, Sprite[]> sprites;
readonly string[] exts;
Sprite[] LoadSprites(string filename)
{
var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts));
return shp.Select(a => SheetBuilder.Add(a.Image, shp.Size)).ToArray();
}
public Sprite[] LoadAllSprites(string filename) { return sprites[filename]; }
}
}

View File

@@ -1,96 +1,96 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using OpenRA.FileFormats.Graphics;
namespace OpenRA.Graphics
{
public class SpriteRenderer : Renderer.IBatchRenderer
{
Renderer renderer;
IShader shader;
Vertex[] vertices = new Vertex[Renderer.TempBufferSize];
ushort[] indices = new ushort[Renderer.TempBufferSize];
Sheet currentSheet = null;
int nv = 0, ni = 0;
public SpriteRenderer(Renderer renderer, IShader shader)
{
this.renderer = renderer;
this.shader = shader;
}
public SpriteRenderer(Renderer renderer)
: this(renderer, renderer.SpriteShader) { }
public void Flush()
{
if (ni > 0)
{
shader.SetValue( "DiffuseTexture", currentSheet.Texture );
shader.Render(() =>
{
var vb = renderer.GetTempVertexBuffer();
var ib = renderer.GetTempIndexBuffer();
vb.SetData(vertices, nv);
ib.SetData(indices, ni);
renderer.DrawBatch(vb, ib,
new Range<int>(0, nv),
new Range<int>(0, ni),
PrimitiveType.TriangleList,
shader);
});
nv = 0; ni = 0;
currentSheet = null;
}
}
public void DrawSprite(Sprite s, float2 location, WorldRenderer wr, string palette)
{
DrawSprite(s, location, wr.GetPaletteIndex(palette), s.size);
}
public void DrawSprite(Sprite s, float2 location, WorldRenderer wr, string palette, float2 size)
{
DrawSprite(s, location, wr.GetPaletteIndex(palette), size);
}
public void DrawSprite(Sprite s, float2 location, int paletteIndex, float2 size)
{
Renderer.CurrentBatchRenderer = this;
if (s.sheet != currentSheet)
Flush();
if( nv + 4 > Renderer.TempBufferSize )
Flush();
if( ni + 6 > Renderer.TempBufferSize )
Flush();
currentSheet = s.sheet;
Util.FastCreateQuad(vertices, indices, location.ToInt2(), s, paletteIndex, nv, ni, size);
nv += 4; ni += 6;
}
// For RGBASpriteRenderer, which doesn't use palettes
public void DrawSprite(Sprite s, float2 location)
{
DrawSprite(s, location, 0, s.size);
}
public void DrawSprite(Sprite s, float2 location, float2 size)
{
DrawSprite(s, location, 0, size);
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using OpenRA.FileFormats.Graphics;
namespace OpenRA.Graphics
{
public class SpriteRenderer : Renderer.IBatchRenderer
{
Renderer renderer;
IShader shader;
Vertex[] vertices = new Vertex[Renderer.TempBufferSize];
ushort[] indices = new ushort[Renderer.TempBufferSize];
Sheet currentSheet = null;
int nv = 0, ni = 0;
public SpriteRenderer(Renderer renderer, IShader shader)
{
this.renderer = renderer;
this.shader = shader;
}
public SpriteRenderer(Renderer renderer)
: this(renderer, renderer.SpriteShader) { }
public void Flush()
{
if (ni > 0)
{
shader.SetValue( "DiffuseTexture", currentSheet.Texture );
shader.Render(() =>
{
var vb = renderer.GetTempVertexBuffer();
var ib = renderer.GetTempIndexBuffer();
vb.SetData(vertices, nv);
ib.SetData(indices, ni);
renderer.DrawBatch(vb, ib,
new Range<int>(0, nv),
new Range<int>(0, ni),
PrimitiveType.TriangleList,
shader);
});
nv = 0; ni = 0;
currentSheet = null;
}
}
public void DrawSprite(Sprite s, float2 location, WorldRenderer wr, string palette)
{
DrawSprite(s, location, wr.GetPaletteIndex(palette), s.size);
}
public void DrawSprite(Sprite s, float2 location, WorldRenderer wr, string palette, float2 size)
{
DrawSprite(s, location, wr.GetPaletteIndex(palette), size);
}
public void DrawSprite(Sprite s, float2 location, int paletteIndex, float2 size)
{
Renderer.CurrentBatchRenderer = this;
if (s.sheet != currentSheet)
Flush();
if( nv + 4 > Renderer.TempBufferSize )
Flush();
if( ni + 6 > Renderer.TempBufferSize )
Flush();
currentSheet = s.sheet;
Util.FastCreateQuad(vertices, indices, location.ToInt2(), s, paletteIndex, nv, ni, size);
nv += 4; ni += 6;
}
// For RGBASpriteRenderer, which doesn't use palettes
public void DrawSprite(Sprite s, float2 location)
{
DrawSprite(s, location, 0, s.size);
}
public void DrawSprite(Sprite s, float2 location, float2 size)
{
DrawSprite(s, location, 0, size);
}
}
}

View File

@@ -1,105 +1,105 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Drawing;
using OpenRA.FileFormats;
using OpenRA.FileFormats.Graphics;
using OpenRA.Traits;
namespace OpenRA.Graphics
{
class TerrainRenderer
{
IVertexBuffer<Vertex> vertexBuffer;
IIndexBuffer indexBuffer;
Sheet terrainSheet;
World world;
Map map;
public TerrainRenderer(World world, WorldRenderer wr)
{
this.world = world;
this.map = world.Map;
Size tileSize = new Size( Game.CellSize, Game.CellSize );
var tileMapping = new Cache<TileReference<ushort,byte>, Sprite>(
x => Game.modData.SheetBuilder.Add(world.TileSet.GetBytes(x), tileSize));
Vertex[] vertices = new Vertex[4 * map.Bounds.Height * map.Bounds.Width];
ushort[] indices = new ushort[6 * map.Bounds.Height * map.Bounds.Width];
terrainSheet = tileMapping[map.MapTiles.Value[map.Bounds.Left, map.Bounds.Top]].sheet;
int nv = 0;
int ni = 0;
for( int j = map.Bounds.Top; j < map.Bounds.Bottom; j++ )
for( int i = map.Bounds.Left; i < map.Bounds.Right; i++ )
{
Sprite tile = tileMapping[map.MapTiles.Value[i, j]];
// TODO: The zero below should explicitly refer to the terrain palette, but this code is called
// before the palettes are created. Therefore assumes that "terrain" is the first palette to be defined
Util.FastCreateQuad(vertices, indices, Game.CellSize * new float2(i, j), tile, Game.modData.Palette.GetPaletteIndex("terrain"), nv, ni, tile.size);
nv += 4;
ni += 6;
if (tileMapping[map.MapTiles.Value[i, j]].sheet != terrainSheet)
throw new InvalidOperationException("Terrain sprites span multiple sheets");
}
vertexBuffer = Game.Renderer.Device.CreateVertexBuffer( vertices.Length );
vertexBuffer.SetData( vertices, nv );
indexBuffer = Game.Renderer.Device.CreateIndexBuffer( indices.Length );
indexBuffer.SetData( indices, ni );
}
public void Draw( WorldRenderer wr, Viewport viewport )
{
int indicesPerRow = map.Bounds.Width * 6;
int verticesPerRow = map.Bounds.Width * 4;
int visibleRows = (int)(viewport.Height * 1f / Game.CellSize + 2);
int firstRow = (int)(viewport.Location.Y * 1f / Game.CellSize - map.Bounds.Top);
int lastRow = firstRow + visibleRows;
if (lastRow < 0 || firstRow > map.Bounds.Height)
return;
if (firstRow < 0) firstRow = 0;
if (lastRow > map.Bounds.Height) lastRow = map.Bounds.Height;
if (world.LocalPlayer != null && !world.LocalShroud.Disabled && world.LocalShroud.Bounds.HasValue)
{
var r = world.LocalShroud.Bounds.Value;
if (firstRow < r.Top - map.Bounds.Top)
firstRow = r.Top - map.Bounds.Top;
if (firstRow > r.Bottom - map.Bounds.Top)
firstRow = r.Bottom - map.Bounds.Top;
}
if( lastRow < firstRow ) lastRow = firstRow;
Game.Renderer.SpriteShader.SetValue( "DiffuseTexture", terrainSheet.Texture );
Game.Renderer.SpriteShader.Render(() =>
Game.Renderer.DrawBatch(vertexBuffer, indexBuffer,
new Range<int>(verticesPerRow * firstRow, verticesPerRow * lastRow),
new Range<int>(indicesPerRow * firstRow, indicesPerRow * lastRow),
PrimitiveType.TriangleList, Game.Renderer.SpriteShader));
foreach (var r in world.WorldActor.TraitsImplementing<IRenderOverlay>())
r.Render( wr );
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Drawing;
using OpenRA.FileFormats;
using OpenRA.FileFormats.Graphics;
using OpenRA.Traits;
namespace OpenRA.Graphics
{
class TerrainRenderer
{
IVertexBuffer<Vertex> vertexBuffer;
IIndexBuffer indexBuffer;
Sheet terrainSheet;
World world;
Map map;
public TerrainRenderer(World world, WorldRenderer wr)
{
this.world = world;
this.map = world.Map;
Size tileSize = new Size( Game.CellSize, Game.CellSize );
var tileMapping = new Cache<TileReference<ushort,byte>, Sprite>(
x => Game.modData.SheetBuilder.Add(world.TileSet.GetBytes(x), tileSize));
Vertex[] vertices = new Vertex[4 * map.Bounds.Height * map.Bounds.Width];
ushort[] indices = new ushort[6 * map.Bounds.Height * map.Bounds.Width];
terrainSheet = tileMapping[map.MapTiles.Value[map.Bounds.Left, map.Bounds.Top]].sheet;
int nv = 0;
int ni = 0;
for( int j = map.Bounds.Top; j < map.Bounds.Bottom; j++ )
for( int i = map.Bounds.Left; i < map.Bounds.Right; i++ )
{
Sprite tile = tileMapping[map.MapTiles.Value[i, j]];
// TODO: The zero below should explicitly refer to the terrain palette, but this code is called
// before the palettes are created. Therefore assumes that "terrain" is the first palette to be defined
Util.FastCreateQuad(vertices, indices, Game.CellSize * new float2(i, j), tile, Game.modData.Palette.GetPaletteIndex("terrain"), nv, ni, tile.size);
nv += 4;
ni += 6;
if (tileMapping[map.MapTiles.Value[i, j]].sheet != terrainSheet)
throw new InvalidOperationException("Terrain sprites span multiple sheets");
}
vertexBuffer = Game.Renderer.Device.CreateVertexBuffer( vertices.Length );
vertexBuffer.SetData( vertices, nv );
indexBuffer = Game.Renderer.Device.CreateIndexBuffer( indices.Length );
indexBuffer.SetData( indices, ni );
}
public void Draw( WorldRenderer wr, Viewport viewport )
{
int indicesPerRow = map.Bounds.Width * 6;
int verticesPerRow = map.Bounds.Width * 4;
int visibleRows = (int)(viewport.Height * 1f / Game.CellSize + 2);
int firstRow = (int)(viewport.Location.Y * 1f / Game.CellSize - map.Bounds.Top);
int lastRow = firstRow + visibleRows;
if (lastRow < 0 || firstRow > map.Bounds.Height)
return;
if (firstRow < 0) firstRow = 0;
if (lastRow > map.Bounds.Height) lastRow = map.Bounds.Height;
if (world.LocalPlayer != null && !world.LocalShroud.Disabled && world.LocalShroud.Bounds.HasValue)
{
var r = world.LocalShroud.Bounds.Value;
if (firstRow < r.Top - map.Bounds.Top)
firstRow = r.Top - map.Bounds.Top;
if (firstRow > r.Bottom - map.Bounds.Top)
firstRow = r.Bottom - map.Bounds.Top;
}
if( lastRow < firstRow ) lastRow = firstRow;
Game.Renderer.SpriteShader.SetValue( "DiffuseTexture", terrainSheet.Texture );
Game.Renderer.SpriteShader.Render(() =>
Game.Renderer.DrawBatch(vertexBuffer, indexBuffer,
new Range<int>(verticesPerRow * firstRow, verticesPerRow * lastRow),
new Range<int>(indicesPerRow * firstRow, indicesPerRow * lastRow),
PrimitiveType.TriangleList, Game.Renderer.SpriteShader));
foreach (var r in world.WorldActor.TraitsImplementing<IRenderOverlay>())
r.Render( wr );
}
}
}

View File

@@ -1,122 +1,122 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using OpenRA.FileFormats.Graphics;
namespace OpenRA.Graphics
{
public static class Util
{
public static string[] ReadAllLines(Stream s)
{
List<string> result = new List<string>();
using (StreamReader reader = new StreamReader(s))
while(!reader.EndOfStream)
{
var line = reader.ReadLine();
if( !string.IsNullOrEmpty( line ) && line[0] != '#' )
result.Add( line );
}
return result.ToArray();
}
public static T[] MakeArray<T>(int count, Converter<int, T> f)
{
T[] result = new T[count];
for (int i = 0; i < count; i++)
result[i] = f(i);
return result;
}
static float[] channelSelect = { 0.75f, 0.25f, -0.25f, -0.75f };
public static void FastCreateQuad(Vertex[] vertices, ushort[] indices, float2 o, Sprite r, int palette, int nv, int ni, float2 size)
{
var attrib = new float2(palette / (float)HardwarePalette.MaxPalettes, channelSelect[(int)r.channel]);
vertices[nv] = new Vertex(o,
r.FastMapTextureCoords(0), attrib);
vertices[nv + 1] = new Vertex(new float2(o.X + size.X, o.Y),
r.FastMapTextureCoords(1), attrib);
vertices[nv + 2] = new Vertex(new float2(o.X, o.Y + size.Y),
r.FastMapTextureCoords(2), attrib);
vertices[nv + 3] = new Vertex(new float2(o.X + size.X, o.Y + size.Y),
r.FastMapTextureCoords(3), attrib);
indices[ni] = (ushort)(nv);
indices[ni + 1] = indices[ni + 3] = (ushort)(nv + 1);
indices[ni + 2] = indices[ni + 5] = (ushort)(nv + 2);
indices[ni + 4] = (ushort)(nv + 3);
}
public static void FastCopyIntoChannel(Sprite dest, byte[] src)
{
var masks = new int[] { 2, 1, 0, 3 }; // hack, our channel order is nuts.
var data = dest.sheet.Data;
var srcStride = dest.bounds.Width;
var destStride = dest.sheet.Size.Width * 4;
var destOffset = destStride * dest.bounds.Top + dest.bounds.Left * 4 + masks[(int)dest.channel];
var destSkip = destStride - 4 * srcStride;
var height = dest.bounds.Height;
var srcOffset = 0;
for (var j = 0; j < height; j++)
{
for (int i = 0; i < srcStride; i++, srcOffset++)
{
data[destOffset] = src[srcOffset];
destOffset += 4;
}
destOffset += destSkip;
}
}
public static Color Lerp(float t, Color a, Color b)
{
return Color.FromArgb(
LerpChannel(t, a.A, b.A),
LerpChannel(t, a.R, b.R),
LerpChannel(t, a.G, b.G),
LerpChannel(t, a.B, b.B));
}
public static int LerpARGBColor(float t, int c1, int c2)
{
int a = LerpChannel(t, (c1 >> 24) & 255, (c2 >> 24) & 255);
int r = LerpChannel(t, (c1 >> 16) & 255, (c2 >> 16) & 255);
int g = LerpChannel(t, (c1 >> 8) & 255, (c2 >> 8) & 255);
int b = LerpChannel(t, c1 & 255, c2 & 255);
return (a << 24) | (r << 16) | (g << 8) | b;
}
public static int LerpChannel(float t, int a, int b)
{
return (int)((1 - t) * a + t * b);
}
public static int NextPowerOf2(int v)
{
--v;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
++v;
return v;
}
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using OpenRA.FileFormats.Graphics;
namespace OpenRA.Graphics
{
public static class Util
{
public static string[] ReadAllLines(Stream s)
{
List<string> result = new List<string>();
using (StreamReader reader = new StreamReader(s))
while(!reader.EndOfStream)
{
var line = reader.ReadLine();
if( !string.IsNullOrEmpty( line ) && line[0] != '#' )
result.Add( line );
}
return result.ToArray();
}
public static T[] MakeArray<T>(int count, Converter<int, T> f)
{
T[] result = new T[count];
for (int i = 0; i < count; i++)
result[i] = f(i);
return result;
}
static float[] channelSelect = { 0.75f, 0.25f, -0.25f, -0.75f };
public static void FastCreateQuad(Vertex[] vertices, ushort[] indices, float2 o, Sprite r, int palette, int nv, int ni, float2 size)
{
var attrib = new float2(palette / (float)HardwarePalette.MaxPalettes, channelSelect[(int)r.channel]);
vertices[nv] = new Vertex(o,
r.FastMapTextureCoords(0), attrib);
vertices[nv + 1] = new Vertex(new float2(o.X + size.X, o.Y),
r.FastMapTextureCoords(1), attrib);
vertices[nv + 2] = new Vertex(new float2(o.X, o.Y + size.Y),
r.FastMapTextureCoords(2), attrib);
vertices[nv + 3] = new Vertex(new float2(o.X + size.X, o.Y + size.Y),
r.FastMapTextureCoords(3), attrib);
indices[ni] = (ushort)(nv);
indices[ni + 1] = indices[ni + 3] = (ushort)(nv + 1);
indices[ni + 2] = indices[ni + 5] = (ushort)(nv + 2);
indices[ni + 4] = (ushort)(nv + 3);
}
public static void FastCopyIntoChannel(Sprite dest, byte[] src)
{
var masks = new int[] { 2, 1, 0, 3 }; // hack, our channel order is nuts.
var data = dest.sheet.Data;
var srcStride = dest.bounds.Width;
var destStride = dest.sheet.Size.Width * 4;
var destOffset = destStride * dest.bounds.Top + dest.bounds.Left * 4 + masks[(int)dest.channel];
var destSkip = destStride - 4 * srcStride;
var height = dest.bounds.Height;
var srcOffset = 0;
for (var j = 0; j < height; j++)
{
for (int i = 0; i < srcStride; i++, srcOffset++)
{
data[destOffset] = src[srcOffset];
destOffset += 4;
}
destOffset += destSkip;
}
}
public static Color Lerp(float t, Color a, Color b)
{
return Color.FromArgb(
LerpChannel(t, a.A, b.A),
LerpChannel(t, a.R, b.R),
LerpChannel(t, a.G, b.G),
LerpChannel(t, a.B, b.B));
}
public static int LerpARGBColor(float t, int c1, int c2)
{
int a = LerpChannel(t, (c1 >> 24) & 255, (c2 >> 24) & 255);
int r = LerpChannel(t, (c1 >> 16) & 255, (c2 >> 16) & 255);
int g = LerpChannel(t, (c1 >> 8) & 255, (c2 >> 8) & 255);
int b = LerpChannel(t, c1 & 255, c2 & 255);
return (a << 24) | (r << 16) | (g << 8) | b;
}
public static int LerpChannel(float t, int a, int b)
{
return (int)((1 - t) * a + t * b);
}
public static int NextPowerOf2(int v)
{
--v;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
++v;
return v;
}
}
}

View File

@@ -1,157 +1,157 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Widgets;
namespace OpenRA.Graphics
{
public class Viewport
{
readonly int2 screenSize;
int2 scrollPosition;
readonly Renderer renderer;
readonly Rectangle adjustedMapBounds;
public float2 Location { get { return scrollPosition; } }
public int Width { get { return screenSize.X; } }
public int Height { get { return screenSize.Y; } }
float cursorFrame = 0f;
public static int TicksSinceLastMove = 0;
public static int2 LastMousePos;
public void Scroll(float2 delta)
{
this.Scroll(delta, false);
}
public void Scroll(float2 delta, bool ignoreBorders)
{
var d = delta.ToInt2();
var newScrollPosition = scrollPosition + d;
if(!ignoreBorders)
newScrollPosition = this.NormalizeScrollPosition(newScrollPosition);
scrollPosition = newScrollPosition;
}
private int2 NormalizeScrollPosition(int2 newScrollPosition)
{
return newScrollPosition.Clamp(adjustedMapBounds);
}
public ScrollDirection GetBlockedDirections()
{
ScrollDirection blockedDirections = ScrollDirection.None;
if(scrollPosition.Y <= adjustedMapBounds.Top)
blockedDirections = blockedDirections.Set(ScrollDirection.Up, true);
if(scrollPosition.X <= adjustedMapBounds.Left)
blockedDirections = blockedDirections.Set(ScrollDirection.Left, true);
if(scrollPosition.Y >= adjustedMapBounds.Bottom)
blockedDirections = blockedDirections.Set(ScrollDirection.Down, true);
if(scrollPosition.X >= adjustedMapBounds.Right)
blockedDirections = blockedDirections.Set(ScrollDirection.Right, true);
return blockedDirections;
}
public Viewport(int2 screenSize, Rectangle mapBounds, Renderer renderer)
{
this.screenSize = screenSize;
this.renderer = renderer;
this.adjustedMapBounds = new Rectangle(Game.CellSize*mapBounds.X - screenSize.X/2,
Game.CellSize*mapBounds.Y - screenSize.Y/2,
Game.CellSize*mapBounds.Width,
Game.CellSize*mapBounds.Height);
this.scrollPosition = new int2(adjustedMapBounds.Location) + new int2(adjustedMapBounds.Size)/2;
}
public void DrawRegions( WorldRenderer wr, IInputHandler inputHandler )
{
renderer.BeginFrame(scrollPosition);
if (wr != null)
wr.Draw();
Widget.DoDraw();
var cursorName = Widget.RootWidget.GetCursorOuter(Viewport.LastMousePos) ?? "default";
new Cursor(cursorName).Draw((int)cursorFrame, Viewport.LastMousePos + Location);
renderer.EndFrame( inputHandler );
}
public void Tick()
{
cursorFrame += 0.5f;
}
public float2 ViewToWorld(int2 loc)
{
return (1f / Game.CellSize) * (loc.ToFloat2() + Location);
}
public float2 ViewToWorld(MouseInput mi)
{
return ViewToWorld(mi.Location);
}
public void Center(float2 loc)
{
scrollPosition = this.NormalizeScrollPosition((Game.CellSize*loc - screenSize / 2).ToInt2());
}
public void Center(IEnumerable<Actor> actors)
{
if (!actors.Any()) return;
var avgPos = actors
.Select(a => a.CenterLocation)
.Aggregate((a, b) => a + b) / actors.Count();
scrollPosition = this.NormalizeScrollPosition((avgPos - screenSize / 2));
}
public Rectangle ViewBounds(World world)
{
var r = WorldBounds(world);
var left = (int)(Game.CellSize * r.Left - Game.viewport.Location.X);
var top = (int)(Game.CellSize * r.Top - Game.viewport.Location.Y);
var right = left + (int)(Game.CellSize * r.Width);
var bottom = top + (int)(Game.CellSize * r.Height);
if (left < 0) left = 0;
if (top < 0) top = 0;
if (right > Game.viewport.Width) right = Game.viewport.Width;
if (bottom > Game.viewport.Height) bottom = Game.viewport.Height;
return new Rectangle(left, top, right - left, bottom - top);
}
int2 cachedScroll = new int2(int.MaxValue, int.MaxValue);
Rectangle cachedRect;
public Rectangle WorldBounds(World world)
{
if (cachedScroll != scrollPosition)
{
int2 boundary = new int2(1,1); // Add a curtain of cells around the viewport to account for rounding errors
var tl = ViewToWorld(int2.Zero).ToInt2() - boundary;
var br = ViewToWorld(new int2(Width, Height)).ToInt2() + boundary;
cachedRect = Rectangle.Intersect(Rectangle.FromLTRB(tl.X, tl.Y, br.X, br.Y), world.Map.Bounds);
cachedScroll = scrollPosition;
}
var b = world.LocalShroud.Bounds;
return (b.HasValue) ? Rectangle.Intersect(cachedRect, b.Value) : cachedRect;
}
}
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Widgets;
namespace OpenRA.Graphics
{
public class Viewport
{
readonly int2 screenSize;
int2 scrollPosition;
readonly Renderer renderer;
readonly Rectangle adjustedMapBounds;
public float2 Location { get { return scrollPosition; } }
public int Width { get { return screenSize.X; } }
public int Height { get { return screenSize.Y; } }
float cursorFrame = 0f;
public static int TicksSinceLastMove = 0;
public static int2 LastMousePos;
public void Scroll(float2 delta)
{
this.Scroll(delta, false);
}
public void Scroll(float2 delta, bool ignoreBorders)
{
var d = delta.ToInt2();
var newScrollPosition = scrollPosition + d;
if(!ignoreBorders)
newScrollPosition = this.NormalizeScrollPosition(newScrollPosition);
scrollPosition = newScrollPosition;
}
private int2 NormalizeScrollPosition(int2 newScrollPosition)
{
return newScrollPosition.Clamp(adjustedMapBounds);
}
public ScrollDirection GetBlockedDirections()
{
ScrollDirection blockedDirections = ScrollDirection.None;
if(scrollPosition.Y <= adjustedMapBounds.Top)
blockedDirections = blockedDirections.Set(ScrollDirection.Up, true);
if(scrollPosition.X <= adjustedMapBounds.Left)
blockedDirections = blockedDirections.Set(ScrollDirection.Left, true);
if(scrollPosition.Y >= adjustedMapBounds.Bottom)
blockedDirections = blockedDirections.Set(ScrollDirection.Down, true);
if(scrollPosition.X >= adjustedMapBounds.Right)
blockedDirections = blockedDirections.Set(ScrollDirection.Right, true);
return blockedDirections;
}
public Viewport(int2 screenSize, Rectangle mapBounds, Renderer renderer)
{
this.screenSize = screenSize;
this.renderer = renderer;
this.adjustedMapBounds = new Rectangle(Game.CellSize*mapBounds.X - screenSize.X/2,
Game.CellSize*mapBounds.Y - screenSize.Y/2,
Game.CellSize*mapBounds.Width,
Game.CellSize*mapBounds.Height);
this.scrollPosition = new int2(adjustedMapBounds.Location) + new int2(adjustedMapBounds.Size)/2;
}
public void DrawRegions( WorldRenderer wr, IInputHandler inputHandler )
{
renderer.BeginFrame(scrollPosition);
if (wr != null)
wr.Draw();
Widget.DoDraw();
var cursorName = Widget.RootWidget.GetCursorOuter(Viewport.LastMousePos) ?? "default";
new Cursor(cursorName).Draw((int)cursorFrame, Viewport.LastMousePos + Location);
renderer.EndFrame( inputHandler );
}
public void Tick()
{
cursorFrame += 0.5f;
}
public float2 ViewToWorld(int2 loc)
{
return (1f / Game.CellSize) * (loc.ToFloat2() + Location);
}
public float2 ViewToWorld(MouseInput mi)
{
return ViewToWorld(mi.Location);
}
public void Center(float2 loc)
{
scrollPosition = this.NormalizeScrollPosition((Game.CellSize*loc - screenSize / 2).ToInt2());
}
public void Center(IEnumerable<Actor> actors)
{
if (!actors.Any()) return;
var avgPos = actors
.Select(a => a.CenterLocation)
.Aggregate((a, b) => a + b) / actors.Count();
scrollPosition = this.NormalizeScrollPosition((avgPos - screenSize / 2));
}
public Rectangle ViewBounds(World world)
{
var r = WorldBounds(world);
var left = (int)(Game.CellSize * r.Left - Game.viewport.Location.X);
var top = (int)(Game.CellSize * r.Top - Game.viewport.Location.Y);
var right = left + (int)(Game.CellSize * r.Width);
var bottom = top + (int)(Game.CellSize * r.Height);
if (left < 0) left = 0;
if (top < 0) top = 0;
if (right > Game.viewport.Width) right = Game.viewport.Width;
if (bottom > Game.viewport.Height) bottom = Game.viewport.Height;
return new Rectangle(left, top, right - left, bottom - top);
}
int2 cachedScroll = new int2(int.MaxValue, int.MaxValue);
Rectangle cachedRect;
public Rectangle WorldBounds(World world)
{
if (cachedScroll != scrollPosition)
{
int2 boundary = new int2(1,1); // Add a curtain of cells around the viewport to account for rounding errors
var tl = ViewToWorld(int2.Zero).ToInt2() - boundary;
var br = ViewToWorld(new int2(Width, Height)).ToInt2() + boundary;
cachedRect = Rectangle.Intersect(Rectangle.FromLTRB(tl.X, tl.Y, br.X, br.Y), world.Map.Bounds);
cachedScroll = scrollPosition;
}
var b = world.LocalShroud.Bounds;
return (b.HasValue) ? Rectangle.Intersect(cachedRect, b.Value) : cachedRect;
}
}
}

View File

@@ -1,184 +1,184 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA.Graphics
{
public class WorldRenderer
{
public readonly World world;
internal readonly TerrainRenderer terrainRenderer;
internal readonly ShroudRenderer shroudRenderer;
public readonly UiOverlay uiOverlay;
internal readonly HardwarePalette palette;
internal WorldRenderer(World world)
{
this.world = world;
this.palette = Game.modData.Palette;
foreach( var pal in world.traitDict.ActorsWithTraitMultiple<IPalette>( world ) )
pal.Trait.InitPalette( this );
terrainRenderer = new TerrainRenderer(world, this);
shroudRenderer = new ShroudRenderer(world);
uiOverlay = new UiOverlay();
}
public int GetPaletteIndex(string name) { return palette.GetPaletteIndex(name); }
public Palette GetPalette(string name) { return palette.GetPalette(name); }
public void AddPalette(string name, Palette pal) { palette.AddPalette(name, pal); }
class SpriteComparer : IComparer<Renderable>
{
public int Compare(Renderable x, Renderable y)
{
return (x.Z + x.ZOffset).CompareTo(y.Z + y.ZOffset);
}
}
IEnumerable<Renderable> SpritesToRender()
{
var bounds = Game.viewport.ViewBounds(world);
var comparer = new SpriteComparer();
bounds.Offset((int)Game.viewport.Location.X, (int)Game.viewport.Location.Y);
var actors = world.FindUnits(
new float2(bounds.Left, bounds.Top),
new float2(bounds.Right, bounds.Bottom));
var renderables = actors.SelectMany(a => a.Render())
.OrderBy(r => r, comparer);
var effects = world.Effects.SelectMany(e => e.Render());
return renderables.Concat(effects);
}
public void Draw()
{
RefreshPalette();
var bounds = Game.viewport.ViewBounds(world);
Game.Renderer.EnableScissor(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
terrainRenderer.Draw(this, Game.viewport);
foreach (var a in world.traitDict.ActorsWithTraitMultiple<IRenderAsTerrain>(world))
foreach (var r in a.Trait.RenderAsTerrain(a.Actor))
r.Sprite.DrawAt(r.Pos, this.GetPaletteIndex(r.Palette), r.Scale);
foreach (var a in world.Selection.Actors)
if (!a.Destroyed)
foreach (var t in a.TraitsImplementing<IPreRenderSelection>())
t.RenderBeforeWorld(this, a);
Game.Renderer.Flush();
if (world.OrderGenerator != null)
world.OrderGenerator.RenderBeforeWorld(this, world);
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
foreach (var image in SpritesToRender() )
image.Sprite.DrawAt(image.Pos, this.GetPaletteIndex(image.Palette), image.Scale);
uiOverlay.Draw(this, world);
// added for contrails
foreach (var a in world.Actors)
if (!a.Destroyed)
foreach (var t in a.TraitsImplementing<IPostRender>())
t.RenderAfterWorld(this, a);
if (world.OrderGenerator != null)
world.OrderGenerator.RenderAfterWorld(this, world);
shroudRenderer.Draw( this );
Game.Renderer.DisableScissor();
foreach (var a in world.Selection.Actors)
if (!a.Destroyed)
foreach (var t in a.TraitsImplementing<IPostRenderSelection>())
t.RenderAfterWorld(this, a);
Game.Renderer.Flush();
}
void DrawBox(RectangleF r, Color color)
{
var a = new float2(r.Left, r.Top);
var b = new float2(r.Right - a.X, 0);
var c = new float2(0, r.Bottom - a.Y);
Game.Renderer.LineRenderer.DrawLine(a, a + b, color, color);
Game.Renderer.LineRenderer.DrawLine(a + b, a + b + c, color, color);
Game.Renderer.LineRenderer.DrawLine(a + b + c, a + c, color, color);
Game.Renderer.LineRenderer.DrawLine(a, a + c, color, color);
}
public void DrawSelectionBox(Actor selectedUnit, Color c)
{
var bounds = selectedUnit.GetBounds(false);
var xy = new float2(bounds.Left, bounds.Top);
var Xy = new float2(bounds.Right, bounds.Top);
var xY = new float2(bounds.Left, bounds.Bottom);
var XY = new float2(bounds.Right, bounds.Bottom);
Game.Renderer.LineRenderer.DrawLine(xy, xy + new float2(4, 0), c, c);
Game.Renderer.LineRenderer.DrawLine(xy, xy + new float2(0, 4), c, c);
Game.Renderer.LineRenderer.DrawLine(Xy, Xy + new float2(-4, 0), c, c);
Game.Renderer.LineRenderer.DrawLine(Xy, Xy + new float2(0, 4), c, c);
Game.Renderer.LineRenderer.DrawLine(xY, xY + new float2(4, 0), c, c);
Game.Renderer.LineRenderer.DrawLine(xY, xY + new float2(0, -4), c, c);
Game.Renderer.LineRenderer.DrawLine(XY, XY + new float2(-4, 0), c, c);
Game.Renderer.LineRenderer.DrawLine(XY, XY + new float2(0, -4), c, c);
}
public void DrawLocus(Color c, int2[] cells)
{
var dict = cells.ToDictionary(a => a, a => 0);
foreach (var t in dict.Keys)
{
if (!dict.ContainsKey(t + new int2(-1, 0)))
Game.Renderer.LineRenderer.DrawLine(Game.CellSize * t, Game.CellSize * (t + new int2(0, 1)),
c, c);
if (!dict.ContainsKey(t + new int2(1, 0)))
Game.Renderer.LineRenderer.DrawLine(Game.CellSize * (t + new int2(1, 0)), Game.CellSize * (t + new int2(1, 1)),
c, c);
if (!dict.ContainsKey(t + new int2(0, -1)))
Game.Renderer.LineRenderer.DrawLine(Game.CellSize * t, Game.CellSize * (t + new int2(1, 0)),
c, c);
if (!dict.ContainsKey(t + new int2(0, 1)))
Game.Renderer.LineRenderer.DrawLine(Game.CellSize * (t + new int2(0, 1)), Game.CellSize * (t + new int2(1, 1)),
c, c);
}
}
public void DrawRangeCircle(Color c, float2 location, float range)
{
for (var i = 0; i < 32; i++)
{
var start = location + Game.CellSize * range * float2.FromAngle((float)(Math.PI * i) / 16);
var end = location + Game.CellSize * range * float2.FromAngle((float)(Math.PI * (i + 0.7)) / 16);
Game.Renderer.LineRenderer.DrawLine(start, end, c, c);
}
}
public void RefreshPalette()
{
palette.Update( world.WorldActor.TraitsImplementing<IPaletteModifier>() );
}
}
}
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA.Graphics
{
public class WorldRenderer
{
public readonly World world;
internal readonly TerrainRenderer terrainRenderer;
internal readonly ShroudRenderer shroudRenderer;
public readonly UiOverlay uiOverlay;
internal readonly HardwarePalette palette;
internal WorldRenderer(World world)
{
this.world = world;
this.palette = Game.modData.Palette;
foreach( var pal in world.traitDict.ActorsWithTraitMultiple<IPalette>( world ) )
pal.Trait.InitPalette( this );
terrainRenderer = new TerrainRenderer(world, this);
shroudRenderer = new ShroudRenderer(world);
uiOverlay = new UiOverlay();
}
public int GetPaletteIndex(string name) { return palette.GetPaletteIndex(name); }
public Palette GetPalette(string name) { return palette.GetPalette(name); }
public void AddPalette(string name, Palette pal) { palette.AddPalette(name, pal); }
class SpriteComparer : IComparer<Renderable>
{
public int Compare(Renderable x, Renderable y)
{
return (x.Z + x.ZOffset).CompareTo(y.Z + y.ZOffset);
}
}
IEnumerable<Renderable> SpritesToRender()
{
var bounds = Game.viewport.ViewBounds(world);
var comparer = new SpriteComparer();
bounds.Offset((int)Game.viewport.Location.X, (int)Game.viewport.Location.Y);
var actors = world.FindUnits(
new float2(bounds.Left, bounds.Top),
new float2(bounds.Right, bounds.Bottom));
var renderables = actors.SelectMany(a => a.Render())
.OrderBy(r => r, comparer);
var effects = world.Effects.SelectMany(e => e.Render());
return renderables.Concat(effects);
}
public void Draw()
{
RefreshPalette();
var bounds = Game.viewport.ViewBounds(world);
Game.Renderer.EnableScissor(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
terrainRenderer.Draw(this, Game.viewport);
foreach (var a in world.traitDict.ActorsWithTraitMultiple<IRenderAsTerrain>(world))
foreach (var r in a.Trait.RenderAsTerrain(a.Actor))
r.Sprite.DrawAt(r.Pos, this.GetPaletteIndex(r.Palette), r.Scale);
foreach (var a in world.Selection.Actors)
if (!a.Destroyed)
foreach (var t in a.TraitsImplementing<IPreRenderSelection>())
t.RenderBeforeWorld(this, a);
Game.Renderer.Flush();
if (world.OrderGenerator != null)
world.OrderGenerator.RenderBeforeWorld(this, world);
foreach (var image in SpritesToRender() )
image.Sprite.DrawAt(image.Pos, this.GetPaletteIndex(image.Palette), image.Scale);
uiOverlay.Draw(this, world);
// added for contrails
foreach (var a in world.Actors)
if (!a.Destroyed)
foreach (var t in a.TraitsImplementing<IPostRender>())
t.RenderAfterWorld(this, a);
if (world.OrderGenerator != null)
world.OrderGenerator.RenderAfterWorld(this, world);
shroudRenderer.Draw( this );
Game.Renderer.DisableScissor();
foreach (var a in world.Selection.Actors)
if (!a.Destroyed)
foreach (var t in a.TraitsImplementing<IPostRenderSelection>())
t.RenderAfterWorld(this, a);
Game.Renderer.Flush();
}
void DrawBox(RectangleF r, Color color)
{
var a = new float2(r.Left, r.Top);
var b = new float2(r.Right - a.X, 0);
var c = new float2(0, r.Bottom - a.Y);
Game.Renderer.LineRenderer.DrawLine(a, a + b, color, color);
Game.Renderer.LineRenderer.DrawLine(a + b, a + b + c, color, color);
Game.Renderer.LineRenderer.DrawLine(a + b + c, a + c, color, color);
Game.Renderer.LineRenderer.DrawLine(a, a + c, color, color);
}
public void DrawSelectionBox(Actor selectedUnit, Color c)
{
var bounds = selectedUnit.GetBounds(false);
var xy = new float2(bounds.Left, bounds.Top);
var Xy = new float2(bounds.Right, bounds.Top);
var xY = new float2(bounds.Left, bounds.Bottom);
var XY = new float2(bounds.Right, bounds.Bottom);
Game.Renderer.LineRenderer.DrawLine(xy, xy + new float2(4, 0), c, c);
Game.Renderer.LineRenderer.DrawLine(xy, xy + new float2(0, 4), c, c);
Game.Renderer.LineRenderer.DrawLine(Xy, Xy + new float2(-4, 0), c, c);
Game.Renderer.LineRenderer.DrawLine(Xy, Xy + new float2(0, 4), c, c);
Game.Renderer.LineRenderer.DrawLine(xY, xY + new float2(4, 0), c, c);
Game.Renderer.LineRenderer.DrawLine(xY, xY + new float2(0, -4), c, c);
Game.Renderer.LineRenderer.DrawLine(XY, XY + new float2(-4, 0), c, c);
Game.Renderer.LineRenderer.DrawLine(XY, XY + new float2(0, -4), c, c);
}
public void DrawLocus(Color c, int2[] cells)
{
var dict = cells.ToDictionary(a => a, a => 0);
foreach (var t in dict.Keys)
{
if (!dict.ContainsKey(t + new int2(-1, 0)))
Game.Renderer.LineRenderer.DrawLine(Game.CellSize * t, Game.CellSize * (t + new int2(0, 1)),
c, c);
if (!dict.ContainsKey(t + new int2(1, 0)))
Game.Renderer.LineRenderer.DrawLine(Game.CellSize * (t + new int2(1, 0)), Game.CellSize * (t + new int2(1, 1)),
c, c);
if (!dict.ContainsKey(t + new int2(0, -1)))
Game.Renderer.LineRenderer.DrawLine(Game.CellSize * t, Game.CellSize * (t + new int2(1, 0)),
c, c);
if (!dict.ContainsKey(t + new int2(0, 1)))
Game.Renderer.LineRenderer.DrawLine(Game.CellSize * (t + new int2(0, 1)), Game.CellSize * (t + new int2(1, 1)),
c, c);
}
}
public void DrawRangeCircle(Color c, float2 location, float range)
{
for (var i = 0; i < 32; i++)
{
var start = location + Game.CellSize * range * float2.FromAngle((float)(Math.PI * i) / 16);
var end = location + Game.CellSize * range * float2.FromAngle((float)(Math.PI * (i + 0.7)) / 16);
Game.Renderer.LineRenderer.DrawLine(start, end, c, c);
}
}
public void RefreshPalette()
{
palette.Update( world.WorldActor.TraitsImplementing<IPaletteModifier>() );
}
}
}

Some files were not shown because too many files have changed in this diff Show More