Fix IDE0055

This rule no longer appears to be buggy, so enforce it. Some of the automated fixes are adjusted in order to improve the result. #pragma directives have no option to control indentation, so remove them where possible.
This commit is contained in:
RoosterDragon
2023-11-09 19:56:52 +00:00
committed by Pavel Penev
parent 60cbf79c9b
commit 360f24f609
58 changed files with 719 additions and 714 deletions

View File

@@ -427,10 +427,7 @@ dotnet_diagnostic.IDE0077.severity = warning
### Formatting Rules (IDE0055)
### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0055
# We may eventually wish to enforce this rule, however some existing formatting conflicts with the rule despite being reasonable.
# Additionally, the rule is buggy and likes to report spuriously after invoking Format Document in the IDE.
dotnet_diagnostic.IDE0055.severity = none
dotnet_diagnostic.IDE0055.severity = warning
#dotnet_sort_system_directives_first = true
#dotnet_separate_import_directive_groups = false
@@ -448,7 +445,7 @@ dotnet_diagnostic.IDE0055.severity = none
#csharp_indent_labels = one_less_than_current
#csharp_indent_block_contents = true
#csharp_indent_braces = false
#csharp_indent_case_contents_when_block = true
csharp_indent_case_contents_when_block = false
#csharp_space_after_cast = false
#csharp_space_after_keywords_in_control_flow_statements = true

View File

@@ -50,7 +50,7 @@ namespace OpenRA.FileFormats
var length = IPAddress.NetworkToHostOrder(s.ReadInt32());
var type = s.ReadASCII(4);
var content = s.ReadBytes(length);
/*var crc = */s.ReadInt32();
s.ReadInt32(); // crc
if (!headerParsed && type != "IHDR")
throw new InvalidDataException("Invalid PNG file - header does not appear first.");
@@ -76,7 +76,7 @@ namespace OpenRA.FileFormats
Data = new byte[Width * Height * PixelStride];
var compression = ms.ReadUInt8();
/*var filter = */ms.ReadUInt8();
ms.ReadUInt8(); // filter
var interlace = ms.ReadUInt8();
if (compression != 0)

View File

