2022-03-17 22:54:22 -07:00
using HarmonyLib ;
using Mirror ;
2022-01-14 22:54:18 -08:00
using OWML.Common ;
2020-02-10 23:03:28 +01:00
using OWML.ModHelper ;
2022-06-29 15:00:44 -07:00
using QSB.Localization ;
2021-06-04 11:31:09 +01:00
using QSB.Menus ;
2022-11-07 20:14:03 +00:00
using QSB.Messaging ;
2020-11-03 21:11:10 +00:00
using QSB.Patches ;
2022-01-18 15:50:20 -08:00
using QSB.QuantumSync ;
2022-08-07 20:02:45 +01:00
using QSB.SaveSync ;
2022-11-07 20:14:03 +00:00
using QSB.ServerSettings ;
2020-07-30 22:27:14 +02:00
using QSB.Utility ;
2021-02-18 15:36:11 +00:00
using QSB.WorldSync ;
2023-06-09 23:57:11 +01:00
using Steamworks ;
2022-02-10 04:18:30 -08:00
using System ;
2022-03-29 17:34:44 -07:00
using System.Collections.Generic ;
2022-01-28 18:37:28 -08:00
using System.IO ;
2021-12-07 15:56:08 +00:00
using System.Linq ;
2022-01-28 18:37:28 -08:00
using System.Reflection ;
2020-02-10 23:03:28 +01:00
using UnityEngine ;
2022-01-18 16:19:49 -08:00
using UnityEngine.InputSystem ;
2020-02-10 23:03:28 +01:00
2020-12-17 23:18:47 +00:00
/ *
2023-01-01 14:40:28 +00:00
Copyright ( C ) 2020 - 2023
2021-11-09 17:56:45 -08:00
Henry Pointer ( _nebula / misternebula ) ,
2021-12-19 21:19:11 -08:00
Will Corby ( JohnCorby ) ,
2021-11-09 17:56:45 -08:00
Aleksander Waage ( AmazingAlek ) ,
2020-12-19 21:14:05 +00:00
Ricardo Lopes ( Raicuparta )
2021-11-09 17:56:45 -08:00
2020-12-19 21:14:05 +00:00
This program is free software : you can redistribute it and / or
modify it under the terms of the GNU Affero General Public License
as published by the Free Software Foundation , either version 3 of
the License , or ( at your option ) any later version .
This program 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 Affero General Public License for more details .
You should have received a copy of the GNU Affero General Public License along with this program . If not , see https : //www.gnu.org/licenses/.
2022-05-22 07:13:38 +01:00
This work is unofficial Fan Content created under permission from the Mobius Digital Fan Content Policy .
It includes materials which are the property of Mobius Digital and it is neither approved nor endorsed by Mobius Digital .
2020-12-17 23:18:47 +00:00
* /
2022-03-02 19:46:33 -08:00
namespace QSB ;
public class QSBCore : ModBehaviour
2020-02-15 20:48:02 +01:00
{
2022-03-02 19:46:33 -08:00
public static IModHelper Helper { get ; private set ; }
public static string DefaultServerIP ;
public static AssetBundle NetworkAssetBundle { get ; private set ; }
public static AssetBundle ConversationAssetBundle { get ; private set ; }
public static AssetBundle DebugAssetBundle { get ; private set ; }
2023-02-10 12:01:19 +00:00
public static AssetBundle HUDAssetBundle { get ; private set ; }
2022-03-02 19:46:33 -08:00
public static bool IsHost = > NetworkServer . active ;
2022-07-22 13:39:00 +01:00
public static bool IsInMultiplayer ;
2022-03-25 19:38:33 -07:00
public static string QSBVersion = > Helper . Manifest . Version ;
2022-03-17 22:54:22 -07:00
public static string GameVersion = >
// ignore the last patch numbers like the title screen does
Application . version . Split ( '.' ) . Take ( 3 ) . Join ( delimiter : "." ) ;
2022-03-02 19:46:33 -08:00
public static bool DLCInstalled = > EntitlementsManager . IsDlcOwned ( ) = = EntitlementsManager . AsyncOwnershipStatus . Owned ;
2023-05-06 18:44:20 -07:00
public static bool UseKcpTransport { get ; private set ; }
2022-05-11 00:04:53 +01:00
public static bool IncompatibleModsAllowed { get ; private set ; }
2022-12-02 22:27:23 +00:00
public static bool ShowPlayerNames { get ; private set ; }
2022-11-19 01:21:28 -08:00
public static bool ShipDamage { get ; private set ; }
2023-05-06 18:44:20 -07:00
public static bool ShowExtraHUDElements { get ; private set ; }
2022-08-07 20:02:45 +01:00
public static GameVendor GameVendor { get ; private set ; } = GameVendor . None ;
public static bool IsStandalone = > GameVendor is GameVendor . Epic or GameVendor . Steam ;
public static IProfileManager ProfileManager = > IsStandalone
? QSBStandaloneProfileManager . SharedInstance
: QSBMSStoreProfileManager . SharedInstance ;
2022-03-02 19:46:33 -08:00
public static IMenuAPI MenuApi { get ; private set ; }
public static DebugSettings DebugSettings { get ; private set ; } = new ( ) ;
2022-11-11 14:42:04 +00:00
public const string NEW_HORIZONS = "xen.NewHorizons" ;
public const string NEW_HORIZONS_COMPAT = "xen.NHQSBCompat" ;
2022-06-13 10:18:44 -07:00
public static readonly string [ ] IncompatibleMods =
2022-05-11 00:04:53 +01:00
{
// incompatible mods
"Raicuparta.NomaiVR" ,
2022-10-06 18:54:57 -07:00
// "xen.NewHorizons",
2022-08-13 12:18:53 +01:00
"Vesper.AutoResume" ,
"Vesper.OuterWildsMMO" ,
"_nebula.StopTime" ,
"PacificEngine.OW_Randomizer" ,
2022-05-11 00:04:53 +01:00
} ;
2022-08-07 20:02:45 +01:00
private static void DetermineGameVendor ( )
{
var gameAssemblyTypes = typeof ( AstroObject ) . Assembly . GetTypes ( ) ;
var isEpic = gameAssemblyTypes . Any ( x = > x . Name = = "EpicEntitlementRetriever" ) ;
var isSteam = gameAssemblyTypes . Any ( x = > x . Name = = "SteamEntitlementRetriever" ) ;
var isUWP = gameAssemblyTypes . Any ( x = > x . Name = = "MSStoreEntitlementRetriever" ) ;
if ( isEpic & & ! isSteam & & ! isUWP )
{
GameVendor = GameVendor . Epic ;
}
else if ( ! isEpic & & isSteam & & ! isUWP )
{
GameVendor = GameVendor . Steam ;
}
else if ( ! isEpic & & ! isSteam & & isUWP )
{
GameVendor = GameVendor . Gamepass ;
}
else
{
// ???
DebugLog . ToConsole ( $"FATAL - Could not determine game vendor." , MessageType . Fatal ) ;
}
2023-06-09 23:57:11 +01:00
DebugLog . ToConsole ( $"Determined game vendor as {GameVendor}" , MessageType . Info ) ;
2022-08-07 20:02:45 +01:00
}
2023-06-09 23:57:11 +01:00
private bool _steamworksInitialized ;
2022-03-02 19:46:33 -08:00
public void Awake ( )
2020-12-02 21:29:53 +00:00
{
2022-06-30 10:20:36 +01:00
// no, we cant localize this - languages are loaded after the splash screen
2022-06-08 21:57:16 +01:00
UIHelper . ReplaceUI ( UITextType . PleaseUseController ,
"<color=orange>Quantum Space Buddies</color> is best experienced with friends..." ) ;
2022-08-07 20:02:45 +01:00
DetermineGameVendor ( ) ;
QSBPatchManager . Init ( ) ;
QSBPatchManager . DoPatchType ( QSBPatchTypes . OnModStart ) ;
2023-06-09 23:57:11 +01:00
if ( GameVendor ! = GameVendor . Steam )
{
DebugLog . ToConsole ( $"Not steam, initializing Steamworks..." ) ;
if ( ! Packsize . Test ( ) )
{
DebugLog . ToConsole ( "[Steamworks.NET] Packsize Test returned false, the wrong version of Steamworks.NET is being run in this platform." , MessageType . Error ) ;
}
if ( ! DllCheck . Test ( ) )
{
DebugLog . ToConsole ( "[Steamworks.NET] DllCheck Test returned false, One or more of the Steamworks binaries seems to be the wrong version." , MessageType . Error ) ;
}
2023-06-10 00:33:30 +01:00
// from facepunch.steamworks SteamClient.cs
Environment . SetEnvironmentVariable ( "SteamAppId" , "480" ) ;
Environment . SetEnvironmentVariable ( "SteamGameId" , "480" ) ;
2023-06-09 23:57:11 +01:00
if ( ! SteamAPI . Init ( ) )
{
DebugLog . ToConsole ( $"FATAL - SteamAPI.Init() failed. Refer to Valve's documentation." , MessageType . Fatal ) ;
}
_steamworksInitialized = true ;
}
2023-06-10 01:18:17 +01:00
else
{
DebugLog . ToConsole ( $"Is steam - overriding AppID" ) ;
OverrideAppId ( ) ;
}
}
public void OverrideAppId ( )
{
SteamManager . s_EverInitialized = false ;
var instance = SteamManager . s_instance ;
instance . m_bInitialized = false ;
SteamManager . s_instance = null ;
SteamAPI . Shutdown ( ) ;
2023-06-10 01:42:26 +01:00
Environment . SetEnvironmentVariable ( "SteamAppId" , "480" ) ;
Environment . SetEnvironmentVariable ( "SteamGameId" , "480" ) ;
2023-06-10 01:18:17 +01:00
instance . InitializeOnAwake ( ) ;
2023-06-09 18:41:04 -07:00
// TODO also reregister hook and gamepad thing or else i think that wont work
2023-06-09 23:57:11 +01:00
}
public void OnDestroy ( )
{
if ( _steamworksInitialized )
{
SteamAPI . Shutdown ( ) ;
}
2022-03-02 19:46:33 -08:00
}
public void Start ( )
{
Helper = ModHelper ;
DebugLog . ToConsole ( $"* Start of QSB version {QSBVersion} - authored by {Helper.Manifest.Author}" , MessageType . Info ) ;
2020-02-10 23:03:28 +01:00
2022-11-11 14:42:04 +00:00
CheckCompatibilityMods ( ) ;
2022-03-02 19:46:33 -08:00
DebugSettings = Helper . Storage . Load < DebugSettings > ( "debugsettings.json" ) ? ? new DebugSettings ( ) ;
if ( DebugSettings . HookDebugLogs )
2022-02-27 04:40:44 -08:00
{
2022-03-02 19:46:33 -08:00
Application . logMessageReceived + = ( condition , stackTrace , logType ) = >
2022-03-09 15:22:41 -08:00
DebugLog . ToConsole (
$"[Debug] {condition}" +
( stackTrace ! = string . Empty ? $"\nStacktrace: {stackTrace}" : string . Empty ) ,
logType switch
{
LogType . Error = > MessageType . Error ,
LogType . Assert = > MessageType . Error ,
LogType . Warning = > MessageType . Warning ,
LogType . Log = > MessageType . Message ,
LogType . Exception = > MessageType . Error ,
_ = > throw new ArgumentOutOfRangeException ( nameof ( logType ) , logType , null )
}
) ;
2022-02-27 04:40:44 -08:00
}
2020-12-02 18:40:38 +00:00
2022-06-07 10:44:56 -07:00
if ( DebugSettings . AutoStart )
{
2023-05-06 18:44:20 -07:00
UseKcpTransport = true ;
2022-06-07 10:44:56 -07:00
DebugSettings . DebugMode = true ;
}
2022-04-01 16:23:15 -07:00
RegisterAddons ( ) ;
InitAssemblies ( ) ;
2022-03-02 19:46:33 -08:00
2022-12-14 11:47:01 +00:00
// init again to get addon patches
QSBPatchManager . Init ( ) ;
2022-06-29 15:20:26 -07:00
MenuApi = ModHelper . Interaction . TryGetModApi < IMenuAPI > ( ModHelper . Manifest . Dependencies [ 0 ] ) ;
2022-03-02 19:46:33 -08:00
2022-06-29 15:20:15 -07:00
DebugLog . DebugWrite ( "loading qsb_network_big bundle" , MessageType . Info ) ;
var path = Path . Combine ( ModHelper . Manifest . ModFolderPath , "AssetBundles/qsb_network_big" ) ;
2022-03-04 05:15:54 -08:00
var request = AssetBundle . LoadFromFileAsync ( path ) ;
2022-06-29 15:20:15 -07:00
request . completed + = _ = > DebugLog . DebugWrite ( "qsb_network_big bundle loaded" , MessageType . Success ) ;
2022-03-04 05:15:54 -08:00
2022-06-29 15:20:15 -07:00
NetworkAssetBundle = Helper . Assets . LoadBundle ( "AssetBundles/qsb_network" ) ;
ConversationAssetBundle = Helper . Assets . LoadBundle ( "AssetBundles/qsb_conversation" ) ;
DebugAssetBundle = Helper . Assets . LoadBundle ( "AssetBundles/qsb_debug" ) ;
2023-02-10 12:01:19 +00:00
HUDAssetBundle = Helper . Assets . LoadBundle ( "AssetBundles/qsb_hud" ) ;
2022-03-02 19:46:33 -08:00
2022-06-30 16:50:23 +01:00
if ( NetworkAssetBundle = = null | | ConversationAssetBundle = = null | | DebugAssetBundle = = null )
{
DebugLog . ToConsole ( $"FATAL - An assetbundle is missing! Re-install mod or contact devs." , MessageType . Fatal ) ;
return ;
}
2022-04-22 20:00:52 -07:00
DeterministicManager . Init ( ) ;
2022-06-08 14:00:37 -07:00
QSBLocalization . Init ( ) ;
2022-03-02 19:46:33 -08:00
var components = typeof ( IAddComponentOnStart ) . GetDerivedTypes ( )
. Select ( x = > gameObject . AddComponent ( x ) )
. ToArray ( ) ;
QSBWorldSync . Managers = components . OfType < WorldObjectManager > ( ) . ToArray ( ) ;
QSBPatchManager . OnPatchType + = OnPatchType ;
QSBPatchManager . OnUnpatchType + = OnUnpatchType ;
}
private static void OnPatchType ( QSBPatchTypes type )
{
if ( type = = QSBPatchTypes . OnClientConnect )
2021-02-18 15:36:11 +00:00
{
2022-03-02 19:46:33 -08:00
Application . runInBackground = true ;
2021-07-13 18:46:31 +01:00
}
2022-03-02 19:46:33 -08:00
}
2021-02-21 18:25:25 +00:00
2022-03-02 19:46:33 -08:00
private static void OnUnpatchType ( QSBPatchTypes type )
{
if ( type = = QSBPatchTypes . OnClientConnect )
2021-07-13 18:46:31 +01:00
{
2022-03-02 19:46:33 -08:00
Application . runInBackground = false ;
2021-02-18 15:36:11 +00:00
}
2022-03-02 19:46:33 -08:00
}
2021-02-18 15:36:11 +00:00
2022-04-01 16:23:15 -07:00
public static readonly SortedDictionary < string , IModBehaviour > Addons = new ( ) ;
2022-06-13 10:18:44 -07:00
private void RegisterAddons ( )
2022-03-02 19:46:33 -08:00
{
2022-06-13 10:18:44 -07:00
var addons = GetDependants ( ) ;
2022-04-01 16:23:15 -07:00
foreach ( var addon in addons )
{
2022-12-14 11:47:01 +00:00
DebugLog . DebugWrite ( $"Registering addon {addon.ModHelper.Manifest.UniqueName}" ) ;
2022-04-01 16:23:15 -07:00
Addons . Add ( addon . ModHelper . Manifest . UniqueName , addon ) ;
}
}
private static void InitAssemblies ( )
{
static void Init ( Assembly assembly )
2022-01-28 18:37:28 -08:00
{
2022-03-02 19:46:33 -08:00
DebugLog . DebugWrite ( assembly . ToString ( ) ) ;
assembly
. GetTypes ( )
. SelectMany ( x = > x . GetMethods ( BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Static | BindingFlags . DeclaredOnly ) )
. Where ( x = > x . IsDefined ( typeof ( RuntimeInitializeOnLoadMethodAttribute ) ) )
. ForEach ( x = > x . Invoke ( null , null ) ) ;
2022-01-28 18:37:28 -08:00
}
2022-04-01 16:23:15 -07:00
DebugLog . DebugWrite ( "Running RuntimeInitializeOnLoad methods for our assemblies" , MessageType . Info ) ;
foreach ( var path in Directory . EnumerateFiles ( Helper . Manifest . ModFolderPath , "*.dll" ) )
{
var assembly = Assembly . LoadFile ( path ) ;
Init ( assembly ) ;
}
foreach ( var addon in Addons . Values )
{
var assembly = addon . GetType ( ) . Assembly ;
Init ( assembly ) ;
}
2022-03-02 19:46:33 -08:00
DebugLog . DebugWrite ( "Assemblies initialized" , MessageType . Success ) ;
}
2022-01-18 15:50:20 -08:00
2022-05-11 00:04:53 +01:00
public override void Configure ( IModConfig config )
{
2023-05-06 20:05:54 -07:00
UseKcpTransport = config . GetSettingsValue < bool > ( "useKcpTransport" ) | | DebugSettings . AutoStart ;
2023-05-06 20:05:55 -07:00
QSBNetworkManager . UpdateTransport ( ) ;
2023-05-06 18:44:20 -07:00
2022-05-11 00:04:53 +01:00
DefaultServerIP = config . GetSettingsValue < string > ( "defaultServerIP" ) ;
IncompatibleModsAllowed = config . GetSettingsValue < bool > ( "incompatibleModsAllowed" ) ;
2022-12-02 22:27:23 +00:00
ShowPlayerNames = config . GetSettingsValue < bool > ( "showPlayerNames" ) ;
ShipDamage = config . GetSettingsValue < bool > ( "shipDamage" ) ;
2023-03-03 20:05:15 +00:00
ShowExtraHUDElements = config . GetSettingsValue < bool > ( "showExtraHud" ) ;
2022-12-02 22:27:23 +00:00
if ( IsHost )
2022-11-07 20:14:03 +00:00
{
2022-12-02 22:27:23 +00:00
ServerSettingsManager . ServerShowPlayerNames = ShowPlayerNames ;
new ServerSettingsMessage ( ) . Send ( ) ;
2022-11-07 20:14:03 +00:00
}
2022-05-11 00:04:53 +01:00
}
2022-03-02 19:46:33 -08:00
private void Update ( )
{
2022-09-10 22:43:11 -07:00
if ( Keyboard . current [ Key . Q ] . isPressed & & Keyboard . current [ Key . NumpadEnter ] . wasPressedThisFrame )
2022-01-18 15:50:20 -08:00
{
2022-03-02 19:46:33 -08:00
DebugSettings . DebugMode = ! DebugSettings . DebugMode ;
2022-01-18 15:50:20 -08:00
2022-03-02 19:46:33 -08:00
GetComponent < DebugActions > ( ) . enabled = DebugSettings . DebugMode ;
2022-03-19 21:09:39 -07:00
GetComponent < DebugGUI > ( ) . enabled = DebugSettings . DebugMode ;
2022-03-02 19:46:33 -08:00
QuantumManager . UpdateFromDebugSetting ( ) ;
DebugCameraSettings . UpdateFromDebugSetting ( ) ;
2022-01-18 15:50:20 -08:00
2022-03-02 19:46:33 -08:00
DebugLog . ToConsole ( $"DEBUG MODE = {DebugSettings.DebugMode}" ) ;
2022-01-18 15:50:20 -08:00
}
2023-06-09 23:57:11 +01:00
if ( _steamworksInitialized )
{
SteamAPI . RunCallbacks ( ) ;
}
2020-12-02 21:29:53 +00:00
}
2022-11-11 14:42:04 +00:00
private void CheckCompatibilityMods ( )
{
var mainMod = "" ;
var compatMod = "" ;
var missingCompat = false ;
if ( Helper . Interaction . ModExists ( NEW_HORIZONS ) & & ! Helper . Interaction . ModExists ( NEW_HORIZONS_COMPAT ) )
{
mainMod = NEW_HORIZONS ;
compatMod = NEW_HORIZONS_COMPAT ;
missingCompat = true ;
}
if ( missingCompat )
{
DebugLog . ToConsole ( $"FATAL - You have mod \" { mainMod } \ " installed, which is not compatible with QSB without the compatibility mod \"{compatMod}\". " +
$"Either disable the mod, or install/enable the compatibility mod." , MessageType . Fatal ) ;
}
}
2021-06-18 21:54:32 +01:00
}
/ *
* _nebula ' s music thanks
* I listen to music constantly while programming / working - here ' s my thanks to them for keeping me entertained : P
2021-11-09 17:56:45 -08:00
*
2021-06-18 21:54:32 +01:00
* Wintergatan
* HOME
* C418
* Lupus Nocte
* Max Cooper
* Darren Korb
* Harry Callaghan
* Toby Fox
* Andrew Prahlow
* Valve ( Mike Morasky , Kelly Bailey )
* Joel Nielsen
* Vulfpeck
* Detektivbyrån
* Ben Prunty
* ConcernedApe
* Jake Chudnow
* Murray Gold
* Teleskärm
2021-06-23 16:46:08 +01:00
* Daft Punk
2021-07-19 21:01:41 +01:00
* Natalie Holt
2021-08-17 10:02:19 +01:00
* WMD
2022-04-29 21:52:20 +01:00
* Woody Jackson
2022-04-29 21:47:16 +01:00
* Brian David Gilbert
2022-02-26 02:06:18 -08:00
* /