Merge pull request #7121 from pchote/switchmods

Add Launch.Connect command and on-connect mod switching.
This commit is contained in:
Oliver Brakmann
2014-12-24 16:06:00 +01:00
19 changed files with 193 additions and 116 deletions

View File

@@ -87,10 +87,16 @@ namespace OpenRA
public const int Timestep = 40; public const int Timestep = 40;
public const int TimestepJankThreshold = 250; // Don't catch up for delays larger than 250ms public const int TimestepJankThreshold = 250; // Don't catch up for delays larger than 250ms
public static event Action<string, int> OnRemoteDirectConnect = (a, b) => { };
public static event Action<OrderManager> ConnectionStateChanged = _ => { }; public static event Action<OrderManager> ConnectionStateChanged = _ => { };
static ConnectionState lastConnectionState = ConnectionState.PreConnecting; static ConnectionState lastConnectionState = ConnectionState.PreConnecting;
public static int LocalClientId { get { return orderManager.Connection.LocalClientId; } } public static int LocalClientId { get { return orderManager.Connection.LocalClientId; } }
public static void RemoteDirectConnect(string host, int port)
{
OnRemoteDirectConnect(host, port);
}
// Hacky workaround for orderManager visibility // Hacky workaround for orderManager visibility
public static Widget OpenWindow(World world, string widget) public static Widget OpenWindow(World world, string widget)
{ {
@@ -264,6 +270,9 @@ namespace OpenRA
LobbyInfoChanged = () => { }; LobbyInfoChanged = () => { };
ConnectionStateChanged = om => { }; ConnectionStateChanged = om => { };
BeforeGameStart = () => { }; BeforeGameStart = () => { };
OnRemoteDirectConnect = (a, b) => { };
delayedActions = new ActionQueue();
Ui.ResetAll(); Ui.ResetAll();
if (worldRenderer != null) if (worldRenderer != null)
@@ -356,45 +365,7 @@ namespace OpenRA
Environment.Exit(0); Environment.Exit(0);
} }
else else
{ modData.LoadScreen.StartGame(args);
var window = args != null ? args.GetValue("Launch.Window", null) : null;
if (!string.IsNullOrEmpty(window))
{
var installData = modData.Manifest.ContentInstaller;
if (installData.InstallerBackgroundWidget != null)
Ui.LoadWidget(installData.InstallerBackgroundWidget, Ui.Root, new WidgetArgs());
Widgets.Ui.OpenWindow(window, new WidgetArgs());
}
else
{
modData.LoadScreen.StartGame();
Settings.Save();
var replay = args != null ? args.GetValue("Launch.Replay", null) : null;
if (!string.IsNullOrEmpty(replay))
Game.JoinReplay(replay);
}
}
}
public static void TestAndContinue()
{
Ui.ResetAll();
var installData = modData.Manifest.ContentInstaller;
if (!installData.TestFiles.All(f => GlobalFileSystem.Exists(f)))
{
var args = new WidgetArgs()
{
{ "continueLoading", () => InitializeMod(Game.Settings.Game.Mod, null) },
};
if (installData.InstallerBackgroundWidget != null)
Ui.LoadWidget(installData.InstallerBackgroundWidget, Ui.Root, args);
Ui.OpenWindow(installData.InstallerMenuWidget, args);
}
else
LoadShellMap();
} }
public static void LoadShellMap() public static void LoadShellMap()

View File