@@ -43,7 +43,7 @@ namespace OpenRA.Graphics
: base("model")
{ }
public override ShaderVertexAttribute[] Attributes { get; } = new[]
public override ShaderVertexAttribute[] Attributes { get; } = new[]
{
new ShaderVertexAttribute("aVertexPosition", ShaderVertexAttributeType.Float, 3, 0),
new ShaderVertexAttribute("aVertexTexCoord", ShaderVertexAttributeType.Float, 4, 12),

View File

@@ -55,7 +55,7 @@ namespace OpenRA.Graphics
indexRowStride = 6 * map.MapSize.X;
lock (IndexBuffers)
{
{
indexBufferWrapper = IndexBuffers.GetValue(world, world => new IndexBufferRc(world));
indexBufferWrapper.AddRef();
}

View File

@@ -53,7 +53,7 @@ namespace OpenRA.Graphics
: base("combined")
{ }
public override ShaderVertexAttribute[] Attributes { get; } = new[]
public override ShaderVertexAttribute[] Attributes { get; } = new[]
{
new ShaderVertexAttribute("aVertexPosition", ShaderVertexAttributeType.Float, 3, 0),
new ShaderVertexAttribute("aVertexTexCoord", ShaderVertexAttributeType.Float, 4, 12),

View File

@@ -152,8 +152,9 @@ namespace OpenRA
// If a more specific init is not available, fall back to an unnamed init.
// If duplicate inits are defined, take the last to match standard yaml override expectations
if (info != null && !string.IsNullOrEmpty(info.InstanceName))
return inits.LastOrDefault(i => i.InstanceName == info.InstanceName) ??
inits.LastOrDefault(i => string.IsNullOrEmpty(i.InstanceName));
return
inits.LastOrDefault(i => i.InstanceName == info.InstanceName) ??
inits.LastOrDefault(i => string.IsNullOrEmpty(i.InstanceName));
// Untagged traits will only use untagged inits
return inits.LastOrDefault(i => string.IsNullOrEmpty(i.InstanceName));

View File

@@ -58,158 +58,158 @@ namespace OpenRA.Network
// Client side translated server message
case "LocalizedMessage":
{
if (string.IsNullOrEmpty(order.TargetString))
break;
var yaml = MiniYaml.FromString(order.TargetString);
foreach (var node in yaml)
{
var localizedMessage = new LocalizedMessage(node.Value);
if (localizedMessage.Key == Joined)
TextNotificationsManager.AddPlayerJoinedLine(localizedMessage.Key, localizedMessage.Arguments);
else if (localizedMessage.Key == Left)
TextNotificationsManager.AddPlayerLeftLine(localizedMessage.Key, localizedMessage.Arguments);
else
TextNotificationsManager.AddSystemLine(localizedMessage.Key, localizedMessage.Arguments);
}
{
if (string.IsNullOrEmpty(order.TargetString))
break;
var yaml = MiniYaml.FromString(order.TargetString);
foreach (var node in yaml)
{
var localizedMessage = new LocalizedMessage(node.Value);
if (localizedMessage.Key == Joined)
TextNotificationsManager.AddPlayerJoinedLine(localizedMessage.Key, localizedMessage.Arguments);
else if (localizedMessage.Key == Left)
TextNotificationsManager.AddPlayerLeftLine(localizedMessage.Key, localizedMessage.Arguments);
else
TextNotificationsManager.AddSystemLine(localizedMessage.Key, localizedMessage.Arguments);
}
break;
}
case "DisableChatEntry":
{
if (OrderNotFromServerOrWorldIsReplay(clientId, world))
break;
// Server may send MaxValue to indicate that it is disabled until further notice
if (order.ExtraData == uint.MaxValue)
TextNotificationsManager.ChatDisabledUntil = uint.MaxValue;
else
TextNotificationsManager.ChatDisabledUntil = Game.RunTime + order.ExtraData;
{
if (OrderNotFromServerOrWorldIsReplay(clientId, world))
break;
}
// Server may send MaxValue to indicate that it is disabled until further notice
if (order.ExtraData == uint.MaxValue)
TextNotificationsManager.ChatDisabledUntil = uint.MaxValue;
else
TextNotificationsManager.ChatDisabledUntil = Game.RunTime + order.ExtraData;
break;
}
case "StartKickVote":
{
if (OrderNotFromServerOrWorldIsReplay(clientId, world))
break;
KickVoteTarget = (int)order.ExtraData;
{
if (OrderNotFromServerOrWorldIsReplay(clientId, world))
break;
}
KickVoteTarget = (int)order.ExtraData;
break;
}
case "EndKickVote":
{
if (OrderNotFromServerOrWorldIsReplay(clientId, world))
break;
if (KickVoteTarget == (int)order.ExtraData)
KickVoteTarget = null;
{
if (OrderNotFromServerOrWorldIsReplay(clientId, world))
break;
}
if (KickVoteTarget == (int)order.ExtraData)
KickVoteTarget = null;
break;
}
case "Chat":
{
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
if (client == null)
break;
// Cut chat messages to the hard limit to avoid exploits
var message = order.TargetString;
if (message.Length > ChatMessageMaxLength)
message = order.TargetString[..ChatMessageMaxLength];
// ExtraData 0 means this is a normal chat order, everything else is team chat
if (order.ExtraData == 0)
{
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
if (client == null)
break;
var p = world?.FindPlayerByClient(client);
var suffix = (p != null && p.WinState == WinState.Lost) ? " (Dead)" : "";
suffix = client.IsObserver ? " (Spectator)" : suffix;
// Cut chat messages to the hard limit to avoid exploits
var message = order.TargetString;
if (message.Length > ChatMessageMaxLength)
message = order.TargetString[..ChatMessageMaxLength];
if (orderManager.LocalClient != null && client != orderManager.LocalClient && client.Team > 0 && client.Team == orderManager.LocalClient.Team)
suffix += " (Ally)";
// ExtraData 0 means this is a normal chat order, everything else is team chat
if (order.ExtraData == 0)
{
var p = world?.FindPlayerByClient(client);
var suffix = (p != null && p.WinState == WinState.Lost) ? " (Dead)" : "";
suffix = client.IsObserver ? " (Spectator)" : suffix;
TextNotificationsManager.AddChatLine(clientId, client.Name + suffix, message, client.Color);
break;
}
if (orderManager.LocalClient != null && client != orderManager.LocalClient && client.Team > 0 && client.Team == orderManager.LocalClient.Team)
suffix += " (Ally)";
TextNotificationsManager.AddChatLine(clientId, client.Name + suffix, message, client.Color);
break;
}
// We are still in the lobby
if (world == null)
{
var prefix = order.ExtraData == uint.MaxValue ? "[Spectators] " : "[Team] ";
if (orderManager.LocalClient != null && client.Team == orderManager.LocalClient.Team)
TextNotificationsManager.AddChatLine(clientId, prefix + client.Name, message, client.Color);
break;
}
var player = world.FindPlayerByClient(client);
var localClientIsObserver = world.IsReplay || (orderManager.LocalClient != null && orderManager.LocalClient.IsObserver)
|| (world.LocalPlayer != null && world.LocalPlayer.WinState != WinState.Undefined);
// ExtraData gives us the team number, uint.MaxValue means Spectators
if (order.ExtraData == uint.MaxValue && localClientIsObserver)
{
// Validate before adding the line
if (client.IsObserver || (player != null && player.WinState != WinState.Undefined))
TextNotificationsManager.AddChatLine(clientId, "[Spectators] " + client.Name, message, client.Color);
break;
}
var valid = client.Team == order.ExtraData && player != null && player.WinState == WinState.Undefined;
var isSameTeam = orderManager.LocalClient != null && order.ExtraData == orderManager.LocalClient.Team
&& world.LocalPlayer != null && world.LocalPlayer.WinState == WinState.Undefined;
if (valid && (isSameTeam || world.IsReplay))
TextNotificationsManager.AddChatLine(clientId, "[Team" + (world.IsReplay ? " " + order.ExtraData : "") + "] " + client.Name, message, client.Color);
// We are still in the lobby
if (world == null)
{
var prefix = order.ExtraData == uint.MaxValue ? "[Spectators] " : "[Team] ";
if (orderManager.LocalClient != null && client.Team == orderManager.LocalClient.Team)
TextNotificationsManager.AddChatLine(clientId, prefix + client.Name, message, client.Color);
break;
}
var player = world.FindPlayerByClient(client);
var localClientIsObserver = world.IsReplay || (orderManager.LocalClient != null && orderManager.LocalClient.IsObserver)
|| (world.LocalPlayer != null && world.LocalPlayer.WinState != WinState.Undefined);
// ExtraData gives us the team number, uint.MaxValue means Spectators
if (order.ExtraData == uint.MaxValue && localClientIsObserver)
{
// Validate before adding the line
if (client.IsObserver || (player != null && player.WinState != WinState.Undefined))
TextNotificationsManager.AddChatLine(clientId, "[Spectators] " + client.Name, message, client.Color);
break;
}
var valid = client.Team == order.ExtraData && player != null && player.WinState == WinState.Undefined;
var isSameTeam = orderManager.LocalClient != null && order.ExtraData == orderManager.LocalClient.Team
&& world.LocalPlayer != null && world.LocalPlayer.WinState == WinState.Undefined;
if (valid && (isSameTeam || world.IsReplay))
TextNotificationsManager.AddChatLine(clientId, "[Team" + (world.IsReplay ? " " + order.ExtraData : "") + "] " + client.Name, message, client.Color);
break;
}
case "StartGame":
{
if (Game.ModData.MapCache[orderManager.LobbyInfo.GlobalSettings.Map].Status != MapStatus.Available)
{
if (Game.ModData.MapCache[orderManager.LobbyInfo.GlobalSettings.Map].Status != MapStatus.Available)
{
Game.Disconnect();
Game.LoadShellMap();
Game.Disconnect();
Game.LoadShellMap();
// TODO: After adding a startup error dialog, notify the replay load failure.
break;
}
if (!string.IsNullOrEmpty(order.TargetString))
{
var data = MiniYaml.FromString(order.TargetString);
var saveLastOrdersFrame = data.FirstOrDefault(n => n.Key == "SaveLastOrdersFrame");
if (saveLastOrdersFrame != null)
orderManager.GameSaveLastFrame =
FieldLoader.GetValue<int>("saveLastOrdersFrame", saveLastOrdersFrame.Value.Value);
var saveSyncFrame = data.FirstOrDefault(n => n.Key == "SaveSyncFrame");
if (saveSyncFrame != null)
orderManager.GameSaveLastSyncFrame =
FieldLoader.GetValue<int>("SaveSyncFrame", saveSyncFrame.Value.Value);
}
else
TextNotificationsManager.AddSystemLine(GameStarted);
Game.StartGame(orderManager.LobbyInfo.GlobalSettings.Map, WorldType.Regular);
// TODO: After adding a startup error dialog, notify the replay load failure.
break;
}
if (!string.IsNullOrEmpty(order.TargetString))
{
var data = MiniYaml.FromString(order.TargetString);
var saveLastOrdersFrame = data.FirstOrDefault(n => n.Key == "SaveLastOrdersFrame");
if (saveLastOrdersFrame != null)
orderManager.GameSaveLastFrame =
FieldLoader.GetValue<int>("saveLastOrdersFrame", saveLastOrdersFrame.Value.Value);
var saveSyncFrame = data.FirstOrDefault(n => n.Key == "SaveSyncFrame");
if (saveSyncFrame != null)
orderManager.GameSaveLastSyncFrame =
FieldLoader.GetValue<int>("SaveSyncFrame", saveSyncFrame.Value.Value);
}
else
TextNotificationsManager.AddSystemLine(GameStarted);
Game.StartGame(orderManager.LobbyInfo.GlobalSettings.Map, WorldType.Regular);
break;
}
case "SaveTraitData":
{
var data = MiniYaml.FromString(order.TargetString)[0];
var traitIndex = Exts.ParseInt32Invariant(data.Key);
{
var data = MiniYaml.FromString(order.TargetString)[0];
var traitIndex = Exts.ParseInt32Invariant(data.Key);
world?.AddGameSaveTraitData(traitIndex, data.Value);
world?.AddGameSaveTraitData(traitIndex, data.Value);
break;
}
break;
}
case "GameSaved":
if (!orderManager.World.IsReplay)
@@ -220,188 +220,188 @@ namespace OpenRA.Network
break;
case "PauseGame":
{
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
if (client != null)
{
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
if (client != null)
{
var pause = order.TargetString == "Pause";
var pause = order.TargetString == "Pause";
// Prevent injected unpause orders from restarting a finished game
if (orderManager.World.IsGameOver && !pause)
break;
// Prevent injected unpause orders from restarting a finished game
if (orderManager.World.IsGameOver && !pause)
break;
if (orderManager.World.Paused != pause && world != null && world.LobbyInfo.NonBotClients.Count() > 1)
TextNotificationsManager.AddSystemLine(pause ? GamePaused : GameUnpaused, Translation.Arguments("player", client.Name));
if (orderManager.World.Paused != pause && world != null && world.LobbyInfo.NonBotClients.Count() > 1)
TextNotificationsManager.AddSystemLine(pause ? GamePaused : GameUnpaused, Translation.Arguments("player", client.Name));
orderManager.World.Paused = pause;
orderManager.World.PredictedPaused = pause;
}
break;
orderManager.World.Paused = pause;
orderManager.World.PredictedPaused = pause;
}
break;
}
case "HandshakeRequest":
{
// Switch to the server's mod if we need and are able to
var mod = Game.ModData.Manifest;
var request = HandshakeRequest.Deserialize(order.TargetString);
var externalKey = ExternalMod.MakeKey(request.Mod, request.Version);
if ((request.Mod != mod.Id || request.Version != mod.Metadata.Version) &&
Game.ExternalMods.TryGetValue(externalKey, out var external))
{
// Switch to the server's mod if we need and are able to
var mod = Game.ModData.Manifest;
var request = HandshakeRequest.Deserialize(order.TargetString);
var externalKey = ExternalMod.MakeKey(request.Mod, request.Version);
if ((request.Mod != mod.Id || request.Version != mod.Metadata.Version) &&
Game.ExternalMods.TryGetValue(externalKey, out var external))
{
// The ConnectionFailedLogic will prompt the user to switch mods
CurrentServerSettings.ServerExternalMod = external;
orderManager.Connection.Dispose();
break;
}
Game.Settings.Player.Name = Settings.SanitizedPlayerName(Game.Settings.Player.Name);
Game.Settings.Save();
// Otherwise send the handshake with our current settings and let the server reject us
var info = new Session.Client()
{
Name = Game.Settings.Player.Name,
PreferredColor = Game.Settings.Player.Color,
Color = Game.Settings.Player.Color,
Faction = "Random",
SpawnPoint = 0,
Team = 0,
State = Session.ClientState.Invalid
};
var localProfile = Game.LocalPlayerProfile;
var response = new HandshakeResponse()
{
Client = info,
Mod = mod.Id,
Version = mod.Metadata.Version,
Password = CurrentServerSettings.Password,
Fingerprint = localProfile.Fingerprint,
OrdersProtocol = ProtocolVersion.Orders
};
if (request.AuthToken != null && response.Fingerprint != null)
response.AuthSignature = localProfile.Sign(request.AuthToken);
orderManager.IssueOrder(new Order("HandshakeResponse", null, false)
{
Type = OrderType.Handshake,
IsImmediate = true,
TargetString = response.Serialize()
});
// The ConnectionFailedLogic will prompt the user to switch mods
CurrentServerSettings.ServerExternalMod = external;
orderManager.Connection.Dispose();
break;
}
Game.Settings.Player.Name = Settings.SanitizedPlayerName(Game.Settings.Player.Name);
Game.Settings.Save();
// Otherwise send the handshake with our current settings and let the server reject us
var info = new Session.Client()
{
Name = Game.Settings.Player.Name,
PreferredColor = Game.Settings.Player.Color,
Color = Game.Settings.Player.Color,
Faction = "Random",
SpawnPoint = 0,
Team = 0,
State = Session.ClientState.Invalid
};
var localProfile = Game.LocalPlayerProfile;
var response = new HandshakeResponse()
{
Client = info,
Mod = mod.Id,
Version = mod.Metadata.Version,
Password = CurrentServerSettings.Password,
Fingerprint = localProfile.Fingerprint,
OrdersProtocol = ProtocolVersion.Orders
};
if (request.AuthToken != null && response.Fingerprint != null)
response.AuthSignature = localProfile.Sign(request.AuthToken);
orderManager.IssueOrder(new Order("HandshakeResponse", null, false)
{
Type = OrderType.Handshake,
IsImmediate = true,
TargetString = response.Serialize()
});
break;
}
case "ServerError":
{
orderManager.ServerError = order.TargetString;
orderManager.AuthenticationFailed = false;
break;
}
{
orderManager.ServerError = order.TargetString;
orderManager.AuthenticationFailed = false;
break;
}
case "AuthenticationError":
{
// The ConnectionFailedLogic will prompt the user for the password
orderManager.ServerError = order.TargetString;
orderManager.AuthenticationFailed = true;
break;
}
{
// The ConnectionFailedLogic will prompt the user for the password
orderManager.ServerError = order.TargetString;
orderManager.AuthenticationFailed = true;
break;
}
case "SyncInfo":
{
orderManager.LobbyInfo = Session.Deserialize(order.TargetString);
Game.SyncLobbyInfo();
break;
}
{
orderManager.LobbyInfo = Session.Deserialize(order.TargetString);
Game.SyncLobbyInfo();
break;
}
case "SyncLobbyClients":
{
var clients = new List<Session.Client>();
var nodes = MiniYaml.FromString(order.TargetString);
foreach (var node in nodes)
{
var clients = new List<Session.Client>();
var nodes = MiniYaml.FromString(order.TargetString);
foreach (var node in nodes)
{
var strings = node.Key.Split('@');
if (strings[0] == "Client")
clients.Add(Session.Client.Deserialize(node.Value));
}
orderManager.LobbyInfo.Clients = clients;
Game.SyncLobbyInfo();
break;
var strings = node.Key.Split('@');
if (strings[0] == "Client")
clients.Add(Session.Client.Deserialize(node.Value));
}
orderManager.LobbyInfo.Clients = clients;
Game.SyncLobbyInfo();
break;
}
case "SyncLobbySlots":
{
var slots = new Dictionary<string, Session.Slot>();
var nodes = MiniYaml.FromString(order.TargetString);
foreach (var node in nodes)
{
var slots = new Dictionary<string, Session.Slot>();
var nodes = MiniYaml.FromString(order.TargetString);
foreach (var node in nodes)
var strings = node.Key.Split('@');
if (strings[0] == "Slot")
{
var strings = node.Key.Split('@');
if (strings[0] == "Slot")
{
var slot = Session.Slot.Deserialize(node.Value);
slots.Add(slot.PlayerReference, slot);
}
var slot = Session.Slot.Deserialize(node.Value);
slots.Add(slot.PlayerReference, slot);
}
orderManager.LobbyInfo.Slots = slots;
Game.SyncLobbyInfo();
break;
}
orderManager.LobbyInfo.Slots = slots;
Game.SyncLobbyInfo();
break;
}
case "SyncLobbyGlobalSettings":
{
var nodes = MiniYaml.FromString(order.TargetString);
foreach (var node in nodes)
{
var nodes = MiniYaml.FromString(order.TargetString);
foreach (var node in nodes)
{
var strings = node.Key.Split('@');
if (strings[0] == "GlobalSettings")
orderManager.LobbyInfo.GlobalSettings = Session.Global.Deserialize(node.Value);
}
Game.SyncLobbyInfo();
break;
var strings = node.Key.Split('@');
if (strings[0] == "GlobalSettings")
orderManager.LobbyInfo.GlobalSettings = Session.Global.Deserialize(node.Value);
}
Game.SyncLobbyInfo();
break;
}
case "SyncConnectionQuality":
{
var nodes = MiniYaml.FromString(order.TargetString);
foreach (var node in nodes)
{
var nodes = MiniYaml.FromString(order.TargetString);
foreach (var node in nodes)
var strings = node.Key.Split('@');
if (strings[0] == "ConnectionQuality")
{
var strings = node.Key.Split('@');
if (strings[0] == "ConnectionQuality")
{
var client = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.Index == Exts.ParseInt32Invariant(strings[1]));
if (client != null)
client.ConnectionQuality = FieldLoader.GetValue<Session.ConnectionQuality>("ConnectionQuality", node.Value.Value);
}
var client = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.Index == Exts.ParseInt32Invariant(strings[1]));
if (client != null)
client.ConnectionQuality = FieldLoader.GetValue<Session.ConnectionQuality>("ConnectionQuality", node.Value.Value);
}
break;
}
break;
}
case "SyncMapPool":
{
orderManager.ServerMapPool = FieldLoader.GetValue<HashSet<string>>("SyncMapPool", order.TargetString);
break;
}
{
orderManager.ServerMapPool = FieldLoader.GetValue<HashSet<string>>("SyncMapPool", order.TargetString);
break;
}
default:
{
if (world == null)
break;
if (order.GroupedActors == null)
ResolveOrder(order, world, orderManager, clientId);
else
foreach (var subject in order.GroupedActors)
ResolveOrder(Order.FromGroupedOrder(order, subject), world, orderManager, clientId);
{
if (world == null)
break;
}
if (order.GroupedActors == null)
ResolveOrder(order, world, orderManager, clientId);
else
foreach (var subject in order.GroupedActors)
ResolveOrder(Order.FromGroupedOrder(order, subject), world, orderManager, clientId);
break;
}
}
}

