Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F118366
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
56 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/scripts/menu/main_menu.as b/scripts/menu/main_menu.as
index ccf6fdb..c36d1ac 100644
--- a/scripts/menu/main_menu.as
+++ b/scripts/menu/main_menu.as
@@ -1,343 +1,342 @@
import menus;
import settings.game_settings;
from new_game import showNewGame;
from multiplayer_menu import showMultiplayer;
from irc_window import openIRC, closeIRC, LinkableMarkupText;
import dialogs.QuestionDialog;
import icons;
// TODO: Switch this out once we fix multiple starts.
const bool M_BROKEN = false;
enum MenuActions {
MA_NewGame,
MA_EndGame,
MA_Tutorial,
MA_Campaign,
MA_LoadGame,
MA_SaveGame,
MA_Options,
MA_Resume,
MA_Quit,
MA_OpenIRC,
MA_CloseIRC,
MA_Multiplayer,
MA_Disconnect,
MA_Sandbox,
MA_Update,
MA_Mods,
};
-class MainMenu : MenuBox {
MenuNews news;
MainMenu() {
super();
}
void buildMenu() {
if(game_running && gameSpeed == 0)
title.text = locale::PAUSED_MENU;
else
title.text = locale::MAIN_MENU;
if(game_running) {
if(gameSpeed == 0 && settings::bMenuPause)
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 10), locale::RESUME_GAME, MA_Resume));
else
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 10), locale::RETURN_TO_GAME, MA_Resume));
}
if(mpClient)
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 8), locale::DISCONNECT, MA_Disconnect));
else if(game_running)
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 8), locale::END_GAME, MA_EndGame));
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 3), locale::TUTORIAL, MA_Tutorial));
//items.addItem(MenuAction(Sprite(material::TabPlanets), locale::CAMPAIGN, MA_Campaign));
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 0), locale::NEW_GAME, MA_NewGame));
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 1), locale::LOAD_GAME, MA_LoadGame));
if(game_running && !mpClient)
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 2), locale::SAVE_GAME, MA_SaveGame));
items.addItem(MenuAction(Sprite(spritesheet::ResourceIconsSmall, 46), locale::MODS_MENU, MA_Mods));
- if(!game_running && !STEAM_EQUIV_BUILD)
- items.addItem(MenuAction(icons::Refresh, locale::CHECK_FOR_UPDATES, MA_Update));
+ //if(!game_running && !STEAM_EQUIV_BUILD)
+ //items.addItem(MenuAction(icons::Refresh, locale::CHECK_FOR_UPDATES, MA_Update));
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 4), locale::MULTIPLAYER, MA_Multiplayer));
items.addItem(MenuAction(Sprite(material::TabDesigns), locale::SANDBOX, MA_Sandbox));
if(IRC.running)
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 5), locale::CLOSE_IRC, MA_CloseIRC));
else
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 6), locale::OPEN_IRC, MA_OpenIRC));
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 7), locale::MENU_OPTIONS, MA_Options));
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 8), locale::QUIT_GAME, MA_Quit));
}
void tick(double time) {
if(!game_running && !menu_container.animating && menu_container.visible) {
if(mpIsConnected())
showNewGame(true);
else if(mpIsConnecting() || cloud::queueRequest)
showMultiplayer();
}
}
void startTutorial() {
GameSettings settings;
settings.defaults();
settings.galaxies[0].map_id = "Tutorial.Tutorial";
Message msg;
settings.write(msg);
if(topMod !is baseMod) {
array<string> basemods = {"base"};
switchToMods(basemods);
}
startNewGame(msg);
}
void startSandbox() {
GameSettings settings;
settings.defaults();
settings.galaxies[0].map_id = "Sandbox.Sandbox";
Message msg;
settings.write(msg);
startNewGame(msg);
}
void _stopGame() {
stopGame();
refresh();
}
void animate(MenuAnimation type) {
if(type == MAni_LeftOut || type == MAni_RightOut)
showDescBox(null);
MenuBox::animate(type);
}
void completeAnimation(MenuAnimation type) {
if(type == MAni_LeftShow || type == MAni_RightShow)
showDescBox(news);
MenuBox::completeAnimation(type);
}
void onSelected(const string& name, int value) {
switch(value) {
case MA_Resume:
switchToGame();
break;
case MA_NewGame:
showNewGame();
break;
case MA_Tutorial:
if(game_running)
question(locale::PROMPT_TUTORIAL, ConfirmChoice(MenuChoice(this.startTutorial)));
else
startTutorial();
break;
case MA_Campaign:
switchToMenu(campaign_menu);
break;
case MA_Sandbox:
if(game_running)
question(locale::PROMPT_SANDBOX, ConfirmChoice(MenuChoice(this.startSandbox)));
else
startSandbox();
break;
case MA_Options:
switchToMenu(options_menu);
break;
case MA_LoadGame:
switchToMenu(load_menu);
break;
case MA_SaveGame:
switchToMenu(save_menu);
break;
case MA_Mods:
switchToMenu(mods_menu);
break;
case MA_EndGame:
if(game_running)
question(locale::PROMPT_END, ConfirmChoice(MenuChoice(this._stopGame)));
else
_stopGame();
break;
case MA_Disconnect:
if(game_running)
question(locale::PROMPT_DISCONNECT, ConfirmChoice(MenuChoice(this._stopGame)));
else {
mpDisconnect();
_stopGame();
}
break;
case MA_OpenIRC:
if(!IRC.running) {
IRC.nickname = settings::sNickname;
IRC.connect();
openIRC();
refresh();
}
break;
case MA_CloseIRC:
if(IRC.running) {
IRC.disconnect();
closeIRC();
refresh();
}
break;
case MA_Quit:
if(game_running)
question(locale::PROMPT_QUIT, ConfirmChoice(quitGame));
else
quitGame();
break;
case MA_Multiplayer:
showMultiplayer();
break;
case MA_Update:
checkForUpdates();
break;
}
}
};
funcdef void MenuChoice();
class ConfirmChoice : QuestionDialogCallback {
MenuChoice@ choice;
ConfirmChoice(MenuChoice@ Choice) {
@choice = Choice;
}
void questionCallback(QuestionDialog@ dialog, int answer) {
if(answer == QA_Yes)
choice();
}
};
class MenuNews : DescBox {
GuiPanel@ newsPanel;
LinkableMarkupText@ newsText;
WebData wdata;
bool shown = false;
GuiPanel@ modsPanel;
GuiMarkupText@ modsText;
GuiButton@ modsButton;
GuiButton@ workshopButton;
GuiButton@ internetButton;
MenuNews() {
@newsPanel = GuiPanel(this, Alignment(Left, Top, Right, Bottom-100));
@newsText = LinkableMarkupText(newsPanel, recti_area(12,12,100,100));
newsText.text = "...";
newsText.paragraphize = true;
@modsPanel = GuiPanel(this, Alignment(Left, Bottom-88, Right, Bottom));
@modsText = GuiMarkupText(modsPanel, Alignment(Left+12, Top+12, Right-12, Bottom-52));
modsText.defaultFont = FT_Bold;
@modsButton = GuiButton(modsPanel, Alignment(Left+0.5f-204, Bottom-50, Width=200, Height=40), locale::MANAGE_MODS);
modsButton.buttonIcon = Sprite(spritesheet::ResourceIconsSmall, 46);
@workshopButton = GuiButton(modsPanel, Alignment(Left+0.5f+4, Bottom-50, Width=200, Height=40), locale::OPEN_WORKSHOP);
workshopButton.buttonIcon = icons::Import;
@internetButton = GuiButton(newsPanel, Alignment(Left+0.5f-200, Top+0.5f-30, Left+0.5f+200, Top+0.5f+30), locale::ENABLE_INTERNET);
internetButton.visible = false;
if(cloud::isActive) {
settings::bEnableInternet = true;
}
else {
workshopButton.visible = false;
modsButton.alignment.left.pixels += 104;
}
if(settings::bEnableInternet) {
getWikiPage("News", wdata);
}
else {
internetButton.visible = true;
newsText.text = "[font=Medium]News[/font]";
shown = true;
}
refresh();
updateAbsolutePosition();
}
void updateAbsolutePosition() {
DescBox::updateAbsolutePosition();
if(newsText !is null)
newsText.size = vec2i(newsPanel.size.width-24, newsText.renderer.height+10);
}
void refresh() {
uint installed = 0;
uint enabled = 0;
for(uint i = 0, cnt = modCount; i < cnt; ++i) {
auto@ mod = getMod(i);
if(!mod.listed)
continue;
installed += 1;
if(mod.enabled)
enabled += 1;
}
modsText.text = format("[center]"+locale::MENU_MOD_COUNTS+"[/center]", toString(installed), toString(enabled));
}
bool onGuiEvent(const GuiEvent& evt) override {
if(evt.type == GUI_Clicked) {
if(evt.caller is modsButton) {
switchToMenu(mods_menu);
return true;
}
else if(evt.caller is workshopButton) {
openBrowser("http://steamcommunity.com/app/282590/workshop/");
return true;
}
else if(evt.caller is internetButton) {
internetButton.visible = false;
shown = false;
getWikiPage("News", wdata);
settings::bEnableInternet = true;
saveSettings();
return true;
}
}
return DescBox::onGuiEvent(evt);
}
void show() {
DescBox::show();
refresh();
}
void draw() {
if(!shown && wdata.completed) {
string result = wdata.result;
newsText.text = result;
shown = true;
updateAbsolutePosition();
}
skin.draw(SS_PlainBox, SF_Normal, newsPanel.AbsolutePosition, Color(0xffffffff));
skin.draw(SS_PlainBox, SF_Normal, modsPanel.AbsolutePosition, Color(0xffffffff));
BaseGuiElement::draw();
}
};
void init() {
MainMenu menu;
@main_menu = menu;
showDescBox(menu.news);
switchToMenu(menu);
}
diff --git a/source/game/main/initialization.cpp b/source/game/main/initialization.cpp
index c4e7b3d..b3be41c 100644
--- a/source/game/main/initialization.cpp
+++ b/source/game/main/initialization.cpp
@@ -1,1726 +1,1731 @@
#include "util/random.h"
#include "util/threaded_loader.h"
#include "util/name_generator.h"
#include "render/gl_driver.h"
#include "render/lighting.h"
#include "main/profiler.h"
#include "main/initialization.h"
#include "main/logging.h"
#include "main/input_handling.h"
#include "main/version.h"
#include "main/references.h"
#include "main/console.h"
#include "main/game_platform.h"
#include "os/glfw_driver.h"
#include "scripts/manager.h"
#include "scripts/binds.h"
#include "scripts/context_cache.h"
#include "scripts/script_components.h"
#include "constants.h"
#include "files.h"
#include "threads.h"
#include "processing.h"
#include "general_states.h"
#include "empire.h"
#include "empire_stats.h"
#include "scene/node.h"
#include "scene/mesh_node.h"
#include "scene/plane_node.h"
#include "scene/billboard_node.h"
#include "scene/animation/anim_node_sync.h"
#include "scene/scripted_node.h"
#include "obj/universe.h"
#include "obj/lock.h"
#include "as/as_jit.h"
#include "design/hull.h"
#include "design/design.h"
#include "design/subsystem.h"
#include "design/effect.h"
#include "design/projectiles.h"
#include "ISoundDevice.h"
#include "network/network_manager.h"
#include "str_util.h"
#include "physics/physics_world.h"
#include "util/save_file.h"
#include "save_load.h"
#include "render/lighting.h"
#include <stdio.h>
#include <fstream>
namespace scripts {
void processEvents();
};
#ifdef _WIN32
#define USE_JIT
#endif
#ifdef __i386__
#define USE_JIT
#endif
#ifdef __amd64__
#define USE_JIT
#endif
GameConfig gameConfig;
bool create_window = true;
bool load_resources = true;
bool watch_resources = false;
bool monitor_files = false;
bool use_sound = true;
bool use_steam = true;
bool isLoadedGame = false;
int SAVE_VERSION = -1, START_VERSION = -1;
bool gameEnding = false;
bool fullscreen = false;
bool cancelAssets = false;
#ifdef USE_JIT
bool useJIT = true;
#else
bool useJIT = false;
#endif
std::string loadSaveName;
std::unordered_set<std::string> dlcList;
//Poor mans steam-independent DLC checks
bool hasDLC(const std::string& name) {
return dlcList.find(name) != dlcList.end();
}
void checkDLC(const std::string& name, const std::string& hashname) {
- std::string fname("data/dlc/");
- fname += hashname;
- if(fileExists(fname) || (devices.cloud && devices.cloud->hasDLC(name)))
- dlcList.insert(name);
+ //std::string fname("data/dlc/");
+ //fname += hashname;
+ //if(fileExists(fname) || (devices.cloud && devices.cloud->hasDLC(name)))
+
+ // Open source version always has DLC
+ dlcList.insert(name);
}
void checkDLC() {
dlcList.clear();
- checkDLC("Heralds", "bb8280a0fdc547ddbd8d3ae3f9242a14");
+ checkDLC("Heralds", "");
}
void checkCloudDLC(const std::string& name, const std::string& hashname) {
- std::string fname("data/dlc/");
+ /*std::string fname("data/dlc/");
fname += hashname;
if(devices.cloud->hasDLC(name)) {
if(!fileExists(fname)) {
makeDirectory("data/dlc/");
std::fstream file(fname, std::ios_base::out | std::ios_base::binary);
file << "\n";
file.close();
}
dlcList.insert("Heralds");
}
else {
if(fileExists(fname))
remove(fname.c_str());
dlcList.erase(name);
- }
+ }*/
+
+ // Open source version always has DLC
+ dlcList.insert(name);
}
void checkCloudDLC() {
if(!devices.cloud)
return;
- checkCloudDLC("Heralds", "bb8280a0fdc547ddbd8d3ae3f9242a14");
+ checkCloudDLC("Heralds", "");
}
extern const render::Shader* fsShader;
extern std::set<std::string> validPaths;
extern void prepareShaderStateVars();
extern void clearShaderStateVars();
int threadCount;
extern bool queuedModSwitch;
extern std::vector<std::string> modSetup;
template<resource::ResourceType type>
void loadLibraryFile(const std::string& path) {
devices.library.load(type, path);
}
#define libraryDir(dir, type) devices.mods.listFiles(dir, "*.txt", loadLibraryFile<type>);
bool processQueuedMeshes();
asCJITCompiler* makeJITCompiler() {
#ifdef USE_JIT
if(!useJIT)
return 0;
unsigned flags = 0;
#ifndef PROFILE_EXECUTION
return new asCJITCompiler(flags | JIT_NO_SUSPEND | JIT_SYSCALL_FPU_NORESET | JIT_ALLOC_SIMPLE | JIT_FAST_REFCOUNT);
#else
return new asCJITCompiler(flags | JIT_SYSCALL_FPU_NORESET | JIT_ALLOC_SIMPLE | JIT_FAST_REFCOUNT);
#endif
#else
return 0;
#endif
}
void loadEngineSettings();
Threaded(std::vector<std::function<void()>>*) cleanupFunctions = 0;
threads::Mutex scriptListLock;
std::map<std::string, std::map<std::string, std::string>*> scriptfiles;
void clearScriptList() {
threads::Lock lock(scriptListLock);
for(auto i = scriptfiles.begin(), end = scriptfiles.end(); i != end; ++i)
delete i->second;
scriptfiles.clear();
}
const std::map<std::string, std::string>& findScripts(const std::string& path) {
threads::Lock lock(scriptListLock);
auto*& m = scriptfiles[path];
if(!m) {
m = new std::map<std::string, std::string>;
devices.mods.listFiles(path, *m, "*.as", true);
}
return *m;
}
void onScripts(const std::string& path, std::function<void(const std::pair<std::string,std::string>&)> f) {
auto& scripts = findScripts(path);
for(auto i = scripts.cbegin(), end = scripts.cend(); i != end; ++i)
f(*i);
}
threads::Signal scriptPreloads;
threads::threadreturn threadcall PreloadBatch(void* arg) {
std::string* pPath = (std::string*)arg;
std::string& path = *pPath;
auto preload = [](const std::pair<std::string,std::string>& file) {
if(file.second.find("/include/") == std::string::npos)
scripts::preloadScript(file.second);
};
onScripts(path, preload);
scriptPreloads.signalDown();
delete pPath;
return 0;
}
void initNewThread() {
//Start up random number generator
initRandomizer();
//Initialize thread-local script context cache
scripts::initContextCache();
}
void cleanupThread() {
scripts::freeContextCache();
asThreadCleanup();
freeRandomizer();
if(cleanupFunctions) {
foreach(it, (*cleanupFunctions))
(*it)();
delete cleanupFunctions;
cleanupFunctions = 0;
}
}
void addThreadCleanup(std::function<void()> func) {
if(!cleanupFunctions)
cleanupFunctions = new std::vector<std::function<void()>>();
cleanupFunctions->push_back(func);
}
bool initGlobal(bool loadGraphics, bool createWindow) {
//Create the sound device
try {
if(use_sound) {
print("Initializing sound");
auto* audioDevice = devices.settings.engine.getSetting("sAudioDevice");
if(audioDevice)
devices.sound = audio::createAudioDevice(audioDevice->toString().c_str());
else
devices.sound = audio::createAudioDevice();
}
if(!devices.sound)
devices.sound = audio::createDummyAudioDevice();
}
catch(const char* err) {
error("Sound Error: %s", err);
devices.sound = audio::createDummyAudioDevice();
}
devices.sound->setVolume(0.5f);
devices.sound->setRolloffFactor(1.f / 10000.f);
//Safe AS multithreading
asPrepareMultithread();
print("Initializing window system");
devices.driver = os::getGLFWDriver();
devices.driver->resetTimer();
//Load engine settings
print("Loading engine settings");
loadEngineSettings();
console.addCommand("fov", [](argList& args) {
if(devices.render && !args.empty()) {
double newFOV = toNumber<double>(args[0]);
if(newFOV > 0.1 && newFOV < 179.9)
devices.render->setFOV(newFOV);
else
console.printLn("FOV must be within 0.1 and 179.9 degrees");
}
} );
console.addCommand("vsync", [](argList& args) {
if(devices.driver) {
if(args.empty())
devices.driver->setVerticalSync(true);
else if(streq_nocase(args[0],"adaptive"))
devices.driver->setVerticalSync(-1);
else
devices.driver->setVerticalSync(toBool(args[0]));
}
} );
console.addCommand("load", [](argList& args) {
std::string savePath = devices.mods.getProfile("saves");
std::string filename = path_join(savePath, args.empty() ? "quicksave.sr2" : args[0]);
if(!match(filename.c_str(),"*.sr2"))
filename += ".sr2";
scripts::scr_loadGame(filename);
});
console.addCommand("maxfps", [](argList& args) {
extern double* maxfps;
if(!args.empty())
*maxfps = toNumber<double>(args[0]);
console.printLn(toString(maxfps,0));
} );
console.addCommand("r", [](argList& args) {
if(devices.scripts.client && !args.empty())
devices.scripts.client->reload(args[0]);
} );
if(load_resources) {
print("Initializing OpenGL Engine");
devices.render = render::createGLDriver();
}
else {
devices.render = nullptr;
}
create_window = createWindow;
load_resources = loadGraphics;
//Create network driver
devices.network = new NetworkManager();
auto* netLimit = devices.settings.engine.getSetting("iNetworkRateLimit");
net::Transport::RATE_LIMIT = (netLimit ? *netLimit : 250) * 1024;
devices.scripts.client = nullptr;
devices.scripts.server = nullptr;
devices.scripts.cache_server = nullptr;
devices.scripts.cache_shadow = nullptr;
devices.scripts.menu = nullptr;
devices.engines.client = nullptr;
devices.engines.server = nullptr;
devices.engines.menu = nullptr;
//Check marked DLCs
checkDLC();
//Add mod sources
print("Registering mods");
devices.mods.registerDirectory("mods");
devices.mods.registerDirectory(getProfileRoot() + "mods");
//Shortcut for the scene tree
if(devices.render)
devices.scene = &devices.render->rootNode;
else
devices.scene = nullptr;
devices.universe = nullptr;
//Initialize input handling
registerInput();
//Create processing queue
unsigned cpuCount = devices.driver->getProcessorCount();
threadCount = std::max(cpuCount+1,1u);
print("Starting %d threads on %d processors.", threadCount, cpuCount);
processing::start(threadCount);
return true;
}
void destroyGlobal() {
devices.network->disconnect();
delete devices.network;
asUnprepareMultithread();
devices.driver->closeWindow();
delete devices.driver;
}
void loadLocales(std::string folder, mods::Mod* mod) {
if(mod->parent != nullptr)
loadLocales(folder, mod->parent);
std::map<std::string, std::string> files;
mod->listFiles(folder, files, "*.txt", true, false);
foreach(file, files)
devices.locale.load(file->second);
}
void switchLocale(const std::string& locale) {
devices.locale.clear();
foreach(m, devices.mods.activeMods)
loadLocales("locales/english", *m);
if(locale != "english") {
std::string dirname = path_join("locales", locale);
foreach(m, devices.mods.activeMods)
loadLocales(dirname, *m);
}
}
std::string makeModuleName(const std::string& fname) {
std::string mname;
std::vector<std::string> components;
path_split(fname, components);
for(size_t i = 0, cnt = components.size() - 1; i < cnt; ++i)
mname += components[i]+".";
mname += getBasename(fname, false);
return mname;
}
static threads::Signal jitInit;
void loadServerScripts() {
std::map<std::string, std::string> scriptfiles;
double start = devices.driver->getAccurateTime();
devices.scripts.cache_server = new scripts::Manager(makeJITCompiler());
#ifdef PROFILE_LOCKS
devices.scripts.cache_server->threadedCallMutex.name = "Server Threaded Call Lock";
devices.scripts.cache_server->threadedCallMutex.observed = true;
#endif
devices.scripts.cache_server->addIncludePath("scripts/");
devices.scripts.cache_server->addIncludePath("scripts/server");
devices.scripts.cache_server->addIncludePath("scripts/shared");
devices.scripts.cache_server->addIncludePath("scripts/definitions");
devices.scripts.cache_server->addIncludePath("maps/");
scripts::RegisterServerBinds(devices.scripts.cache_server->engine);
auto load = [](const std::pair<std::string,std::string>& file) {
if(cancelAssets)
return;
if(file.second.find("/include/") != std::string::npos)
return;
devices.scripts.cache_server->load(
makeModuleName(file.first),
file.second);
};
onScripts("scripts/server", load);
onScripts("scripts/shared", load);
onScripts("scripts/definitions", load);
onScripts("maps", load);
double load_end = devices.driver->getAccurateTime();
devices.scripts.cache_server->compile(
devices.mods.getProfile("as_cache/server"),
SERVER_SCRIPT_BUILD);
double compile_end = devices.driver->getAccurateTime();
print("Server scripts: %dms load, %dms compile",
int((load_end - start) * 1000.0),
int((compile_end - load_end) * 1000.0));
}
void loadShadowScripts() {
std::map<std::string, std::string> scriptfiles;
double start = devices.driver->getAccurateTime();
devices.scripts.cache_shadow = new scripts::Manager(makeJITCompiler());
#ifdef PROFILE_LOCKS
devices.scripts.cache_shadow->threadedCallMutex.name = "Shadow Threaded Call Lock";
devices.scripts.cache_shadow->threadedCallMutex.observed = true;
#endif
devices.scripts.cache_shadow->addIncludePath("scripts/");
devices.scripts.cache_shadow->addIncludePath("scripts/shadow");
devices.scripts.cache_shadow->addIncludePath("scripts/shared");
devices.scripts.cache_shadow->addIncludePath("scripts/definitions");
devices.scripts.cache_shadow->addIncludePath("maps/");
scripts::RegisterShadowBinds(devices.scripts.cache_shadow->engine);
auto load = [](const std::pair<std::string,std::string>& file) {
if(cancelAssets)
return;
if(file.second.find("/include/") != std::string::npos)
return;
devices.scripts.cache_shadow->load(
makeModuleName(file.first),
file.second);
};
onScripts("scripts/shadow", load);
onScripts("scripts/shared", load);
onScripts("scripts/definitions", load);
onScripts("maps", load);
double load_end = devices.driver->getAccurateTime();
devices.scripts.cache_shadow->compile(
devices.mods.getProfile("as_cache/shadow"),
SERVER_SCRIPT_BUILD);
double compile_end = devices.driver->getAccurateTime();
print("Shadow scripts: %dms load, %dms compile",
int((load_end - start) * 1000.0),
int((compile_end - load_end) * 1000.0));
}
void loadClientScripts() {
std::map<std::string, std::string> scriptfiles;
double start = devices.driver->getAccurateTime();
devices.scripts.client = new scripts::Manager(makeJITCompiler());
devices.engines.client = devices.scripts.client->engine;
#ifdef PROFILE_LOCKS
devices.scripts.client->threadedCallMutex.name = "Client Threaded Call Lock";
devices.scripts.client->threadedCallMutex.observed = true;
#endif
scripts::RegisterClientBinds(devices.scripts.client->engine);
devices.scripts.client->addIncludePath("scripts/");
devices.scripts.client->addIncludePath("scripts/client");
devices.scripts.client->addIncludePath("scripts/gui");
devices.scripts.client->addIncludePath("scripts/shared");
devices.scripts.client->addIncludePath("scripts/toolkit");
devices.scripts.client->addIncludePath("scripts/definitions");
devices.scripts.client->addIncludePath("maps/");
auto load = [](const std::pair<std::string,std::string>& file) {
if(cancelAssets)
return;
if(file.second.find("/include/") != std::string::npos)
return;
devices.scripts.client->load(
makeModuleName(file.first),
file.second);
};
onScripts("scripts/client", load);
onScripts("scripts/gui", load);
onScripts("scripts/shared", load);
onScripts("scripts/toolkit", load);
onScripts("scripts/definitions", load);
onScripts("maps", load);
double load_end = devices.driver->getAccurateTime();
devices.scripts.client->compile(
devices.mods.getProfile("as_cache/client"),
CLIENT_SCRIPT_BUILD);
double compile_end = devices.driver->getAccurateTime();
print("Client scripts: %dms load, %dms compile",
int((load_end - start) * 1000.0),
int((compile_end - load_end) * 1000.0));
}
void bindScripts() {
//Bind all script binds
scripts::BindEventBinds();
bindScriptObjectTypes();
scripts::bindComponentClasses();
scene::bindScriptNodeTypes();
//We cannot actually execute things on
//the shadow, so don't try to bind things
bindEffectorHooks(devices.network->isClient);
bindSubsystemHooks();
if(!devices.network->isClient) {
bindEffectHooks();
}
}
volatile bool idleImageActive = false;
threads::threadreturn threadcall idleProcessImages(void*) {
idleImageActive = true;
while(devices.library.hasQueuedImages()) {
devices.library.processImages(INT_MIN,1);
threads::sleep(1);
}
idleImageActive = false;
return 0;
}
volatile bool idleSoundsActive = false;
threads::threadreturn threadcall idleProcessSounds(void*) {
idleSoundsActive = true;
while(devices.library.hasQueuedSounds()) {
devices.library.processSounds(INT_MIN,1);
threads::sleep(1);
}
idleSoundsActive = false;
return 0;
}
volatile bool idleHullsActive = false;
threads::threadreturn threadcall idleComputeHulls(void*) {
double tstart = devices.driver->getAccurateTime();
idleHullsActive = true;
initRandomizer();
while(!isFinishedComputingHulls() && !cancelAssets) {
computeHulls(1);
threads::sleep(1);
}
idleHullsActive = false;
double tend = devices.driver->getAccurateTime();
print("Finished computing hulls in %gms", (tend-tstart)*1000.0);
return 0;
}
bool preloading = false;
void startPreload() {
if(preloading)
return;
//Preload things for the game
Loading::prepare(5, initNewThread, cleanupThread);
Loading::addTask("ServerScripts", 0, [] {
loadServerScripts();
});
Loading::addTask("ShadowScripts", 0, [] {
loadShadowScripts();
});
Loading::addTask("ClientScripts", 0, [] {
loadClientScripts();
});
Loading::addTask("CleanupScripts", "ServerScripts,ShadowScripts,ClientScripts", [] {
clearScriptList();
scripts::clearCachedScripts();
});
Loading::addTask("ProcessImages", 0, [] {
devices.library.processImages(-10);
threads::createThread(idleProcessImages, 0);
});
Loading::addTask("ProcessSounds", 0, [] {
devices.library.processSounds(-10);
threads::createThread(idleProcessSounds, 0);
});
Loading::addTask("ComputeHulls", 0, [] {
if(load_resources)
threads::createThread(idleComputeHulls, 0);
});
#ifdef DOCUMENT_API
Loading::addTask("Documentation", "ClientScripts,ServerScripts", [] {
scripts::documentBinds();
});
#endif
preloading = true;
}
bool isPreloading() {
return preloading;
}
void finishPreload() {
if(!preloading) {
startPreload();
Loading::finalize();
}
while(!Loading::finished()) {
Loading::process();
devices.driver->handleEvents(1);
}
const int priority = -10;
while(devices.library.processImages(priority)) {}
while(devices.library.processTextures(priority)) {}
while(devices.library.processSounds(priority)) {}
while(devices.library.processMeshes(priority)) {}
while(!Loading::finished()) {
Loading::process();
devices.driver->handleEvents(1);
}
Loading::finish();
preloading = false;
}
namespace resource {
extern threads::Signal unqueuedMeshes;
};
void cancelLoad() {
cancelAssets = true;
while(!Loading::finished()) {
Loading::process();
devices.driver->handleEvents(1);
}
const int priority = INT_MIN;
while(devices.library.processImages(priority)) {}
while(idleImageActive) { devices.driver->handleEvents(1); }
while(devices.library.processTextures(priority)) {}
while(devices.library.processSounds(priority)) {}
while(devices.library.processMeshes(priority)) {}
while(idleSoundsActive) { devices.driver->handleEvents(1); }
while(idleHullsActive) { devices.driver->handleEvents(1); }
resource::unqueuedMeshes.wait(0);
Loading::finish();
cancelAssets = false;
preloading = false;
}
void readGameConfig(const std::string& filename) {
gameConfig.count = 0;
//delete gameConfig.names;
//delete gameConfig.values;
gameConfig.indices.clear();
std::vector<std::string> names;
std::vector<double> values;
DataHandler file;
file.defaultHandler([&](std::string& key, std::string& value) {
names.push_back(key);
values.push_back(toNumber<double>(value));
});
file.read(filename);
gameConfig.count = names.size();
gameConfig.names = new std::string[gameConfig.count];
gameConfig.values = new double[gameConfig.count];
gameConfig.defaultValues = new double[gameConfig.count];
for(size_t i = 0; i < gameConfig.count; ++i) {
gameConfig.names[i] = names[i];
gameConfig.values[i] = values[i];
gameConfig.defaultValues[i] = values[i];
gameConfig.indices[names[i]] = i;
}
}
void resetGameConfig() {
for(size_t i = 0; i < gameConfig.count; ++i)
gameConfig.values[i] = gameConfig.defaultValues[i];
}
void readGameConfig(net::Message& msg) {
for(size_t i = 0; i < gameConfig.count; ++i)
msg >> gameConfig.values[i];
}
void writeGameConfig(net::Message& msg) {
for(size_t i = 0; i < gameConfig.count; ++i)
msg << gameConfig.values[i];
}
void saveGameConfig(SaveFile& file) {
file << (unsigned)gameConfig.count;
for(size_t i = 0; i < gameConfig.count; ++i) {
file << gameConfig.names[i];
file << gameConfig.values[i];
}
}
void loadGameConfig(SaveFile& file) {
unsigned count = 0;
if(file >= SFV_0003) {
file >> count;
}
else {
size_t woops = 0;
file >> woops;
count = (unsigned)woops;
}
for(size_t i = 0; i < count; ++i) {
std::string name;
file >> name;
double value;
file >> value;
auto it = gameConfig.indices.find(name);
if(it != gameConfig.indices.end())
gameConfig.values[it->second] = value;
}
}
bool loadPrep(const std::string& fname) {
if(!scripts::isAccessible(fname))
return false;
SaveFileInfo info;
getSaveFileInfo(fname, info);
//Check if we need to switch mods
std::vector<bool> modCheck;
unsigned modCnt = info.mods.size();
unsigned activeCnt = devices.mods.activeMods.size();
modCheck.resize(activeCnt);
for(unsigned i = 0; i < activeCnt; ++i)
modCheck[i] = false;
std::vector<std::string> ids;
bool shouldSwitch = false;
for(unsigned i = 0; i < modCnt; ++i) {
bool found = false;
auto* mod = devices.mods.getMod(info.mods[i].id);
if(mod)
mod = mod->getFallback(info.mods[i].version);
if(mod == nullptr)
return false;
ids.push_back(mod->ident);
for(unsigned j = 0; j < activeCnt; ++j) {
if(modCheck[j])
continue;
if(devices.mods.activeMods[j] == mod) {
found = true;
modCheck[j] = true;
break;
}
}
if(!found) {
shouldSwitch = true;
break;
}
}
for(unsigned i = 0; i < activeCnt; ++i) {
if(!modCheck[i]) {
shouldSwitch = true;
break;
}
}
if(game_running)
destroyGame();
//Switch mods if needed
if(shouldSwitch) {
::info("Switching mods for savegame...");
destroyMod();
initMods(ids);
}
//Actually load
clearGameSettings();
loadSaveName = fname;
game_state = GS_Game;
return true;
}
struct ToggleConsoleBind : profile::Keybind {
void call(bool pressed) {
if(!pressed) {
console.toggle();
}
}
};
void initMods(const std::vector<std::string>& mods) {
auto prevSection = enterSection(NS_Loading);
//Load global resources
Loading::prepare(5, initNewThread, cleanupThread);
Loading::addTask("CloudInit", 0, [] {
#ifndef NSTEAM
if(use_steam && !devices.cloud)
devices.cloud = GamePlatform::acquireSteam();
#endif
} );
static bool didCloudFiles = false, didCloudMods = false;
Loading::addTask("CloudMods", "CloudInit", [] {
if(didCloudMods)
return;
didCloudMods = true;
if(devices.cloud) {
CloudDownload dl;
for(unsigned i = 0, cnt = devices.cloud->getDownloadedItemCount(); i < cnt; ++i) {
if(devices.cloud->getDownloadedItem(i, dl)) {
validPaths.insert(dl.path);
auto folderNameEnds = dl.path.find_last_not_of("\\/");
auto folderNameStarts = dl.path.find_last_of("\\/", folderNameEnds);
if(folderNameStarts != std::string::npos)
devices.mods.registerMod(dl.path, dl.path.substr(folderNameStarts+1, folderNameEnds - folderNameStarts));
}
}
checkCloudDLC();
}
devices.mods.finalize();
} );
Loading::addTask("CloudFiles", "CloudInit", [] {
if(devices.cloud && !didCloudFiles) {
didCloudFiles = false;
devices.cloud->addCloudFolder(getProfileRoot(), "saves");
devices.cloud->syncCloudFiles(getProfileRoot());
}
} );
Loading::addTask("ModInit", "CloudMods", [&] {
//Set the mod
devices.mods.clearMods();
if(mods.empty()) {
foreach(mod, devices.mods.mods) {
if((*mod)->enabled) {
if(devices.mods.enableMod((*mod)->name))
info("Loading enabled mod %s", (*mod)->name.c_str());
}
}
}
else foreach(mod, mods) {
if(devices.mods.enableMod(*mod))
info("Loading mod %s", mod->c_str());
}
//Initialize the library
devices.library.prepErrorResources();
//Load keybind descriptors
std::vector<std::string> bindfiles;
devices.mods.resolve("data/keybinds.txt", bindfiles);
foreach(it, bindfiles)
devices.keybinds.loadDescriptors(*it);
//Load keybind values from profile, or set defaults
std::string bindFile = path_join(devices.mods.getProfile("settings"), "keybinds.txt");
devices.keybinds.setDefaultBinds();
if(fileExists(bindFile)) {
devices.keybinds.loadBinds(bindFile);
}
else {
//Load parent keybinds
foreach(it, devices.mods.activeMods) {
mods::Mod* prt = *it;
while(prt) {
std::string kfile(prt->getProfile("settings"));
kfile = path_join(kfile, "keybinds.txt");
if(fileExists(kfile))
devices.keybinds.loadBinds(kfile);
prt = prt->parent;
}
}
devices.keybinds.saveBinds(bindFile);
}
//Do console bind
auto* group = devices.keybinds.getGroup("Global");
if(group) {
auto* desc = group->getDescriptor("TOGGLE_CONSOLE");
if(desc) {
console.keybind = new ToggleConsoleBind();
group->addBind(desc->id, console.keybind);
}
}
//Run menu autoexec
console.executeFile(path_join(getProfileRoot(), "autoexec_menu.txt"));
//Load the locales
switchLocale(game_locale);
//Load setting descriptors
std::vector<std::string> settingfiles;
devices.mods.resolve("data/settings.txt", settingfiles);
foreach(it, settingfiles)
devices.settings.mod.loadDescriptors(*it);
//Load setting values from profile, or set defaults
std::string stFile = path_join(devices.mods.getProfile("settings"), "settings.txt");
if(fileExists(stFile)) {
devices.settings.mod.loadSettings(stFile);
}
else {
//Load parent keybinds
foreach(it, devices.mods.activeMods) {
mods::Mod* prt = *it;
while(prt) {
std::string kfile(prt->getProfile("settings"));
kfile = path_join(kfile, "settings.txt");
if(fileExists(kfile))
devices.settings.mod.loadSettings(kfile);
prt = prt->parent;
}
}
devices.settings.mod.saveSettings(stFile);
}
});
Loading::addTask("Window", "ModInit", [] {
if(create_window) {
os::WindowData windat;
windat.verticalSync = 1;
bool cursorCapture = false;
auto* vsync = devices.settings.engine.getSetting("iVsync");
if(vsync)
windat.verticalSync = *vsync;
extern double ui_scale;
auto* scale = devices.settings.engine.getSetting("dGUIScale");
if(scale)
ui_scale = *scale;
if(!fullscreen)
fullscreen = *devices.settings.engine.getSetting("bFullscreen");
if(fullscreen) {
windat.mode = os::WM_Fullscreen;
auto* ovr = devices.settings.engine.getSetting("bOverrideResolution");
if(ovr)
windat.overrideMonitor = *ovr;
unsigned w, h;
devices.driver->getDesktopSize(w, h);
auto* screenWidth = devices.settings.engine.getSetting("iFsResolutionX");
int settingWidth = screenWidth ? *screenWidth : 0;
windat.width = settingWidth > 0 ? settingWidth : (int)w;
auto* screenHeight = devices.settings.engine.getSetting("iFsResolutionY");
int settingHeight = screenHeight ? *screenHeight : 0;
windat.height = settingHeight > 0 ? settingHeight : (int)h;
auto* fsCapture = devices.settings.engine.getSetting("bFsCursorCapture");
cursorCapture = fsCapture ? *fsCapture : true;
auto* mon = devices.settings.engine.getSetting("sMonitor");
if(mon)
windat.targetMonitor = mon->toString();
}
else {
auto* screenWidth = devices.settings.engine.getSetting("iResolutionX");
windat.width = screenWidth ? *screenWidth : 1280;
auto* screenHeight = devices.settings.engine.getSetting("iResolutionY");
windat.height = screenHeight ? *screenHeight : 720;
auto* fsCapture = devices.settings.engine.getSetting("bCursorCapture");
cursorCapture = fsCapture ? *fsCapture : true;
}
auto* aa = devices.settings.engine.getSetting("iSamples");
if(aa)
windat.aa_samples = *aa;
auto* ss = devices.settings.engine.getSetting("bSupersample");
if(ss) {
extern double scale_3d;
scale_3d = (bool)*ss ? 2.0 : 1.0;
}
auto* refresh = devices.settings.engine.getSetting("iRefreshRate");
if(refresh)
windat.refreshRate = *refresh;
devices.driver->createWindow(windat);
devices.driver->setCursorLocked(cursorCapture);
devices.driver->setWindowTitle("Star Ruler 2");
devices.render->init();
//We should only make a window once
create_window = 0;
}
}, threads::getThreadID() );
if(load_resources) {
Loading::addTask("Errors", "Window", [] {
devices.library.generateErrorResources();
}, threads::getThreadID() );
}
Loading::addTask("EmpireStats", "ModInit", [] {
loadEmpireStats( devices.mods.resolve("data/stats.txt") );
} );
Loading::addTask("ObjectTypes", "ModInit", [] {
loadStateDefinitions(devices.mods.resolve("data/objects.txt"), "Object");
prepScriptObjectTypes();
} );
Loading::addTask("Generics", "ObjectTypes", [] {
scripts::initGenericTypes();
for(unsigned i = 0, cnt = getScriptObjectTypeCount(); i < cnt; ++i) {
auto* type = getScriptObjectType(i);
scripts::bindGenericObjectType(type, type->name);
}
} );
Loading::addTask("NodeTypes", "Generics", [] {
scene::loadScriptNodeTypes(devices.mods.resolve("data/nodes.txt"));
} );
Loading::addTask("Components", "Generics", [] {
devices.mods.listFiles("data/components", "*.txt", [](const std::string& file) {
scripts::loadComponents(file);
});
} );
Loading::addTask("States", "Components,ObjectTypes", [] {
resetStateValueTypes();
addObjectStateValueTypes();
scripts::addComponentStateValueTypes();
scripts::addNamespaceState();
loadStateDefinitions(devices.mods.resolve("data/empire_states.txt"));
finalizeStateDefinitions();
Empire::setEmpireStates(&getStateDefinition("Empire"));
scripts::BindEmpireComponentOffsets();
scripts::buildEmpAttribIndices();
setScriptObjectStates();
} );
Loading::addTask("GameConfig", "ModInit", [] {
readGameConfig(devices.mods.resolve("data/game_config.txt"));
} );
Loading::addTask("ObjComponentOffsets", "ObjectTypes,Components,States", [] {
scripts::SetObjectTypeOffsets();
});
Loading::addTask("Effects", "ModInit", [] {
devices.mods.listFiles("data/effects", "*.txt", loadEffectDefinitions, true);
} );
Loading::addTask("Effectors", "Effects", [] {
devices.mods.listFiles("data/effectors", "*.txt", loadEffectorDefinitions, true);
} );
Loading::addTask("SubSystems", "Effects,Effectors,GameConfig", [] {
devices.mods.listFiles("data/subsystems", "*.txt", loadSubsystemDefinitions, true);
executeSubsystemTemplates();
finalizeSubsystems();
} );
Loading::addTask("Shaders", "ModInit", [] {
devices.library.clearShaderGlobals();
libraryDir("data/shaders", resource::RT_Shader);
});
Loading::addTask("Materials", "Shaders", [] {
libraryDir("data/materials", resource::RT_Material);
devices.mods.listFiles("data/shipsets", "materials.txt", loadLibraryFile<resource::RT_Material>, true);
});
if(load_resources) {
Loading::addTask("CompileShaders", "Shaders,Window", [] {
devices.library.compileShaders();
}, threads::getThreadID() );
}
Loading::addTask("Fonts", "ModInit", [] {
libraryDir("data/fonts", resource::RT_Font);
} );
Loading::addTask("Sounds", "ModInit", [] {
libraryDir("data/sounds", resource::RT_Sound);
} );
Loading::addTask("Particles", "Materials,Sounds", [] {
devices.mods.listFiles("data/particles", "*.ps", loadLibraryFile<resource::RT_ParticleSystem>, true);
});
Loading::addTask("SkinStyles", "Fonts", [] {
libraryDir("data/skin styles", resource::RT_Skin);
} );
Loading::addTask("Events", "Generics", [] {
devices.mods.listFiles("data/events", "*.txt", [](const std::string& file) {
scripts::ReadEvents(file);
});
scripts::LoadScriptHooks(devices.mods.resolve("data/hooks.txt"));
} );
Loading::addTask("MaterialBinds", "Materials,SkinStyles,Particles,SubSystems", [] {
devices.library.bindSkinMaterials();
bindSubsystemMaterials();
} );
Loading::addTask("ResourceBinds", "Materials,Sounds,Particles", [] {
bindEffectorResources();
} );
Loading::addTask("Models", "ModInit", [] {
libraryDir("data/models", resource::RT_Mesh);
devices.mods.listFiles("data/shipsets", "models.txt", loadLibraryFile<resource::RT_Mesh>, true);
} );
Loading::addTask("Shipsets", "Models,Materials,SubSystems", [] {
devices.mods.listFiles("data/shipsets", "hulls.txt", loadHullDefinitions, true);
devices.mods.listFiles("data/shipsets", "shipset.txt", loadShipset, true);
initAllShipset();
} );
if(load_resources) {
Loading::addTask("ShaderStateVars", "Shaders,ObjectTypes,States", [] {
prepareShaderStateVars();
});
Loading::addTask("ProcessSounds", "Sounds", [] {
devices.library.processSounds(10);
});
Loading::addTask("ProcessImages", "Materials,Fonts,Window", [] {
devices.library.processImages(10);
});
Loading::addTask("ProcessTextures", "ProcessImages,Window", [] {
devices.library.processTextures(10);
}, threads::getThreadID() );
Loading::addTask("ProcessModels", "Models,Window,Shipsets", [] {
devices.library.processMeshes();
}, threads::getThreadID() );
}
Loading::addTask("LocateScripts", "ModInit", [] {
findScripts("scripts/shared");
findScripts("scripts/definitions");
findScripts("maps");
findScripts("scripts/menu");
findScripts("scripts/toolkit");
findScripts("scripts/server");
findScripts("scripts/client");
});
Loading::addTask("PreloadScripts", "LocateScripts", [] {
scriptPreloads.signal(7);
threads::createThread(PreloadBatch, new std::string("scripts/shared"));
threads::createThread(PreloadBatch, new std::string("scripts/definitions"));
threads::createThread(PreloadBatch, new std::string("scripts/menu"));
threads::createThread(PreloadBatch, new std::string("maps"));
threads::createThread(PreloadBatch, new std::string("scripts/toolkit"));
threads::createThread(PreloadBatch, new std::string("scripts/server"));
threads::createThread(PreloadBatch, new std::string("scripts/client"));
});
Loading::addTask("MenuScripts", "LocateScripts,SkinStyles,Materials,Models,Sounds,SubSystems", [] {
std::map<std::string, std::string> scriptfiles;
devices.scripts.menu = new scripts::Manager(makeJITCompiler());
devices.engines.menu = devices.scripts.menu->engine;
devices.scripts.menu->addIncludePath("scripts/menu");
devices.scripts.menu->addIncludePath("scripts/shared");
devices.scripts.menu->addIncludePath("scripts/toolkin");
devices.scripts.menu->addIncludePath("scripts/gui");
devices.scripts.menu->addIncludePath("scripts/definitions");
devices.scripts.menu->addIncludePath("maps/");
auto loadScript = [](const std::pair<std::string,std::string>& file) {
if(file.second.find("/include/") != std::string::npos)
return;
devices.scripts.menu->load(
makeModuleName(file.first),
file.second);
};
onScripts("scripts/menu", loadScript);
onScripts("scripts/toolkit", loadScript);
onScripts("maps", loadScript);
scripts::RegisterMenuBinds(devices.scripts.menu->engine);
devices.scripts.menu->compile(
devices.mods.getProfile("as_cache/menu"),
MENU_SCRIPT_BUILD);
devices.scripts.menu->init();
bindInputScripts(GS_Menu, devices.scripts.menu);
scripts::BindEventBinds(true);
} );
Loading::finalize();
while(!Loading::finished()) {
Loading::process();
devices.driver->handleEvents(1);
}
Loading::finish();
enterSection(prevSection);
devices.library.bindHotloading();
startPreload();
Loading::finalize();
if(devices.scripts.menu)
devices.scripts.menu->garbageCollect(true);
if(devices.scripts.client)
devices.scripts.client->garbageCollect(true);
if(devices.scripts.server)
devices.scripts.server->garbageCollect(true);
}
void destroyMod() {
//Make sure we finish loading, or we could de-initialize while adding resources
cancelLoad();
stopProjectiles();
//End processing
processing::end();
processing::clear();
//Remove input script binds
clearInputScripts(GS_Menu);
//Clear any active game
if(game_running)
destroyGame();
clearEmpireStats();
//Remove script nodes
scene::clearScriptNodeTypes();
//Clear keybinds
devices.keybinds.clear();
//Destroy skin indices
gui::skin::clearDynamicIndices();
//Clear shader state vars
clearShaderStateVars();
//Clear resources
devices.library.clear();
fsShader = nullptr;
//Clear menu scripts
delete devices.scripts.menu;
devices.scripts.menu = 0;
devices.engines.menu = 0;
scripts::resetContextCache(true);
//Stop playing sounds
if(devices.sound)
devices.sound->stopAllSounds();
//Clear console commands
console.clearCommands();
//Clear state definitions (For objects, empires)
clearStateDefinitions();
//Clear other definitions
clearHullDefinitions();
clearShipsets();
scripts::ClearEvents();
scripts::clearComponents();
clearEffectDefinitions();
clearEffectorDefinitions();
clearEffectors();
clearSubsystemDefinitions();
Empire::setEmpireStates(0);
}
net::Message game_settings;
void setGameSettings(net::Message& msg) {
game_settings = msg;
}
void clearGameSettings() {
game_settings.clear();
}
void passSettings(scripts::Manager* man) {
auto& modules = man->modules;
for(auto it = modules.begin(); it != modules.end(); ++it) {
scripts::Module& mod = *it->second;
if(mod.callbacks[scripts::SC_game_settings] > 0) {
game_settings.rewind();
scripts::Call cl = mod.call(scripts::SC_game_settings);
cl.push(&game_settings);
cl.call();
}
}
}
void initGame() {
if(queuedModSwitch) {
queuedModSwitch = false;
destroyMod();
initMods(modSetup);
}
//Tell all the clients to start the game
if(devices.network->isServer)
devices.network->startSignal();
//Wait for all the preloading to finish
finishPreload();
//Set the correct server engine to use
if(devices.network->isClient)
devices.scripts.server = devices.scripts.cache_shadow;
else
devices.scripts.server = devices.scripts.cache_server;
devices.engines.server = devices.scripts.server->engine;
bindScripts();
//Initialize default empire
processing::resume();
if(!processing::isRunning()) {
unsigned cpuCount = devices.driver->getProcessorCount();
threadCount = std::max(cpuCount+1,1u);
processing::start(cpuCount);
}
Empire::initEmpires();
//Enable projectile processing
initProjectiles();
//Create lock groups
processing::pause();
initLocks(threadCount);
Object::GALAXY_CREATION = true;
processing::resume();
//Create the universe
devices.driver->resetGameTime(0.0);
resetGameTime();
resetGameConfig();
devices.universe = new Universe();
isLoadedGame = false;
bool loaded = false;
if(devices.network->isClient) {
//Tell the server we're ready to receive
devices.network->signalClientReady();
//Initialize server scripts
devices.scripts.server->init();
//Wait for the galaxy to be received before
//starting all the scripts
while(!devices.network->currentPlayer.hasGalaxy) {
if(!devices.network->client || !devices.network->client->active) {
devices.scripts.client->init();
destroyGame();
clearGameSettings();
game_state = GS_Menu;
return;
}
game_state = GS_Menu;
tickMenu();
game_state = GS_Game;
}
//Pass in game settings after objects
passSettings(devices.scripts.server);
passSettings(devices.scripts.client);
//Initialize client scripts
devices.scripts.client->init();
}
else {
isLoadedGame = !loadSaveName.empty();
//Create the universe by passing game settings
passSettings(devices.scripts.server);
passSettings(devices.scripts.client);
volatile bool done = false;
if(isLoadedGame) {
//LoadGame does script init() in the right place
threads::async([&done,&loaded]() -> int {
initNewThread();
pauseProjectiles();
loaded = loadGame(loadSaveName);
resumeProjectiles();
done = true;
cleanupThread();
return 0;
});
}
else {
threads::async([&done]() -> int {
initNewThread();
devices.scripts.server->init();
devices.scripts.client->init();
done = true;
cleanupThread();
return 0;
});
}
while(!done) {
tickMenu();
threads::sleep(1);
}
}
loadSaveName.clear();
if(isLoadedGame && !loaded) {
game_state = GS_Menu;
return;
}
bindInputScripts(GS_Game, devices.scripts.client);
//Run console autoexec
console.executeFile(path_join(getProfileRoot(), "autoexec.txt"));
//Tell the clients we're ready to transmit galaxies
Object::GALAXY_CREATION = false;
devices.network->currentPlayer.emp = Empire::getPlayerEmpire();
Empire::getPlayerEmpire()->player = &devices.network->currentPlayer;
if(devices.network->isServer)
devices.network->signalServerReady();
game_running = true;
//Process events that were deferred until client scripts were initialized
scripts::processEvents();
}
void destroyGame() {
gameEnding = true;
stopProjectiles();
//Wait for all processing jobs to finish
processing::end();
processing::clear();
//Inform the network
if(devices.network->serverReady)
devices.network->endGame();
//Clear game scripts
if(devices.scripts.server)
devices.scripts.server->deinit();
if(devices.scripts.client)
devices.scripts.client->deinit();
//Disconnect network interface if multiplayer
if(devices.network->isClient || devices.network->serverReady)
devices.network->disconnect();
//Clear all lights
render::light::destroyLights();
//Remove lock groups
destroyLocks();
//Remove input script binds
clearInputScripts(GS_Game);
//Clear all object IDs
clearObjects();
//Destroy universe
if(devices.universe) {
devices.universe->destroyAll();
devices.universe->drop();
devices.universe = 0;
}
if(devices.physics) {
devices.physics->drop();
devices.physics = 0;
}
if(devices.nodePhysics) {
devices.nodePhysics->drop();
devices.nodePhysics = 0;
}
//Destroy scene
extern void endAnimation();
endAnimation();
extern void clearProjectileBatches();
clearProjectileBatches();
devices.scene->destroyTree();
scene::clearNodeEvents();
//Delete existing empires
Empire::clearEmpires();
scripts::resetContextCache();
delete devices.scripts.cache_server;
delete devices.scripts.cache_shadow;
delete devices.scripts.client;
devices.scripts.cache_server = 0;
devices.scripts.cache_shadow = 0;
devices.scripts.client = 0;
devices.scripts.server = 0;
devices.engines.client = 0;
devices.engines.server = 0;
gameEnding = false;
console.clearCommands();
game_running = false;
if(devices.network->isClient || devices.network->serverReady)
devices.network->resetNetState();
}
void loadEngineSettings() {
//Hardcoded engine settings go here
{
profile::SettingCategory* cat = new profile::SettingCategory("Graphics");
cat->settings.push_back(new NamedGeneric("iSamples", 4));
cat->settings.push_back(new NamedGeneric("bSupersample", false));
cat->settings.push_back(new NamedGeneric("iRefreshRate", (int)0));
cat->settings.push_back(new NamedGeneric("iResolutionX", 1280));
cat->settings.push_back(new NamedGeneric("iResolutionY", 720));
cat->settings.push_back(new NamedGeneric("iFsResolutionX", (int)0));
cat->settings.push_back(new NamedGeneric("iFsResolutionY", (int)0));
cat->settings.push_back(new NamedGeneric("bFullscreen", true));
cat->settings.push_back(new NamedGeneric("bOverrideResolution", false));
cat->settings.push_back(new NamedGeneric("iVsync", 1));
cat->settings.push_back(new NamedGeneric("sMonitor", ""));
cat->settings.push_back(new NamedGeneric("bShaderFallback", false));
auto* guiScale = new NamedGeneric("dGUIScale", 1.0);
guiScale->flt_min = 0.25;
guiScale->flt_max = 4.0;
cat->settings.push_back(guiScale);
auto* fps = new NamedGeneric("dMaxFPS", 65.0);
fps->flt_min = 24.0;
fps->flt_max = 200.0;
extern double* maxfps;
maxfps = &fps->flt;
cat->settings.push_back(fps);
auto* tq = new NamedGeneric("iTextureQuality", 3);
tq->num_min = 2;
tq->num_max = 5;
cat->settings.push_back(tq);
auto* sl = new NamedGeneric("iShaderLevel", 3);
sl->num_min = 1;
sl->num_max = 4;
cat->settings.push_back(sl);
devices.settings.engine.addCategory(cat);
}
{
profile::SettingCategory* cat = new profile::SettingCategory("Sound");
cat->settings.push_back(new NamedGeneric("sAudioDevice", ""));
devices.settings.engine.addCategory(cat);
}
{
profile::SettingCategory* cat = new profile::SettingCategory("Input");
cat->settings.push_back(new NamedGeneric("bCursorCapture", true));
cat->settings.push_back(new NamedGeneric("bFsCursorCapture", true));
cat->settings.push_back(new NamedGeneric("iDoubleClickMS", (int)devices.driver->getDoubleClickTime()));
devices.settings.engine.addCategory(cat);
}
{
profile::SettingCategory* cat = new profile::SettingCategory("General");
cat->settings.push_back(new NamedGeneric("sLocale", "english"));
cat->settings.push_back(new NamedGeneric("sAPIToken", ""));
auto* autosave = new NamedGeneric("dAutosaveMinutes", 3.0);
autosave->flt_min = 0.0;
autosave->flt_max = 60.0;
cat->settings.push_back(autosave);
auto* count = new NamedGeneric("iAutosaveCount", (int)0);
count->num_min = 1;
count->num_max = 10;
cat->settings.push_back(count);
cat->settings.push_back(new NamedGeneric("iNetworkRateLimit", (int)250));
devices.settings.engine.addCategory(cat);
}
//Save to profile
std::string file = path_join(getProfileRoot(), "settings.txt");
if(fileExists(file))
devices.settings.engine.loadSettings(file);
else
devices.settings.engine.saveSettings(file);
//Generate new tokens
{
auto* token = devices.settings.engine.getSetting("sAPIToken");
if(token && (token->toString().empty() || token->toString() == "JGeaaKcaaa")) {
std::string pass;
do {
pass.clear();
uint64_t pw = (uint64_t)sysRandomi() << 32 | (uint64_t)sysRandomi();
const char* base64 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-+=!~$%#&^*";
for(unsigned i = 0; i < 10; ++i) {
auto v = (pw % 64);
pw >>= 6;
pass.append(1, base64[v]);
}
} while(pass == "JGeaaKcaaa");
token->setString(pass);
devices.settings.engine.saveSettings(file);
}
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, May 16, 7:09 AM (8 h, 45 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
64055
Default Alt Text
(56 KB)
Attached To
Mode
R80 StarRuler2-Source
Attached
Detach File
Event Timeline