@@ -20,8 +20,9 @@ namespace OpenRA
{ {
public class InstallData public class InstallData
{ {
public readonly string InstallerMenuWidget = null; public readonly string MenuWidget = null;
public readonly string InstallerBackgroundWidget = null; public readonly string MusicMenuWidget = null;
public readonly string BackgroundWidget = null;
public readonly string[] TestFiles = {}; public readonly string[] TestFiles = {};
public readonly string[] DiskTestFiles = {}; public readonly string[] DiskTestFiles = {};
public readonly string PackageToExtractFromCD = null; public readonly string PackageToExtractFromCD = null;

View File

@@ -180,6 +180,6 @@ namespace OpenRA
{ {
void Init(Manifest m, Dictionary<string, string> info); void Init(Manifest m, Dictionary<string, string> info);
void Display(); void Display();
void StartGame(); void StartGame(Arguments args);
} }
} }

View File

@@ -51,6 +51,8 @@ namespace OpenRA.Network
public readonly ReadOnlyList<ChatLine> ChatCache; public readonly ReadOnlyList<ChatLine> ChatCache;
bool disposed;
static void OutOfSync(int frame) static void OutOfSync(int frame)
{ {
throw new InvalidOperationException("Out of sync in frame {0}.\n Compare syncreport.log with other players.".F(frame)); throw new InvalidOperationException("Out of sync in frame {0}.\n Compare syncreport.log with other players.".F(frame));
@@ -122,8 +124,16 @@ namespace OpenRA.Network
}); });
foreach (var p in immediatePackets) foreach (var p in immediatePackets)
{
foreach (var o in p.Second.ToOrderList(World)) foreach (var o in p.Second.ToOrderList(World))
{
UnitOrders.ProcessOrder(this, World, p.First, o); UnitOrders.ProcessOrder(this, World, p.First, o);
// A mod switch or other event has pulled the ground from beneath us
if (disposed)
return;
}
}
} }
Dictionary<int, byte[]> syncForFrame = new Dictionary<int, byte[]>(); Dictionary<int, byte[]> syncForFrame = new Dictionary<int, byte[]>();
@@ -213,6 +223,7 @@ namespace OpenRA.Network
public void Dispose() public void Dispose()
{ {
disposed = true;
if (Connection != null) if (Connection != null)
Connection.Dispose(); Connection.Dispose();
} }

View File