View File

@@ -274,7 +274,7 @@ namespace OpenRA
throw new DirectoryNotFoundException(path);
if (!path.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal) &&
!path.EndsWith(Path.AltDirectorySeparatorChar.ToString(), StringComparison.Ordinal))
!path.EndsWith(Path.AltDirectorySeparatorChar.ToString(), StringComparison.Ordinal))
path += Path.DirectorySeparatorChar;
engineDirAccessed = true;

View File

@@ -169,12 +169,12 @@ namespace OpenRA.Primitives
byte alpha = 255;
if (!byte.TryParse(value.AsSpan(0, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var red)
|| !byte.TryParse(value.AsSpan(2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var green)
|| !byte.TryParse(value.AsSpan(4, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var blue))
|| !byte.TryParse(value.AsSpan(2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var green)
|| !byte.TryParse(value.AsSpan(4, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var blue))
return false;
if (value.Length == 8
&& !byte.TryParse(value.AsSpan(6, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out alpha))
&& !byte.TryParse(value.AsSpan(6, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out alpha))
return false;
color = FromArgb(alpha, red, green, blue);

View File

@@ -280,7 +280,8 @@ namespace OpenRA.Server
}
}
}
}) { Name = $"Connection listener ({listener.LocalEndpoint})", IsBackground = true }.Start();
})
{ Name = $"Connection listener ({listener.LocalEndpoint})", IsBackground = true }.Start();
}
catch (SocketException ex)
{
@@ -990,70 +991,42 @@ namespace OpenRA.Server
switch (o.OrderString)
{
case "Command":
{
var handledBy = serverTraits.WithInterface<IInterpretCommand>()
.FirstOrDefault(t => t.InterpretCommand(this, conn, GetClient(conn), o.TargetString));
if (handledBy == null)
{
var handledBy = serverTraits.WithInterface<IInterpretCommand>()
.FirstOrDefault(t => t.InterpretCommand(this, conn, GetClient(conn), o.TargetString));
if (handledBy == null)
{
Log.Write("server", $"Unknown server command: {o.TargetString}");
SendLocalizedMessageTo(conn, UnknownServerCommand, Translation.Arguments("command", o.TargetString));
}
break;
Log.Write("server", $"Unknown server command: {o.TargetString}");
SendLocalizedMessageTo(conn, UnknownServerCommand, Translation.Arguments("command", o.TargetString));
}
break;
}
case "Chat":
{
if (Type == ServerType.Local || !playerMessageTracker.IsPlayerAtFloodLimit(conn))
DispatchOrdersToClients(conn, 0, o.Serialize());
{
if (Type == ServerType.Local || !playerMessageTracker.IsPlayerAtFloodLimit(conn))
DispatchOrdersToClients(conn, 0, o.Serialize());
break;
}
break;
}
case "GameSaveTraitData":
{
if (GameSave != null)
{
if (GameSave != null)
{
var data = MiniYaml.FromString(o.TargetString)[0];
GameSave.AddTraitData(OpenRA.Exts.ParseInt32Invariant(data.Key), data.Value);
}
break;
var data = MiniYaml.FromString(o.TargetString)[0];
GameSave.AddTraitData(OpenRA.Exts.ParseInt32Invariant(data.Key), data.Value);
}
break;
}
case "CreateGameSave":
{
if (GameSave != null)
{
if (GameSave != null)
{
// Sanitize potentially malicious input
var filename = o.TargetString;
var invalidIndex = -1;
var invalidChars = Path.GetInvalidFileNameChars();
while ((invalidIndex = filename.IndexOfAny(invalidChars)) != -1)
filename = filename.Remove(invalidIndex, 1);
var baseSavePath = Path.Combine(
Platform.SupportDir,
"Saves",
ModData.Manifest.Id,
ModData.Manifest.Metadata.Version);
if (!Directory.Exists(baseSavePath))
Directory.CreateDirectory(baseSavePath);
GameSave.Save(Path.Combine(baseSavePath, filename));
DispatchServerOrdersToClients(Order.FromTargetString("GameSaved", filename, true));
}
break;
}
case "LoadGameSave":
{
if (Type == ServerType.Dedicated || State >= ServerState.GameStarted)
break;
// Sanitize potentially malicious input
var filename = o.TargetString;
var invalidIndex = -1;
@@ -1061,62 +1034,90 @@ namespace OpenRA.Server
while ((invalidIndex = filename.IndexOfAny(invalidChars)) != -1)
filename = filename.Remove(invalidIndex, 1);
var savePath = Path.Combine(
var baseSavePath = Path.Combine(
Platform.SupportDir,
"Saves",
ModData.Manifest.Id,
ModData.Manifest.Metadata.Version,
filename);
ModData.Manifest.Metadata.Version);
GameSave = new GameSave(savePath);
LobbyInfo.GlobalSettings = GameSave.GlobalSettings;
LobbyInfo.Slots = GameSave.Slots;
if (!Directory.Exists(baseSavePath))
Directory.CreateDirectory(baseSavePath);
// Reassign clients to slots
// - Bot ordering is preserved
// - Humans are assigned on a first-come-first-serve basis
// - Leftover humans become spectators
// Start by removing all bots and assigning all players as spectators
foreach (var c in LobbyInfo.Clients)
{
if (c.Bot != null)
LobbyInfo.Clients.Remove(c);
else
c.Slot = null;
}
// Rebuild/remap the saved client state
// TODO: Multiplayer saves should leave all humans as spectators so they can manually pick slots
var adminClientIndex = LobbyInfo.Clients.First(c => c.IsAdmin).Index;
foreach (var kv in GameSave.SlotClients)
{
if (kv.Value.Bot != null)
{
var bot = new Session.Client()
{
Index = ChooseFreePlayerIndex(),
State = Session.ClientState.NotReady,
BotControllerClientIndex = adminClientIndex
};
kv.Value.ApplyTo(bot);
LobbyInfo.Clients.Add(bot);
}
else
{
// This will throw if the server doesn't have enough human clients to fill all player slots
// See TODO above - this isn't a problem in practice because MP saves won't use this
var client = LobbyInfo.Clients.First(c => c.Slot == null);
kv.Value.ApplyTo(client);
}
}
SyncLobbyInfo();
SyncLobbyClients();
break;
GameSave.Save(Path.Combine(baseSavePath, filename));
DispatchServerOrdersToClients(Order.FromTargetString("GameSaved", filename, true));
}
break;
}
case "LoadGameSave":
{
if (Type == ServerType.Dedicated || State >= ServerState.GameStarted)
break;
// Sanitize potentially malicious input
var filename = o.TargetString;
var invalidIndex = -1;
var invalidChars = Path.GetInvalidFileNameChars();
while ((invalidIndex = filename.IndexOfAny(invalidChars)) != -1)
filename = filename.Remove(invalidIndex, 1);
var savePath = Path.Combine(
Platform.SupportDir,
"Saves",
ModData.Manifest.Id,
ModData.Manifest.Metadata.Version,
filename);
GameSave = new GameSave(savePath);
LobbyInfo.GlobalSettings = GameSave.GlobalSettings;
LobbyInfo.Slots = GameSave.Slots;
// Reassign clients to slots
// - Bot ordering is preserved
// - Humans are assigned on a first-come-first-serve basis
// - Leftover humans become spectators
// Start by removing all bots and assigning all players as spectators
foreach (var c in LobbyInfo.Clients)
{
if (c.Bot != null)
LobbyInfo.Clients.Remove(c);
else
c.Slot = null;
}
// Rebuild/remap the saved client state
// TODO: Multiplayer saves should leave all humans as spectators so they can manually pick slots
var adminClientIndex = LobbyInfo.Clients.First(c => c.IsAdmin).Index;
foreach (var kv in GameSave.SlotClients)
{
if (kv.Value.Bot != null)
{
var bot = new Session.Client()
{
Index = ChooseFreePlayerIndex(),
State = Session.ClientState.NotReady,
BotControllerClientIndex = adminClientIndex
};
kv.Value.ApplyTo(bot);
LobbyInfo.Clients.Add(bot);
}
else
{
// This will throw if the server doesn't have enough human clients to fill all player slots
// See TODO above - this isn't a problem in practice because MP saves won't use this
var client = LobbyInfo.Clients.First(c => c.Slot == null);
kv.Value.ApplyTo(client);
}
}
SyncLobbyInfo();
SyncLobbyClients();
break;
}
}
}
}
@@ -1504,9 +1505,9 @@ namespace OpenRA.Server
readonly int[] pingHistory;
// TODO: future net code changes
#pragma warning disable IDE0052
#pragma warning disable IDE0052
readonly byte queueLength;
#pragma warning restore IDE0052
#pragma warning restore IDE0052
public ConnectionPingEvent(Connection connection, int[] pingHistory, byte queueLength)
{

View File

@@ -157,28 +157,26 @@ namespace OpenRA
var lsq = x * x + y * y + z * z + w * w;
// Quaternion components use 10 bits, so there's no risk of overflow
#pragma warning disable SA1115 // Allow blank lines to visually separate matrix rows
mtx = new Int32Matrix4x4(
lsq - 2 * (y * y + z * z),
2 * (x * y + z * w),
2 * (x * z - y * w),
0,
/* row */
2 * (x * y - z * w),
lsq - 2 * (x * x + z * z),
2 * (y * z + x * w),
0,
/* row */
2 * (x * z + y * w),
2 * (y * z - x * w),
lsq - 2 * (x * x + y * y),
0,
/* row */
0,
0,
0,
lsq);
#pragma warning restore SA1115
}
public Int32Matrix4x4 AsMatrix()

