Remove runtime mod merging. Closes #3421.
This commit is contained in:
@@ -255,18 +255,6 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
public static Dictionary<String, Mod> CurrentMods
|
||||
{
|
||||
get
|
||||
{
|
||||
// Initialization hasn't completed yet
|
||||
if (Mod.AllMods == null || modData == null)
|
||||
return null;
|
||||
|
||||
return Mod.AllMods.Where(k => modData.Manifest.Mods.Contains(k.Key)).ToDictionary(k => k.Key, k => k.Value);
|
||||
}
|
||||
}
|
||||
|
||||
static Modifiers modifiers;
|
||||
public static Modifiers GetModifierKeys() { return modifiers; }
|
||||
internal static void HandleModifierKeys(Modifiers mods) { modifiers = mods; }
|
||||
@@ -328,7 +316,8 @@ namespace OpenRA
|
||||
Console.WriteLine("Available mods:");
|
||||
foreach(var mod in Mod.AllMods)
|
||||
Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Title, mod.Value.Version);
|
||||
InitializeWithMods(Settings.Game.Mods);
|
||||
|
||||
InitializeWithMod(Settings.Game.Mod);
|
||||
|
||||
if (Settings.Server.DiscoverNatDevices)
|
||||
{
|
||||
@@ -338,7 +327,7 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
public static void InitializeWithMods(string[] mods)
|
||||
public static void InitializeWithMod(string mod)
|
||||
{
|
||||
// Clear static state if we have switched mods
|
||||
LobbyInfoChanged = () => {};
|
||||
@@ -353,17 +342,18 @@ namespace OpenRA
|
||||
if (orderManager != null)
|
||||
orderManager.Dispose();
|
||||
|
||||
// Discard any invalid mods, set RA as default
|
||||
var mm = mods.Where( m => Mod.AllMods.ContainsKey( m ) ).ToArray();
|
||||
if (mm.Length == 0) mm = new[] { "ra" };
|
||||
Console.WriteLine("Loading mods: {0}", mm.JoinWith(","));
|
||||
Settings.Game.Mods = mm;
|
||||
// Fall back to RA if the mod doesn't exist
|
||||
if (!Mod.AllMods.ContainsKey(mod))
|
||||
mod = "ra";
|
||||
|
||||
Console.WriteLine("Loading mod: {0}", mod);
|
||||
Settings.Game.Mod = mod;
|
||||
|
||||
Sound.StopMusic();
|
||||
Sound.StopVideo();
|
||||
Sound.Initialize();
|
||||
|
||||
modData = new ModData(mm);
|
||||
modData = new ModData(mod);
|
||||
Renderer.InitializeFonts(modData.Manifest);
|
||||
modData.InitializeLoaders();
|
||||
|
||||
@@ -480,8 +470,7 @@ namespace OpenRA
|
||||
|
||||
public static void CreateServer(ServerSettings settings)
|
||||
{
|
||||
server = new Server.Server(new IPEndPoint(IPAddress.Any, settings.ListenPort),
|
||||
Settings.Game.Mods, settings, modData);
|
||||
server = new Server.Server(new IPEndPoint(IPAddress.Any, settings.ListenPort), settings, modData);
|
||||
}
|
||||
|
||||
public static int CreateLocalServer(string map)
|
||||
@@ -494,8 +483,7 @@ namespace OpenRA
|
||||
AllowPortForward = false
|
||||
};
|
||||
|
||||
server = new Server.Server(new IPEndPoint(IPAddress.Loopback, 0),
|
||||
Settings.Game.Mods, settings, modData);
|
||||
server = new Server.Server(new IPEndPoint(IPAddress.Loopback, 0), settings, modData);
|
||||
|
||||
return server.Port;
|
||||
}
|
||||
@@ -509,16 +497,19 @@ namespace OpenRA
|
||||
{
|
||||
try
|
||||
{
|
||||
var mod = CurrentMods.First().Value.Id;
|
||||
var dirPath = "{1}maps{0}{2}".F(Path.DirectorySeparatorChar, Platform.SupportDir, mod);
|
||||
if(!Directory.Exists(dirPath))
|
||||
var mod = Game.modData.Manifest.Mod;
|
||||
var dirPath = new [] { Platform.SupportDir, "maps", mod.Id }.Aggregate(Path.Combine);
|
||||
if (!Directory.Exists(dirPath))
|
||||
Directory.CreateDirectory(dirPath);
|
||||
var mapPath = "{1}{0}{2}".F(Path.DirectorySeparatorChar, dirPath, mapHash+".oramap");
|
||||
|
||||
var mapPath = Path.Combine(dirPath, mapHash+".oramap");
|
||||
Console.Write("Trying to download map to {0} ... ".F(mapPath));
|
||||
|
||||
WebClient webClient = new WebClient();
|
||||
webClient.DownloadFile(Game.Settings.Game.MapRepository + mapHash, mapPath);
|
||||
Game.modData.AvailableMaps.Add(mapHash, new Map(mapPath));
|
||||
Console.WriteLine("done");
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (WebException e)
|
||||
|
||||
@@ -124,7 +124,7 @@ namespace OpenRA.GameRules
|
||||
|
||||
public class GameSettings
|
||||
{
|
||||
public string[] Mods = { "ra" };
|
||||
public string Mod = "ra";
|
||||
|
||||
public bool ShowShellmap = true;
|
||||
|
||||
|
||||
@@ -50,13 +50,13 @@ namespace OpenRA
|
||||
return dirsWithMaps.Concat(Directory.GetFiles(dir, "*.oramap"));
|
||||
}
|
||||
|
||||
public ModData(params string[] mods)
|
||||
public ModData(string mod)
|
||||
{
|
||||
Languages = new string[0];
|
||||
Manifest = new Manifest(mods);
|
||||
Manifest = new Manifest(mod);
|
||||
ObjectCreator = new ObjectCreator(Manifest);
|
||||
LoadScreen = ObjectCreator.CreateObject<ILoadScreen>(Manifest.LoadScreen.Value);
|
||||
LoadScreen.Init(Manifest.LoadScreen.NodesDict.ToDictionary(x => x.Key, x => x.Value.Value));
|
||||
LoadScreen.Init(Manifest, Manifest.LoadScreen.NodesDict.ToDictionary(x => x.Key, x => x.Value.Value));
|
||||
LoadScreen.Display();
|
||||
WidgetLoader = new WidgetLoader(this);
|
||||
|
||||
@@ -149,9 +149,7 @@ namespace OpenRA
|
||||
Dictionary<string, Map> FindMaps()
|
||||
{
|
||||
var paths = Manifest.MapFolders.SelectMany(f => FindMapsIn(f));
|
||||
|
||||
var ret = new Dictionary<string, Map>();
|
||||
|
||||
foreach (var path in paths)
|
||||
{
|
||||
try
|
||||
@@ -177,7 +175,7 @@ namespace OpenRA
|
||||
|
||||
public interface ILoadScreen
|
||||
{
|
||||
void Init(Dictionary<string, string> info);
|
||||
void Init(Manifest m, Dictionary<string, string> info);
|
||||
void Display();
|
||||
void StartGame();
|
||||
}
|
||||
|
||||
@@ -21,49 +21,47 @@ namespace OpenRA.Network
|
||||
public readonly int State = 0;
|
||||
public readonly int Players = 0;
|
||||
public readonly string Map = null;
|
||||
public readonly string[] Mods = { };
|
||||
|
||||
// Retained name compatibility with the master server
|
||||
public readonly string Mods = "";
|
||||
public readonly int TTL = 0;
|
||||
|
||||
public Dictionary<string, string> UsefulMods
|
||||
{
|
||||
get
|
||||
{
|
||||
return Mods
|
||||
.Where(v => v.Contains('@'))
|
||||
.ToDictionary(v => v.Split('@')[0], v => v.Split('@')[1]);
|
||||
}
|
||||
}
|
||||
|
||||
static bool AreVersionsCompatible(string a, string b)
|
||||
{
|
||||
if (Game.Settings.Debug.IgnoreVersionMismatch)
|
||||
return true;
|
||||
|
||||
return a == b;
|
||||
}
|
||||
|
||||
public bool CanJoin()
|
||||
{
|
||||
//"waiting for players"
|
||||
// "waiting for players"
|
||||
if (State != 1)
|
||||
return false;
|
||||
|
||||
// Mods won't match if there are a different number
|
||||
if (Game.CurrentMods.Count != Mods.Count())
|
||||
if (!CompatibleVersion())
|
||||
return false;
|
||||
|
||||
// Don't have the map locally
|
||||
if (!Game.modData.AvailableMaps.ContainsKey(Map))
|
||||
if (!Game.Settings.Game.AllowDownloading)
|
||||
return false;
|
||||
// TODO: We allow joining, then drop on game start if the map isn't available
|
||||
if (!Game.modData.AvailableMaps.ContainsKey(Map) && !Game.Settings.Game.AllowDownloading)
|
||||
return false;
|
||||
|
||||
return CompatibleVersion();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CompatibleVersion()
|
||||
{
|
||||
return UsefulMods.All(m => Game.CurrentMods.ContainsKey(m.Key)
|
||||
&& AreVersionsCompatible(m.Value, Game.CurrentMods[m.Key].Version));
|
||||
// Invalid game listing - we require one entry of id@version
|
||||
var modVersion = Mods.Split('@');
|
||||
if (modVersion.Length != 2)
|
||||
return false;
|
||||
|
||||
var mod = Game.modData.Manifest.Mod;
|
||||
|
||||
// Different mod
|
||||
// TODO: Allow mod switch when joining server
|
||||
if (modVersion[0] != mod.Id)
|
||||
return false;
|
||||
|
||||
// Same mod, but different version
|
||||
if (modVersion[1] != mod.Version && !Game.Settings.Debug.IgnoreVersionMismatch)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@ namespace OpenRA.Network
|
||||
{
|
||||
public class HandshakeRequest
|
||||
{
|
||||
public string[] Mods;
|
||||
public string Mod;
|
||||
public string Version;
|
||||
public string Map;
|
||||
|
||||
public string Serialize()
|
||||
@@ -36,7 +37,8 @@ namespace OpenRA.Network
|
||||
|
||||
public class HandshakeResponse
|
||||
{
|
||||
public string[] Mods;
|
||||
public string Mod;
|
||||
public string Version;
|
||||
public string Password;
|
||||
[FieldLoader.Ignore] public Session.Client Client;
|
||||
|
||||
@@ -44,7 +46,7 @@ namespace OpenRA.Network
|
||||
{
|
||||
var data = new List<MiniYamlNode>();
|
||||
data.Add( new MiniYamlNode( "Handshake", null,
|
||||
new string[]{ "Mods", "Password" }.Select( p => FieldSaver.SaveField(this, p) ).ToList() ) );
|
||||
new string[]{ "Mod", "Version", "Password" }.Select( p => FieldSaver.SaveField(this, p) ).ToList() ) );
|
||||
data.Add(new MiniYamlNode("Client", FieldSaver.Save(Client)));
|
||||
|
||||
return data.WriteToString();
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace OpenRA.Network
|
||||
readonly SyncReport syncReport;
|
||||
readonly FrameData frameData = new FrameData();
|
||||
|
||||
public Session LobbyInfo = new Session(Game.Settings.Game.Mods);
|
||||
public Session LobbyInfo = new Session();
|
||||
public Session.Client LocalClient { get { return LobbyInfo.ClientWithIndex(Connection.LocalClientId); } }
|
||||
public World world;
|
||||
|
||||
|
||||
@@ -34,7 +34,8 @@ namespace OpenRA.Network
|
||||
void StartSavingReplay(byte[] initialContent)
|
||||
{
|
||||
var filename = chooseFilename();
|
||||
var dir = new[] { Platform.SupportDir, "Replays", WidgetUtils.ActiveModId(), WidgetUtils.ActiveModVersion() }.Aggregate(Path.Combine);
|
||||
var mod = Game.modData.Manifest.Mod;
|
||||
var dir = new[] { Platform.SupportDir, "Replays", mod.Id, mod.Version }.Aggregate(Path.Combine);
|
||||
|
||||
if (!Directory.Exists(dir))
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace OpenRA.Network
|
||||
{
|
||||
try
|
||||
{
|
||||
var session = new Session(Game.Settings.Game.Mods);
|
||||
var session = new Session();
|
||||
|
||||
var ys = MiniYaml.FromString(data);
|
||||
foreach (var y in ys)
|
||||
@@ -123,10 +123,9 @@ namespace OpenRA.Network
|
||||
{
|
||||
public string ServerName;
|
||||
public string Map;
|
||||
public string[] Mods = { "ra" }; // mod names
|
||||
public int OrderLatency = 3; // net tick frames (x 120 = ms)
|
||||
public int OrderLatency = 3; // net tick frames (x 120 = ms)
|
||||
public int RandomSeed = 0;
|
||||
public bool FragileAlliances = false; // Allow diplomatic stance changes after game start.
|
||||
public bool FragileAlliances = false; // Allow diplomatic stance changes after game start.
|
||||
public bool AllowCheats = false;
|
||||
public bool Dedicated;
|
||||
public string Difficulty;
|
||||
@@ -140,12 +139,6 @@ namespace OpenRA.Network
|
||||
public string GameUid;
|
||||
}
|
||||
|
||||
public Session(string[] mods)
|
||||
{
|
||||
this.GlobalSettings.Mods = mods.ToArray();
|
||||
this.GlobalSettings.GameUid = Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
public string Serialize()
|
||||
{
|
||||
var clientData = new List<MiniYamlNode>();
|
||||
|
||||
@@ -178,8 +178,8 @@ namespace OpenRA.Network
|
||||
{
|
||||
if (r.Frame == frame)
|
||||
{
|
||||
var mod = Game.modData.Manifest.Mod;
|
||||
Log.Write("sync", "Player: {0} ({1} {2} {3})", Game.Settings.Player.Name, Platform.CurrentPlatform, Environment.OSVersion, Platform.RuntimeVersion);
|
||||
var mod = Game.CurrentMods.First().Value;
|
||||
Log.Write("sync", "Game ID: {0} (Mod: {1} at Version {2})", orderManager.LobbyInfo.GlobalSettings.GameUid, mod.Title, mod.Version);
|
||||
Log.Write("sync", "Sync for net frame {0} -------------", r.Frame);
|
||||
Log.Write("sync", "SharedRandom: {0} (#{1})", r.SyncedRandom, r.TotalCount);
|
||||
|
||||
@@ -119,9 +119,14 @@ namespace OpenRA.Network
|
||||
case "HandshakeRequest":
|
||||
{
|
||||
var request = HandshakeRequest.Deserialize(order.TargetString);
|
||||
var localMods = orderManager.LobbyInfo.GlobalSettings.Mods.Select(m => "{0}@{1}".F(m, Mod.AllMods[m].Version)).ToArray();
|
||||
|
||||
// TODO: Switch to the server's mod if we have it
|
||||
// Otherwise send the handshake with our current settings and let the server reject us
|
||||
var mod = Game.modData.Manifest.Mod;
|
||||
|
||||
// Check that the map exists on the client
|
||||
// TODO: This will behave badly if joining a server with a different mod
|
||||
// This needs to occur *after* joining the server
|
||||
if (!Game.modData.AvailableMaps.ContainsKey(request.Map))
|
||||
{
|
||||
if (Game.Settings.Game.AllowDownloading)
|
||||
@@ -144,7 +149,8 @@ namespace OpenRA.Network
|
||||
var response = new HandshakeResponse()
|
||||
{
|
||||
Client = info,
|
||||
Mods = localMods,
|
||||
Mod = mod.Id,
|
||||
Version = mod.Version,
|
||||
Password = orderManager.Password
|
||||
};
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace OpenRA.Server
|
||||
t.GameEnded(this);
|
||||
}
|
||||
|
||||
public Server(IPEndPoint endpoint, string[] mods, ServerSettings settings, ModData modData)
|
||||
public Server(IPEndPoint endpoint, ServerSettings settings, ModData modData)
|
||||
{
|
||||
Log.AddChannel("server", "server.log");
|
||||
|
||||
@@ -117,7 +117,7 @@ namespace OpenRA.Server
|
||||
foreach (var trait in modData.Manifest.ServerTraits)
|
||||
serverTraits.Add(modData.ObjectCreator.CreateObject<ServerTrait>(trait));
|
||||
|
||||
LobbyInfo = new Session(mods);
|
||||
LobbyInfo = new Session();
|
||||
LobbyInfo.GlobalSettings.RandomSeed = randomSeed;
|
||||
LobbyInfo.GlobalSettings.Map = settings.Map;
|
||||
LobbyInfo.GlobalSettings.ServerName = settings.Name;
|
||||
@@ -127,10 +127,7 @@ namespace OpenRA.Server
|
||||
foreach (var t in serverTraits.WithInterface<INotifyServerStart>())
|
||||
t.ServerStarted(this);
|
||||
|
||||
Log.Write("server", "Initial mods: ");
|
||||
foreach (var m in LobbyInfo.GlobalSettings.Mods)
|
||||
Log.Write("server", "- {0}", m);
|
||||
|
||||
Log.Write("server", "Initial mod: {0}", ModData.Manifest.Mod.Id);
|
||||
Log.Write("server", "Initial map: {0}", LobbyInfo.GlobalSettings.Map);
|
||||
|
||||
new Thread(_ =>
|
||||
@@ -226,9 +223,11 @@ namespace OpenRA.Server
|
||||
// Dispatch a handshake order
|
||||
var request = new HandshakeRequest()
|
||||
{
|
||||
Map = LobbyInfo.GlobalSettings.Map,
|
||||
Mods = LobbyInfo.GlobalSettings.Mods.Select(m => "{0}@{1}".F(m, Mod.AllMods[m].Version)).ToArray()
|
||||
Mod = ModData.Manifest.Mod.Id,
|
||||
Version = ModData.Manifest.Mod.Version,
|
||||
Map = LobbyInfo.GlobalSettings.Map
|
||||
};
|
||||
|
||||
DispatchOrdersToClient(newConn, 0, 0, new ServerOrder("HandshakeRequest", request.Serialize()).Serialize());
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -282,13 +281,7 @@ namespace OpenRA.Server
|
||||
else
|
||||
client.Color = HSLColor.FromRGB(255, 255, 255);
|
||||
|
||||
// Check that the client has compatible mods
|
||||
var mods = handshake.Mods;
|
||||
var validMod = mods.All(m => m.Contains('@')) && // valid format
|
||||
mods.Count() == Game.CurrentMods.Count() && // same number
|
||||
mods.Select(m => Pair.New(m.Split('@')[0], m.Split('@')[1])).All(kv => Game.CurrentMods.ContainsKey(kv.First));
|
||||
|
||||
if (!validMod)
|
||||
if (ModData.Manifest.Mod.Id != handshake.Mod)
|
||||
{
|
||||
Log.Write("server", "Rejected connection from {0}; mods do not match.",
|
||||
newConn.socket.RemoteEndPoint);
|
||||
@@ -298,10 +291,7 @@ namespace OpenRA.Server
|
||||
return;
|
||||
}
|
||||
|
||||
var validVersion = mods.Select(m => Pair.New(m.Split('@')[0], m.Split('@')[1])).All(
|
||||
kv => kv.Second == Game.CurrentMods[kv.First].Version);
|
||||
|
||||
if (!validVersion && !LobbyInfo.GlobalSettings.AllowVersionMismatch)
|
||||
if (ModData.Manifest.Mod.Version != handshake.Version && !LobbyInfo.GlobalSettings.AllowVersionMismatch)
|
||||
{
|
||||
Log.Write("server", "Rejected connection from {0}; Not running the same version.",
|
||||
newConn.socket.RemoteEndPoint);
|
||||
@@ -338,13 +328,14 @@ namespace OpenRA.Server
|
||||
// Send initial ping
|
||||
SendOrderTo(newConn, "Ping", Environment.TickCount.ToString());
|
||||
|
||||
if (File.Exists("{0}motd_{1}.txt".F(Platform.SupportDir, LobbyInfo.GlobalSettings.Mods[0])))
|
||||
var motdPath = Path.Combine(Platform.SupportDir, "motd_{0}.txt".F(ModData.Manifest.Mod.Id));
|
||||
if (File.Exists(motdPath))
|
||||
{
|
||||
var motd = File.ReadAllText("{0}motd_{1}.txt".F(Platform.SupportDir, LobbyInfo.GlobalSettings.Mods[0]));
|
||||
var motd = System.IO.File.ReadAllText(motdPath);
|
||||
SendOrderTo(newConn, "Message", motd);
|
||||
}
|
||||
|
||||
if (mods.Any(m => m.Contains("{DEV_VERSION}")))
|
||||
if (handshake.Mod == "{DEV_VERSION}")
|
||||
SendMessage("{0} is running an unversioned development build, ".F(client.Name) +
|
||||
"and may desynchronize the game state if they have incompatible rules.");
|
||||
|
||||
|
||||
@@ -47,9 +47,9 @@ namespace OpenRA
|
||||
{
|
||||
Log.AddChannel("exception", "exception.log");
|
||||
|
||||
if (Game.CurrentMods != null)
|
||||
if (Game.modData != null)
|
||||
{
|
||||
var mod = Game.CurrentMods.First().Value;
|
||||
var mod = Game.modData.Manifest.Mod;
|
||||
Log.Write("exception", "{0} Mod at Version {1}", mod.Title, mod.Version);
|
||||
}
|
||||
|
||||
|
||||
@@ -225,24 +225,6 @@ namespace OpenRA.Widgets
|
||||
|
||||
public static Action Once( Action a ) { return () => { if (a != null) { a(); a = null; } }; }
|
||||
|
||||
public static string ActiveModVersion()
|
||||
{
|
||||
var mod = Game.modData.Manifest.Mods[0];
|
||||
return Mod.AllMods[mod].Version;
|
||||
}
|
||||
|
||||
public static string ActiveModTitle()
|
||||
{
|
||||
var mod = Game.modData.Manifest.Mods[0];
|
||||
return Mod.AllMods[mod].Title;
|
||||
}
|
||||
|
||||
public static string ActiveModId()
|
||||
{
|
||||
var mod = Game.modData.Manifest.Mods[0];
|
||||
return Mod.AllMods[mod].Id;
|
||||
}
|
||||
|
||||
public static string ChooseInitialMap(string map)
|
||||
{
|
||||
var availableMaps = Game.modData.AvailableMaps;
|
||||
|
||||
Reference in New Issue
Block a user