@@ -33,9 +33,12 @@ namespace OpenRA.Network
public readonly int TickCount; public readonly int TickCount;
public readonly bool IsValid; public readonly bool IsValid;
public readonly Session LobbyInfo; public readonly Session LobbyInfo;
public readonly string Filename;
public ReplayConnection(string replayFilename) public ReplayConnection(string replayFilename)
{ {
Filename = replayFilename;
// Parse replay data into a struct that can be fed to the game in chunks // Parse replay data into a struct that can be fed to the game in chunks
// to avoid issues with all immediate orders being resolved on the first tick. // to avoid issues with all immediate orders being resolved on the first tick.
using (var rs = File.OpenRead(replayFilename)) using (var rs = File.OpenRead(replayFilename))

View File

@@ -119,10 +119,27 @@ namespace OpenRA.Network
case "HandshakeRequest": case "HandshakeRequest":
{ {
// TODO: Switch to the server's mod if we have it // Switch to the server's mod if we need and are able to
// Otherwise send the handshake with our current settings and let the server reject us
var mod = Game.modData.Manifest.Mod; var mod = Game.modData.Manifest.Mod;
var request = HandshakeRequest.Deserialize(order.TargetString);
ModMetadata serverMod;
if (request.Mod != mod.Id &&
ModMetadata.AllMods.TryGetValue(request.Mod, out serverMod) &&
serverMod.Version == request.Version)
{
var replay = orderManager.Connection as ReplayConnection;
var launchCommand = replay != null ?
"Launch.Replay=" + replay.Filename :
"Launch.Connect=" + orderManager.Host + ":" + orderManager.Port;
Game.modData.LoadScreen.Display();
Game.InitializeMod(request.Mod, new Arguments(launchCommand));
break;
}
// Otherwise send the handshake with our current settings and let the server reject us
var info = new Session.Client() var info = new Session.Client()
{ {
Name = Game.Settings.Player.Name, Name = Game.Settings.Player.Name,

View File

@@ -12,12 +12,15 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing; using System.Drawing;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.Mods.Common.LoadScreens;
using OpenRA.Widgets; using OpenRA.Widgets;
namespace OpenRA.Mods.Cnc namespace OpenRA.Mods.Cnc
{ {
public sealed class CncLoadScreen : ILoadScreen public sealed class CncLoadScreen : BlankLoadScreen
{ {
readonly NullInputHandler nih = new NullInputHandler();
Dictionary<string, string> loadInfo; Dictionary<string, string> loadInfo;
Stopwatch loadTimer = Stopwatch.StartNew(); Stopwatch loadTimer = Stopwatch.StartNew();
Sheet sheet; Sheet sheet;
@@ -27,9 +30,8 @@ namespace OpenRA.Mods.Cnc
Sprite nodLogo, gdiLogo, evaLogo, brightBlock, dimBlock; Sprite nodLogo, gdiLogo, evaLogo, brightBlock, dimBlock;
Rectangle bounds; Rectangle bounds;
Renderer r; Renderer r;
readonly NullInputHandler nih = new NullInputHandler();
public void Init(Manifest m, Dictionary<string, string> info) public override void Init(Manifest m, Dictionary<string, string> info)
{ {
loadInfo = info; loadInfo = info;
@@ -72,7 +74,7 @@ namespace OpenRA.Mods.Cnc
string loadingText, versionText; string loadingText, versionText;
float2 loadingPos, versionPos; float2 loadingPos, versionPos;
public void Display() public override void Display()
{ {
if (r == null || loadTimer.Elapsed.TotalSeconds < 0.25) if (r == null || loadTimer.Elapsed.TotalSeconds < 0.25)
return; return;
@@ -118,12 +120,7 @@ namespace OpenRA.Mods.Cnc
r.EndFrame(nih); r.EndFrame(nih);
} }
public void StartGame() public override void Dispose()
{
Game.TestAndContinue();
}
public void Dispose()
{ {
if (sheet != null) if (sheet != null)
sheet.Dispose(); sheet.Dispose();

View File

@@ -0,0 +1,91 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileSystem;
using OpenRA.Widgets;
using OpenRA.Mods.Common.Widgets.Logic;
namespace OpenRA.Mods.Common.LoadScreens
{
public class BlankLoadScreen : ILoadScreen
{
public virtual void Init(Manifest m, Dictionary<string, string> info) { }
public virtual void Display()
{
if (Game.Renderer == null)
return;
// Draw a black screen
Game.Renderer.BeginFrame(int2.Zero, 1f);
Game.Renderer.EndFrame(new NullInputHandler());
}
public void StartGame(Arguments args)
{
Ui.ResetAll();
Game.Settings.Save();
// Check whether the mod content is installed
// TODO: The installation code has finally been beaten into shape, so we can
// finally move it all into the planned "Manage Content" panel in the modchooser mod.
var installData = Game.modData.Manifest.ContentInstaller;
var installModContent = !installData.TestFiles.All(f => GlobalFileSystem.Exists(f));
var installModMusic = args != null && args.Contains("Install.Music");
if (installModContent || installModMusic)
{
var widgetArgs = new WidgetArgs()
{
{ "continueLoading", () => Game.InitializeMod(Game.Settings.Game.Mod, args) },
};
if (installData.BackgroundWidget != null)
Ui.LoadWidget(installData.BackgroundWidget, Ui.Root, widgetArgs);
var menu = installModContent ? installData.MenuWidget : installData.MusicMenuWidget;
Ui.OpenWindow(menu, widgetArgs);
return;
}
// Join a server directly
var connect = args != null ? args.GetValue("Launch.Connect", null) : null;
if (!string.IsNullOrEmpty(connect))
{
var parts = connect.Split(':');
if (parts.Length == 2)
{
var host = parts[0];
var port = Exts.ParseIntegerInvariant(parts[1]);
Game.LoadShellMap();
Game.RemoteDirectConnect(host, port);
return;
}
}
// Load a replay directly
var replay = args != null ? args.GetValue("Launch.Replay", null) : null;
if (!string.IsNullOrEmpty(replay))
{
Game.JoinReplay(replay);
return;
}
Game.LoadShellMap();
Game.Settings.Save();
}
public virtual void Dispose() { }
}
}

View File

@@ -16,7 +16,7 @@ using OpenRA.Widgets;
namespace OpenRA.Mods.Common.LoadScreens namespace OpenRA.Mods.Common.LoadScreens
{ {
public sealed class DefaultLoadScreen : ILoadScreen public sealed class LogoStripeLoadScreen : BlankLoadScreen
{ {
Stopwatch lastUpdate = Stopwatch.StartNew(); Stopwatch lastUpdate = Stopwatch.StartNew();
Renderer r; Renderer r;
@@ -27,7 +27,7 @@ namespace OpenRA.Mods.Common.LoadScreens
Sprite stripe, logo; Sprite stripe, logo;
string[] messages; string[] messages;
public void Init(Manifest m, Dictionary<string, string> info) public override void Init(Manifest m, Dictionary<string, string> info)
{ {
// Avoid standard loading mechanisms so we // Avoid standard loading mechanisms so we
// can display the loadscreen as early as possible // can display the loadscreen as early as possible
@@ -43,7 +43,7 @@ namespace OpenRA.Mods.Common.LoadScreens
logoPos = new float2(r.Resolution.Width / 2 - 128, r.Resolution.Height / 2 - 128); logoPos = new float2(r.Resolution.Width / 2 - 128, r.Resolution.Height / 2 - 128);
} }
public void Display() public override void Display()
{ {
if (r == null) if (r == null)
return; return;
@@ -66,12 +66,7 @@ namespace OpenRA.Mods.Common.LoadScreens
r.EndFrame(new NullInputHandler()); r.EndFrame(new NullInputHandler());
} }
public void StartGame() public override void Dispose()
{
Game.TestAndContinue();
}
public void Dispose()
{ {
if (sheet != null) if (sheet != null)
sheet.Dispose(); sheet.Dispose();

View File

@@ -39,7 +39,7 @@ namespace OpenRA.Mods.Common.LoadScreens
r.EndFrame(new NullInputHandler()); r.EndFrame(new NullInputHandler());
} }
public void StartGame() public void StartGame(Arguments args)
{ {
Ui.LoadWidget("MODCHOOSER", Ui.Root, new WidgetArgs()); Ui.LoadWidget("MODCHOOSER", Ui.Root, new WidgetArgs());
} }

View File

@@ -1,39 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.LoadScreens
{
public sealed class NullLoadScreen : ILoadScreen
{
public void Init(Manifest m, Dictionary<string, string> info) { }
public void Display()
{
if (Game.Renderer == null)
return;
// Draw a black screen
Game.Renderer.BeginFrame(int2.Zero, 1f);
Game.Renderer.EndFrame(new NullInputHandler());
}
public void StartGame()
{
Ui.ResetAll();
}
public void Dispose()
{
}
}
}

View File

@@ -80,9 +80,7 @@
<Compile Include="Graphics\TextRenderable.cs" /> <Compile Include="Graphics\TextRenderable.cs" />
<Compile Include="Graphics\VoxelActorPreview.cs" /> <Compile Include="Graphics\VoxelActorPreview.cs" />
<Compile Include="Graphics\VoxelRenderable.cs" /> <Compile Include="Graphics\VoxelRenderable.cs" />
<Compile Include="LoadScreens\DefaultLoadScreen.cs" />
<Compile Include="LoadScreens\ModChooserLoadScreen.cs" /> <Compile Include="LoadScreens\ModChooserLoadScreen.cs" />
<Compile Include="LoadScreens\NullLoadScreen.cs" />
<Compile Include="Orders\DeployOrderTargeter.cs" /> <Compile Include="Orders\DeployOrderTargeter.cs" />
<Compile Include="Orders\EnterAlliedActorTargeter.cs" /> <Compile Include="Orders\EnterAlliedActorTargeter.cs" />
<Compile Include="Orders\UnitOrderTargeter.cs" /> <Compile Include="Orders\UnitOrderTargeter.cs" />
@@ -243,6 +241,8 @@
<Compile Include="SpriteLoaders\ShpD2Loader.cs" /> <Compile Include="SpriteLoaders\ShpD2Loader.cs" />
<Compile Include="Widgets\Logic\SettingsLogic.cs" /> <Compile Include="Widgets\Logic\SettingsLogic.cs" />
<Compile Include="Widgets\TerrainTemplatePreviewWidget.cs" /> <Compile Include="Widgets\TerrainTemplatePreviewWidget.cs" />
<Compile Include="LoadScreens\LogoStripeLoadScreen.cs" />
<Compile Include="LoadScreens\BlankLoadScreen.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup> <PropertyGroup>

View File

@@ -48,7 +48,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic
Ui.OpenWindow("SERVERBROWSER_PANEL", new WidgetArgs Ui.OpenWindow("SERVERBROWSER_PANEL", new WidgetArgs
{ {
{ "onStart", RemoveShellmapUI }, { "onStart", RemoveShellmapUI },
{ "onExit", () => menuType = MenuType.Main } { "onExit", () => menuType = MenuType.Main },
{ "directConnectHost", null },
{ "directConnectPort", 0 },
}); });
}; };
@@ -173,6 +175,18 @@ namespace OpenRA.Mods.RA.Widgets.Logic
newsButton.IsHighlighted = () => newsHighlighted && Game.LocalTick % 50 < 25; newsButton.IsHighlighted = () => newsHighlighted && Game.LocalTick % 50 < 25;
} }
Game.OnRemoteDirectConnect += (host, port) =>
{
menuType = MenuType.None;
Ui.OpenWindow("SERVERBROWSER_PANEL", new WidgetArgs
{
{ "onStart", RemoveShellmapUI },
{ "onExit", () => menuType = MenuType.Main },
{ "directConnectHost", host },
{ "directConnectPort", port },
});
};
} }
void SetNewsStatus(string message) void SetNewsStatus(string message)

View File

@@ -85,7 +85,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
if (installButton != null) if (installButton != null)
{ {
installButton.IsDisabled = () => world == null || !world.IsShellmap; installButton.IsDisabled = () => world == null || !world.IsShellmap;
var args = new string[] { "Launch.Window=INSTALL_MUSIC_PANEL" }; var args = new string[] { "Install.Music=true" };
installButton.OnClick = () => installButton.OnClick = () =>
{ {
Game.modData.LoadScreen.Display(); // HACK: prevent a flicker when transitioning to the installation dialog Game.modData.LoadScreen.Display(); // HACK: prevent a flicker when transitioning to the installation dialog

View File

@@ -51,7 +51,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
} }
[ObjectCreator.UseCtor] [ObjectCreator.UseCtor]
public ServerBrowserLogic(Widget widget, Action onStart, Action onExit) public ServerBrowserLogic(Widget widget, Action onStart, Action onExit, string directConnectHost, int directConnectPort)
{ {
panel = widget; panel = widget;
this.onStart = onStart; this.onStart = onStart;
@@ -116,6 +116,18 @@ namespace OpenRA.Mods.RA.Widgets.Logic
} }
RefreshServerList(); RefreshServerList();
if (directConnectHost != null)
{
// The connection window must be opened at the end of the tick for the widget hierarchy to
// work out, but we also want to prevent the server browser from flashing visible for one tick.
widget.Visible = false;
Game.RunAfterTick(() =>
{
ConnectionLogic.Connect(directConnectHost, directConnectPort, "", OpenLobby, DoNothing);
widget.Visible = true;
});
}
} }
void RefreshServerList() void RefreshServerList()

View File

@@ -138,8 +138,9 @@ LoadScreen: CncLoadScreen
ContentInstaller: ContentInstaller:
TestFiles: conquer.mix, desert.mix, sounds.mix, speech.mix, temperat.mix, tempicnh.mix, winter.mix TestFiles: conquer.mix, desert.mix, sounds.mix, speech.mix, temperat.mix, tempicnh.mix, winter.mix
InstallerBackgroundWidget: INSTALL_BACKGROUND BackgroundWidget: INSTALL_BACKGROUND
InstallerMenuWidget: INSTALL_PANEL MenuWidget: INSTALL_PANEL
MusicMenuWidget: INSTALL_MUSIC_PANEL
FilesToCopy: CONQUER.MIX, DESERT.MIX, SCORES.MIX, SOUNDS.MIX, TEMPERAT.MIX, WINTER.MIX FilesToCopy: CONQUER.MIX, DESERT.MIX, SCORES.MIX, SOUNDS.MIX, TEMPERAT.MIX, WINTER.MIX
FilesToExtract: speech.mix, tempicnh.mix, transit.mix FilesToExtract: speech.mix, tempicnh.mix, transit.mix
PackageMirrorList: http://www.openra.net/packages/cnc-mirrors.txt PackageMirrorList: http://www.openra.net/packages/cnc-mirrors.txt

View File

@@ -117,12 +117,13 @@ Movies:
Translations: Translations:
./mods/d2k/languages/english.yaml ./mods/d2k/languages/english.yaml
LoadScreen: DefaultLoadScreen LoadScreen: LogoStripeLoadScreen
Image: ./mods/d2k/uibits/loadscreen.png Image: ./mods/d2k/uibits/loadscreen.png
Text: Filling Crates..., Breeding Sandworms... Text: Filling Crates..., Breeding Sandworms...
ContentInstaller: ContentInstaller:
InstallerMenuWidget: INSTALL_PANEL MenuWidget: INSTALL_PANEL
MusicMenuWidget: INSTALL_MUSIC_PANEL
# TODO: check if DATA.R8 is at 1.03 patch level with 4840 frames # TODO: check if DATA.R8 is at 1.03 patch level with 4840 frames
TestFiles: BLOXBASE.R8, BLOXBAT.R8, BLOXBGBS.R8, BLOXICE.R8, BLOXTREE.R8, BLOXWAST.R8, DATA.R8, SOUND.RS TestFiles: BLOXBASE.R8, BLOXBAT.R8, BLOXBGBS.R8, BLOXICE.R8, BLOXTREE.R8, BLOXWAST.R8, DATA.R8, SOUND.RS
PackageMirrorList: http://www.openra.net/packages/d2k-103-mirrors.txt PackageMirrorList: http://www.openra.net/packages/d2k-103-mirrors.txt

View File

@@ -132,12 +132,13 @@ Movies:
Translations: Translations:
./mods/ra/languages/english.yaml ./mods/ra/languages/english.yaml
LoadScreen: DefaultLoadScreen LoadScreen: LogoStripeLoadScreen
Image: ./mods/ra/uibits/loadscreen.png Image: ./mods/ra/uibits/loadscreen.png
Text: Filling Crates..., Charging Capacitors..., Reticulating Splines..., Planting Trees..., Building Bridges..., Aging Empires..., Compiling EVA..., Constructing Pylons..., Activating Skynet..., Splitting Atoms... Text: Filling Crates..., Charging Capacitors..., Reticulating Splines..., Planting Trees..., Building Bridges..., Aging Empires..., Compiling EVA..., Constructing Pylons..., Activating Skynet..., Splitting Atoms...
ContentInstaller: ContentInstaller:
InstallerMenuWidget: INSTALL_PANEL MenuWidget: INSTALL_PANEL
MusicMenuWidget: INSTALL_MUSIC_PANEL
TestFiles: allies.mix, conquer.mix, interior.mix, redalert.mix, russian.mix, snow.mix, sounds.mix, temperat.mix TestFiles: allies.mix, conquer.mix, interior.mix, redalert.mix, russian.mix, snow.mix, sounds.mix, temperat.mix
PackageMirrorList: http://www.openra.net/packages/ra-mirrors.txt PackageMirrorList: http://www.openra.net/packages/ra-mirrors.txt
DiskTestFiles: MAIN.MIX, INSTALL/REDALERT.MIX DiskTestFiles: MAIN.MIX, INSTALL/REDALERT.MIX

View File

@@ -162,12 +162,13 @@ Movies:
Translations: Translations:
./mods/ts/languages/english.yaml ./mods/ts/languages/english.yaml
LoadScreen: DefaultLoadScreen LoadScreen: LogoStripeLoadScreen
Image: ./mods/ts/uibits/loadscreen.png Image: ./mods/ts/uibits/loadscreen.png
Text: Updating EVA installation..., Changing perspective... Text: Updating EVA installation..., Changing perspective...
ContentInstaller: ContentInstaller:
InstallerMenuWidget: INSTALL_PANEL MenuWidget: INSTALL_PANEL
MusicMenuWidget: INSTALL_MUSIC_PANEL
TestFiles: cache.mix, conquer.mix, isosnow.mix, isotemp.mix, local.mix, sidec01.mix, sidec02.mix, sno.mix, snow.mix, sounds.mix, speech01.mix, tem.mix, temperat.mix TestFiles: cache.mix, conquer.mix, isosnow.mix, isotemp.mix, local.mix, sidec01.mix, sidec02.mix, sno.mix, snow.mix, sounds.mix, speech01.mix, tem.mix, temperat.mix
PackageMirrorList: http://www.openra.net/packages/ts-mirrors.txt PackageMirrorList: http://www.openra.net/packages/ts-mirrors.txt
DiskTestFiles: MULTI.MIX, INSTALL/TIBSUN.MIX DiskTestFiles: MULTI.MIX, INSTALL/TIBSUN.MIX