using Barotrauma.Networking;
using Barotrauma.Particles;
using Barotrauma.Steam;
using FarseerPhysics;
using FarseerPhysics.Dynamics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using GameAnalyticsSDK.Net;
using Barotrauma.IO;
using System.Threading;
using Barotrauma.Tutorials;
using Barotrauma.Media;
using Barotrauma.Extensions;
using System.Threading.Tasks;
namespace Barotrauma
{
class GameMain : Game
{
public static LuaSetup Lua;
public static bool ShowFPS = false;
public static bool ShowPerf = false;
public static bool DebugDraw;
public static bool IsSingleplayer => NetworkMember == null;
public static bool IsMultiplayer => NetworkMember != null;
public static PerformanceCounter PerformanceCounter;
public static readonly Version Version = Assembly.GetEntryAssembly().GetName().Version;
public static string[] ConsoleArguments;
public static GameScreen GameScreen;
public static MainMenuScreen MainMenuScreen;
public static NetLobbyScreen NetLobbyScreen;
public static ServerListScreen ServerListScreen;
public static SteamWorkshopScreen SteamWorkshopScreen;
public static SubEditorScreen SubEditorScreen;
public static TestScreen TestScreen;
public static ParticleEditorScreen ParticleEditorScreen;
public static LevelEditorScreen LevelEditorScreen;
public static SpriteEditorScreen SpriteEditorScreen;
public static EventEditorScreen EventEditorScreen;
public static CharacterEditor.CharacterEditorScreen CharacterEditorScreen;
public static CampaignEndScreen CampaignEndScreen;
public static Lights.LightManager LightManager;
public static Sounds.SoundManager SoundManager;
public static Thread MainThread { get; private set; }
private static ContentPackage vanillaContent;
public static ContentPackage VanillaContent
{
get
{
if (vanillaContent == null)
{
// TODO: Dynamic method for defining and finding the vanilla content package.
vanillaContent = ContentPackage.CorePackages.SingleOrDefault(cp => Path.GetFileName(cp.Path).Equals("vanilla 0.9.xml", StringComparison.OrdinalIgnoreCase));
}
return vanillaContent;
}
}
private static GameSession gameSession;
public static GameSession GameSession
{
get { return gameSession; }
set
{
if (gameSession == value) { return; }
if (gameSession?.GameMode != null && gameSession.GameMode != value?.GameMode)
{
gameSession.GameMode.Remove();
}
gameSession = value;
}
}
public static ParticleManager ParticleManager;
public static DecalManager DecalManager;
private static World world;
public static World World
{
get
{
if (world == null) { world = new World(new Vector2(0, -9.82f)); }
return world;
}
set { world = value; }
}
public static LoadingScreen TitleScreen;
private bool loadingScreenOpen;
public static GameSettings Config;
private CoroutineHandle loadingCoroutine;
private bool hasLoaded;
private readonly GameTime fixedTime;
public string ConnectName;
public string ConnectEndpoint;
public UInt64 ConnectLobby;
private static SpriteBatch spriteBatch;
private Viewport defaultViewport;
public event Action ResolutionChanged;
private bool exiting;
public static GameMain Instance
{
get;
private set;
}
public static GraphicsDeviceManager GraphicsDeviceManager
{
get;
private set;
}
public static WindowMode WindowMode
{
get;
private set;
}
public static int GraphicsWidth
{
get;
private set;
}
public static int GraphicsHeight
{
get;
private set;
}
public static bool WindowActive
{
get
{
try
{
return Instance != null && !Instance.exiting && Instance.IsActive;
}
catch (NullReferenceException)
{
return false;
}
}
}
public static GameClient Client;
public static NetworkMember NetworkMember
{
get { return Client; }
}
public static RasterizerState ScissorTestEnable
{
get;
private set;
}
public bool LoadingScreenOpen
{
get { return loadingScreenOpen; }
}
public bool Paused
{
get; private set;
}
private const GraphicsProfile GfxProfile = GraphicsProfile.Reach;
#if DEBUG
public static bool FirstLoad = true;
public static bool CancelQuickStart;
#endif
public GameMain(string[] args)
{
Content.RootDirectory = "Content";
#if DEBUG && WINDOWS
GraphicsAdapter.UseDebugLayers = true;
#endif
GraphicsDeviceManager = new GraphicsDeviceManager(this)
{
IsFullScreen = false,
GraphicsProfile = GfxProfile
};
GraphicsDeviceManager.ApplyChanges();
Window.Title = "Barotrauma";
Instance = this;
if (!Directory.Exists(Content.RootDirectory))
{
throw new Exception("Content folder not found. If you are trying to compile the game from the source code and own a legal copy of the game, you can copy the Content folder from the game's files to BarotraumaShared/Content.");
}
Config = new GameSettings();
Lua = new LuaSetup();
Md5Hash.LoadCache();
ConsoleArguments = args;
ConnectName = null;
ConnectEndpoint = null;
ConnectLobby = 0;
try
{
ToolBox.ParseConnectCommand(ConsoleArguments, out ConnectName, out ConnectEndpoint, out ConnectLobby);
}
catch (IndexOutOfRangeException e)
{
DebugConsole.ThrowError($"Failed to parse console arguments ({string.Join(' ', ConsoleArguments)})", e);
ConnectName = null;
ConnectEndpoint = null;
ConnectLobby = 0;
}
GUI.KeyboardDispatcher = new EventInput.KeyboardDispatcher(Window);
PerformanceCounter = new PerformanceCounter();
IsFixedTimeStep = false;
GameMain.ResetFrameTime();
fixedTime = new GameTime();
FarseerPhysics.Settings.AllowSleep = true;
FarseerPhysics.Settings.ContinuousPhysics = false;
FarseerPhysics.Settings.VelocityIterations = 1;
FarseerPhysics.Settings.PositionIterations = 1;
MainThread = Thread.CurrentThread;
Window.FileDropped += OnFileDropped;
}
public static void OnFileDropped(object sender, FileDropEventArgs args)
{
if (!(Screen.Selected is { } screen)) { return; }
string filePath = args.FilePath;
if (string.IsNullOrWhiteSpace(filePath)) { return; }
string extension = Path.GetExtension(filePath).ToLower();
System.IO.FileInfo info = new System.IO.FileInfo(args.FilePath);
if (!info.Exists) { return; }
screen.OnFileDropped(filePath, extension);
}
public void ApplyGraphicsSettings()
{
GraphicsWidth = Config.GraphicsWidth;
GraphicsHeight = Config.GraphicsHeight;
switch (Config.WindowMode)
{
case WindowMode.BorderlessWindowed:
GraphicsWidth = GraphicsDevice.DisplayMode.Width;
GraphicsHeight = GraphicsDevice.DisplayMode.Height;
break;
case WindowMode.Windowed:
GraphicsWidth = Math.Min(GraphicsDevice.DisplayMode.Width, GraphicsWidth);
GraphicsHeight = Math.Min(GraphicsDevice.DisplayMode.Height, GraphicsHeight);
break;
}
GraphicsDeviceManager.GraphicsProfile = GfxProfile;
GraphicsDeviceManager.PreferredBackBufferFormat = SurfaceFormat.Color;
GraphicsDeviceManager.PreferMultiSampling = false;
GraphicsDeviceManager.SynchronizeWithVerticalRetrace = Config.VSyncEnabled;
SetWindowMode(Config.WindowMode);
defaultViewport = GraphicsDevice.Viewport;
ResolutionChanged?.Invoke();
}
public void SetWindowMode(WindowMode windowMode)
{
WindowMode = windowMode;
GraphicsDeviceManager.HardwareModeSwitch = Config.WindowMode != WindowMode.BorderlessWindowed;
GraphicsDeviceManager.IsFullScreen = Config.WindowMode == WindowMode.Fullscreen || Config.WindowMode == WindowMode.BorderlessWindowed;
Window.IsBorderless = !GraphicsDeviceManager.HardwareModeSwitch;
GraphicsDeviceManager.PreferredBackBufferWidth = GraphicsWidth;
GraphicsDeviceManager.PreferredBackBufferHeight = GraphicsHeight;
GraphicsDeviceManager.ApplyChanges();
if (windowMode == WindowMode.BorderlessWindowed)
{
GraphicsWidth = GraphicsDevice.PresentationParameters.Bounds.Width;
GraphicsHeight = GraphicsDevice.PresentationParameters.Bounds.Height;
GraphicsDevice.Viewport = new Viewport(0,0,GraphicsWidth,GraphicsHeight);
GraphicsDevice.ScissorRectangle = new Rectangle(0,0,GraphicsWidth,GraphicsHeight);
GraphicsDeviceManager.PreferredBackBufferWidth = GraphicsWidth;
GraphicsDeviceManager.PreferredBackBufferHeight = GraphicsHeight;
GraphicsDeviceManager.ApplyChanges();
}
}
public void ResetViewPort()
{
GraphicsDevice.Viewport = defaultViewport;
}
///
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
///
protected override void Initialize()
{
base.Initialize();
ApplyGraphicsSettings();
ScissorTestEnable = new RasterizerState() { ScissorTestEnable = true };
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(typeof(Character));
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(typeof(Item));
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(typeof(Items.Components.ItemComponent));
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(typeof(Hull));
}
///
/// LoadContent will be called once per game and is the place to load
/// all of your content.
///
protected override void LoadContent()
{
GraphicsWidth = GraphicsDevice.Viewport.Width;
GraphicsHeight = GraphicsDevice.Viewport.Height;
ApplyGraphicsSettings();
ConvertUnits.SetDisplayUnitToSimUnitRatio(Physics.DisplayToSimRation);
spriteBatch = new SpriteBatch(GraphicsDevice);
TextureLoader.Init(GraphicsDevice);
//do this here because we need it for the loading screen
WaterRenderer.Instance = new WaterRenderer(base.GraphicsDevice, Content);
Quad.Init(GraphicsDevice);
loadingScreenOpen = true;
TitleScreen = new LoadingScreen(GraphicsDevice)
{
WaitForLanguageSelection = Config.ShowLanguageSelectionPrompt
};
bool canLoadInSeparateThread = true;
loadingCoroutine = CoroutineManager.StartCoroutine(Load(canLoadInSeparateThread), "Load", canLoadInSeparateThread);
}
private void InitUserStats()
{
return;
if (GameSettings.ShowUserStatisticsPrompt)
{
if (TextManager.ContainsTag("statisticspromptheader") && TextManager.ContainsTag("statisticsprompttext"))
{
var userStatsPrompt = new GUIMessageBox(
TextManager.Get("statisticspromptheader"),
TextManager.Get("statisticsprompttext"),
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
userStatsPrompt.Buttons[0].OnClicked += (btn, userdata) =>
{
GameSettings.ShowUserStatisticsPrompt = false;
GameSettings.SendUserStatistics = true;
GameAnalyticsManager.Init();
Config.SaveNewPlayerConfig();
return true;
};
userStatsPrompt.Buttons[0].OnClicked += userStatsPrompt.Close;
userStatsPrompt.Buttons[1].OnClicked += (btn, userdata) =>
{
GameSettings.ShowUserStatisticsPrompt = false;
GameSettings.SendUserStatistics = false;
Config.SaveNewPlayerConfig();
return true;
};
userStatsPrompt.Buttons[1].OnClicked += userStatsPrompt.Close;
}
else
{
//user statistics enabled by default if the prompt cannot be shown in the user's language
GameSettings.ShowUserStatisticsPrompt = false;
GameSettings.SendUserStatistics = true;
GameAnalyticsManager.Init();
Config.SaveNewPlayerConfig();
}
}
else if (GameSettings.SendUserStatistics)
{
GameAnalyticsManager.Init();
}
}
public class LoadingException : Exception
{
public LoadingException(Exception e) : base("Loading was interrupted due to an error.", innerException: e)
{
}
}
private IEnumerable