#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it 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.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Network;
using OpenRA.Server;
using OpenRA.Support;
using OpenRA.Traits;
using OpenRA.Widgets;
using Timer = OpenRA.Support.Timer;
using XRandom = OpenRA.Thirdparty.Random;
namespace OpenRA
{
public static class Game
{
public static readonly int CellSize = 24;
public static World world;
internal static Viewport viewport;
public static Controller controller;
internal static Chrome chrome;
internal static UserSettings Settings;
internal static OrderManager orderManager;
public static bool skipMakeAnims = true;
public static XRandom CosmeticRandom = new XRandom(); // not synced
internal static Renderer renderer;
static int2 clientSize;
static string mapName;
public static Session LobbyInfo = new Session();
static bool packageChangePending;
static bool mapChangePending;
static Pair[] ModAssemblies;
static void LoadModPackages(Manifest manifest)
{
FileSystem.UnmountAll();
Timer.Time("reset: {0}");
foreach (var dir in manifest.Folders) FileSystem.Mount(dir);
foreach (var pkg in manifest.Packages) FileSystem.Mount(pkg);
Timer.Time("mount temporary packages: {0}");
}
public static void LoadModAssemblies(Manifest m)
{
// All the core namespaces
var asms = typeof(Game).Assembly.GetNamespaces()
.Select(c => Pair.New(typeof(Game).Assembly, c))
.ToList();
// Namespaces from each mod assembly
foreach (var a in m.Assemblies)
{
var asm = Assembly.LoadFile(Path.GetFullPath(a));
asms.AddRange(asm.GetNamespaces().Select(ns => Pair.New(asm, ns)));
}
ModAssemblies = asms.ToArray();
}
public static T CreateObject(string classname)
{
foreach (var mod in ModAssemblies)
{
var fullTypeName = mod.Second + "." + classname;
var obj = mod.First.CreateInstance(fullTypeName);
if (obj != null)
return (T)obj;
}
throw new InvalidOperationException("Cannot locate type: {0}".F(classname));
}
public static Dictionary AvailableMaps;
// TODO: Do this nicer
static Dictionary FindMaps(string[] mods)
{
Console.WriteLine("Finding maps");
foreach (var mod in mods)
Console.WriteLine(mod);
var paths = new[] { "maps/" }.Concat(mods.Select(m => "mods/" + m + "/maps/"))
.Where(p => Directory.Exists(p))
.SelectMany(p => Directory.GetDirectories(p)).ToList();
return paths.Select(p => new MapStub(new Folder(p))).ToDictionary(m => m.Uid);
}
static void ChangeMods()
{
Timer.Time("----ChangeMods");
var manifest = new Manifest(LobbyInfo.GlobalSettings.Mods);
Timer.Time("manifest: {0}");
LoadModAssemblies(manifest);
SheetBuilder.Initialize(renderer);
LoadModPackages(manifest);
Timer.Time("load assemblies, packages: {0}");
packageChangePending = false;
}
static void LoadMap(string mapName)
{
Timer.Time("----LoadMap");
SheetBuilder.Initialize(renderer);
var manifest = new Manifest(LobbyInfo.GlobalSettings.Mods);
Timer.Time("manifest: {0}");
if (!Game.AvailableMaps.ContainsKey(mapName))
throw new InvalidDataException("Cannot find map with Uid {0}".F(mapName));
var map = new Map(Game.AvailableMaps[mapName].Package);
viewport = new Viewport(clientSize, map.TopLeft, map.BottomRight, renderer);
world = null; // trying to access the old world will NRE, rather than silently doing it wrong.
ChromeProvider.Initialize(manifest.Chrome);
Timer.Time("viewport, ChromeProvider: {0}");
world = new World(manifest, map);
Timer.Time("world: {0}");
SequenceProvider.Initialize(manifest.Sequences);
Timer.Time("ChromeProv, SeqProv: {0}");
chrome = new Chrome(renderer, manifest);
Timer.Time("chrome: {0}");
Timer.Time("----end LoadMap");
Debug("Map change {0} -> {1}".F(Game.mapName, mapName));
}
public static void MoveViewport(int2 loc)
{
viewport.Center(loc);
}
internal static string CurrentHost = "";
internal static int CurrentPort = 0;
internal static void JoinServer(string host, int port)
{
if (orderManager != null) orderManager.Dispose();
CurrentHost = host;
CurrentPort = port;
orderManager = new OrderManager(new NetworkConnection(host, port), ChooseReplayFilename());
}
static string ChooseReplayFilename()
{
return DateTime.UtcNow.ToString("OpenRA-yyyy-MM-ddThhmmssZ.rep");
}
static void JoinLocal()
{
if (orderManager != null) orderManager.Dispose();
orderManager = new OrderManager(new EchoConnection());
}
static int lastTime = Environment.TickCount;
static void ResetTimer()
{
lastTime = Environment.TickCount;
}
internal static int RenderFrame = 0;
internal static Chat chat = new Chat();
internal static int LocalTick = 0;
const int NetTickScale = 3; // 120ms net tick for 40ms local tick
static Queue> syncReports = new Queue>();
const int numSyncReports = 5;
internal static void UpdateSyncReport()
{
if (!Settings.RecordSyncReports)
return;
while (syncReports.Count >= numSyncReports) syncReports.Dequeue();
syncReports.Enqueue(Pair.New(orderManager.FrameNumber, GenerateSyncReport()));
}
static string GenerateSyncReport()
{
var sb = new StringBuilder();
sb.AppendLine("Actors:");
foreach (var a in world.Actors)
sb.AppendLine("\t {0} {1} {2} ({3})".F(
a.ActorID,
a.Info.Name,
(a.Owner == null) ? "null" : a.Owner.InternalName,
Sync.CalculateSyncHash(a)));
sb.AppendLine("Tick Actors:");
foreach (var a in world.Queries.WithTraitMultiple