diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 7472aeea1e..fc368eb89d 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -47,7 +47,6 @@ namespace OpenRA var map = modData.PrepareMap(uid); viewport = new Viewport(new float2(Renderer.Resolution), map.TopLeft, map.BottomRight, Renderer); - world = null; // trying to access the old world will NRE, rather than silently doing it wrong. world = new World(modData.Manifest, map); } @@ -101,7 +100,7 @@ namespace OpenRA static ConnectionState lastConnectionState = ConnectionState.PreConnecting; public static int LocalClientId { get { return orderManager.Connection.LocalClientId; } } - static void Tick() + static void Tick( World world, OrderManager orderManager, Viewport viewPort ) { if (orderManager.Connection.ConnectionState != lastConnectionState) { @@ -159,7 +158,7 @@ namespace OpenRA internal static event Action LobbyInfoChanged = () => { }; - internal static void SyncLobbyInfo(string data) + internal static void SyncLobbyInfo( World world, string data) { LobbyInfo = Session.Deserialize(data); @@ -186,6 +185,7 @@ namespace OpenRA public static event Action BeforeGameStart = () => {}; internal static void StartGame(string map) { + world = null; BeforeGameStart(); LoadMap(map); if (orderManager.GameStarted) return; @@ -200,23 +200,20 @@ namespace OpenRA public static void DispatchMouseInput(MouseInputEvent ev, MouseEventArgs e, Modifiers modifierKeys) { - if (world == null) - return; - - int sync = world.SyncHash(); - var initialWorld = world; + var world = Game.world; + if (world == null) return; - var mi = new MouseInput + Sync.CheckSyncUnchanged( world, () => { - Button = (MouseButton)(int)e.Button, - Event = ev, - Location = new int2(e.Location), - Modifiers = modifierKeys, - }; - Widget.HandleInput(world, mi); - - if (sync != world.SyncHash() && world == initialWorld) - throw new InvalidOperationException("Desync in DispatchMouseInput"); + var mi = new MouseInput + { + Button = (MouseButton)(int)e.Button, + Event = ev, + Location = new int2( e.Location ), + Modifiers = modifierKeys, + }; + Widget.HandleInput( world, mi ); + } ); } public static bool IsHost @@ -231,16 +228,13 @@ namespace OpenRA public static void HandleKeyEvent(KeyInput e) { - if (world == null) - return; - - int sync = world.SyncHash(); - - if (Widget.HandleKeyPress(e)) - return; + var world = Game.world; + if( world == null ) return; - if (sync != Game.world.SyncHash()) - throw new InvalidOperationException("Desync in OnKeyPress"); + Sync.CheckSyncUnchanged( world, () => + { + Widget.HandleKeyPress( e ); + } ); } static Modifiers modifiers; @@ -324,7 +318,7 @@ namespace OpenRA { while (!quit) { - Tick(); + Tick( world, orderManager, viewport ); Application.DoEvents(); } } diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index 4edafa587a..d40f259c8f 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -97,8 +97,8 @@ namespace OpenRA.Graphics if (world.OrderGenerator != null) world.OrderGenerator.RenderBeforeWorld(world); - foreach (var image in worldSprites) - image.Sprite.DrawAt(image.Pos, image.Palette); + foreach( var image in worldSprites ) + image.Sprite.DrawAt( image.Pos, this.GetPaletteIndex( image.Palette ) ); uiOverlay.Draw(world); if (world.OrderGenerator != null) diff --git a/OpenRA.Game/Network/UnitOrders.cs b/OpenRA.Game/Network/UnitOrders.cs index e2ac120e84..57787e25fc 100755 --- a/OpenRA.Game/Network/UnitOrders.cs +++ b/OpenRA.Game/Network/UnitOrders.cs @@ -78,7 +78,7 @@ namespace OpenRA.Network } case "SyncInfo": { - Game.SyncLobbyInfo(order.TargetString); + Game.SyncLobbyInfo( world, order.TargetString); break; } case "SetStance": diff --git a/OpenRA.Game/Sync.cs b/OpenRA.Game/Sync.cs index 5579054f62..6ed32a3498 100755 --- a/OpenRA.Game/Sync.cs +++ b/OpenRA.Game/Sync.cs @@ -129,5 +129,22 @@ namespace OpenRA return p.Index * 0x567; return 0; } + + public static void CheckSyncUnchanged( World world, Action fn ) + { + int sync = world.SyncHash(); + fn(); + if( sync != world.SyncHash() ) + throw new InvalidOperationException( "Desync in DispatchMouseInput" ); + } + + public static T CheckSyncUnchanged( World world, Func fn ) + { + int sync = world.SyncHash(); + var ret = fn(); + if( sync != world.SyncHash() ) + throw new InvalidOperationException( "Desync in DispatchMouseInput" ); + return ret; + } } } diff --git a/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs b/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs index e0d0688bc6..b283900709 100644 --- a/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs +++ b/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs @@ -6,14 +6,14 @@ * as published by the Free Software Foundation. For more information, * see LICENSE. */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Orders; +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Orders; using OpenRA.Traits; namespace OpenRA.Widgets @@ -109,9 +109,8 @@ namespace OpenRA.Widgets public override string GetCursor(int2 pos) { var world = Game.world; - int sync = world.SyncHash(); - try - { + return Sync.CheckSyncUnchanged( world, () => + { if (!world.GameHasStarted) return "default"; @@ -122,29 +121,24 @@ namespace OpenRA.Widgets Modifiers = Game.GetModifierKeys() }; - return Game.world.OrderGenerator.GetCursor( world, Game.viewport.ViewToWorld(mi).ToInt2(), mi ); - } - finally - { - if( sync != world.SyncHash() ) - throw new InvalidOperationException( "Desync in InputControllerWidget.GetCursor" ); - } + return world.OrderGenerator.GetCursor( world, Game.viewport.ViewToWorld(mi).ToInt2(), mi ); + } ); } public override bool HandleKeyPressInner(KeyInput e) { if (e.Event == KeyInputEvent.Down) - { - if (e.KeyName.Length == 1 && char.IsDigit(e.KeyName[0])) - { - Game.world.Selection.DoControlGroup(Game.world, e.KeyName[0] - '0', e.Modifiers); - return true; - } - - if (e.KeyChar == '\b') - { - GotoNextBase(); - return true; + { + if (e.KeyName.Length == 1 && char.IsDigit(e.KeyName[0])) + { + Game.world.Selection.DoControlGroup(Game.world, e.KeyName[0] - '0', e.Modifiers); + return true; + } + + if (e.KeyChar == '\b') + { + GotoNextBase(); + return true; } } return false; diff --git a/OpenRA.Mods.RA/Widgets/MoneyBinWidget.cs b/OpenRA.Mods.RA/Widgets/MoneyBinWidget.cs index 3a2fa099e8..fdfc6d9776 100755 --- a/OpenRA.Mods.RA/Widgets/MoneyBinWidget.cs +++ b/OpenRA.Mods.RA/Widgets/MoneyBinWidget.cs @@ -35,6 +35,8 @@ namespace OpenRA.Mods.RA.Widgets public override void DrawInner(World world) { + if( world.LocalPlayer == null ) return; + var playerResources = world.LocalPlayer.PlayerActor.Trait(); var digitCollection = "digits-" + world.LocalPlayer.Country.Race; diff --git a/OpenRA.Mods.RA/Widgets/PowerBinWidget.cs b/OpenRA.Mods.RA/Widgets/PowerBinWidget.cs index 302364881d..ee73761ac6 100755 --- a/OpenRA.Mods.RA/Widgets/PowerBinWidget.cs +++ b/OpenRA.Mods.RA/Widgets/PowerBinWidget.cs @@ -27,6 +27,8 @@ namespace OpenRA.Mods.RA.Widgets public override void DrawInner(World world) { + if( world.LocalPlayer == null ) return; + powerCollection = "power-" + world.LocalPlayer.Country.Race; var power = world.LocalPlayer.PlayerActor.Trait(); diff --git a/OpenRA.Mods.RA/Widgets/RadarBinWidget.cs b/OpenRA.Mods.RA/Widgets/RadarBinWidget.cs index 8e922c2d17..a30e541f7f 100755 --- a/OpenRA.Mods.RA/Widgets/RadarBinWidget.cs +++ b/OpenRA.Mods.RA/Widgets/RadarBinWidget.cs @@ -120,7 +120,9 @@ namespace OpenRA.Mods.RA.Widgets } public override void DrawInner(World world) - { + { + if( world.LocalPlayer == null ) return; + radarCollection = "radar-" + world.LocalPlayer.Country.Race; Game.Renderer.RgbaSpriteRenderer.DrawSprite(ChromeProvider.GetImage(radarCollection, "left"), radarOrigin); diff --git a/OpenRA.Mods.RA/Widgets/SpecialPowerBinWidget.cs b/OpenRA.Mods.RA/Widgets/SpecialPowerBinWidget.cs index 435e768ee6..a99c7bfac3 100755 --- a/OpenRA.Mods.RA/Widgets/SpecialPowerBinWidget.cs +++ b/OpenRA.Mods.RA/Widgets/SpecialPowerBinWidget.cs @@ -15,91 +15,93 @@ using System.Linq; using OpenRA.FileFormats; using OpenRA.Graphics; using OpenRA.Traits; -using OpenRA.Widgets; - -namespace OpenRA.Mods.RA.Widgets -{ - class SpecialPowerBinWidget : Widget - { - static Dictionary spsprites; - Animation ready; - Animation clock; - readonly List>> buttons = new List>>(); - - public SpecialPowerBinWidget() : base() { } - - public override void Initialize() - { - base.Initialize(); - - if (spsprites == null) - spsprites = Rules.Info.Values.SelectMany( u => u.Traits.WithInterface() ) - .ToDictionary( - u => u.Image, - u => SpriteSheetBuilder.LoadAllSprites(u.Image)[0]); - - ready = new Animation("pips"); - ready.PlayRepeating("ready"); - clock = new Animation("clock"); +using OpenRA.Widgets; + +namespace OpenRA.Mods.RA.Widgets +{ + class SpecialPowerBinWidget : Widget + { + static Dictionary spsprites; + Animation ready; + Animation clock; + readonly List>> buttons = new List>>(); + + public SpecialPowerBinWidget() : base() { } + + public override void Initialize() + { + base.Initialize(); + + if (spsprites == null) + spsprites = Rules.Info.Values.SelectMany( u => u.Traits.WithInterface() ) + .ToDictionary( + u => u.Image, + u => SpriteSheetBuilder.LoadAllSprites(u.Image)[0]); + + ready = new Animation("pips"); + ready.PlayRepeating("ready"); + clock = new Animation("clock"); } public override Rectangle EventBounds { get { return buttons.Any() ? buttons.Select(b => b.First).Aggregate(Rectangle.Union) : Bounds; } - } - - public override bool HandleInputInner(MouseInput mi) - { - if (mi.Event == MouseInputEvent.Down) - { - var action = buttons.Where(a => a.First.Contains(mi.Location.ToPoint())) - .Select(a => a.Second).FirstOrDefault(); - if (action == null) - return false; - - action(mi); - return true; - } - - return false; - } - - public override void DrawInner(World world) - { - buttons.Clear(); - - var powers = world.LocalPlayer.PlayerActor.TraitsImplementing(); - var numPowers = powers.Count(p => p.IsAvailable); - if (numPowers == 0) return; - var rectBounds = RenderBounds; - WidgetUtils.DrawRGBA(WidgetUtils.GetChromeImage(world, "specialbin-top"),new float2(rectBounds.X,rectBounds.Y)); - for (var i = 1; i < numPowers; i++) - WidgetUtils.DrawRGBA(WidgetUtils.GetChromeImage(world,"specialbin-middle"), new float2(rectBounds.X, rectBounds.Y + i * 51)); + } + + public override bool HandleInputInner(MouseInput mi) + { + if (mi.Event == MouseInputEvent.Down) + { + var action = buttons.Where(a => a.First.Contains(mi.Location.ToPoint())) + .Select(a => a.Second).FirstOrDefault(); + if (action == null) + return false; + + action(mi); + return true; + } + + return false; + } + + public override void DrawInner(World world) + { + buttons.Clear(); + + if( world.LocalPlayer == null ) return; + + var powers = world.LocalPlayer.PlayerActor.TraitsImplementing(); + var numPowers = powers.Count(p => p.IsAvailable); + if (numPowers == 0) return; + var rectBounds = RenderBounds; + WidgetUtils.DrawRGBA(WidgetUtils.GetChromeImage(world, "specialbin-top"),new float2(rectBounds.X,rectBounds.Y)); + for (var i = 1; i < numPowers; i++) + WidgetUtils.DrawRGBA(WidgetUtils.GetChromeImage(world,"specialbin-middle"), new float2(rectBounds.X, rectBounds.Y + i * 51)); WidgetUtils.DrawRGBA(WidgetUtils.GetChromeImage(world,"specialbin-bottom"), new float2(rectBounds.X, rectBounds.Y + numPowers * 51)); - // Hack Hack Hack - rectBounds.Width = 69; - rectBounds.Height = 10 + numPowers * 51 + 21; - - var y = rectBounds.Y + 10; - foreach (var sp in powers) - { - var image = spsprites[sp.Info.Image]; - if (sp.IsAvailable) - { - var drawPos = new float2(rectBounds.X + 5, y); - var rect = new Rectangle(rectBounds.X + 5, y, 64, 48); - - if (rect.Contains(Viewport.LastMousePos.ToPoint())) - { - var pos = drawPos.ToInt2(); - var tl = new int2(pos.X-3,pos.Y-3); - var m = new int2(pos.X+64+3,pos.Y+48+3); - var br = tl + new int2(64+3+20,60); - - if (sp.Info.LongDesc != null) - br += Game.Renderer.RegularFont.Measure(sp.Info.LongDesc.Replace("\\n", "\n")); - else + // Hack Hack Hack + rectBounds.Width = 69; + rectBounds.Height = 10 + numPowers * 51 + 21; + + var y = rectBounds.Y + 10; + foreach (var sp in powers) + { + var image = spsprites[sp.Info.Image]; + if (sp.IsAvailable) + { + var drawPos = new float2(rectBounds.X + 5, y); + var rect = new Rectangle(rectBounds.X + 5, y, 64, 48); + + if (rect.Contains(Viewport.LastMousePos.ToPoint())) + { + var pos = drawPos.ToInt2(); + var tl = new int2(pos.X-3,pos.Y-3); + var m = new int2(pos.X+64+3,pos.Y+48+3); + var br = tl + new int2(64+3+20,60); + + if (sp.Info.LongDesc != null) + br += Game.Renderer.RegularFont.Measure(sp.Info.LongDesc.Replace("\\n", "\n")); + else br += new int2(300,0); var border = WidgetUtils.GetBorderSizes("dialog4"); @@ -109,47 +111,47 @@ namespace OpenRA.Mods.RA.Widgets WidgetUtils.DrawPanelPartial("dialog4", Rectangle.FromLTRB(m.X - border[2], tl.Y, br.X, m.Y + border[1]), PanelSides.Top | PanelSides.Right); WidgetUtils.DrawPanelPartial("dialog4", Rectangle.FromLTRB(m.X, m.Y - border[1], br.X, br.Y), - PanelSides.Left | PanelSides.Right | PanelSides.Bottom); - - pos += new int2(77, 5); - Game.Renderer.BoldFont.DrawText(sp.Info.Description, pos, Color.White); - - pos += new int2(0,20); - Game.Renderer.BoldFont.DrawText(WorldUtils.FormatTime(sp.RemainingTime).ToString(), pos, Color.White); - Game.Renderer.BoldFont.DrawText("/ {0}".F(WorldUtils.FormatTime(sp.TotalTime)), pos + new int2(45,0), Color.White); - - if (sp.Info.LongDesc != null) - { - pos += new int2(0, 20); - Game.Renderer.RegularFont.DrawText(sp.Info.LongDesc.Replace("\\n", "\n"), pos, Color.White); - } - } - - WidgetUtils.DrawSHP(image, drawPos); - - clock.PlayFetchIndex("idle", - () => (sp.TotalTime - sp.RemainingTime) - * (clock.CurrentSequence.Length - 1) / sp.TotalTime); - clock.Tick(); - - WidgetUtils.DrawSHP(clock.Image, drawPos); - - if (sp.IsReady) - { - ready.Play("ready"); - WidgetUtils.DrawSHP(ready.Image, drawPos + new float2((64 - ready.Image.size.X) / 2, 2)); - } - - buttons.Add(Pair.New(rect,HandleSupportPower(sp))); - - y += 51; - } - } - } - - Action HandleSupportPower(SupportPower sp) - { - return mi => { if (mi.Button == MouseButton.Left) sp.Activate(); }; - } - } + PanelSides.Left | PanelSides.Right | PanelSides.Bottom); + + pos += new int2(77, 5); + Game.Renderer.BoldFont.DrawText(sp.Info.Description, pos, Color.White); + + pos += new int2(0,20); + Game.Renderer.BoldFont.DrawText(WorldUtils.FormatTime(sp.RemainingTime).ToString(), pos, Color.White); + Game.Renderer.BoldFont.DrawText("/ {0}".F(WorldUtils.FormatTime(sp.TotalTime)), pos + new int2(45,0), Color.White); + + if (sp.Info.LongDesc != null) + { + pos += new int2(0, 20); + Game.Renderer.RegularFont.DrawText(sp.Info.LongDesc.Replace("\\n", "\n"), pos, Color.White); + } + } + + WidgetUtils.DrawSHP(image, drawPos); + + clock.PlayFetchIndex("idle", + () => (sp.TotalTime - sp.RemainingTime) + * (clock.CurrentSequence.Length - 1) / sp.TotalTime); + clock.Tick(); + + WidgetUtils.DrawSHP(clock.Image, drawPos); + + if (sp.IsReady) + { + ready.Play("ready"); + WidgetUtils.DrawSHP(ready.Image, drawPos + new float2((64 - ready.Image.size.X) / 2, 2)); + } + + buttons.Add(Pair.New(rect,HandleSupportPower(sp))); + + y += 51; + } + } + } + + Action HandleSupportPower(SupportPower sp) + { + return mi => { if (mi.Button == MouseButton.Left) sp.Activate(); }; + } + } } \ No newline at end of file