diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
index b412dd55c5..e94c56c42a 100644
--- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
+++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
@@ -411,6 +411,7 @@
+
diff --git a/OpenRA.Mods.Common/Traits/Player/ParallelProductionQueue.cs b/OpenRA.Mods.Common/Traits/Player/ParallelProductionQueue.cs
new file mode 100644
index 0000000000..040ca96520
--- /dev/null
+++ b/OpenRA.Mods.Common/Traits/Player/ParallelProductionQueue.cs
@@ -0,0 +1,62 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2018 The OpenRA Developers (see AUTHORS)
+ * This file is part of OpenRA, which is free software. It is made
+ * available to you under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version. For more
+ * information, see COPYING.
+ */
+#endregion
+
+using System.Linq;
+
+namespace OpenRA.Mods.Common.Traits
+{
+ public class ParallelProductionQueueInfo : ProductionQueueInfo
+ {
+ public override object Create(ActorInitializer init) { return new ParallelProductionQueue(init, init.Self.Owner.PlayerActor, this); }
+ }
+
+ public class ParallelProductionQueue : ProductionQueue
+ {
+ public ParallelProductionQueue(ActorInitializer init, Actor playerActor, ParallelProductionQueueInfo info)
+ : base(init, playerActor, info) { }
+
+ protected override void TickInner(Actor self, bool allProductionPaused)
+ {
+ CancelUnbuildableItems();
+
+ var item = Queue.FirstOrDefault(i => !i.Paused);
+ if (item == null)
+ return;
+
+ var before = item.RemainingTime;
+ item.Tick(playerResources);
+
+ if (item.RemainingTime == before)
+ return;
+
+ // As we have progressed this actor type, we will move all queued items of this actor to the end.
+ foreach (var other in Queue.FindAll(a => a.Item == item.Item))
+ {
+ Queue.Remove(other);
+ Queue.Add(other);
+ }
+ }
+
+ public override bool IsProducing(ProductionItem item)
+ {
+ return Queue.Contains(item);
+ }
+
+ public override int RemainingTimeActual(ProductionItem item)
+ {
+ var parallelBuilds = Queue.FindAll(i => !i.Paused && !i.Done)
+ .GroupBy(i => i.Item)
+ .ToList()
+ .Count;
+ return item.RemainingTimeActual * parallelBuilds;
+ }
+ }
+}