View File

@@ -51,7 +51,7 @@ namespace OpenRA.Mods.Cnc.Activities
// The target may become hidden between the initial order request and the first tick (e.g. if queued)
// Moving to any position (even if quite stale) is still better than immediately giving up
if ((target.Type == TargetType.Actor && target.Actor.CanBeViewedByPlayer(self.Owner))
|| target.Type == TargetType.FrozenActor || target.Type == TargetType.Terrain)
|| target.Type == TargetType.FrozenActor || target.Type == TargetType.Terrain)
{
lastVisibleTarget = Target.FromPos(target.CenterPosition);
lastVisibleMinRange = attack.GetMinimumRangeVersusTarget(target);

View File

@@ -171,53 +171,53 @@ namespace OpenRA.Mods.Cnc.AudioLoaders
{
// Sound data
case 1:
{
if (block.Length < 2)
throw new InvalidDataException("Invalid sound data block length in voc file");
var freqDiv = stream.ReadUInt8();
block.SampleBlock.Rate = GetSampleRateFromVocRate(freqDiv);
var codec = stream.ReadUInt8();
if (codec != 0)
throw new InvalidDataException("Unhandled codec used in voc file");
skip = block.Length - 2;
block.SampleBlock.Samples = skip;
block.SampleBlock.Offset = stream.Position;
// See if last block contained additional information
if (blockList.Count > 0)
{
if (block.Length < 2)
throw new InvalidDataException("Invalid sound data block length in voc file");
var freqDiv = stream.ReadUInt8();
block.SampleBlock.Rate = GetSampleRateFromVocRate(freqDiv);
var codec = stream.ReadUInt8();
if (codec != 0)
throw new InvalidDataException("Unhandled codec used in voc file");
skip = block.Length - 2;
block.SampleBlock.Samples = skip;
block.SampleBlock.Offset = stream.Position;
// See if last block contained additional information
if (blockList.Count > 0)
var b = blockList.Last();
if (b.Code == 8)
{
var b = blockList.Last();
if (b.Code == 8)
{
block.SampleBlock.Rate = b.SampleBlock.Rate;
blockList.Remove(b);
}
block.SampleBlock.Rate = b.SampleBlock.Rate;
blockList.Remove(b);
}
sampleRate = Math.Max(sampleRate, block.SampleBlock.Rate);
break;
}
sampleRate = Math.Max(sampleRate, block.SampleBlock.Rate);
break;
}
// Silence
case 3:
{
if (block.Length != 3)
throw new InvalidDataException("Invalid silence block length in voc file");
block.SampleBlock.Offset = 0;
block.SampleBlock.Samples = stream.ReadUInt16() + 1;
var freqDiv = stream.ReadUInt8();
block.SampleBlock.Rate = GetSampleRateFromVocRate(freqDiv);
break;
}
{
if (block.Length != 3)
throw new InvalidDataException("Invalid silence block length in voc file");
block.SampleBlock.Offset = 0;
block.SampleBlock.Samples = stream.ReadUInt16() + 1;
var freqDiv = stream.ReadUInt8();
block.SampleBlock.Rate = GetSampleRateFromVocRate(freqDiv);
break;
}
// Repeat start
case 6:
{
if (block.Length != 2)
throw new InvalidDataException("Invalid repeat start block length in voc file");
block.LoopBlock.Count = stream.ReadUInt16() + 1;
break;
}
{
if (block.Length != 2)
throw new InvalidDataException("Invalid repeat start block length in voc file");
block.LoopBlock.Count = stream.ReadUInt16() + 1;
break;
}
// Repeat end
case 7:
@@ -225,23 +225,23 @@ namespace OpenRA.Mods.Cnc.AudioLoaders
// Extra info
case 8:
{
if (block.Length != 4)
throw new InvalidDataException("Invalid info block length in voc file");
int freqDiv = stream.ReadUInt16();
if (freqDiv == 65536)
throw new InvalidDataException("Invalid frequency divisor 65536 in voc file");
var codec = stream.ReadUInt8();
if (codec != 0)
throw new InvalidDataException("Unhandled codec used in voc file");
var channels = stream.ReadUInt8() + 1;
if (channels != 1)
throw new InvalidDataException("Unhandled number of channels in voc file");
block.SampleBlock.Offset = 0;
block.SampleBlock.Samples = 0;
block.SampleBlock.Rate = (int)(256000000L / (65536L - freqDiv));
break;
}
{
if (block.Length != 4)
throw new InvalidDataException("Invalid info block length in voc file");
int freqDiv = stream.ReadUInt16();
if (freqDiv == 65536)
throw new InvalidDataException("Invalid frequency divisor 65536 in voc file");
var codec = stream.ReadUInt8();
if (codec != 0)
throw new InvalidDataException("Unhandled codec used in voc file");
var channels = stream.ReadUInt8() + 1;
if (channels != 1)
throw new InvalidDataException("Unhandled number of channels in voc file");
block.SampleBlock.Offset = 0;
block.SampleBlock.Samples = 0;
block.SampleBlock.Rate = (int)(256000000L / (65536L - freqDiv));
break;
}
// Sound data (New format)
case 9:

View File

@@ -251,9 +251,7 @@ namespace OpenRA.Mods.Cnc.FileFormats
*op++ = *ip++;
if (t > 2)
{
#pragma warning disable IDE0047
(*op++) = *ip++;
#pragma warning restore IDE0047
*op++ = *ip++;
}
}

View File

@@ -68,13 +68,13 @@ namespace OpenRA.Mods.Cnc.FileFormats
// Decode FORM chunk
if (stream.ReadASCII(4) != "FORM")
throw new InvalidDataException("Invalid vqa (invalid FORM section)");
/*var length = */stream.ReadUInt32();
stream.ReadUInt32(); // length
if (stream.ReadASCII(8) != "WVQAVQHD")
throw new InvalidDataException("Invalid vqa (not WVQAVQHD)");
/*var length2 = */stream.ReadUInt32();
stream.ReadUInt32(); // length2
/*var version = */stream.ReadUInt16();
stream.ReadUInt16(); // version
videoFlags = stream.ReadUInt16();
FrameCount = stream.ReadUInt16();
Width = stream.ReadUInt16();
@@ -87,20 +87,20 @@ namespace OpenRA.Mods.Cnc.FileFormats
blocks = new int2(Width / blockWidth, Height / blockHeight);
numColors = stream.ReadUInt16();
/*var maxBlocks = */stream.ReadUInt16();
/*var unknown1 = */stream.ReadUInt16();
/*var unknown2 = */stream.ReadUInt32();
stream.ReadUInt16(); // maxBlocks
stream.ReadUInt16(); // unknown1
stream.ReadUInt32(); // unknown2
// Audio
SampleRate = stream.ReadUInt16();
AudioChannels = stream.ReadUInt8();
SampleBits = stream.ReadUInt8();
/*var unknown3 =*/stream.ReadUInt32();
/*var unknown4 =*/stream.ReadUInt16();
/*maxCbfzSize =*/stream.ReadUInt32(); // Unreliable
stream.ReadUInt32(); // unknown3
stream.ReadUInt16(); // unknown4
stream.ReadUInt32(); // maxCbfzSize, unreliable
/*var unknown5 =*/stream.ReadUInt32();
stream.ReadUInt32(); // unknown5
if (IsHqVqa)
{
@@ -131,8 +131,8 @@ namespace OpenRA.Mods.Cnc.FileFormats
throw new NotSupportedException($"Vqa uses unknown Subtype: {type}");
}
/*var length = */stream.ReadUInt16();
/*var unknown4 = */stream.ReadUInt16();
stream.ReadUInt16(); // length
stream.ReadUInt16(); // unknown4
// Frame offsets
offsets = new uint[FrameCount];

View File

@@ -45,13 +45,13 @@ namespace OpenRA.Mods.Cnc.FileFormats
FrameCount = stream.ReadUInt16();
/*var x = */stream.ReadUInt16();
/*var y = */stream.ReadUInt16();
stream.ReadUInt16(); // x
stream.ReadUInt16(); // y
Width = stream.ReadUInt16();
Height = stream.ReadUInt16();
/*var delta = */stream.ReadUInt16(); /* + 37*/
stream.ReadUInt16(); // delta (+37)
var flags = stream.ReadUInt16();
frameOffsets = new uint[FrameCount + 2];

View File

@@ -35,7 +35,7 @@ namespace OpenRA.Mods.Cnc.FileSystem
try
{
/* var signature = */ s.ReadASCII(4);
s.ReadASCII(4); // signature
// Total archive size.
s.ReadUInt32();

View File

@@ -113,7 +113,7 @@ namespace OpenRA.Mods.Cnc.FileSystem
{
s.Seek(offset, SeekOrigin.Begin);
var numFiles = s.ReadUInt16();
/*uint dataSize = */s.ReadUInt32();
s.ReadUInt32(); // dataSize
var items = new List<PackageEntry>();
for (var i = 0; i < numFiles; i++)

View File

@@ -69,38 +69,38 @@ namespace OpenRA.Mods.Cnc.FileSystem
switch (type)
{
case PackageHashType.Classic:
{
for (var p = 0; p < padding; p++)
upperPaddedName[paddedLength - 1 - p] = '\0';
{
for (var p = 0; p < padding; p++)
upperPaddedName[paddedLength - 1 - p] = '\0';
var asciiBytes = paddedLength < 64 ? stackalloc byte[paddedLength] : new byte[paddedLength];
Encoding.ASCII.GetBytes(upperPaddedName, asciiBytes);
var asciiBytes = paddedLength < 64 ? stackalloc byte[paddedLength] : new byte[paddedLength];
Encoding.ASCII.GetBytes(upperPaddedName, asciiBytes);
var data = MemoryMarshal.Cast<byte, uint>(asciiBytes);
var result = 0u;
foreach (var next in data)
result = ((result << 1) | (result >> 31)) + next;
var data = MemoryMarshal.Cast<byte, uint>(asciiBytes);
var result = 0u;
foreach (var next in data)
result = ((result << 1) | (result >> 31)) + next;
return result;
}
return result;
}
case PackageHashType.CRC32:
{
var length = name.Length;
var lengthRoundedDownToFour = length / 4 * 4;
if (length != lengthRoundedDownToFour)
{
var length = name.Length;
var lengthRoundedDownToFour = length / 4 * 4;
if (length != lengthRoundedDownToFour)
{
upperPaddedName[length] = (char)(length - lengthRoundedDownToFour);
for (var p = 1; p < padding; p++)
upperPaddedName[length + p] = upperPaddedName[lengthRoundedDownToFour];
}
var asciiBytes = paddedLength < 64 ? stackalloc byte[paddedLength] : new byte[paddedLength];
Encoding.ASCII.GetBytes(upperPaddedName, asciiBytes);
return CRC32.Calculate(asciiBytes);
upperPaddedName[length] = (char)(length - lengthRoundedDownToFour);
for (var p = 1; p < padding; p++)
upperPaddedName[length + p] = upperPaddedName[lengthRoundedDownToFour];
}
var asciiBytes = paddedLength < 64 ? stackalloc byte[paddedLength] : new byte[paddedLength];
Encoding.ASCII.GetBytes(upperPaddedName, asciiBytes);
return CRC32.Calculate(asciiBytes);
}
default: throw new NotImplementedException($"Unknown hash type `{type}`");
}
}

View File

@@ -27,7 +27,7 @@ namespace OpenRA.Mods.Cnc.Graphics
}
[Desc("A sprite sequence that can have tileset-specific variants and has the oddities " +
"that come with first-generation Westwood titles.")]
"that come with first-generation Westwood titles.")]
public class ClassicTilesetSpecificSpriteSequence : ClassicSpriteSequence
{
[Desc("Dictionary of <tileset name>: filename to override the Filename key.")]

View File

@@ -37,7 +37,8 @@ namespace OpenRA.Mods.Cnc.Graphics
: this(renderer, models, pos, zOffset, camera, scale,
lightSource, lightAmbientColor, lightDiffuseColor,
color, normals, shadow, 1f,
float3.Ones, TintModifiers.None) { }
float3.Ones, TintModifiers.None)
{ }
public ModelRenderable(
ModelRenderer renderer, IEnumerable<ModelAnimation> models, WPos pos, int zOffset, in WRot camera, float scale,

View File

@@ -172,26 +172,26 @@ namespace OpenRA.Mods.Cnc.SpriteLoaders
{
case Format.XORPrev:
case Format.XORLCW:
{
if (h.RefImage.Data == null)
{
if (h.RefImage.Data == null)
{
++recurseDepth;
Decompress(h.RefImage);
--recurseDepth;
}
h.Data = CopyImageData(h.RefImage.Data);
XORDeltaCompression.DecodeInto(shpBytes, h.Data, (int)(h.FileOffset - shpBytesFileOffset));
break;
++recurseDepth;
Decompress(h.RefImage);
--recurseDepth;
}
h.Data = CopyImageData(h.RefImage.Data);
XORDeltaCompression.DecodeInto(shpBytes, h.Data, (int)(h.FileOffset - shpBytesFileOffset));
break;
}
case Format.LCW:
{
var imageBytes = new byte[Size.Width * Size.Height];
LCWCompression.DecodeInto(shpBytes, imageBytes, (int)(h.FileOffset - shpBytesFileOffset));
h.Data = imageBytes;
break;
}
{
var imageBytes = new byte[Size.Width * Size.Height];
LCWCompression.DecodeInto(shpBytes, imageBytes, (int)(h.FileOffset - shpBytesFileOffset));
h.Data = imageBytes;
break;
}
default:
throw new InvalidDataException();

View File

@@ -196,18 +196,24 @@ namespace OpenRA.Mods.Cnc.Traits
}
public Activity MoveTo(CPos cell, int nearEnough = 0, Actor ignoreActor = null,
bool evaluateNearestMovableCell = false, Color? targetLineColor = null) { return null; }
bool evaluateNearestMovableCell = false, Color? targetLineColor = null)
{ return null; }
public Activity MoveWithinRange(in Target target, WDist range,
WPos? initialTargetPosition = null, Color? targetLineColor = null) { return null; }
WPos? initialTargetPosition = null, Color? targetLineColor = null)
{ return null; }
public Activity MoveWithinRange(in Target target, WDist minRange, WDist maxRange,
WPos? initialTargetPosition = null, Color? targetLineColor = null) { return null; }
WPos? initialTargetPosition = null, Color? targetLineColor = null)
{ return null; }
public Activity MoveFollow(Actor self, in Target target, WDist minRange, WDist maxRange,
WPos? initialTargetPosition = null, Color? targetLineColor = null) { return null; }
WPos? initialTargetPosition = null, Color? targetLineColor = null)
{ return null; }
public Activity ReturnToCell(Actor self) { return null; }
public Activity MoveToTarget(Actor self, in Target target,
WPos? initialTargetPosition = null, Color? targetLineColor = null) { return null; }
WPos? initialTargetPosition = null, Color? targetLineColor = null)
{ return null; }
public Activity MoveOntoTarget(Actor self, in Target target, in WVec offset,
WAngle? facing, Color? targetLineColor = null) { return null; }
WAngle? facing, Color? targetLineColor = null)
{ return null; }
public Activity MoveIntoTarget(Actor self, in Target target) { return null; }
public Activity LocalMove(Actor self, WPos fromPos, WPos toPos) { return null; }

