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:
committed by
Pavel Penev
parent
60cbf79c9b
commit
360f24f609
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace OpenRA.Graphics
|
||||
|
||||
indexRowStride = 6 * map.MapSize.X;
|
||||
lock (IndexBuffers)
|
||||
{
|
||||
{
|
||||
indexBufferWrapper = IndexBuffers.GetValue(world, world => new IndexBufferRc(world));
|
||||
indexBufferWrapper.AddRef();
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace OpenRA.Mods.Cnc.FileSystem
|
||||
|
||||
try
|
||||
{
|
||||
/* var signature = */ s.ReadASCII(4);
|
||||
s.ReadASCII(4); // signature
|
||||
|
||||
// Total archive size.
|
||||
s.ReadUInt32();
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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}`");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.")]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)")]
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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.")]
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)))
|
||||
{
|
||||
|
||||
@@ -217,8 +217,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
chargedToken = self.RevokeCondition(chargedToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (chargedToken == Actor.InvalidConditionToken)
|
||||
chargedToken = self.GrantCondition(Info.ChargedCondition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 });
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user