Skip to content

Commit

Permalink
Merge branch 'bleed' into rv-engine
Browse files Browse the repository at this point in the history
  • Loading branch information
MustaphaTR committed Jan 7, 2024
2 parents b05b65e + 0741439 commit 52cc2d3
Show file tree
Hide file tree
Showing 131 changed files with 1,172 additions and 137 deletions.
8 changes: 5 additions & 3 deletions OpenRA.Game/FileFormats/Png.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using System.Net;
using System.Text;
using ICSharpCode.SharpZipLib.Checksum;
using ICSharpCode.SharpZipLib.Zip.Compression;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using OpenRA.Graphics;
using OpenRA.Primitives;
Expand Down Expand Up @@ -371,13 +372,14 @@ public byte[] Save()

using (var data = new MemoryStream())
{
using (var compressed = new DeflaterOutputStream(data))
using (var compressed = new DeflaterOutputStream(data, new Deflater(Deflater.BEST_COMPRESSION)))
{
var rowStride = Width * PixelStride;
for (var y = 0; y < Height; y++)
{
// Write uncompressed scanlines for simplicity
compressed.WriteByte(0);
// Assuming no filtering for simplicity
const byte FilterType = 0;
compressed.WriteByte(FilterType);
compressed.Write(Data, y * rowStride, rowStride);
}

Expand Down
6 changes: 3 additions & 3 deletions OpenRA.Mods.Common/Orders/UnitOrderGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class UnitOrderGenerator : IOrderGenerator
readonly string worldSelectCursor = ChromeMetrics.Get<string>("WorldSelectCursor");
readonly string worldDefaultCursor = ChromeMetrics.Get<string>("WorldDefaultCursor");

static Target TargetForInput(World world, CPos cell, int2 worldPixel, MouseInput mi)
protected static Target TargetForInput(World world, CPos cell, int2 worldPixel, MouseInput mi)
{
var actor = world.ScreenMap.ActorsAtMouse(mi)
.Where(a => !a.Actor.IsDead && a.Actor.Info.HasTraitInfo<ITargetableInfo>() && !world.FogObscures(a.Actor))
Expand Down Expand Up @@ -134,7 +134,7 @@ public virtual void SelectionChanged(World world, IEnumerable<Actor> selected) {
/// First priority is given to orders that interact with the given actors.
/// Second priority is given to actors in the given cell.
/// </summary>
static UnitOrderResult OrderForUnit(Actor self, Target target, CPos xy, MouseInput mi)
protected static UnitOrderResult OrderForUnit(Actor self, Target target, CPos xy, MouseInput mi)
{
if (mi.Button != Game.Settings.Game.MouseButtonPreference.Action)
return null;
Expand Down Expand Up @@ -194,7 +194,7 @@ static Order CheckSameOrder(IOrderTargeter iot, Order order)
return order;
}

sealed class UnitOrderResult
protected sealed class UnitOrderResult
{
public readonly Actor Actor;
public readonly IOrderTargeter Order;
Expand Down
7 changes: 7 additions & 0 deletions OpenRA.Mods.Common/Traits/Armament.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using System.Collections.Generic;
using System.Linq;
using OpenRA.GameRules;
using OpenRA.Mods.Common.Traits.Render;
using OpenRA.Traits;

namespace OpenRA.Mods.Common.Traits
Expand Down Expand Up @@ -154,6 +155,8 @@ public class Armament : PausableConditionalTrait<ArmamentInfo>, ITick
public readonly WeaponInfo CasingWeapon;
public readonly Barrel[] Barrels;
Turreted turret;
Hovers hovers;

BodyOrientation coords;
INotifyBurstComplete[] notifyBurstComplete;
INotifyAttack[] notifyAttacks;
Expand Down Expand Up @@ -212,6 +215,7 @@ public virtual WDist MaxRange()
protected override void Created(Actor self)
{
turret = self.TraitsImplementing<Turreted>().FirstOrDefault(t => t.Name == Info.Turret);
hovers = self.TraitOrDefault<Hovers>();
coords = self.Trait<BodyOrientation>();
notifyBurstComplete = self.TraitsImplementing<INotifyBurstComplete>().ToArray();
notifyAttacks = self.TraitsImplementing<INotifyAttack>().ToArray();
Expand Down Expand Up @@ -494,6 +498,9 @@ protected virtual WVec CalculateFireEffectOffset(Actor self, WVec offset)
// Weapon offset in turret coordinates
var effectOffset = offset + new WVec(-Recoil, WDist.Zero, WDist.Zero);

if (hovers != null)
localOffset += hovers.WorldVisualOffset;

Check failure on line 502 in OpenRA.Mods.Common/Traits/Armament.cs

View workflow job for this annotation

GitHub Actions / Linux (.NET 6.0)

The name 'localOffset' does not exist in the current context

Check failure on line 502 in OpenRA.Mods.Common/Traits/Armament.cs

View workflow job for this annotation

GitHub Actions / Linux (.NET 6.0)

The name 'localOffset' does not exist in the current context

Check failure on line 502 in OpenRA.Mods.Common/Traits/Armament.cs

View workflow job for this annotation

GitHub Actions / Windows (.NET 6.0)

The name 'localOffset' does not exist in the current context

Check failure on line 502 in OpenRA.Mods.Common/Traits/Armament.cs

View workflow job for this annotation

GitHub Actions / Windows (.NET 6.0)

The name 'localOffset' does not exist in the current context

Check failure on line 502 in OpenRA.Mods.Common/Traits/Armament.cs

View workflow job for this annotation

GitHub Actions / Windows (.NET 6.0)

The name 'localOffset' does not exist in the current context

Check failure on line 502 in OpenRA.Mods.Common/Traits/Armament.cs

View workflow job for this annotation

GitHub Actions / Windows (.NET 6.0)

The name 'localOffset' does not exist in the current context

// Turret coordinates to body coordinates
var bodyOrientation = coords.QuantizeOrientation(self.Orientation);
if (turret != null)
Expand Down
18 changes: 10 additions & 8 deletions OpenRA.Mods.Common/Traits/Render/Hovers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ public class Hovers : ConditionalTrait<HoversInfo>, IRenderModifier, ITick
readonly int fallTickHeight;

int ticks;
WVec worldVisualOffset;

[Sync]
public WVec WorldVisualOffset { get; private set; }

public Hovers(HoversInfo info)
: base(info)
Expand All @@ -85,11 +87,11 @@ void ITick.Tick(Actor self)
{
if (IsTraitDisabled)
{
if (worldVisualOffset.Z < 0)
if (WorldVisualOffset.Z < 0)
return;

var fallTicks = worldVisualOffset.Z / fallTickHeight - 1;
worldVisualOffset = new WVec(0, 0, fallTickHeight * fallTicks);
var fallTicks = WorldVisualOffset.Z / fallTickHeight - 1;
WorldVisualOffset = new WVec(0, 0, fallTickHeight * fallTicks);
}
else
ticks++;
Expand All @@ -104,13 +106,13 @@ IEnumerable<IRenderable> IRenderModifier.ModifyRender(Actor self, WorldRenderer
var currentHeight = info.BobDistance.Length * visualOffset / 1024 + info.InitialHeight.Length;

// This part rises the actor up from disabled state
if (worldVisualOffset.Z < currentHeight)
currentHeight = Math.Min(worldVisualOffset.Z + info.InitialHeight.Length / info.RiseTicks, currentHeight);
if (WorldVisualOffset.Z < currentHeight)
currentHeight = Math.Min(WorldVisualOffset.Z + info.InitialHeight.Length / info.RiseTicks, currentHeight);

worldVisualOffset = new WVec(0, 0, currentHeight);
WorldVisualOffset = new WVec(0, 0, currentHeight);
}

return r.Select(a => a.OffsetBy(worldVisualOffset));
return r.Select(a => a.OffsetBy(WorldVisualOffset));
}

IEnumerable<Rectangle> IRenderModifier.ModifyScreenBounds(Actor self, WorldRenderer wr, IEnumerable<Rectangle> bounds)
Expand Down
17 changes: 16 additions & 1 deletion OpenRA.Mods.Common/Traits/World/SmudgeLayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ public class SmudgeLayerInfo : TraitInfo
[Desc("Chance of smoke rising from the ground")]
public readonly int SmokeChance = 0;

[Desc("By how much (in each direction) can the smoke appearance offset stray from the center of the cell?",
"Note: Limit this to half a cell for square and 1/3 a cell for isometric cells to avoid straying into neighbour cells.")]
public readonly WDist MaxSmokeOffsetDistance = WDist.Zero;

[Desc("Smoke sprite image name")]
public readonly string SmokeImage = null;

Expand Down Expand Up @@ -152,8 +156,19 @@ public void AddSmudge(CPos loc)
return;

if (hasSmoke && Game.CosmeticRandom.Next(0, 100) <= Info.SmokeChance)
{
var maxOffsetDistance = Info.MaxSmokeOffsetDistance.Length;

// TODO: With offset added height is not accurate for TS maps
var position = world.Map.CenterOfCell(loc);
if (maxOffsetDistance != 0)
position += new WVec(Game.CosmeticRandom.Next(-maxOffsetDistance, maxOffsetDistance),
Game.CosmeticRandom.Next(-maxOffsetDistance, maxOffsetDistance),
0);

world.AddFrameEndTask(w => w.Add(new SpriteEffect(
w.Map.CenterOfCell(loc), w, Info.SmokeImage, Info.SmokeSequences.Random(w.SharedRandom), Info.SmokePalette)));
position, w, Info.SmokeImage, Info.SmokeSequences.Random(Game.CosmeticRandom), Info.SmokePalette)));
}

// A null Sequence indicates a deleted smudge.
if ((!dirty.ContainsKey(loc) || dirty[loc].Sequence == null) && !tiles.ContainsKey(loc))
Expand Down
162 changes: 162 additions & 0 deletions OpenRA.Test/OpenRA.Game/PngTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#region Copyright & License Information
/*
* Copyright (c) The OpenRA Developers and Contributors
* 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, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion

using System.IO;
using System.Linq;
using NUnit.Framework;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Primitives;

namespace OpenRA.Test
{
[TestFixture]
public class PngTests
{
[Test]
public void Save_ShouldProduceValidPngFile()
{
// Arrange
var colors = Enumerable.Range(0, 256).Select(i => Color.FromArgb(i, i, i)).ToArray();
var png = new Png(new byte[10 * 20], SpriteFrameType.Indexed8, 10, 20, colors);

// Act
var result = png.Save();

// Assert
Assert.IsTrue(Png.Verify(new MemoryStream(result)));
}

[Test]
public void Save_Method_Should_Write_Indexed8_Palette_If_256_Colors_Or_Less()
{
// Arrange
var colors = Enumerable.Range(0, 256).Select(i => Color.FromArgb(i, i, i)).ToArray();
var png = new Png(new byte[10 * 20], SpriteFrameType.Indexed8, 10, 20, colors);

// Act
var result = png.Save();

// Assert
// Byte at index 25 contains color type information
// 0x03 represents Indexed8 with a palette
var colorTypeByte = result[25];
Assert.That(colorTypeByte, Is.EqualTo(0x03));
}

[Test]
public void Save_Method_Should_Write_Rgba32_If_Alpha_Channel_Required()
{
// Arrange
var png = new Png(new byte[10 * 20 * 4], SpriteFrameType.Rgba32, 10, 20);

// Act
var result = png.Save();

// Assert
// Byte at index 25 contains color type information
// 0x06 represents RGBA32 with alpha
var colorTypeByte = result[25];
Assert.That(colorTypeByte, Is.EqualTo(0x06));
}

[Test]
public void Save_ShouldThrowException_WhenDataLenghtNotEqualExpectedLenght()
{
// Arrange
var colors = Enumerable.Range(0, 256).Select(i => Color.FromArgb(i, i, i)).ToArray();

// Act
void TestDelegate() => new Png(new byte[10 * 20], SpriteFrameType.Indexed8, 100, 20, colors);

// Assert
var ex = Assert.Throws<InvalidDataException>(TestDelegate);
Assert.That(ex.Message, Is.EqualTo("Input data does not match expected length"));
}

[Test]
public void PngConstructor_InvalidSignature_ThrowsInvalidDataException()
{
// Arrange
byte[] invalidSignature = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };

// Act & Assert
var exception = Assert.Throws<InvalidDataException>(() => new Png(new MemoryStream(invalidSignature)));
StringAssert.Contains("PNG Signature is bogus", exception.Message);
}

[Test]
public void PngConstructor_HeaderNotFirst_ThrowsInvalidDataException()
{
// Arrange
var invalidPngData = new byte[]
{
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44,
0x00, 0x00, 0x00, 0x00,
};

// Act & Assert
var exception = Assert.Throws<InvalidDataException>(() => new Png(new MemoryStream(invalidPngData)));
StringAssert.Contains("Invalid PNG file - header does not appear first.", exception.Message);
}

[Test]
public void PngConstructor_DuplicateIhdrHeader_ThrowsInvalidDataException()
{
// Arrange
var invalidPngData = new byte[]
{
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x00,
};

using (var stream = new MemoryStream(invalidPngData))
{
// Act & Assert
var exception = Assert.Throws<EndOfStreamException>(() => new Png(stream));
}
}

public void PngConstructor_CompressionMethodNotSupported_ThrowsInvalidDataException()
{
// Arrange
var invalidPngData = new byte[]
{
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00,
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x00,
};

using (var stream = new MemoryStream(invalidPngData))
{
// Act & Assert
var exception = Assert.Throws<InvalidDataException>(() => new Png(stream));
Assert.AreEqual("Compression method not supported", exception.Message);
}
}

[Test]
public void Constructor_ThrowsExceptionForNullPaletteIfTypeIsIndexed8()
{
// Arrange
const int Width = 100;
const int Height = 100;
const SpriteFrameType Type = SpriteFrameType.Indexed8;

// Act and Assert
Assert.Throws<InvalidDataException>(() => new Png(new byte[Width * Height], Type, Width, Height, null));
}
}
}
6 changes: 4 additions & 2 deletions mods/cnc/rules/world.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -167,14 +167,16 @@ World:
Type: Scorch
Sequence: scorches
SmokeChance: 50
SmokeImage: smoke_m
SmokeSequences: idle
SmokeImage: scorch_flames
SmokeSequences: large_flame, medium_flame, small_flame
MaxSmokeOffsetDistance: 341
SmudgeLayer@CRATER:
Type: Crater
Sequence: craters
SmokeChance: 25
SmokeImage: smoke_m
SmokeSequences: idle
MaxSmokeOffsetDistance: 213
ResourceLayer:
RecalculateResourceDensity: true
ResourceTypes:
Expand Down
Loading

0 comments on commit 52cc2d3

Please sign in to comment.