Remove runtime mod merging. Closes #3421.

This commit is contained in:
Paul Chote
2013-10-06 12:44:20 +13:00
parent 4d893cb1f2
commit 6d6d1e230b
35 changed files with 143 additions and 186 deletions

View File

@@ -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)

View File

@@ -124,7 +124,7 @@ namespace OpenRA.GameRules
public class GameSettings
{
public string[] Mods = { "ra" };
public string Mod = "ra";
public bool ShowShellmap = true;

View File

@@ -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();
}

View File

@@ -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;
}
}
}

View File

@@ -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();

View File

@@ -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;

View File

@@ -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);

View File

@@ -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>();

View File

@@ -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);

View File

@@ -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
};

View File

@@ -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.");

View File

@@ -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);
}

View File

@@ -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;