View File

@@ -194,7 +194,7 @@ namespace OpenRA.Mods.Cnc.Traits
var correctionTransform = Util.MatrixMultiply(translateMtx, FlipMtx);
var shadowCorrectionTransform = Util.MatrixMultiply(shadowTranslateMtx, ShadowScaleFlipMtx);
doRender.Add((sprite.Sheet, () =>
void RenderFunc()
{
foreach (var m in models)
{
@@ -235,7 +235,9 @@ namespace OpenRA.Mods.Cnc.Traits
ShadowAmbient, ShadowDiffuse, shadowPalette.TextureIndex, normals.TextureIndex);
}
}
}));
}
doRender.Add((sprite.Sheet, RenderFunc));
var screenLightVector = Util.MatrixVectorMultiply(invShadowTransform, ZVector);
screenLightVector = Util.MatrixVectorMultiply(cameraTransform, screenLightVector);

View File

@@ -119,10 +119,10 @@ namespace OpenRA.Mods.Cnc.UtilityCommands
var rx = mf.ReadUInt16();
var ry = mf.ReadUInt16();
var tilenum = mf.ReadUInt16();
/*var zero1 = */mf.ReadInt16();
mf.ReadInt16(); // zero1
var subtile = mf.ReadUInt8();
var z = mf.ReadUInt8();
/*var zero2 = */mf.ReadUInt8();
mf.ReadUInt8(); // zero2
var uv = ToMPos(rx, ry, fullSize.X);

View File

@@ -115,8 +115,8 @@ namespace OpenRA.Mods.Cnc.UtilityCommands
var templateWidth = s.ReadUInt32();
var templateHeight = s.ReadUInt32();
/* var tileWidth = */s.ReadInt32();
/* var tileHeight = */s.ReadInt32();
s.ReadInt32(); // tileWidth
s.ReadInt32(); // tileHeight
var offsets = new uint[templateWidth * templateHeight];
for (var j = 0; j < offsets.Length; j++)
offsets[j] = s.ReadUInt32();

View File

@@ -40,15 +40,15 @@ namespace OpenRA.Mods.Cnc.VideoLoaders
if (frames <= 1) // TODO: find a better way to differentiate .shp icons
return false;
/* var x = */ s.ReadUInt16();
/* var y = */ s.ReadUInt16();
s.ReadUInt16(); // x
s.ReadUInt16(); // y
var width = s.ReadUInt16();
var height = s.ReadUInt16();
if (width <= 0 || height <= 0)
return false;
/*var delta = */ s.ReadUInt16(); /* + 37;*/
s.ReadUInt16(); // delta (+37)
var flags = s.ReadUInt16();
@@ -58,7 +58,7 @@ namespace OpenRA.Mods.Cnc.VideoLoaders
if (flags == 1)
{
/* var palette = */ s.ReadBytes(768);
s.ReadBytes(768); // palette
for (var i = 0; i < offsets.Length; i++)
offsets[i] += 768;
}

View File

@@ -46,7 +46,7 @@ namespace OpenRA.Mods.Common.Activities
// The target may become hidden between the initial order request and the first tick (e.g. if queued)
// Moving to any position (even if quite stale) is still better than immediately giving up
if ((target.Type == TargetType.Actor && target.Actor.CanBeViewedByPlayer(self.Owner))
|| target.Type == TargetType.FrozenActor || target.Type == TargetType.Terrain)
|| target.Type == TargetType.FrozenActor || target.Type == TargetType.Terrain)
lastVisibleTarget = Target.FromPos(target.CenterPosition);
else if (initialTargetPosition.HasValue)
lastVisibleTarget = Target.FromPos(initialTargetPosition.Value);

View File

@@ -40,7 +40,7 @@ namespace OpenRA.Mods.Common.Activities
// The target may become hidden between the initial order request and the first tick (e.g. if queued)
// Moving to any position (even if quite stale) is still better than immediately giving up
if ((target.Type == TargetType.Actor && target.Actor.CanBeViewedByPlayer(self.Owner))
|| target.Type == TargetType.FrozenActor || target.Type == TargetType.Terrain)
|| target.Type == TargetType.FrozenActor || target.Type == TargetType.Terrain)
lastVisibleTarget = Target.FromPos(target.CenterPosition);
else if (initialTargetPosition.HasValue)
lastVisibleTarget = Target.FromPos(initialTargetPosition.Value);

View File

@@ -64,7 +64,7 @@ namespace OpenRA.Mods.Common.Activities
// The target may become hidden between the initial order request and the first tick (e.g. if queued)
// Moving to any position (even if quite stale) is still better than immediately giving up
if ((target.Type == TargetType.Actor && target.Actor.CanBeViewedByPlayer(self.Owner))
|| target.Type == TargetType.FrozenActor || target.Type == TargetType.Terrain)
|| target.Type == TargetType.FrozenActor || target.Type == TargetType.Terrain)
{
lastVisibleTarget = Target.FromPos(target.CenterPosition);

View File

@@ -40,7 +40,7 @@ namespace OpenRA.Mods.Common.Activities
// The target may become hidden between the initial order request and the first tick (e.g. if queued)
// Moving to any position (even if quite stale) is still better than immediately giving up
if ((target.Type == TargetType.Actor && target.Actor.CanBeViewedByPlayer(self.Owner))
|| target.Type == TargetType.FrozenActor || target.Type == TargetType.Terrain)
|| target.Type == TargetType.FrozenActor || target.Type == TargetType.Terrain)
lastVisibleTarget = Target.FromPos(target.CenterPosition);
else if (initialTargetPosition.HasValue)
lastVisibleTarget = Target.FromPos(initialTargetPosition.Value);

View File

@@ -39,7 +39,7 @@ namespace OpenRA.Mods.Common.Activities
// The target may become hidden between the initial order request and the first tick (e.g. if queued)
// Moving to any position (even if quite stale) is still better than immediately giving up
if ((target.Type == TargetType.Actor && target.Actor.CanBeViewedByPlayer(self.Owner))
|| target.Type == TargetType.FrozenActor || target.Type == TargetType.Terrain)
|| target.Type == TargetType.FrozenActor || target.Type == TargetType.Terrain)
{
lastVisibleTarget = Target.FromPos(target.CenterPosition);
SetVisibleTargetLocation(self, target);

View File

@@ -106,7 +106,7 @@ namespace OpenRA.Mods.Common.Widgets
{
editorActorPreview = editorLayer.Add(actor);
Text = TranslationProvider.GetString(AddedActor,
Translation.Arguments("name", editorActorPreview.Info.Name, "id", editorActorPreview.ID));
Translation.Arguments("name", editorActorPreview.Info.Name, "id", editorActorPreview.ID));
}
public void Undo()

View File

@@ -49,11 +49,11 @@ namespace OpenRA.Mods.Common.FileSystem
try
{
// Parse package header
/*var signature = */s.ReadUInt32();
s.ReadUInt32(); // signature
s.Position += 8;
/*var FileCount = */s.ReadUInt16();
s.ReadUInt16(); // FileCount
s.Position += 4;
/*var ArchiveSize = */s.ReadUInt32();
s.ReadUInt32(); // ArchiveSize
s.Position += 19;
var tocAddress = s.ReadInt32();
s.Position += 4;

View File

@@ -139,7 +139,7 @@ namespace OpenRA.Mods.Common.Graphics
protected static readonly SpriteSequenceField<int> Tick = new(nameof(Tick), 40);
[Desc("Value controlling the Z-order. A higher values means rendering on top of other sprites at the same position. " +
"Use power of 2 values to avoid glitches.")]
"Use power of 2 values to avoid glitches.")]
protected static readonly SpriteSequenceField<WDist> ZOffset = new(nameof(ZOffset), WDist.Zero);
[Desc("Additional sprite depth Z offset to apply as a function of sprite Y (0: vertical, 1: flat on terrain)")]

View File

@@ -38,7 +38,8 @@ namespace OpenRA.Mods.Common.Graphics
: this(font, pos, zOffset, color,
ChromeMetrics.Get<Color>("TextContrastColorDark"),
ChromeMetrics.Get<Color>("TextContrastColorLight"),
text) { }
text)
{ }
public WPos Pos { get; }
public int ZOffset { get; }

View File

@@ -40,7 +40,8 @@ namespace OpenRA.Mods.Common.Graphics
: this(font, effectiveWorldPos, screenPos, zOffset, color,
ChromeMetrics.Get<Color>("TextContrastColorDark"),
ChromeMetrics.Get<Color>("TextContrastColorLight"),
text) { }
text)
{ }
public WPos Pos { get; }
public int ZOffset { get; }

View File

@@ -136,7 +136,7 @@ namespace OpenRA.Mods.Common.Scripting
public Actor[] NamedActors => sma.Actors.Values.ToArray();
[Desc("Returns the actor that was specified with a given name in " +
"the map file (or nil, if the actor is dead or not found).")]
"the map file (or nil, if the actor is dead or not found).")]
public Actor NamedActor(string actorName)
{
if (!sma.Actors.TryGetValue(actorName, out var ret))

View File

@@ -35,7 +35,7 @@ namespace OpenRA.Mods.Common.Scripting
public int PowerDrained => pm.PowerDrained;
[Desc("Returns the player's power state " +
"(\"Normal\", \"Low\" or \"Critical\").")]
"(\"Normal\", \"Low\" or \"Critical\").")]
public string PowerState => pm.PowerState.ToString();
[Desc("Triggers low power for the chosen amount of ticks.")]

View File

@@ -1192,7 +1192,7 @@ namespace OpenRA.Mods.Common.Server
return true;
if (!Exts.TryParseInt32Invariant(parts[1], out var spawnPoint)
|| spawnPoint < 0 || spawnPoint > server.Map.SpawnPoints.Length)
|| spawnPoint < 0 || spawnPoint > server.Map.SpawnPoints.Length)
{
Log.Write("server", $"Invalid spawn point: {parts[1]}");
return true;

View File

@@ -1262,9 +1262,8 @@ namespace OpenRA.Mods.Common.Traits
foreach (var cell in rallyPoint)
self.QueueActivity(new AttackMoveActivity(self, () => aircraft.MoveTo(cell, 1, evaluateNearestMovableCell: true, targetLineColor: Color.OrangeRed)));
}
else
if (self.World.Map.DistanceAboveTerrain(aircraft.CenterPosition).Length <= aircraft.LandAltitude.Length)
QueueChild(new TakeOff(self));
else if (self.World.Map.DistanceAboveTerrain(aircraft.CenterPosition).Length <= aircraft.LandAltitude.Length)
QueueChild(new TakeOff(self));
aircraft.UnReserve();
return true;

View File

@@ -142,7 +142,7 @@ namespace OpenRA.Mods.Common.Traits
IsAiming = CanAimAtTarget(self, OpportunityTarget, opportunityForceAttack);
if (!IsAiming && Info.OpportunityFire && autoTarget != null &&
!autoTarget.IsTraitDisabled && autoTarget.Stance >= UnitStance.Defend)
!autoTarget.IsTraitDisabled && autoTarget.Stance >= UnitStance.Defend)
{
OpportunityTarget = autoTarget.ScanForTarget(self, false, false);
opportunityForceAttack = false;
@@ -265,7 +265,7 @@ namespace OpenRA.Mods.Common.Traits
// The target may become hidden between the initial order request and the first tick (e.g. if queued)
// Moving to any position (even if quite stale) is still better than immediately giving up
if ((target.Type == TargetType.Actor && target.Actor.CanBeViewedByPlayer(self.Owner))
|| target.Type == TargetType.FrozenActor || target.Type == TargetType.Terrain)
|| target.Type == TargetType.FrozenActor || target.Type == TargetType.Terrain)
{
lastVisibleTarget = Target.FromPos(target.CenterPosition);
lastVisibleMaximumRange = attack.GetMaximumRangeVersusTarget(target);

View File

@@ -204,9 +204,9 @@ namespace OpenRA.Mods.Common.Traits
var explored = self.Owner.Shroud.IsExplored(location);
if (!self.World.Map.Contains(location) ||
!(self.CurrentActivity is Transform || mobile.transforms.Any(t => !t.IsTraitDisabled && !t.IsTraitPaused))
|| (!explored && !mobile.locomotor.Info.MoveIntoShroud)
|| (explored && !CanEnterCell(self, location)))
!(self.CurrentActivity is Transform || mobile.transforms.Any(t => !t.IsTraitDisabled && !t.IsTraitPaused))
|| (!explored && !mobile.locomotor.Info.MoveIntoShroud)
|| (explored && !CanEnterCell(self, location)))
cursor = mobile.Info.BlockedCursor;
else if (!explored || !mobile.Info.TerrainCursors.TryGetValue(self.World.Map.GetTerrainInfo(location).Type, out cursor))
cursor = mobile.Info.Cursor;

View File

@@ -409,7 +409,7 @@ namespace OpenRA.Mods.Common.Traits
}
void INotifyKilled.Killed(Actor self, AttackInfo e)
{
{
// IsAtGroundLevel contains Map.Contains(self.Location) check.
if (Info.EjectOnDeath && self.IsAtGroundLevel() && (!checkTerrainType || Info.UnloadTerrainTypes.Contains(self.World.Map.GetTerrainInfo(self.Location).Type)))
{

View File

@@ -217,8 +217,10 @@ namespace OpenRA.Mods.Common.Traits
chargedToken = self.RevokeCondition(chargedToken);
}
else
{
if (chargedToken == Actor.InvalidConditionToken)
chargedToken = self.GrantCondition(Info.ChargedCondition);
}
}
}

View File

@@ -34,7 +34,7 @@ namespace OpenRA.Mods.Common.Traits
// TODO: This won't make sense for MP saves
var localPlayer = worldRenderer.World.LocalPlayer;
if ((localPlayer != null && localPlayer.PlayerActor != self) ||
(localPlayer == null && self.Owner != self.World.Players.FirstOrDefault(p => p.IsBot)))
(localPlayer == null && self.Owner != self.World.Players.FirstOrDefault(p => p.IsBot)))
return null;
var nodes = new List<MiniYamlNode>()

View File

@@ -23,7 +23,7 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNodeBuilder actorNode)
{
if (actorNode.ChildrenMatching("Selection").Any(x => !x.IsRemoval())
&& !actorNode.ChildrenMatching("ControlGroups").Any())
&& !actorNode.ChildrenMatching("ControlGroups").Any())
actorNode.AddNode(new MiniYamlNodeBuilder("ControlGroups", ""));
yield break;

View File

@@ -27,10 +27,11 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules
public override IEnumerable<string> AfterUpdate(ModData modData)
{
if (locations.Count > 0)
yield return "The *Palette fields have been removed from the *PlaceBuildingPreview traits.\n" +
"You may wish to inspect the following definitions and define new Alpha or\n" +
"LineBuildSegmentAlpha properties as appropriate to recreate transparency effects:\n" +
UpdateUtils.FormatMessageList(locations);
yield return
"The *Palette fields have been removed from the *PlaceBuildingPreview traits.\n" +
"You may wish to inspect the following definitions and define new Alpha or\n" +
"LineBuildSegmentAlpha properties as appropriate to recreate transparency effects:\n" +
UpdateUtils.FormatMessageList(locations);
locations.Clear();
}

View File

@@ -24,8 +24,9 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules
public override IEnumerable<string> AfterUpdate(ModData modData)
{
if (locations.Count > 0)
yield return "You must define new Color fields on the following traits:\n" +
UpdateUtils.FormatMessageList(locations);
yield return
"You must define new Color fields on the following traits:\n" +
UpdateUtils.FormatMessageList(locations);
locations.Clear();
}

View File

@@ -56,9 +56,10 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules
if (requiredMetadata.Count != 0)
{
yield return $"The ExplicitSequenceFilenames rule requires {requiredMetadata.JoinWith(", ")}\n" +
"to be defined under the SpriteSequenceFormat definition in mod.yaml.\n" +
"Add these definitions back and run the update rule again.";
yield return
$"The ExplicitSequenceFilenames rule requires {requiredMetadata.JoinWith(", ")}\n" +
"to be defined under the SpriteSequenceFormat definition in mod.yaml.\n" +
"Add these definitions back and run the update rule again.";
disabled = true;
}
}
@@ -457,8 +458,7 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules
var overrideFilename = filename;
if (useTilesetCode)
overrideFilename = filename[..1] + tilesetCodes[sequenceTileset] +
filename[2..];
overrideFilename = filename[..1] + tilesetCodes[sequenceTileset] + filename[2..];
if (addExtension)
overrideFilename += useTilesetExtension ? tilesetExtensions[sequenceTileset] : defaultSpriteExtension;

View File

@@ -26,9 +26,10 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules
public override IEnumerable<string> AfterUpdate(ModData modData)
{
if (locations.Count > 0)
yield return "The PaletteFromEmbeddedSpritePalette trait no longer references a sequence.\n" +
"You must manually define Filename (and Frame if needed) on the following actors:\n" +
UpdateUtils.FormatMessageList(locations);
yield return
"The PaletteFromEmbeddedSpritePalette trait no longer references a sequence.\n" +
"You must manually define Filename (and Frame if needed) on the following actors:\n" +
UpdateUtils.FormatMessageList(locations);
locations.Clear();
}

View File

@@ -79,9 +79,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
}
var png = new Png(pngData, SpriteFrameType.Indexed8, frameSize.Width, frameSize.Height, palColors);
#pragma warning disable SA1003
png.Save($"{prefix}-{count++:D4}.png");
#pragma warning restore SA1003
}
Console.WriteLine("Saved {0}-[0..{1}].png", prefix, count - 1);

View File

@@ -73,9 +73,7 @@ namespace OpenRA.Mods.Common.Widgets
{
for (var s = 0; s < 256; s++)
{
#pragma warning disable IDE0047
(*(c + s * 256 + v)) = Color.FromAhsv(newHue.Value, 1 - s / 255f, v / 255f).ToArgb();
#pragma warning restore IDE0047
*(c + s * 256 + v) = Color.FromAhsv(newHue.Value, 1 - s / 255f, v / 255f).ToArgb();
}
}
}

View File

@@ -39,9 +39,7 @@ namespace OpenRA.Mods.Common.Widgets
var c = (int*)cc;
for (var h = 0; h < 256; h++)
{
#pragma warning disable IDE0047
(*(c + 0 * 256 + h)) = Color.FromAhsv(h / 255f, 1, 1).ToArgb();
#pragma warning restore IDE0047
*(c + 0 * 256 + h) = Color.FromAhsv(h / 255f, 1, 1).ToArgb();
}
}
}

View File

@@ -65,24 +65,24 @@ namespace OpenRA.Mods.Common.Widgets.Logic
labelText = viewport.ResourceTooltip;
break;
case WorldTooltipType.Actor:
{
o = viewport.ActorTooltip.Owner;
showOwner = o != null && !o.NonCombatant && viewport.ActorTooltip.TooltipInfo.IsOwnerRowVisible;
{
o = viewport.ActorTooltip.Owner;
showOwner = o != null && !o.NonCombatant && viewport.ActorTooltip.TooltipInfo.IsOwnerRowVisible;
var stance = o == null || world.RenderPlayer == null ? PlayerRelationship.None : o.RelationshipWith(world.RenderPlayer);
labelText = viewport.ActorTooltip.TooltipInfo.TooltipForPlayerStance(stance);
break;
}
var stance = o == null || world.RenderPlayer == null ? PlayerRelationship.None : o.RelationshipWith(world.RenderPlayer);
labelText = viewport.ActorTooltip.TooltipInfo.TooltipForPlayerStance(stance);
break;
}
case WorldTooltipType.FrozenActor:
{
o = viewport.FrozenActorTooltip.TooltipOwner;
showOwner = o != null && !o.NonCombatant && viewport.FrozenActorTooltip.TooltipInfo.IsOwnerRowVisible;
{
o = viewport.FrozenActorTooltip.TooltipOwner;
showOwner = o != null && !o.NonCombatant && viewport.FrozenActorTooltip.TooltipInfo.IsOwnerRowVisible;
var stance = o == null || world.RenderPlayer == null ? PlayerRelationship.None : o.RelationshipWith(world.RenderPlayer);
labelText = viewport.FrozenActorTooltip.TooltipInfo.TooltipForPlayerStance(stance);
break;
}
var stance = o == null || world.RenderPlayer == null ? PlayerRelationship.None : o.RelationshipWith(world.RenderPlayer);
labelText = viewport.FrozenActorTooltip.TooltipInfo.TooltipForPlayerStance(stance);
break;
}
}
if (viewport.ActorTooltipExtra != null)

View File

@@ -749,8 +749,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var players = item.GetOrNull<LabelWithTooltipWidget>("PLAYERS");
if (players != null)
{
var label = $"{game.Players + game.Bots} / {game.MaxPlayers + game.Bots}"
+ (game.Spectators > 0 ? $" + {game.Spectators}" : "");
var label =
$"{game.Players + game.Bots} / {game.MaxPlayers + game.Bots}"
+ (game.Spectators > 0 ? $" + {game.Spectators}" : "");
var color = canJoin ? players.TextColor : incompatibleGameColor;
players.GetText = () => label;

View File

@@ -79,147 +79,87 @@ namespace OpenRA.Platforms.Default
break;
case SDL.SDL_EventType.SDL_WINDOWEVENT:
{
switch (e.window.windowEvent)
{
switch (e.window.windowEvent)
{
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_LOST:
device.HasInputFocus = false;
break;
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_LOST:
device.HasInputFocus = false;
break;
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_GAINED:
device.HasInputFocus = true;
break;
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_GAINED:
device.HasInputFocus = true;
break;
// Triggered when moving between displays with different DPI settings
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SIZE_CHANGED:
device.WindowSizeChanged();
break;
// Triggered when moving between displays with different DPI settings
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SIZE_CHANGED:
device.WindowSizeChanged();
break;
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_HIDDEN:
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_MINIMIZED:
device.IsSuspended = true;
break;
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_HIDDEN:
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_MINIMIZED:
device.IsSuspended = true;
break;
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_EXPOSED:
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SHOWN:
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_MAXIMIZED:
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_RESTORED:
device.IsSuspended = false;
break;
}
break;
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_EXPOSED:
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SHOWN:
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_MAXIMIZED:
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_RESTORED:
device.IsSuspended = false;
break;
}
break;
}
case SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN:
case SDL.SDL_EventType.SDL_MOUSEBUTTONUP:
{
// Mouse 1, Mouse 2 and Mouse 3 are handled as mouse inputs
// Mouse 4 and Mouse 5 are treated as (pseudo) keyboard inputs
if (e.button.button == SDL.SDL_BUTTON_LEFT ||
e.button.button == SDL.SDL_BUTTON_MIDDLE ||
e.button.button == SDL.SDL_BUTTON_RIGHT)
{
// Mouse 1, Mouse 2 and Mouse 3 are handled as mouse inputs
// Mouse 4 and Mouse 5 are treated as (pseudo) keyboard inputs
if (e.button.button == SDL.SDL_BUTTON_LEFT ||
e.button.button == SDL.SDL_BUTTON_MIDDLE ||
e.button.button == SDL.SDL_BUTTON_RIGHT)
if (pendingMotion != null)
{
if (pendingMotion != null)
{
inputHandler.OnMouseInput(pendingMotion.Value);
pendingMotion = null;
}
var button = MakeButton(e.button.button);
if (e.type == SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN)
lastButtonBits |= button;
else
lastButtonBits &= ~button;
var input = lockedMousePosition ?? new int2(e.button.x, e.button.y);
var pos = EventPosition(device, input.X, input.Y);
if (e.type == SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN)
inputHandler.OnMouseInput(new MouseInput(
MouseInputEvent.Down, button, pos, int2.Zero, mods,
MultiTapDetection.DetectFromMouse(e.button.button, pos)));
else
inputHandler.OnMouseInput(new MouseInput(
MouseInputEvent.Up, button, pos, int2.Zero, mods,
MultiTapDetection.InfoFromMouse(e.button.button)));
inputHandler.OnMouseInput(pendingMotion.Value);
pendingMotion = null;
}
if (e.button.button == SDL.SDL_BUTTON_X1 ||
e.button.button == SDL.SDL_BUTTON_X2)
{
Keycode keyCode;
var button = MakeButton(e.button.button);
if (e.button.button == SDL.SDL_BUTTON_X1)
keyCode = Keycode.MOUSE4;
else
keyCode = Keycode.MOUSE5;
if (e.type == SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN)
lastButtonBits |= button;
else
lastButtonBits &= ~button;
var type = e.type == SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN ?
KeyInputEvent.Down : KeyInputEvent.Up;
var tapCount = e.type == SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN ?
MultiTapDetection.DetectFromKeyboard(keyCode, mods) :
MultiTapDetection.InfoFromKeyboard(keyCode, mods);
var keyEvent = new KeyInput
{
Event = type,
Key = keyCode,
Modifiers = mods,
UnicodeChar = '?',
MultiTapCount = tapCount,
IsRepeat = e.key.repeat != 0
};
inputHandler.OnKeyInput(keyEvent);
}
break;
}
case SDL.SDL_EventType.SDL_MOUSEMOTION:
{
var mousePos = new int2(e.motion.x, e.motion.y);
var input = lockedMousePosition ?? mousePos;
var input = lockedMousePosition ?? new int2(e.button.x, e.button.y);
var pos = EventPosition(device, input.X, input.Y);
var delta = lockedMousePosition == null
? EventPosition(device, e.motion.xrel, e.motion.yrel)
: mousePos - lockedMousePosition.Value;
pendingMotion = new MouseInput(
MouseInputEvent.Move, lastButtonBits, pos, delta, mods, 0);
break;
if (e.type == SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN)
inputHandler.OnMouseInput(new MouseInput(
MouseInputEvent.Down, button, pos, int2.Zero, mods,
MultiTapDetection.DetectFromMouse(e.button.button, pos)));
else
inputHandler.OnMouseInput(new MouseInput(
MouseInputEvent.Up, button, pos, int2.Zero, mods,
MultiTapDetection.InfoFromMouse(e.button.button)));
}
case SDL.SDL_EventType.SDL_MOUSEWHEEL:
if (e.button.button == SDL.SDL_BUTTON_X1 ||
e.button.button == SDL.SDL_BUTTON_X2)
{
SDL.SDL_GetMouseState(out var x, out var y);
Keycode keyCode;
var pos = EventPosition(device, x, y);
inputHandler.OnMouseInput(new MouseInput(MouseInputEvent.Scroll, MouseButton.None, pos, new int2(0, e.wheel.y), mods, 0));
if (e.button.button == SDL.SDL_BUTTON_X1)
keyCode = Keycode.MOUSE4;
else
keyCode = Keycode.MOUSE5;
break;
}
case SDL.SDL_EventType.SDL_TEXTINPUT:
{
var rawBytes = new byte[SDL.SDL_TEXTINPUTEVENT_TEXT_SIZE];
unsafe { Marshal.Copy((IntPtr)e.text.text, rawBytes, 0, SDL.SDL_TEXTINPUTEVENT_TEXT_SIZE); }
inputHandler.OnTextInput(Encoding.UTF8.GetString(rawBytes, 0, Array.IndexOf(rawBytes, (byte)0)));
break;
}
case SDL.SDL_EventType.SDL_KEYDOWN:
case SDL.SDL_EventType.SDL_KEYUP:
{
var keyCode = (Keycode)e.key.keysym.sym;
var type = e.type == SDL.SDL_EventType.SDL_KEYDOWN ?
var type = e.type == SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN ?
KeyInputEvent.Down : KeyInputEvent.Up;
var tapCount = e.type == SDL.SDL_EventType.SDL_KEYDOWN ?
var tapCount = e.type == SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN ?
MultiTapDetection.DetectFromKeyboard(keyCode, mods) :
MultiTapDetection.InfoFromKeyboard(keyCode, mods);
@@ -228,20 +168,80 @@ namespace OpenRA.Platforms.Default
Event = type,
Key = keyCode,
Modifiers = mods,
UnicodeChar = (char)e.key.keysym.sym,
UnicodeChar = '?',
MultiTapCount = tapCount,
IsRepeat = e.key.repeat != 0
};
// Special case workaround for windows users
if (e.key.keysym.sym == SDL.SDL_Keycode.SDLK_F4 && mods.HasModifier(Modifiers.Alt) &&
Platform.CurrentPlatform == PlatformType.Windows)
Game.Exit();
else
inputHandler.OnKeyInput(keyEvent);
break;
inputHandler.OnKeyInput(keyEvent);
}
break;
}
case SDL.SDL_EventType.SDL_MOUSEMOTION:
{
var mousePos = new int2(e.motion.x, e.motion.y);
var input = lockedMousePosition ?? mousePos;
var pos = EventPosition(device, input.X, input.Y);
var delta = lockedMousePosition == null
? EventPosition(device, e.motion.xrel, e.motion.yrel)
: mousePos - lockedMousePosition.Value;
pendingMotion = new MouseInput(
MouseInputEvent.Move, lastButtonBits, pos, delta, mods, 0);
break;
}
case SDL.SDL_EventType.SDL_MOUSEWHEEL:
{
SDL.SDL_GetMouseState(out var x, out var y);
var pos = EventPosition(device, x, y);
inputHandler.OnMouseInput(new MouseInput(MouseInputEvent.Scroll, MouseButton.None, pos, new int2(0, e.wheel.y), mods, 0));
break;
}
case SDL.SDL_EventType.SDL_TEXTINPUT:
{
var rawBytes = new byte[SDL.SDL_TEXTINPUTEVENT_TEXT_SIZE];
unsafe { Marshal.Copy((IntPtr)e.text.text, rawBytes, 0, SDL.SDL_TEXTINPUTEVENT_TEXT_SIZE); }
inputHandler.OnTextInput(Encoding.UTF8.GetString(rawBytes, 0, Array.IndexOf(rawBytes, (byte)0)));
break;
}
case SDL.SDL_EventType.SDL_KEYDOWN:
case SDL.SDL_EventType.SDL_KEYUP:
{
var keyCode = (Keycode)e.key.keysym.sym;
var type = e.type == SDL.SDL_EventType.SDL_KEYDOWN ?
KeyInputEvent.Down : KeyInputEvent.Up;
var tapCount = e.type == SDL.SDL_EventType.SDL_KEYDOWN ?
MultiTapDetection.DetectFromKeyboard(keyCode, mods) :
MultiTapDetection.InfoFromKeyboard(keyCode, mods);
var keyEvent = new KeyInput
{
Event = type,
Key = keyCode,
Modifiers = mods,
UnicodeChar = (char)e.key.keysym.sym,
MultiTapCount = tapCount,
IsRepeat = e.key.repeat != 0
};
// Special case workaround for windows users
if (e.key.keysym.sym == SDL.SDL_Keycode.SDLK_F4 && mods.HasModifier(Modifiers.Alt) &&
Platform.CurrentPlatform == PlatformType.Windows)
Game.Exit();
else
inputHandler.OnKeyInput(keyEvent);
break;
}
}
}

View File

@@ -99,7 +99,7 @@ namespace OpenRA.Platforms.Default
getCreateVertexBuffer =
tuple =>
{
(object t, var type) = ((int, Type))tuple;
(object t, var type) = ((int, Type))tuple;
var vertexBuffer = context.GetType().GetMethod(nameof(CreateVertexBuffer)).MakeGenericMethod(type).Invoke(context, new[] { t });
return typeof(ThreadedVertexBuffer<>).MakeGenericType(type).GetConstructors()[0].Invoke(new[] { this, vertexBuffer });
};