2024-06-25 12:03:01 -07:00
|
|
|
/* Copyright (C) 2024 Wildfire Games.
|
2023-12-02 16:30:12 -08:00
|
|
|
* This file is part of 0 A.D.
|
2009-04-18 10:00:33 -07:00
|
|
|
*
|
2023-12-02 16:30:12 -08:00
|
|
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
2009-04-18 10:00:33 -07:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
2023-12-02 16:30:12 -08:00
|
|
|
* 0 A.D. is distributed in the hope that it will be useful,
|
2009-04-18 10:00:33 -07:00
|
|
|
* 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
|
2023-12-02 16:30:12 -08:00
|
|
|
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
2009-04-18 10:00:33 -07:00
|
|
|
*/
|
|
|
|
|
|
2004-06-01 10:34:12 -07:00
|
|
|
#include "precompiled.h"
|
2004-05-29 13:56:24 -07:00
|
|
|
|
|
|
|
|
#include "MapReader.h"
|
# Added tool for viewing models and animations outside the game.
Atlas: Added ActorViewer. Moved GL canvas into separate class for shared
use. Disabled message-handling callback while blocked on the game, and
stopped creating dialog boxes inside the game thread in order to avoid
deadlocks (hopefully). Support multiple Views (for independent sets of
camera/update/render code). Recalculate territory boundaries when
necessary. Changed default list of animations to match those currently
used by actors.
# Tidied up more code.
Moved some more #includes out of .h files, to minimise unnecessary
compilation.
MathUtil: Deleted unused/unuseful macros (M_PI (use PI instead), M_PI_2
(use PI/2), MAX3, ABS (use abs)).
ObjectManager: Removed some ScEd-specific things.
Unit: Moved creation out of UnitManager, so units can be created without
adding to the manager. Changed CStr8 to the more conventional CStr.
app_hooks: Removed warning for setting multiple times.
win: Restored SEH catcher.
GameSetup, GameView: Removed RenderNoCull, because it doesn't seem to do
what it says it does ("force renderer to load everything") since we're
loading-on-demand most stuff and it doesn't seem especially useful since
we'd prefer to minimise loading times (but feel free to correct me if
I'm wrong). (And because it crashes when things need to be initialised
in a different order, so it's easier to remove than to understand and
fix it.)
PatchRData, Renderer: Work sensibly when there's no game (hence no LOS
manager, water, etc).
LOSManager: Use entity position instead of actor position when possible.
TerritoryManager: Allow delayed recalculations (so Atlas can issue lots
of move+recalculate commands per frame).
Cinematic: Non-pointer wxTimer, so it doesn't leak and doesn't have to
be deleted manually.
This was SVN commit r4261.
2006-08-28 10:36:42 -07:00
|
|
|
|
|
|
|
|
#include "graphics/Camera.h"
|
2015-12-30 13:16:35 -08:00
|
|
|
#include "graphics/CinemaManager.h"
|
2011-03-21 18:34:45 -07:00
|
|
|
#include "graphics/Entity.h"
|
2010-08-13 06:26:29 -07:00
|
|
|
#include "graphics/GameView.h"
|
2011-03-21 18:34:45 -07:00
|
|
|
#include "graphics/MapGenerator.h"
|
# Added tool for viewing models and animations outside the game.
Atlas: Added ActorViewer. Moved GL canvas into separate class for shared
use. Disabled message-handling callback while blocked on the game, and
stopped creating dialog boxes inside the game thread in order to avoid
deadlocks (hopefully). Support multiple Views (for independent sets of
camera/update/render code). Recalculate territory boundaries when
necessary. Changed default list of animations to match those currently
used by actors.
# Tidied up more code.
Moved some more #includes out of .h files, to minimise unnecessary
compilation.
MathUtil: Deleted unused/unuseful macros (M_PI (use PI instead), M_PI_2
(use PI/2), MAX3, ABS (use abs)).
ObjectManager: Removed some ScEd-specific things.
Unit: Moved creation out of UnitManager, so units can be created without
adding to the manager. Changed CStr8 to the more conventional CStr.
app_hooks: Removed warning for setting multiple times.
win: Restored SEH catcher.
GameSetup, GameView: Removed RenderNoCull, because it doesn't seem to do
what it says it does ("force renderer to load everything") since we're
loading-on-demand most stuff and it doesn't seem especially useful since
we'd prefer to minimise loading times (but feel free to correct me if
I'm wrong). (And because it crashes when things need to be initialised
in a different order, so it's easier to remove than to understand and
fix it.)
PatchRData, Renderer: Work sensibly when there's no game (hence no LOS
manager, water, etc).
LOSManager: Use entity position instead of actor position when possible.
TerritoryManager: Allow delayed recalculations (so Atlas can issue lots
of move+recalculate commands per frame).
Cinematic: Non-pointer wxTimer, so it doesn't leak and doesn't have to
be deleted manually.
This was SVN commit r4261.
2006-08-28 10:36:42 -07:00
|
|
|
#include "graphics/Patch.h"
|
|
|
|
|
#include "graphics/Terrain.h"
|
2010-09-04 14:26:52 -07:00
|
|
|
#include "graphics/TerrainTextureEntry.h"
|
|
|
|
|
#include "graphics/TerrainTextureManager.h"
|
# Added tool for viewing models and animations outside the game.
Atlas: Added ActorViewer. Moved GL canvas into separate class for shared
use. Disabled message-handling callback while blocked on the game, and
stopped creating dialog boxes inside the game thread in order to avoid
deadlocks (hopefully). Support multiple Views (for independent sets of
camera/update/render code). Recalculate territory boundaries when
necessary. Changed default list of animations to match those currently
used by actors.
# Tidied up more code.
Moved some more #includes out of .h files, to minimise unnecessary
compilation.
MathUtil: Deleted unused/unuseful macros (M_PI (use PI instead), M_PI_2
(use PI/2), MAX3, ABS (use abs)).
ObjectManager: Removed some ScEd-specific things.
Unit: Moved creation out of UnitManager, so units can be created without
adding to the manager. Changed CStr8 to the more conventional CStr.
app_hooks: Removed warning for setting multiple times.
win: Restored SEH catcher.
GameSetup, GameView: Removed RenderNoCull, because it doesn't seem to do
what it says it does ("force renderer to load everything") since we're
loading-on-demand most stuff and it doesn't seem especially useful since
we'd prefer to minimise loading times (but feel free to correct me if
I'm wrong). (And because it crashes when things need to be initialised
in a different order, so it's easier to remove than to understand and
fix it.)
PatchRData, Renderer: Work sensibly when there's no game (hence no LOS
manager, water, etc).
LOSManager: Use entity position instead of actor position when possible.
TerritoryManager: Allow delayed recalculations (so Atlas can issue lots
of move+recalculate commands per frame).
Cinematic: Non-pointer wxTimer, so it doesn't leak and doesn't have to
be deleted manually.
This was SVN commit r4261.
2006-08-28 10:36:42 -07:00
|
|
|
#include "lib/timer.h"
|
|
|
|
|
#include "maths/MathUtil.h"
|
|
|
|
|
#include "ps/CLogger.h"
|
|
|
|
|
#include "ps/Loader.h"
|
2023-12-04 12:23:37 -08:00
|
|
|
#include "ps/Profiler2.h"
|
2023-11-19 11:19:32 -08:00
|
|
|
#include "ps/TaskManager.h"
|
2011-04-06 19:32:16 -07:00
|
|
|
#include "ps/World.h"
|
2006-09-14 16:03:16 -07:00
|
|
|
#include "ps/XML/Xeromyces.h"
|
2012-10-15 03:34:23 -07:00
|
|
|
#include "renderer/PostprocManager.h"
|
# Added tool for viewing models and animations outside the game.
Atlas: Added ActorViewer. Moved GL canvas into separate class for shared
use. Disabled message-handling callback while blocked on the game, and
stopped creating dialog boxes inside the game thread in order to avoid
deadlocks (hopefully). Support multiple Views (for independent sets of
camera/update/render code). Recalculate territory boundaries when
necessary. Changed default list of animations to match those currently
used by actors.
# Tidied up more code.
Moved some more #includes out of .h files, to minimise unnecessary
compilation.
MathUtil: Deleted unused/unuseful macros (M_PI (use PI instead), M_PI_2
(use PI/2), MAX3, ABS (use abs)).
ObjectManager: Removed some ScEd-specific things.
Unit: Moved creation out of UnitManager, so units can be created without
adding to the manager. Changed CStr8 to the more conventional CStr.
app_hooks: Removed warning for setting multiple times.
win: Restored SEH catcher.
GameSetup, GameView: Removed RenderNoCull, because it doesn't seem to do
what it says it does ("force renderer to load everything") since we're
loading-on-demand most stuff and it doesn't seem especially useful since
we'd prefer to minimise loading times (but feel free to correct me if
I'm wrong). (And because it crashes when things need to be initialised
in a different order, so it's easier to remove than to understand and
fix it.)
PatchRData, Renderer: Work sensibly when there's no game (hence no LOS
manager, water, etc).
LOSManager: Use entity position instead of actor position when possible.
TerritoryManager: Allow delayed recalculations (so Atlas can issue lots
of move+recalculate commands per frame).
Cinematic: Non-pointer wxTimer, so it doesn't leak and doesn't have to
be deleted manually.
This was SVN commit r4261.
2006-08-28 10:36:42 -07:00
|
|
|
#include "renderer/SkyManager.h"
|
|
|
|
|
#include "renderer/WaterManager.h"
|
2021-05-13 10:23:52 -07:00
|
|
|
#include "scriptinterface/Object.h"
|
2020-11-18 06:39:04 -08:00
|
|
|
#include "scriptinterface/ScriptContext.h"
|
2023-11-19 11:19:32 -08:00
|
|
|
#include "scriptinterface/ScriptInterface.h"
|
2021-05-14 03:18:03 -07:00
|
|
|
#include "scriptinterface/ScriptRequest.h"
|
|
|
|
|
#include "scriptinterface/JSON.h"
|
2010-01-09 11:20:14 -08:00
|
|
|
#include "simulation2/Simulation2.h"
|
2017-04-04 20:59:20 -07:00
|
|
|
#include "simulation2/components/ICmpCinemaManager.h"
|
2020-03-15 06:54:50 -07:00
|
|
|
#include "simulation2/components/ICmpGarrisonHolder.h"
|
2012-08-01 14:38:13 -07:00
|
|
|
#include "simulation2/components/ICmpObstruction.h"
|
2010-01-22 12:03:14 -08:00
|
|
|
#include "simulation2/components/ICmpOwnership.h"
|
|
|
|
|
#include "simulation2/components/ICmpPlayer.h"
|
|
|
|
|
#include "simulation2/components/ICmpPlayerManager.h"
|
2010-01-09 11:20:14 -08:00
|
|
|
#include "simulation2/components/ICmpPosition.h"
|
2010-07-25 07:11:21 -07:00
|
|
|
#include "simulation2/components/ICmpTerrain.h"
|
2020-11-11 11:40:44 -08:00
|
|
|
#include "simulation2/components/ICmpTurretHolder.h"
|
2013-02-02 18:16:52 -08:00
|
|
|
#include "simulation2/components/ICmpVisual.h"
|
2010-05-27 16:23:53 -07:00
|
|
|
#include "simulation2/components/ICmpWaterManager.h"
|
2005-03-18 14:02:20 -08:00
|
|
|
|
2010-07-03 06:15:57 -07:00
|
|
|
#include <boost/algorithm/string/predicate.hpp>
|
|
|
|
|
|
2020-11-26 14:28:50 -08:00
|
|
|
#if defined(_MSC_VER) && _MSC_VER > 1900
|
|
|
|
|
#pragma warning(disable: 4456) // Declaration hides previous local declaration.
|
|
|
|
|
#pragma warning(disable: 4458) // Declaration hides class member.
|
|
|
|
|
#endif
|
2010-10-29 21:02:42 -07:00
|
|
|
|
2023-11-19 11:19:32 -08:00
|
|
|
// TODO: Maybe this should be optimized depending on the map size.
|
|
|
|
|
constexpr int MAP_GENERATION_CONTEXT_SIZE{96 * MiB};
|
|
|
|
|
|
|
|
|
|
CMapReader::CMapReader() = default;
|
2004-05-29 13:56:24 -07:00
|
|
|
|
|
|
|
|
// LoadMap: try to load the map from given file; reinitialise the scene to new data if successful
|
2020-11-18 06:39:04 -08:00
|
|
|
void CMapReader::LoadMap(const VfsPath& pathname, const ScriptContext& cx, JS::HandleValue settings, CTerrain *pTerrain_,
|
2010-07-03 06:15:57 -07:00
|
|
|
WaterManager* pWaterMan_, SkyManager* pSkyMan_,
|
2012-10-15 03:34:23 -07:00
|
|
|
CLightEnv *pLightEnv_, CGameView *pGameView_, CCinemaManager* pCinema_, CTriggerManager* pTrigMan_, CPostprocManager* pPostproc_,
|
2011-10-24 07:31:05 -07:00
|
|
|
CSimulation2 *pSimulation2_, const CSimContext* pSimContext_, int playerID_, bool skipEntities)
|
2004-05-29 13:56:24 -07:00
|
|
|
{
|
2005-03-22 13:00:56 -08:00
|
|
|
pTerrain = pTerrain_;
|
|
|
|
|
pLightEnv = pLightEnv_;
|
2010-08-13 06:26:29 -07:00
|
|
|
pGameView = pGameView_;
|
2006-06-11 00:03:59 -07:00
|
|
|
pWaterMan = pWaterMan_;
|
2006-06-21 15:37:31 -07:00
|
|
|
pSkyMan = pSkyMan_;
|
2006-08-21 19:24:44 -07:00
|
|
|
pCinema = pCinema_;
|
2010-02-08 14:05:05 -08:00
|
|
|
pTrigMan = pTrigMan_;
|
2012-10-15 03:34:23 -07:00
|
|
|
pPostproc = pPostproc_;
|
2010-02-08 14:05:05 -08:00
|
|
|
pSimulation2 = pSimulation2_;
|
2011-10-24 07:31:05 -07:00
|
|
|
pSimContext = pSimContext_;
|
2010-07-03 06:15:57 -07:00
|
|
|
m_PlayerID = playerID_;
|
2011-10-24 07:31:05 -07:00
|
|
|
m_SkipEntities = skipEntities;
|
2011-06-13 16:32:41 -07:00
|
|
|
m_StartingCameraTarget = INVALID_ENTITY;
|
2020-11-18 06:39:04 -08:00
|
|
|
m_ScriptSettings.init(cx.GetGeneralJSContext(), settings);
|
2005-03-18 14:02:20 -08:00
|
|
|
|
2011-03-23 06:36:20 -07:00
|
|
|
filename_xml = pathname.ChangeExtension(L".xml");
|
2004-05-29 13:56:24 -07:00
|
|
|
|
2010-05-03 12:13:58 -07:00
|
|
|
// In some cases (particularly tests) we don't want to bother storing a large
|
|
|
|
|
// mostly-empty .pmp file, so we let the XML file specify basic terrain instead.
|
|
|
|
|
// If there's an .xml file and no .pmp, then we're probably in this XML-only mode
|
|
|
|
|
only_xml = false;
|
2011-02-25 08:30:55 -08:00
|
|
|
if (!VfsFileExists(pathname) && VfsFileExists(filename_xml))
|
2010-05-03 12:13:58 -07:00
|
|
|
{
|
|
|
|
|
only_xml = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file_format_version = CMapIO::FILE_VERSION; // default if there's no .pmp
|
|
|
|
|
|
|
|
|
|
if (!only_xml)
|
|
|
|
|
{
|
|
|
|
|
// [25ms]
|
|
|
|
|
unpacker.Read(pathname, "PSMP");
|
|
|
|
|
file_format_version = unpacker.GetVersion();
|
2004-05-29 13:56:24 -07:00
|
|
|
}
|
|
|
|
|
|
2010-05-03 12:13:58 -07:00
|
|
|
// check oldest supported version
|
|
|
|
|
if (file_format_version < FILE_READ_VERSION)
|
2019-07-20 18:35:39 -07:00
|
|
|
throw PSERROR_Game_World_MapLoadFailed("Could not load terrain file - too old version!");
|
2010-05-03 12:13:58 -07:00
|
|
|
|
2005-05-10 20:07:08 -07:00
|
|
|
// delete all existing entities
|
2010-02-08 14:05:05 -08:00
|
|
|
if (pSimulation2)
|
|
|
|
|
pSimulation2->ResetState();
|
2016-01-13 16:04:32 -08:00
|
|
|
|
2012-10-15 03:34:23 -07:00
|
|
|
// reset post effects
|
|
|
|
|
if (pPostproc)
|
|
|
|
|
pPostproc->SetPostEffect(L"default");
|
2010-02-08 14:05:05 -08:00
|
|
|
|
Implements skirmish maps, based on patch by sanderd17, fixes #1198. Skirmish maps are like scenarios, except the player can choose their civ during match setup. To create a skirmish map: place some skirmish entities for each player in Atlas (see templates/skirmish/* for examples), uncheck the player's civ in Atlas' player panel if desired, and save in the maps/skirmishes directory. The map will appear in match setup under the "Skirmish" match type.
Implements custom, VFS-based map load/save dialogs for Atlas (replaces
broken native file dialogs), fixes #631, #889.
Fixes map loading/saving to handle arbitrary subdirectories for better
organization.
Adds default settings to Atlas player panel, fixes #1872. Each setting
now has a checkbox to choose whether it should be saved with the map
(avoids writing lots of useless default data for each map).
Adds map preview setting to Atlas, refs #1745.
Cleans up and simplifies some duplicate code.
Fixes optional serialization performance test.
This was SVN commit r13938.
2013-10-03 19:29:16 -07:00
|
|
|
// load map or script settings script
|
2015-01-24 06:46:52 -08:00
|
|
|
if (settings.isUndefined())
|
2023-06-26 11:35:34 -07:00
|
|
|
LDR_Register([this](const double)
|
|
|
|
|
{
|
|
|
|
|
return LoadScriptSettings();
|
|
|
|
|
}, L"CMapReader::LoadScriptSettings", 50);
|
Implements skirmish maps, based on patch by sanderd17, fixes #1198. Skirmish maps are like scenarios, except the player can choose their civ during match setup. To create a skirmish map: place some skirmish entities for each player in Atlas (see templates/skirmish/* for examples), uncheck the player's civ in Atlas' player panel if desired, and save in the maps/skirmishes directory. The map will appear in match setup under the "Skirmish" match type.
Implements custom, VFS-based map load/save dialogs for Atlas (replaces
broken native file dialogs), fixes #631, #889.
Fixes map loading/saving to handle arbitrary subdirectories for better
organization.
Adds default settings to Atlas player panel, fixes #1872. Each setting
now has a checkbox to choose whether it should be saved with the map
(avoids writing lots of useless default data for each map).
Adds map preview setting to Atlas, refs #1745.
Cleans up and simplifies some duplicate code.
Fixes optional serialization performance test.
This was SVN commit r13938.
2013-10-03 19:29:16 -07:00
|
|
|
else
|
2023-06-26 11:35:34 -07:00
|
|
|
LDR_Register([this](const double)
|
|
|
|
|
{
|
|
|
|
|
return LoadRMSettings();
|
|
|
|
|
}, L"CMapReader::LoadRMSettings", 50);
|
2010-10-29 21:02:42 -07:00
|
|
|
|
|
|
|
|
// load player settings script (must be done before reading map)
|
2023-06-26 11:35:34 -07:00
|
|
|
LDR_Register([this](const double)
|
|
|
|
|
{
|
|
|
|
|
return LoadPlayerSettings();
|
|
|
|
|
}, L"CMapReader::LoadPlayerSettings", 50);
|
2010-10-29 21:02:42 -07:00
|
|
|
|
2004-05-29 13:56:24 -07:00
|
|
|
// unpack the data
|
2010-05-03 12:13:58 -07:00
|
|
|
if (!only_xml)
|
2023-06-26 11:35:34 -07:00
|
|
|
LDR_Register([this](const double)
|
|
|
|
|
{
|
|
|
|
|
return UnpackTerrain();
|
|
|
|
|
}, L"CMapReader::UnpackMap", 1200);
|
2004-05-29 13:56:24 -07:00
|
|
|
|
2011-03-21 18:34:45 -07:00
|
|
|
// read the corresponding XML file
|
2023-06-26 11:35:34 -07:00
|
|
|
LDR_Register([this](const double)
|
|
|
|
|
{
|
|
|
|
|
return ReadXML();
|
|
|
|
|
}, L"CMapReader::ReadXML", 50);
|
2011-03-21 18:34:45 -07:00
|
|
|
|
2014-06-01 11:08:11 -07:00
|
|
|
// apply terrain data to the world
|
2023-06-26 11:35:34 -07:00
|
|
|
LDR_Register([this](const double)
|
|
|
|
|
{
|
|
|
|
|
return ApplyTerrainData();
|
|
|
|
|
}, L"CMapReader::ApplyTerrainData", 5);
|
2014-06-01 11:08:11 -07:00
|
|
|
|
|
|
|
|
// read entities
|
2023-06-26 11:35:34 -07:00
|
|
|
LDR_Register([this](const double)
|
|
|
|
|
{
|
|
|
|
|
return ReadXMLEntities();
|
|
|
|
|
}, L"CMapReader::ReadXMLEntities", 5800);
|
2014-06-01 11:08:11 -07:00
|
|
|
|
|
|
|
|
// apply misc data to the world
|
2023-06-26 11:35:34 -07:00
|
|
|
LDR_Register([this](const double)
|
|
|
|
|
{
|
|
|
|
|
return ApplyData();
|
|
|
|
|
}, L"CMapReader::ApplyData", 5);
|
2011-03-21 18:34:45 -07:00
|
|
|
|
|
|
|
|
// load map settings script (must be done after reading map)
|
2023-06-26 11:35:34 -07:00
|
|
|
LDR_Register([this](const double)
|
|
|
|
|
{
|
|
|
|
|
return LoadMapSettings();
|
|
|
|
|
}, L"CMapReader::LoadMapSettings", 5);
|
2011-03-21 18:34:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LoadRandomMap: try to load the map data; reinitialise the scene to new data if successful
|
2020-11-18 06:39:04 -08:00
|
|
|
void CMapReader::LoadRandomMap(const CStrW& scriptFile, const ScriptContext& cx, JS::HandleValue settings, CTerrain *pTerrain_,
|
2011-03-21 18:34:45 -07:00
|
|
|
WaterManager* pWaterMan_, SkyManager* pSkyMan_,
|
2012-10-15 03:34:23 -07:00
|
|
|
CLightEnv *pLightEnv_, CGameView *pGameView_, CCinemaManager* pCinema_, CTriggerManager* pTrigMan_, CPostprocManager* pPostproc_,
|
2011-03-21 18:34:45 -07:00
|
|
|
CSimulation2 *pSimulation2_, int playerID_)
|
|
|
|
|
{
|
2015-01-24 06:46:52 -08:00
|
|
|
pSimulation2 = pSimulation2_;
|
|
|
|
|
pSimContext = pSimulation2 ? &pSimulation2->GetSimContext() : NULL;
|
2020-11-18 06:39:04 -08:00
|
|
|
m_ScriptSettings.init(cx.GetGeneralJSContext(), settings);
|
2011-03-21 18:34:45 -07:00
|
|
|
pTerrain = pTerrain_;
|
|
|
|
|
pLightEnv = pLightEnv_;
|
|
|
|
|
pGameView = pGameView_;
|
|
|
|
|
pWaterMan = pWaterMan_;
|
|
|
|
|
pSkyMan = pSkyMan_;
|
|
|
|
|
pCinema = pCinema_;
|
|
|
|
|
pTrigMan = pTrigMan_;
|
2012-10-15 03:34:23 -07:00
|
|
|
pPostproc = pPostproc_;
|
2011-03-21 18:34:45 -07:00
|
|
|
m_PlayerID = playerID_;
|
2011-10-24 07:31:05 -07:00
|
|
|
m_SkipEntities = false;
|
2011-06-13 16:32:41 -07:00
|
|
|
m_StartingCameraTarget = INVALID_ENTITY;
|
2011-03-21 18:34:45 -07:00
|
|
|
|
|
|
|
|
// delete all existing entities
|
|
|
|
|
if (pSimulation2)
|
|
|
|
|
pSimulation2->ResetState();
|
|
|
|
|
|
|
|
|
|
only_xml = false;
|
|
|
|
|
|
|
|
|
|
// copy random map settings (before entity creation)
|
2023-06-26 11:35:34 -07:00
|
|
|
LDR_Register([this](const double)
|
|
|
|
|
{
|
|
|
|
|
return LoadRMSettings();
|
|
|
|
|
}, L"CMapReader::LoadRMSettings", 50);
|
2011-03-21 18:34:45 -07:00
|
|
|
|
|
|
|
|
// load player settings script (must be done before reading map)
|
2023-06-26 11:35:34 -07:00
|
|
|
LDR_Register([this](const double)
|
|
|
|
|
{
|
|
|
|
|
return LoadPlayerSettings();
|
|
|
|
|
}, L"CMapReader::LoadPlayerSettings", 50);
|
2011-03-21 18:34:45 -07:00
|
|
|
|
|
|
|
|
// load map generator with random map script
|
2023-06-26 11:35:34 -07:00
|
|
|
LDR_Register([this, scriptFile](const double)
|
|
|
|
|
{
|
2023-11-19 11:19:32 -08:00
|
|
|
return StartMapGeneration(scriptFile);
|
|
|
|
|
}, L"CMapReader::StartMapGeneration", 1);
|
|
|
|
|
|
|
|
|
|
LDR_Register([this](const double)
|
|
|
|
|
{
|
|
|
|
|
return PollMapGeneration();
|
|
|
|
|
}, L"CMapReader::PollMapGeneration", 19999);
|
2011-03-21 18:34:45 -07:00
|
|
|
|
|
|
|
|
// parse RMS results into terrain structure
|
2023-06-26 11:35:34 -07:00
|
|
|
LDR_Register([this](const double)
|
|
|
|
|
{
|
|
|
|
|
return ParseTerrain();
|
|
|
|
|
}, L"CMapReader::ParseTerrain", 500);
|
2011-03-21 18:34:45 -07:00
|
|
|
|
|
|
|
|
// parse RMS results into environment settings
|
2023-06-26 11:35:34 -07:00
|
|
|
LDR_Register([this](const double)
|
|
|
|
|
{
|
|
|
|
|
return ParseEnvironment();
|
|
|
|
|
}, L"CMapReader::ParseEnvironment", 5);
|
2011-03-21 18:34:45 -07:00
|
|
|
|
|
|
|
|
// parse RMS results into camera settings
|
2023-06-26 11:35:34 -07:00
|
|
|
LDR_Register([this](const double)
|
|
|
|
|
{
|
|
|
|
|
return ParseCamera();
|
|
|
|
|
}, L"CMapReader::ParseCamera", 5);
|
2011-03-21 18:34:45 -07:00
|
|
|
|
2014-06-01 11:08:11 -07:00
|
|
|
// apply terrain data to the world
|
2023-06-26 11:35:34 -07:00
|
|
|
LDR_Register([this](const double)
|
|
|
|
|
{
|
|
|
|
|
return ApplyTerrainData();
|
|
|
|
|
}, L"CMapReader::ApplyTerrainData", 5);
|
2014-06-01 11:08:11 -07:00
|
|
|
|
2011-03-21 18:34:45 -07:00
|
|
|
// parse RMS results into entities
|
2023-06-26 11:35:34 -07:00
|
|
|
LDR_Register([this](const double)
|
|
|
|
|
{
|
|
|
|
|
return ParseEntities();
|
|
|
|
|
}, L"CMapReader::ParseEntities", 1000);
|
2005-03-22 13:00:56 -08:00
|
|
|
|
2014-06-01 11:08:11 -07:00
|
|
|
// apply misc data to the world
|
2023-06-26 11:35:34 -07:00
|
|
|
LDR_Register([this](const double)
|
|
|
|
|
{
|
|
|
|
|
return ApplyData();
|
|
|
|
|
}, L"CMapReader::ApplyData", 5);
|
2005-05-10 20:07:08 -07:00
|
|
|
|
2010-10-29 21:02:42 -07:00
|
|
|
// load map settings script (must be done after reading map)
|
2023-06-26 11:35:34 -07:00
|
|
|
LDR_Register([this](const double)
|
|
|
|
|
{
|
|
|
|
|
return LoadMapSettings();
|
|
|
|
|
}, L"CMapReader::LoadMapSettings", 5);
|
2004-05-29 13:56:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UnpackTerrain: unpack the terrain from the end of the input data stream
|
|
|
|
|
// - data: map size, heightmap, list of textures used by map, texture tile assignments
|
2005-05-04 16:12:46 -07:00
|
|
|
int CMapReader::UnpackTerrain()
|
2004-05-29 13:56:24 -07:00
|
|
|
{
|
2005-10-21 11:01:21 -07:00
|
|
|
// yield after this time is reached. balances increased progress bar
|
|
|
|
|
// smoothness vs. slowing down loading.
|
2008-01-07 12:03:19 -08:00
|
|
|
const double end_time = timer_Time() + 200e-3;
|
2005-05-04 16:12:46 -07:00
|
|
|
|
|
|
|
|
// first call to generator (this is skipped after first call,
|
|
|
|
|
// i.e. when the loop below was interrupted)
|
2005-05-10 20:07:08 -07:00
|
|
|
if (cur_terrain_tex == 0)
|
2005-05-04 16:12:46 -07:00
|
|
|
{
|
2009-11-08 08:49:52 -08:00
|
|
|
m_PatchesPerSide = (ssize_t)unpacker.UnpackSize();
|
2005-05-04 16:12:46 -07:00
|
|
|
|
2005-10-07 14:09:29 -07:00
|
|
|
// unpack heightmap [600us]
|
2009-11-08 08:49:52 -08:00
|
|
|
size_t verticesPerSide = m_PatchesPerSide*PATCH_SIZE+1;
|
2005-05-04 16:12:46 -07:00
|
|
|
m_Heightmap.resize(SQR(verticesPerSide));
|
2005-05-10 20:07:08 -07:00
|
|
|
unpacker.UnpackRaw(&m_Heightmap[0], SQR(verticesPerSide)*sizeof(u16));
|
2004-05-29 13:56:24 -07:00
|
|
|
|
2005-05-04 16:12:46 -07:00
|
|
|
// unpack # textures
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 11:48:32 -07:00
|
|
|
num_terrain_tex = unpacker.UnpackSize();
|
2005-05-04 16:12:46 -07:00
|
|
|
m_TerrainTextures.reserve(num_terrain_tex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// unpack texture names; find handle for each texture.
|
|
|
|
|
// interruptible.
|
2005-05-10 20:07:08 -07:00
|
|
|
while (cur_terrain_tex < num_terrain_tex)
|
2005-05-04 16:12:46 -07:00
|
|
|
{
|
2004-05-29 13:56:24 -07:00
|
|
|
CStr texturename;
|
|
|
|
|
unpacker.UnpackString(texturename);
|
|
|
|
|
|
2022-05-09 10:31:00 -07:00
|
|
|
if (CTerrainTextureManager::IsInitialised())
|
2022-01-29 00:22:28 -08:00
|
|
|
{
|
|
|
|
|
CTerrainTextureEntry* texentry = g_TexMan.FindTexture(texturename);
|
|
|
|
|
m_TerrainTextures.push_back(texentry);
|
|
|
|
|
}
|
2005-05-04 16:12:46 -07:00
|
|
|
|
|
|
|
|
cur_terrain_tex++;
|
|
|
|
|
LDR_CHECK_TIMEOUT(cur_terrain_tex, num_terrain_tex);
|
2004-05-29 13:56:24 -07:00
|
|
|
}
|
2005-05-04 16:12:46 -07:00
|
|
|
|
|
|
|
|
// unpack tile data [3ms]
|
2009-11-08 08:49:52 -08:00
|
|
|
ssize_t tilesPerSide = m_PatchesPerSide*PATCH_SIZE;
|
2008-07-12 03:45:11 -07:00
|
|
|
m_Tiles.resize(size_t(SQR(tilesPerSide)));
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 11:48:32 -07:00
|
|
|
unpacker.UnpackRaw(&m_Tiles[0], sizeof(STileDesc)*m_Tiles.size());
|
2005-05-04 16:12:46 -07:00
|
|
|
|
|
|
|
|
// reset generator state.
|
|
|
|
|
cur_terrain_tex = 0;
|
|
|
|
|
|
|
|
|
|
return 0;
|
2004-05-29 13:56:24 -07:00
|
|
|
}
|
|
|
|
|
|
2014-06-01 11:08:11 -07:00
|
|
|
int CMapReader::ApplyTerrainData()
|
2004-05-29 13:56:24 -07:00
|
|
|
{
|
2010-05-03 12:13:58 -07:00
|
|
|
if (m_PatchesPerSide == 0)
|
|
|
|
|
{
|
|
|
|
|
// we'll probably crash when trying to use this map later
|
2011-04-15 21:04:06 -07:00
|
|
|
throw PSERROR_Game_World_MapLoadFailed("Error loading map: no terrain data.\nCheck application log for details.");
|
2010-05-03 12:13:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!only_xml)
|
|
|
|
|
{
|
|
|
|
|
// initialise the terrain
|
|
|
|
|
pTerrain->Initialize(m_PatchesPerSide, &m_Heightmap[0]);
|
|
|
|
|
|
2022-05-09 10:31:00 -07:00
|
|
|
if (CTerrainTextureManager::IsInitialised())
|
|
|
|
|
{
|
|
|
|
|
// setup the textures on the minipatches
|
|
|
|
|
STileDesc* tileptr = &m_Tiles[0];
|
|
|
|
|
for (ssize_t j=0; j<m_PatchesPerSide; j++) {
|
|
|
|
|
for (ssize_t i=0; i<m_PatchesPerSide; i++) {
|
|
|
|
|
for (ssize_t m=0; m<PATCH_SIZE; m++) {
|
|
|
|
|
for (ssize_t k=0; k<PATCH_SIZE; k++) {
|
|
|
|
|
CMiniPatch& mp = pTerrain->GetPatch(i,j)->m_MiniPatches[m][k]; // can't fail
|
|
|
|
|
|
|
|
|
|
mp.Tex = m_TerrainTextures[tileptr->m_Tex1Index];
|
|
|
|
|
mp.Priority = tileptr->m_Priority;
|
|
|
|
|
|
|
|
|
|
tileptr++;
|
|
|
|
|
}
|
2010-05-03 12:13:58 -07:00
|
|
|
}
|
2004-05-29 13:56:24 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-01 11:08:11 -07:00
|
|
|
CmpPtr<ICmpTerrain> cmpTerrain(*pSimContext, SYSTEM_ENTITY);
|
|
|
|
|
if (cmpTerrain)
|
|
|
|
|
cmpTerrain->ReloadTerrain();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ApplyData: take all the input data, and rebuild the scene from it
|
|
|
|
|
int CMapReader::ApplyData()
|
|
|
|
|
{
|
2011-03-21 18:34:45 -07:00
|
|
|
// copy over the lighting parameters
|
|
|
|
|
if (pLightEnv)
|
|
|
|
|
*pLightEnv = m_LightEnv;
|
2010-07-03 06:15:57 -07:00
|
|
|
|
2011-10-24 07:31:05 -07:00
|
|
|
CmpPtr<ICmpPlayerManager> cmpPlayerManager(*pSimContext, SYSTEM_ENTITY);
|
2011-06-13 16:32:41 -07:00
|
|
|
|
2012-02-07 18:46:15 -08:00
|
|
|
if (pGameView && cmpPlayerManager)
|
2010-07-03 06:15:57 -07:00
|
|
|
{
|
2011-06-13 16:32:41 -07:00
|
|
|
// Default to global camera (with constraints)
|
2010-09-03 02:50:16 -07:00
|
|
|
pGameView->ResetCameraTarget(pGameView->GetCamera()->GetFocus());
|
2016-01-13 16:04:32 -08:00
|
|
|
|
2011-06-16 14:21:33 -07:00
|
|
|
// TODO: Starting rotation?
|
2011-10-24 07:31:05 -07:00
|
|
|
CmpPtr<ICmpPlayer> cmpPlayer(*pSimContext, cmpPlayerManager->GetPlayerByID(m_PlayerID));
|
2012-02-07 18:46:15 -08:00
|
|
|
if (cmpPlayer && cmpPlayer->HasStartingCamera())
|
2010-07-03 06:15:57 -07:00
|
|
|
{
|
2011-06-13 16:32:41 -07:00
|
|
|
// Use player starting camera
|
2011-06-16 14:21:33 -07:00
|
|
|
CFixedVector3D pos = cmpPlayer->GetStartingCameraPos();
|
2011-06-13 16:32:41 -07:00
|
|
|
pGameView->ResetCameraTarget(CVector3D(pos.X.ToFloat(), pos.Y.ToFloat(), pos.Z.ToFloat()));
|
|
|
|
|
}
|
|
|
|
|
else if (m_StartingCameraTarget != INVALID_ENTITY)
|
|
|
|
|
{
|
|
|
|
|
// Point camera at entity
|
2011-10-24 07:31:05 -07:00
|
|
|
CmpPtr<ICmpPosition> cmpPosition(*pSimContext, m_StartingCameraTarget);
|
2012-02-07 18:46:15 -08:00
|
|
|
if (cmpPosition)
|
2010-09-03 02:50:16 -07:00
|
|
|
{
|
|
|
|
|
CFixedVector3D pos = cmpPosition->GetPosition();
|
|
|
|
|
pGameView->ResetCameraTarget(CVector3D(pos.X.ToFloat(), pos.Y.ToFloat(), pos.Z.ToFloat()));
|
|
|
|
|
}
|
2010-07-03 06:15:57 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-03 14:42:09 -07:00
|
|
|
return 0;
|
2004-05-29 13:56:24 -07:00
|
|
|
}
|
2005-01-12 06:31:47 -08:00
|
|
|
|
2010-10-29 21:02:42 -07:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
2005-01-12 06:31:47 -08:00
|
|
|
|
2005-05-03 14:42:09 -07:00
|
|
|
|
2010-08-04 14:15:41 -07:00
|
|
|
PSRETURN CMapSummaryReader::LoadMap(const VfsPath& pathname)
|
|
|
|
|
{
|
2011-03-23 06:36:20 -07:00
|
|
|
VfsPath filename_xml = pathname.ChangeExtension(L".xml");
|
2010-08-04 14:15:41 -07:00
|
|
|
|
|
|
|
|
CXeromyces xmb_file;
|
2015-06-07 14:56:52 -07:00
|
|
|
if (xmb_file.Load(g_VFS, filename_xml, "scenario") != PSRETURN_OK)
|
2010-08-04 14:15:41 -07:00
|
|
|
return PSRETURN_File_ReadFailed;
|
|
|
|
|
|
|
|
|
|
// Define all the relevant elements used in the XML file
|
|
|
|
|
#define EL(x) int el_##x = xmb_file.GetElementID(#x)
|
|
|
|
|
#define AT(x) int at_##x = xmb_file.GetAttributeID(#x)
|
|
|
|
|
EL(scenario);
|
|
|
|
|
EL(scriptsettings);
|
|
|
|
|
#undef AT
|
|
|
|
|
#undef EL
|
|
|
|
|
|
|
|
|
|
XMBElement root = xmb_file.GetRoot();
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(root.GetNodeName() == el_scenario);
|
2010-08-04 14:15:41 -07:00
|
|
|
|
|
|
|
|
XERO_ITER_EL(root, child)
|
|
|
|
|
{
|
|
|
|
|
int child_name = child.GetNodeName();
|
|
|
|
|
if (child_name == el_scriptsettings)
|
|
|
|
|
{
|
|
|
|
|
m_ScriptSettings = child.GetText();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return PSRETURN_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-23 17:32:42 -07:00
|
|
|
void CMapSummaryReader::GetMapSettings(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret)
|
2010-08-04 14:15:41 -07:00
|
|
|
{
|
Improve JS Exception handling.
- Check for pending exceptions after function calls and script
executions.
- Call LOGERROR instead of JS_ReportError when there is a conversion
error in FromJSVal, since that can only be called from C++ (where JS
errors don't really make sense). Instead, C++ callers of FromJSVal
should handle the failure and, themselves, either report an error or
simply do something else.
- Wrap JS_ReportError since that makes updating it later easier.
This isn't a systematical fix since ToJSVal also ought return a boolean
for failures, and we probably should trigger errors instead of warnings
on 'implicit' conversions, rather a preparation diff.
Part of the SM52 migration, stage: SM45 compatible (actually SM52
incompatible, too).
Based on a patch by: Itms
Comments by: Vladislavbelov, Stan`
Refs #742, #4893
Differential Revision: https://code.wildfiregames.com/D3093
This was SVN commit r24187.
2020-11-15 10:29:17 -08:00
|
|
|
ScriptRequest rq(scriptInterface);
|
2016-01-13 16:04:32 -08:00
|
|
|
|
2021-05-13 10:23:52 -07:00
|
|
|
Script::CreateObject(rq, ret);
|
2019-07-22 12:35:14 -07:00
|
|
|
|
2015-01-24 06:46:52 -08:00
|
|
|
if (m_ScriptSettings.empty())
|
|
|
|
|
return;
|
|
|
|
|
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue scriptSettingsVal(rq.cx);
|
2021-05-14 03:18:03 -07:00
|
|
|
Script::ParseJSON(rq, m_ScriptSettings, &scriptSettingsVal);
|
2021-05-13 10:23:52 -07:00
|
|
|
Script::SetProperty(rq, ret, "settings", scriptSettingsVal, false);
|
2010-08-04 14:15:41 -07:00
|
|
|
}
|
|
|
|
|
|
2010-10-29 21:02:42 -07:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
2010-08-04 14:15:41 -07:00
|
|
|
|
2010-10-29 21:02:42 -07:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
2010-08-04 14:15:41 -07:00
|
|
|
|
|
|
|
|
|
2005-05-10 20:07:08 -07:00
|
|
|
// Holds various state data while reading maps, so that loading can be
|
|
|
|
|
// interrupted (e.g. to update the progress display) then later resumed.
|
2009-01-03 10:40:28 -08:00
|
|
|
class CXMLReader
|
2005-01-12 06:31:47 -08:00
|
|
|
{
|
2009-01-03 10:40:28 -08:00
|
|
|
NONCOPYABLE(CXMLReader);
|
2005-05-03 14:42:09 -07:00
|
|
|
public:
|
2009-11-03 13:46:35 -08:00
|
|
|
CXMLReader(const VfsPath& xml_filename, CMapReader& mapReader)
|
2015-06-14 16:50:38 -07:00
|
|
|
: m_MapReader(mapReader), nodes(NULL, 0, NULL)
|
2005-05-03 14:42:09 -07:00
|
|
|
{
|
|
|
|
|
Init(xml_filename);
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-17 12:08:20 -08:00
|
|
|
CStr ReadScriptSettings();
|
2010-10-29 21:02:42 -07:00
|
|
|
|
2014-06-01 11:08:11 -07:00
|
|
|
// read everything except for entities
|
|
|
|
|
void ReadXML();
|
|
|
|
|
|
2005-05-03 14:42:09 -07:00
|
|
|
// return semantics: see Loader.cpp!LoadFunc.
|
2014-06-01 11:08:11 -07:00
|
|
|
int ProgressiveReadEntities();
|
2005-05-03 14:42:09 -07:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
CXeromyces xmb_file;
|
|
|
|
|
|
2005-05-10 20:07:08 -07:00
|
|
|
CMapReader& m_MapReader;
|
|
|
|
|
|
2005-12-08 17:08:08 -08:00
|
|
|
int el_entity;
|
2006-08-21 19:24:44 -07:00
|
|
|
int el_tracks;
|
2005-05-03 14:42:09 -07:00
|
|
|
int el_template, el_player;
|
2012-08-01 14:38:13 -07:00
|
|
|
int el_position, el_orientation, el_obstruction;
|
2020-03-15 06:54:50 -07:00
|
|
|
int el_garrison;
|
2020-11-11 11:40:44 -08:00
|
|
|
int el_turrets;
|
2005-05-03 14:42:09 -07:00
|
|
|
int el_actor;
|
2020-11-26 14:28:50 -08:00
|
|
|
int at_x;
|
|
|
|
|
int at_y;
|
|
|
|
|
int at_z;
|
2012-08-01 14:38:13 -07:00
|
|
|
int at_group, at_group2;
|
2005-05-03 14:42:09 -07:00
|
|
|
int at_angle;
|
2007-01-16 19:25:20 -08:00
|
|
|
int at_uid;
|
2013-02-02 18:16:52 -08:00
|
|
|
int at_seed;
|
2020-11-11 11:40:44 -08:00
|
|
|
int at_turret;
|
2005-05-03 14:42:09 -07:00
|
|
|
|
2005-05-10 20:07:08 -07:00
|
|
|
XMBElementList nodes; // children of root
|
2005-05-03 14:42:09 -07:00
|
|
|
|
|
|
|
|
// loop counters
|
2015-05-31 17:29:35 -07:00
|
|
|
size_t node_idx;
|
|
|
|
|
size_t entity_idx;
|
2005-05-03 14:42:09 -07:00
|
|
|
|
|
|
|
|
// # entities+nonentities processed and total (for progress calc)
|
|
|
|
|
int completed_jobs, total_jobs;
|
|
|
|
|
|
2010-06-30 14:41:04 -07:00
|
|
|
// maximum used entity ID, so we can safely allocate new ones
|
|
|
|
|
entity_id_t max_uid;
|
2005-05-03 14:42:09 -07:00
|
|
|
|
2009-11-03 13:46:35 -08:00
|
|
|
void Init(const VfsPath& xml_filename);
|
2005-05-10 20:07:08 -07:00
|
|
|
|
2010-05-03 12:13:58 -07:00
|
|
|
void ReadTerrain(XMBElement parent);
|
2005-05-10 20:07:08 -07:00
|
|
|
void ReadEnvironment(XMBElement parent);
|
2006-03-21 12:55:45 -08:00
|
|
|
void ReadCamera(XMBElement parent);
|
2016-01-03 04:41:04 -08:00
|
|
|
void ReadPaths(XMBElement parent);
|
2006-11-24 11:45:04 -08:00
|
|
|
void ReadTriggers(XMBElement parent);
|
2005-05-10 20:07:08 -07:00
|
|
|
int ReadEntities(XMBElement parent, double end_time);
|
2005-05-03 14:42:09 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2009-11-03 13:46:35 -08:00
|
|
|
void CXMLReader::Init(const VfsPath& xml_filename)
|
2005-05-03 14:42:09 -07:00
|
|
|
{
|
|
|
|
|
// must only assign once, so do it here
|
2013-02-02 18:16:52 -08:00
|
|
|
node_idx = entity_idx = 0;
|
2005-05-03 14:42:09 -07:00
|
|
|
|
2015-06-07 14:56:52 -07:00
|
|
|
if (xmb_file.Load(g_VFS, xml_filename, "scenario") != PSRETURN_OK)
|
2019-07-20 18:35:39 -07:00
|
|
|
throw PSERROR_Game_World_MapLoadFailed("Could not read map XML file!");
|
2005-01-12 06:31:47 -08:00
|
|
|
|
2005-12-08 17:08:08 -08:00
|
|
|
// define the elements and attributes that are frequently used in the XML file,
|
|
|
|
|
// so we don't need to do lots of string construction and comparison when
|
|
|
|
|
// reading the data.
|
2005-05-10 20:07:08 -07:00
|
|
|
// (Needs to be synchronised with the list in CXMLReader - ugh)
|
2007-05-02 05:07:08 -07:00
|
|
|
#define EL(x) el_##x = xmb_file.GetElementID(#x)
|
|
|
|
|
#define AT(x) at_##x = xmb_file.GetAttributeID(#x)
|
2005-01-12 06:31:47 -08:00
|
|
|
EL(entity);
|
2006-08-21 19:24:44 -07:00
|
|
|
EL(tracks);
|
2005-01-12 06:31:47 -08:00
|
|
|
EL(template);
|
2005-01-16 15:09:41 -08:00
|
|
|
EL(player);
|
2005-01-12 06:31:47 -08:00
|
|
|
EL(position);
|
2020-03-15 06:54:50 -07:00
|
|
|
EL(garrison);
|
2020-11-11 11:40:44 -08:00
|
|
|
EL(turrets);
|
2005-01-12 06:31:47 -08:00
|
|
|
EL(orientation);
|
2012-08-01 14:38:13 -07:00
|
|
|
EL(obstruction);
|
2005-03-29 12:50:04 -08:00
|
|
|
EL(actor);
|
2005-05-10 20:07:08 -07:00
|
|
|
AT(x); AT(y); AT(z);
|
2012-08-01 14:38:13 -07:00
|
|
|
AT(group); AT(group2);
|
2005-01-12 06:31:47 -08:00
|
|
|
AT(angle);
|
2007-01-16 19:25:20 -08:00
|
|
|
AT(uid);
|
2013-02-02 18:16:52 -08:00
|
|
|
AT(seed);
|
2020-11-11 11:40:44 -08:00
|
|
|
AT(turret);
|
2005-01-12 06:31:47 -08:00
|
|
|
#undef AT
|
|
|
|
|
#undef EL
|
|
|
|
|
|
2007-05-02 05:07:08 -07:00
|
|
|
XMBElement root = xmb_file.GetRoot();
|
XMB Improvements, parse JS into XMB, make strings more efficient.
XMB format is bumped to 4, invalidating all cached files. The
differences are:
- element/attribute names are stored after the elements themselves, and
not before. This allows writing XMB data in one pass instead of two.
- names themselves becomes offsets (instead of arbitrary integers),
making getting the string from the int name much more efficient.
XMBFile is renamed to XMBData to clarify that it does not, in fact,
refer to a file on disk.
XMBData::GetElementString is also changed to return a const char*, thus
not creating an std::string. A string_view version is added where
convenient.
The XML->XMB and JS->XMB conversion functions and the corresponding
storage are moved to `ps/XMB`, since that format doesn't particularly
relate to XML. CXeromyces becomes lighter and more focused as a result.
The XML->XMB conversion also benefits from the above streamlining.
Note that in a few cases, string_view gets printed to CLogger via
data(), which is generally not legal, but we know that the strings are
null-terminated here. Our libfmt (version 4) doesn't support
string_view, that would be v5.
Differential Revision: https://code.wildfiregames.com/D3909
This was SVN commit r25375.
2021-05-04 06:02:34 -07:00
|
|
|
ENSURE(xmb_file.GetElementStringView(root.GetNodeName()) == "Scenario");
|
2007-05-02 05:07:08 -07:00
|
|
|
nodes = root.GetChildNodes();
|
2005-01-12 06:31:47 -08:00
|
|
|
|
2005-05-03 14:42:09 -07:00
|
|
|
// find out total number of entities+nonentities
|
|
|
|
|
// (used when calculating progress)
|
|
|
|
|
completed_jobs = 0;
|
|
|
|
|
total_jobs = 0;
|
2015-05-31 17:29:35 -07:00
|
|
|
for (XMBElement node : nodes)
|
|
|
|
|
total_jobs += node.GetChildNodes().size();
|
2010-01-22 12:03:14 -08:00
|
|
|
|
2010-05-20 11:09:23 -07:00
|
|
|
// Find the maximum entity ID, so we can safely allocate new IDs without conflicts
|
2010-01-22 12:03:14 -08:00
|
|
|
|
2010-06-30 14:41:04 -07:00
|
|
|
max_uid = SYSTEM_ENTITY;
|
2010-01-22 12:03:14 -08:00
|
|
|
|
2010-05-20 11:09:23 -07:00
|
|
|
XMBElement ents = nodes.GetFirstNamedItem(xmb_file.GetElementID("Entities"));
|
|
|
|
|
XERO_ITER_EL(ents, ent)
|
|
|
|
|
{
|
2011-02-17 12:08:20 -08:00
|
|
|
CStr uid = ent.GetAttributes().GetNamedItem(at_uid);
|
|
|
|
|
max_uid = std::max(max_uid, (entity_id_t)uid.ToUInt());
|
2010-05-20 11:09:23 -07:00
|
|
|
}
|
2010-06-30 14:41:04 -07:00
|
|
|
}
|
|
|
|
|
|
2010-01-22 12:03:14 -08:00
|
|
|
|
2011-02-17 12:08:20 -08:00
|
|
|
CStr CXMLReader::ReadScriptSettings()
|
2010-06-30 14:41:04 -07:00
|
|
|
{
|
2010-10-29 21:02:42 -07:00
|
|
|
XMBElement root = xmb_file.GetRoot();
|
XMB Improvements, parse JS into XMB, make strings more efficient.
XMB format is bumped to 4, invalidating all cached files. The
differences are:
- element/attribute names are stored after the elements themselves, and
not before. This allows writing XMB data in one pass instead of two.
- names themselves becomes offsets (instead of arbitrary integers),
making getting the string from the int name much more efficient.
XMBFile is renamed to XMBData to clarify that it does not, in fact,
refer to a file on disk.
XMBData::GetElementString is also changed to return a const char*, thus
not creating an std::string. A string_view version is added where
convenient.
The XML->XMB and JS->XMB conversion functions and the corresponding
storage are moved to `ps/XMB`, since that format doesn't particularly
relate to XML. CXeromyces becomes lighter and more focused as a result.
The XML->XMB conversion also benefits from the above streamlining.
Note that in a few cases, string_view gets printed to CLogger via
data(), which is generally not legal, but we know that the strings are
null-terminated here. Our libfmt (version 4) doesn't support
string_view, that would be v5.
Differential Revision: https://code.wildfiregames.com/D3909
This was SVN commit r25375.
2021-05-04 06:02:34 -07:00
|
|
|
ENSURE(xmb_file.GetElementStringView(root.GetNodeName()) == "Scenario");
|
2010-10-29 21:02:42 -07:00
|
|
|
nodes = root.GetChildNodes();
|
2010-06-30 14:41:04 -07:00
|
|
|
|
2010-10-29 21:02:42 -07:00
|
|
|
XMBElement settings = nodes.GetFirstNamedItem(xmb_file.GetElementID("ScriptSettings"));
|
2010-06-30 14:41:04 -07:00
|
|
|
|
2010-10-29 21:02:42 -07:00
|
|
|
return settings.GetText();
|
2005-05-03 14:42:09 -07:00
|
|
|
}
|
2005-01-12 06:31:47 -08:00
|
|
|
|
2005-05-03 14:42:09 -07:00
|
|
|
|
2010-05-03 12:13:58 -07:00
|
|
|
void CXMLReader::ReadTerrain(XMBElement parent)
|
|
|
|
|
{
|
|
|
|
|
#define AT(x) int at_##x = xmb_file.GetAttributeID(#x)
|
|
|
|
|
AT(patches);
|
|
|
|
|
AT(texture);
|
|
|
|
|
AT(priority);
|
|
|
|
|
AT(height);
|
|
|
|
|
#undef AT
|
|
|
|
|
|
|
|
|
|
ssize_t patches = 9;
|
|
|
|
|
CStr texture = "grass1_spring";
|
|
|
|
|
int priority = 0;
|
|
|
|
|
u16 height = 16384;
|
|
|
|
|
|
|
|
|
|
XERO_ITER_ATTR(parent, attr)
|
|
|
|
|
{
|
|
|
|
|
if (attr.Name == at_patches)
|
2011-02-17 12:08:20 -08:00
|
|
|
patches = attr.Value.ToInt();
|
2010-05-03 12:13:58 -07:00
|
|
|
else if (attr.Name == at_texture)
|
2011-02-17 12:08:20 -08:00
|
|
|
texture = attr.Value;
|
2010-05-03 12:13:58 -07:00
|
|
|
else if (attr.Name == at_priority)
|
2011-02-17 12:08:20 -08:00
|
|
|
priority = attr.Value.ToInt();
|
2010-05-03 12:13:58 -07:00
|
|
|
else if (attr.Name == at_height)
|
2011-02-17 12:08:20 -08:00
|
|
|
height = (u16)attr.Value.ToInt();
|
2010-05-03 12:13:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_MapReader.m_PatchesPerSide = patches;
|
|
|
|
|
|
|
|
|
|
// Load the texture
|
2022-05-09 10:31:00 -07:00
|
|
|
CTerrainTextureEntry* texentry = nullptr;
|
|
|
|
|
if (CTerrainTextureManager::IsInitialised())
|
|
|
|
|
texentry = g_TexMan.FindTexture(texture);
|
2010-05-03 12:13:58 -07:00
|
|
|
|
|
|
|
|
m_MapReader.pTerrain->Initialize(patches, NULL);
|
|
|
|
|
|
|
|
|
|
// Fill the heightmap
|
|
|
|
|
u16* heightmap = m_MapReader.pTerrain->GetHeightMap();
|
|
|
|
|
ssize_t verticesPerSide = m_MapReader.pTerrain->GetVerticesPerSide();
|
|
|
|
|
for (ssize_t i = 0; i < SQR(verticesPerSide); ++i)
|
|
|
|
|
heightmap[i] = height;
|
|
|
|
|
|
|
|
|
|
// Fill the texture map
|
|
|
|
|
for (ssize_t pz = 0; pz < patches; ++pz)
|
|
|
|
|
{
|
|
|
|
|
for (ssize_t px = 0; px < patches; ++px)
|
|
|
|
|
{
|
|
|
|
|
CPatch* patch = m_MapReader.pTerrain->GetPatch(px, pz); // can't fail
|
|
|
|
|
|
|
|
|
|
for (ssize_t z = 0; z < PATCH_SIZE; ++z)
|
|
|
|
|
{
|
|
|
|
|
for (ssize_t x = 0; x < PATCH_SIZE; ++x)
|
|
|
|
|
{
|
2010-05-27 16:31:03 -07:00
|
|
|
patch->m_MiniPatches[z][x].Tex = texentry;
|
|
|
|
|
patch->m_MiniPatches[z][x].Priority = priority;
|
2010-05-03 12:13:58 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-10 20:07:08 -07:00
|
|
|
void CXMLReader::ReadEnvironment(XMBElement parent)
|
|
|
|
|
{
|
2007-05-02 05:07:08 -07:00
|
|
|
#define EL(x) int el_##x = xmb_file.GetElementID(#x)
|
|
|
|
|
#define AT(x) int at_##x = xmb_file.GetAttributeID(#x)
|
2012-10-15 03:34:23 -07:00
|
|
|
EL(posteffect);
|
2006-06-21 15:37:31 -07:00
|
|
|
EL(skyset);
|
2015-03-15 16:59:48 -07:00
|
|
|
EL(suncolor);
|
2005-12-08 17:08:08 -08:00
|
|
|
EL(sunelevation);
|
|
|
|
|
EL(sunrotation);
|
2021-01-17 05:10:00 -08:00
|
|
|
EL(ambientcolor);
|
2006-06-11 00:03:59 -07:00
|
|
|
EL(water);
|
|
|
|
|
EL(waterbody);
|
|
|
|
|
EL(type);
|
2015-03-15 16:59:48 -07:00
|
|
|
EL(color);
|
2014-07-03 13:07:15 -07:00
|
|
|
EL(tint);
|
2006-06-11 00:03:59 -07:00
|
|
|
EL(height);
|
|
|
|
|
EL(waviness);
|
2006-09-18 11:09:07 -07:00
|
|
|
EL(murkiness);
|
2014-07-03 13:07:15 -07:00
|
|
|
EL(windangle);
|
2012-10-15 03:34:23 -07:00
|
|
|
EL(fog);
|
2015-03-15 16:59:48 -07:00
|
|
|
EL(fogcolor);
|
2012-10-15 03:34:23 -07:00
|
|
|
EL(fogfactor);
|
|
|
|
|
EL(fogthickness);
|
|
|
|
|
EL(postproc);
|
|
|
|
|
EL(brightness);
|
|
|
|
|
EL(contrast);
|
|
|
|
|
EL(saturation);
|
|
|
|
|
EL(bloom);
|
2005-12-08 17:08:08 -08:00
|
|
|
AT(r); AT(g); AT(b);
|
|
|
|
|
#undef AT
|
|
|
|
|
#undef EL
|
|
|
|
|
|
2005-05-10 20:07:08 -07:00
|
|
|
XERO_ITER_EL(parent, element)
|
|
|
|
|
{
|
2007-05-02 05:07:08 -07:00
|
|
|
int element_name = element.GetNodeName();
|
2005-07-30 13:12:41 -07:00
|
|
|
|
2007-05-02 05:07:08 -07:00
|
|
|
XMBAttributeList attrs = element.GetAttributes();
|
2006-06-21 15:37:31 -07:00
|
|
|
|
2016-12-12 15:46:46 -08:00
|
|
|
if (element_name == el_skyset)
|
2006-06-21 15:37:31 -07:00
|
|
|
{
|
2010-02-08 14:05:05 -08:00
|
|
|
if (m_MapReader.pSkyMan)
|
2011-02-17 12:08:20 -08:00
|
|
|
m_MapReader.pSkyMan->SetSkySet(element.GetText().FromUTF8());
|
2006-06-21 15:37:31 -07:00
|
|
|
}
|
2015-03-15 16:59:48 -07:00
|
|
|
else if (element_name == el_suncolor)
|
2005-05-10 20:07:08 -07:00
|
|
|
{
|
|
|
|
|
m_MapReader.m_LightEnv.m_SunColor = RGBColor(
|
2011-02-17 12:08:20 -08:00
|
|
|
attrs.GetNamedItem(at_r).ToFloat(),
|
|
|
|
|
attrs.GetNamedItem(at_g).ToFloat(),
|
|
|
|
|
attrs.GetNamedItem(at_b).ToFloat());
|
2005-05-10 20:07:08 -07:00
|
|
|
}
|
|
|
|
|
else if (element_name == el_sunelevation)
|
|
|
|
|
{
|
2011-02-17 12:08:20 -08:00
|
|
|
m_MapReader.m_LightEnv.m_Elevation = attrs.GetNamedItem(at_angle).ToFloat();
|
2005-05-10 20:07:08 -07:00
|
|
|
}
|
|
|
|
|
else if (element_name == el_sunrotation)
|
|
|
|
|
{
|
2011-02-17 12:08:20 -08:00
|
|
|
m_MapReader.m_LightEnv.m_Rotation = attrs.GetNamedItem(at_angle).ToFloat();
|
2005-05-10 20:07:08 -07:00
|
|
|
}
|
2021-01-17 05:10:00 -08:00
|
|
|
else if (element_name == el_ambientcolor)
|
2005-05-10 20:07:08 -07:00
|
|
|
{
|
2021-01-17 05:10:00 -08:00
|
|
|
m_MapReader.m_LightEnv.m_AmbientColor = RGBColor(
|
2011-02-17 12:08:20 -08:00
|
|
|
attrs.GetNamedItem(at_r).ToFloat(),
|
|
|
|
|
attrs.GetNamedItem(at_g).ToFloat(),
|
|
|
|
|
attrs.GetNamedItem(at_b).ToFloat());
|
2005-05-10 20:07:08 -07:00
|
|
|
}
|
2012-10-15 03:34:23 -07:00
|
|
|
else if (element_name == el_fog)
|
|
|
|
|
{
|
|
|
|
|
XERO_ITER_EL(element, fog)
|
|
|
|
|
{
|
2020-11-26 14:28:50 -08:00
|
|
|
int fog_element_name = fog.GetNodeName();
|
|
|
|
|
if (fog_element_name == el_fogcolor)
|
2012-10-15 03:34:23 -07:00
|
|
|
{
|
2020-11-26 14:28:50 -08:00
|
|
|
XMBAttributeList fogAttributes = fog.GetAttributes();
|
2012-10-15 03:34:23 -07:00
|
|
|
m_MapReader.m_LightEnv.m_FogColor = RGBColor(
|
2020-11-26 14:28:50 -08:00
|
|
|
fogAttributes.GetNamedItem(at_r).ToFloat(),
|
|
|
|
|
fogAttributes.GetNamedItem(at_g).ToFloat(),
|
|
|
|
|
fogAttributes.GetNamedItem(at_b).ToFloat());
|
2012-10-15 03:34:23 -07:00
|
|
|
}
|
2020-11-26 14:28:50 -08:00
|
|
|
else if (fog_element_name == el_fogfactor)
|
2012-10-15 03:34:23 -07:00
|
|
|
{
|
|
|
|
|
m_MapReader.m_LightEnv.m_FogFactor = fog.GetText().ToFloat();
|
|
|
|
|
}
|
2020-11-26 14:28:50 -08:00
|
|
|
else if (fog_element_name == el_fogthickness)
|
2012-10-15 03:34:23 -07:00
|
|
|
{
|
|
|
|
|
m_MapReader.m_LightEnv.m_FogMax = fog.GetText().ToFloat();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (element_name == el_postproc)
|
|
|
|
|
{
|
|
|
|
|
XERO_ITER_EL(element, postproc)
|
|
|
|
|
{
|
2020-11-26 14:28:50 -08:00
|
|
|
int post_element_name = postproc.GetNodeName();
|
|
|
|
|
if (post_element_name == el_brightness)
|
2012-10-15 03:34:23 -07:00
|
|
|
{
|
|
|
|
|
m_MapReader.m_LightEnv.m_Brightness = postproc.GetText().ToFloat();
|
|
|
|
|
}
|
2020-11-26 14:28:50 -08:00
|
|
|
else if (post_element_name == el_contrast)
|
2012-10-15 03:34:23 -07:00
|
|
|
{
|
|
|
|
|
m_MapReader.m_LightEnv.m_Contrast = postproc.GetText().ToFloat();
|
|
|
|
|
}
|
2020-11-26 14:28:50 -08:00
|
|
|
else if (post_element_name == el_saturation)
|
2012-10-15 03:34:23 -07:00
|
|
|
{
|
|
|
|
|
m_MapReader.m_LightEnv.m_Saturation = postproc.GetText().ToFloat();
|
|
|
|
|
}
|
2020-11-26 14:28:50 -08:00
|
|
|
else if (post_element_name == el_bloom)
|
2012-10-15 03:34:23 -07:00
|
|
|
{
|
|
|
|
|
m_MapReader.m_LightEnv.m_Bloom = postproc.GetText().ToFloat();
|
|
|
|
|
}
|
2020-11-26 14:28:50 -08:00
|
|
|
else if (post_element_name == el_posteffect)
|
2012-10-15 03:34:23 -07:00
|
|
|
{
|
2012-12-03 11:00:20 -08:00
|
|
|
if (m_MapReader.pPostproc)
|
|
|
|
|
m_MapReader.pPostproc->SetPostEffect(postproc.GetText().FromUTF8());
|
2012-10-15 03:34:23 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-06-11 00:03:59 -07:00
|
|
|
else if (element_name == el_water)
|
|
|
|
|
{
|
|
|
|
|
XERO_ITER_EL(element, waterbody)
|
|
|
|
|
{
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(waterbody.GetNodeName() == el_waterbody);
|
2006-06-11 00:03:59 -07:00
|
|
|
XERO_ITER_EL(waterbody, waterelement)
|
|
|
|
|
{
|
2020-11-26 14:28:50 -08:00
|
|
|
int water_element_name = waterelement.GetNodeName();
|
|
|
|
|
if (water_element_name == el_height)
|
2010-05-27 16:23:53 -07:00
|
|
|
{
|
2012-02-07 18:46:15 -08:00
|
|
|
CmpPtr<ICmpWaterManager> cmpWaterManager(*m_MapReader.pSimContext, SYSTEM_ENTITY);
|
|
|
|
|
ENSURE(cmpWaterManager);
|
|
|
|
|
cmpWaterManager->SetWaterLevel(entity_pos_t::FromString(waterelement.GetText()));
|
2010-09-17 13:47:47 -07:00
|
|
|
continue;
|
2010-05-27 16:23:53 -07:00
|
|
|
}
|
2006-09-18 11:09:07 -07:00
|
|
|
|
2010-09-17 10:43:12 -07:00
|
|
|
// The rest are purely graphical effects, and should be ignored if
|
|
|
|
|
// graphics are disabled
|
|
|
|
|
if (!m_MapReader.pWaterMan)
|
|
|
|
|
continue;
|
2016-01-13 16:04:32 -08:00
|
|
|
|
2020-11-26 14:28:50 -08:00
|
|
|
if (water_element_name == el_type)
|
2010-09-17 10:43:12 -07:00
|
|
|
{
|
2014-07-03 13:07:15 -07:00
|
|
|
if (waterelement.GetText() == "default")
|
|
|
|
|
m_MapReader.pWaterMan->m_WaterType = L"ocean";
|
|
|
|
|
else
|
|
|
|
|
m_MapReader.pWaterMan->m_WaterType = waterelement.GetText().FromUTF8();
|
2010-09-17 10:43:12 -07:00
|
|
|
}
|
2015-03-15 16:59:48 -07:00
|
|
|
#define READ_COLOR(el, out) \
|
2020-11-26 14:28:50 -08:00
|
|
|
else if (water_element_name == el) \
|
2006-09-18 11:09:07 -07:00
|
|
|
{ \
|
2020-11-26 14:28:50 -08:00
|
|
|
XMBAttributeList colorAttrs = waterelement.GetAttributes(); \
|
2006-09-18 11:09:07 -07:00
|
|
|
out = CColor( \
|
2020-11-26 14:28:50 -08:00
|
|
|
colorAttrs.GetNamedItem(at_r).ToFloat(), \
|
|
|
|
|
colorAttrs.GetNamedItem(at_g).ToFloat(), \
|
|
|
|
|
colorAttrs.GetNamedItem(at_b).ToFloat(), \
|
2006-09-18 11:09:07 -07:00
|
|
|
1.f); \
|
2006-06-11 00:03:59 -07:00
|
|
|
}
|
2006-09-18 11:09:07 -07:00
|
|
|
|
|
|
|
|
#define READ_FLOAT(el, out) \
|
2020-11-26 14:28:50 -08:00
|
|
|
else if (water_element_name == el) \
|
2006-09-18 11:09:07 -07:00
|
|
|
{ \
|
2011-02-17 12:08:20 -08:00
|
|
|
out = waterelement.GetText().ToFloat(); \
|
2006-09-18 11:09:07 -07:00
|
|
|
} \
|
|
|
|
|
|
2015-03-15 16:59:48 -07:00
|
|
|
READ_COLOR(el_color, m_MapReader.pWaterMan->m_WaterColor)
|
|
|
|
|
READ_COLOR(el_tint, m_MapReader.pWaterMan->m_WaterTint)
|
2006-09-18 11:09:07 -07:00
|
|
|
READ_FLOAT(el_waviness, m_MapReader.pWaterMan->m_Waviness)
|
|
|
|
|
READ_FLOAT(el_murkiness, m_MapReader.pWaterMan->m_Murkiness)
|
2014-07-03 13:07:15 -07:00
|
|
|
READ_FLOAT(el_windangle, m_MapReader.pWaterMan->m_WindAngle)
|
2006-09-18 11:09:07 -07:00
|
|
|
|
|
|
|
|
#undef READ_FLOAT
|
2015-03-15 16:59:48 -07:00
|
|
|
#undef READ_COLOR
|
2006-09-18 11:09:07 -07:00
|
|
|
|
2006-06-11 00:03:59 -07:00
|
|
|
else
|
2009-11-03 13:46:35 -08:00
|
|
|
debug_warn(L"Invalid map XML data");
|
2006-06-11 00:03:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-05-10 20:07:08 -07:00
|
|
|
else
|
2009-11-03 13:46:35 -08:00
|
|
|
debug_warn(L"Invalid map XML data");
|
2005-05-10 20:07:08 -07:00
|
|
|
}
|
2005-05-04 16:12:46 -07:00
|
|
|
|
2005-05-10 20:07:08 -07:00
|
|
|
m_MapReader.m_LightEnv.CalculateSunDirection();
|
|
|
|
|
}
|
2005-05-03 14:42:09 -07:00
|
|
|
|
2006-03-21 12:55:45 -08:00
|
|
|
void CXMLReader::ReadCamera(XMBElement parent)
|
|
|
|
|
{
|
2011-06-13 16:32:41 -07:00
|
|
|
// defaults if we don't find player starting camera
|
2007-05-02 05:07:08 -07:00
|
|
|
#define EL(x) int el_##x = xmb_file.GetElementID(#x)
|
|
|
|
|
#define AT(x) int at_##x = xmb_file.GetAttributeID(#x)
|
2006-03-21 12:55:45 -08:00
|
|
|
EL(declination);
|
|
|
|
|
EL(rotation);
|
|
|
|
|
EL(position);
|
|
|
|
|
AT(angle);
|
|
|
|
|
AT(x); AT(y); AT(z);
|
|
|
|
|
#undef AT
|
|
|
|
|
#undef EL
|
|
|
|
|
|
|
|
|
|
float declination = DEGTORAD(30.f), rotation = DEGTORAD(-45.f);
|
|
|
|
|
CVector3D translation = CVector3D(100, 150, -100);
|
|
|
|
|
|
|
|
|
|
XERO_ITER_EL(parent, element)
|
|
|
|
|
{
|
2007-05-02 05:07:08 -07:00
|
|
|
int element_name = element.GetNodeName();
|
2006-03-21 12:55:45 -08:00
|
|
|
|
2007-05-02 05:07:08 -07:00
|
|
|
XMBAttributeList attrs = element.GetAttributes();
|
2006-03-21 12:55:45 -08:00
|
|
|
if (element_name == el_declination)
|
|
|
|
|
{
|
2011-02-17 12:08:20 -08:00
|
|
|
declination = attrs.GetNamedItem(at_angle).ToFloat();
|
2006-03-21 12:55:45 -08:00
|
|
|
}
|
|
|
|
|
else if (element_name == el_rotation)
|
|
|
|
|
{
|
2011-02-17 12:08:20 -08:00
|
|
|
rotation = attrs.GetNamedItem(at_angle).ToFloat();
|
2006-03-21 12:55:45 -08:00
|
|
|
}
|
|
|
|
|
else if (element_name == el_position)
|
|
|
|
|
{
|
|
|
|
|
translation = CVector3D(
|
2011-02-17 12:08:20 -08:00
|
|
|
attrs.GetNamedItem(at_x).ToFloat(),
|
|
|
|
|
attrs.GetNamedItem(at_y).ToFloat(),
|
|
|
|
|
attrs.GetNamedItem(at_z).ToFloat());
|
2006-03-21 12:55:45 -08:00
|
|
|
}
|
|
|
|
|
else
|
2009-11-03 13:46:35 -08:00
|
|
|
debug_warn(L"Invalid map XML data");
|
2006-03-21 12:55:45 -08:00
|
|
|
}
|
|
|
|
|
|
2010-08-13 06:26:29 -07:00
|
|
|
if (m_MapReader.pGameView)
|
2010-02-08 14:05:05 -08:00
|
|
|
{
|
2010-08-13 06:26:29 -07:00
|
|
|
m_MapReader.pGameView->GetCamera()->m_Orientation.SetXRotation(declination);
|
|
|
|
|
m_MapReader.pGameView->GetCamera()->m_Orientation.RotateY(rotation);
|
|
|
|
|
m_MapReader.pGameView->GetCamera()->m_Orientation.Translate(translation);
|
|
|
|
|
m_MapReader.pGameView->GetCamera()->UpdateFrustum();
|
2010-02-08 14:05:05 -08:00
|
|
|
}
|
2006-03-21 12:55:45 -08:00
|
|
|
}
|
2006-09-27 19:05:56 -07:00
|
|
|
|
2016-01-03 04:41:04 -08:00
|
|
|
void CXMLReader::ReadPaths(XMBElement parent)
|
2006-08-21 19:24:44 -07:00
|
|
|
{
|
2007-05-02 05:07:08 -07:00
|
|
|
#define EL(x) int el_##x = xmb_file.GetElementID(#x)
|
|
|
|
|
#define AT(x) int at_##x = xmb_file.GetAttributeID(#x)
|
2006-08-21 19:24:44 -07:00
|
|
|
|
|
|
|
|
EL(path);
|
|
|
|
|
EL(rotation);
|
|
|
|
|
EL(node);
|
2007-02-26 18:14:18 -08:00
|
|
|
EL(position);
|
2016-01-03 04:41:04 -08:00
|
|
|
EL(target);
|
2006-08-21 19:24:44 -07:00
|
|
|
AT(name);
|
|
|
|
|
AT(timescale);
|
2016-01-03 04:41:04 -08:00
|
|
|
AT(orientation);
|
2006-08-21 19:24:44 -07:00
|
|
|
AT(mode);
|
|
|
|
|
AT(style);
|
|
|
|
|
AT(x);
|
|
|
|
|
AT(y);
|
|
|
|
|
AT(z);
|
2016-01-03 04:41:04 -08:00
|
|
|
AT(deltatime);
|
2006-08-21 19:24:44 -07:00
|
|
|
|
|
|
|
|
#undef EL
|
|
|
|
|
#undef AT
|
2016-01-03 04:41:04 -08:00
|
|
|
|
2017-04-04 20:59:20 -07:00
|
|
|
CmpPtr<ICmpCinemaManager> cmpCinemaManager(*m_MapReader.pSimContext, SYSTEM_ENTITY);
|
2006-08-21 19:24:44 -07:00
|
|
|
XERO_ITER_EL(parent, element)
|
|
|
|
|
{
|
2007-05-02 05:07:08 -07:00
|
|
|
int elementName = element.GetNodeName();
|
2016-01-13 16:04:32 -08:00
|
|
|
|
2015-12-31 05:40:56 -08:00
|
|
|
if (elementName == el_path)
|
2006-08-21 19:24:44 -07:00
|
|
|
{
|
2007-02-26 18:14:18 -08:00
|
|
|
CCinemaData pathData;
|
2016-01-03 04:41:04 -08:00
|
|
|
XMBAttributeList attrs = element.GetAttributes();
|
|
|
|
|
CStrW pathName(attrs.GetNamedItem(at_name).FromUTF8());
|
|
|
|
|
pathData.m_Name = pathName;
|
2017-03-20 08:26:34 -07:00
|
|
|
pathData.m_Timescale = fixed::FromString(attrs.GetNamedItem(at_timescale));
|
2016-01-03 04:41:04 -08:00
|
|
|
pathData.m_Orientation = attrs.GetNamedItem(at_orientation).FromUTF8();
|
|
|
|
|
pathData.m_Mode = attrs.GetNamedItem(at_mode).FromUTF8();
|
|
|
|
|
pathData.m_Style = attrs.GetNamedItem(at_style).FromUTF8();
|
2006-08-21 19:24:44 -07:00
|
|
|
|
2017-03-20 08:26:34 -07:00
|
|
|
TNSpline positionSpline, targetSpline;
|
|
|
|
|
fixed lastPositionTime = fixed::Zero();
|
|
|
|
|
fixed lastTargetTime = fixed::Zero();
|
|
|
|
|
|
2007-02-26 18:14:18 -08:00
|
|
|
XERO_ITER_EL(element, pathChild)
|
2006-08-21 19:24:44 -07:00
|
|
|
{
|
2007-05-02 05:07:08 -07:00
|
|
|
elementName = pathChild.GetNodeName();
|
|
|
|
|
attrs = pathChild.GetAttributes();
|
2006-03-21 12:55:45 -08:00
|
|
|
|
2016-01-03 04:41:04 -08:00
|
|
|
// Load node data used for spline
|
|
|
|
|
if (elementName == el_node)
|
2006-08-21 19:24:44 -07:00
|
|
|
{
|
2017-03-20 08:26:34 -07:00
|
|
|
lastPositionTime += fixed::FromString(attrs.GetNamedItem(at_deltatime));
|
2016-01-03 04:41:04 -08:00
|
|
|
lastTargetTime += fixed::FromString(attrs.GetNamedItem(at_deltatime));
|
2007-02-26 18:14:18 -08:00
|
|
|
XERO_ITER_EL(pathChild, nodeChild)
|
2006-08-21 19:24:44 -07:00
|
|
|
{
|
2007-05-02 05:07:08 -07:00
|
|
|
elementName = nodeChild.GetNodeName();
|
|
|
|
|
attrs = nodeChild.GetAttributes();
|
2016-01-03 04:41:04 -08:00
|
|
|
|
2015-12-31 05:40:56 -08:00
|
|
|
if (elementName == el_position)
|
2006-08-21 19:24:44 -07:00
|
|
|
{
|
2017-03-24 15:49:06 -07:00
|
|
|
CFixedVector3D position(fixed::FromString(attrs.GetNamedItem(at_x)),
|
|
|
|
|
fixed::FromString(attrs.GetNamedItem(at_y)),
|
|
|
|
|
fixed::FromString(attrs.GetNamedItem(at_z)));
|
2017-03-20 08:26:34 -07:00
|
|
|
|
|
|
|
|
positionSpline.AddNode(position, CFixedVector3D(), lastPositionTime);
|
|
|
|
|
lastPositionTime = fixed::Zero();
|
2006-08-21 19:24:44 -07:00
|
|
|
}
|
2015-12-31 05:40:56 -08:00
|
|
|
else if (elementName == el_rotation)
|
2007-02-26 18:14:18 -08:00
|
|
|
{
|
2017-03-20 08:26:34 -07:00
|
|
|
// TODO: Implement rotation slerp/spline as another object
|
2016-01-03 04:41:04 -08:00
|
|
|
}
|
|
|
|
|
else if (elementName == el_target)
|
|
|
|
|
{
|
2017-03-24 15:49:06 -07:00
|
|
|
CFixedVector3D targetPosition(fixed::FromString(attrs.GetNamedItem(at_x)),
|
|
|
|
|
fixed::FromString(attrs.GetNamedItem(at_y)),
|
|
|
|
|
fixed::FromString(attrs.GetNamedItem(at_z)));
|
2016-01-03 04:41:04 -08:00
|
|
|
|
|
|
|
|
targetSpline.AddNode(targetPosition, CFixedVector3D(), lastTargetTime);
|
|
|
|
|
lastTargetTime = fixed::Zero();
|
2007-02-26 18:14:18 -08:00
|
|
|
}
|
2016-01-13 16:04:32 -08:00
|
|
|
else
|
2016-01-03 04:41:04 -08:00
|
|
|
LOGWARNING("Invalid cinematic element for node child");
|
2006-08-21 19:24:44 -07:00
|
|
|
}
|
2007-02-26 18:14:18 -08:00
|
|
|
}
|
2006-08-21 19:24:44 -07:00
|
|
|
else
|
2016-01-03 04:41:04 -08:00
|
|
|
LOGWARNING("Invalid cinematic element for path child");
|
2006-08-21 19:24:44 -07:00
|
|
|
}
|
2007-02-26 18:14:18 -08:00
|
|
|
|
2016-01-03 04:41:04 -08:00
|
|
|
// Construct cinema path with data gathered
|
2017-03-20 08:26:34 -07:00
|
|
|
CCinemaPath path(pathData, positionSpline, targetSpline);
|
2016-01-03 04:41:04 -08:00
|
|
|
if (path.Empty())
|
2007-02-26 18:14:18 -08:00
|
|
|
{
|
2016-01-03 04:41:04 -08:00
|
|
|
LOGWARNING("Path with name '%s' is empty", pathName.ToUTF8());
|
2007-02-26 18:14:18 -08:00
|
|
|
return;
|
|
|
|
|
}
|
2016-01-13 16:04:32 -08:00
|
|
|
|
2017-04-04 20:59:20 -07:00
|
|
|
if (!cmpCinemaManager)
|
|
|
|
|
continue;
|
|
|
|
|
if (!cmpCinemaManager->HasPath(pathName))
|
2017-04-10 18:37:00 -07:00
|
|
|
cmpCinemaManager->AddPath(path);
|
2016-01-03 04:41:04 -08:00
|
|
|
else
|
|
|
|
|
LOGWARNING("Path with name '%s' already exists", pathName.ToUTF8());
|
2006-08-21 19:24:44 -07:00
|
|
|
}
|
2007-02-26 18:14:18 -08:00
|
|
|
else
|
2016-01-03 04:41:04 -08:00
|
|
|
LOGWARNING("Invalid path child with name '%s'", element.GetText());
|
2006-08-21 19:24:44 -07:00
|
|
|
}
|
|
|
|
|
}
|
2005-05-03 14:42:09 -07:00
|
|
|
|
2010-08-01 13:56:34 -07:00
|
|
|
void CXMLReader::ReadTriggers(XMBElement UNUSED(parent))
|
2006-11-24 11:45:04 -08:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-10 20:07:08 -07:00
|
|
|
int CXMLReader::ReadEntities(XMBElement parent, double end_time)
|
2005-05-03 14:42:09 -07:00
|
|
|
{
|
2007-05-02 05:07:08 -07:00
|
|
|
XMBElementList entities = parent.GetChildNodes();
|
2007-01-16 19:25:20 -08:00
|
|
|
|
2011-10-24 07:31:05 -07:00
|
|
|
ENSURE(m_MapReader.pSimulation2);
|
2011-06-09 16:47:20 -07:00
|
|
|
CSimulation2& sim = *m_MapReader.pSimulation2;
|
2011-06-13 16:32:41 -07:00
|
|
|
CmpPtr<ICmpPlayerManager> cmpPlayerManager(sim, SYSTEM_ENTITY);
|
2011-06-09 16:47:20 -07:00
|
|
|
|
2015-05-31 17:29:35 -07:00
|
|
|
while (entity_idx < entities.size())
|
2010-01-09 11:20:14 -08:00
|
|
|
{
|
|
|
|
|
// all new state at this scope and below doesn't need to be
|
|
|
|
|
// wrapped, since we only yield after a complete iteration.
|
|
|
|
|
|
2015-05-31 17:29:35 -07:00
|
|
|
XMBElement entity = entities[entity_idx++];
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(entity.GetNodeName() == el_entity);
|
2010-01-09 11:20:14 -08:00
|
|
|
|
|
|
|
|
XMBAttributeList attrs = entity.GetAttributes();
|
2011-02-17 12:08:20 -08:00
|
|
|
CStr uid = attrs.GetNamedItem(at_uid);
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(!uid.empty());
|
2011-02-17 12:08:20 -08:00
|
|
|
int EntityUid = uid.ToInt();
|
2010-01-09 11:20:14 -08:00
|
|
|
|
|
|
|
|
CStrW TemplateName;
|
2010-01-22 12:03:14 -08:00
|
|
|
int PlayerID = 0;
|
2020-03-15 06:54:50 -07:00
|
|
|
std::vector<entity_id_t> Garrison;
|
2021-01-11 03:26:31 -08:00
|
|
|
std::vector<std::pair<std::string, entity_id_t>> Turrets;
|
2010-01-09 11:20:14 -08:00
|
|
|
CFixedVector3D Position;
|
|
|
|
|
CFixedVector3D Orientation;
|
2013-03-11 09:42:41 -07:00
|
|
|
long Seed = -1;
|
2010-01-09 11:20:14 -08:00
|
|
|
|
2012-08-01 14:38:13 -07:00
|
|
|
// Obstruction control groups.
|
|
|
|
|
entity_id_t ControlGroup = INVALID_ENTITY;
|
|
|
|
|
entity_id_t ControlGroup2 = INVALID_ENTITY;
|
|
|
|
|
|
2010-01-09 11:20:14 -08:00
|
|
|
XERO_ITER_EL(entity, setting)
|
|
|
|
|
{
|
|
|
|
|
int element_name = setting.GetNodeName();
|
|
|
|
|
|
|
|
|
|
// <template>
|
|
|
|
|
if (element_name == el_template)
|
|
|
|
|
{
|
2011-02-17 12:08:20 -08:00
|
|
|
TemplateName = setting.GetText().FromUTF8();
|
2010-01-09 11:20:14 -08:00
|
|
|
}
|
2010-01-22 12:03:14 -08:00
|
|
|
// <player>
|
|
|
|
|
else if (element_name == el_player)
|
|
|
|
|
{
|
2011-02-17 12:08:20 -08:00
|
|
|
PlayerID = setting.GetText().ToInt();
|
2010-01-22 12:03:14 -08:00
|
|
|
}
|
2010-01-09 11:20:14 -08:00
|
|
|
// <position>
|
|
|
|
|
else if (element_name == el_position)
|
|
|
|
|
{
|
2020-11-26 14:28:50 -08:00
|
|
|
XMBAttributeList positionAttrs = setting.GetAttributes();
|
2010-01-09 11:20:14 -08:00
|
|
|
Position = CFixedVector3D(
|
2020-11-26 14:28:50 -08:00
|
|
|
fixed::FromString(positionAttrs.GetNamedItem(at_x)),
|
|
|
|
|
fixed::FromString(positionAttrs.GetNamedItem(at_y)),
|
|
|
|
|
fixed::FromString(positionAttrs.GetNamedItem(at_z)));
|
2010-01-09 11:20:14 -08:00
|
|
|
}
|
|
|
|
|
// <orientation>
|
|
|
|
|
else if (element_name == el_orientation)
|
|
|
|
|
{
|
2020-11-26 14:28:50 -08:00
|
|
|
XMBAttributeList orientationAttrs = setting.GetAttributes();
|
2010-01-09 11:20:14 -08:00
|
|
|
Orientation = CFixedVector3D(
|
2020-11-26 14:28:50 -08:00
|
|
|
fixed::FromString(orientationAttrs.GetNamedItem(at_x)),
|
|
|
|
|
fixed::FromString(orientationAttrs.GetNamedItem(at_y)),
|
|
|
|
|
fixed::FromString(orientationAttrs.GetNamedItem(at_z)));
|
2010-01-09 11:20:14 -08:00
|
|
|
// TODO: what happens if some attributes are missing?
|
|
|
|
|
}
|
2012-08-01 14:38:13 -07:00
|
|
|
// <obstruction>
|
|
|
|
|
else if (element_name == el_obstruction)
|
|
|
|
|
{
|
2020-11-26 14:28:50 -08:00
|
|
|
XMBAttributeList obstructionAttrs = setting.GetAttributes();
|
|
|
|
|
ControlGroup = obstructionAttrs.GetNamedItem(at_group).ToInt();
|
|
|
|
|
ControlGroup2 = obstructionAttrs.GetNamedItem(at_group2).ToInt();
|
2012-08-01 14:38:13 -07:00
|
|
|
}
|
2020-03-15 06:54:50 -07:00
|
|
|
// <garrison>
|
|
|
|
|
else if (element_name == el_garrison)
|
|
|
|
|
{
|
|
|
|
|
XMBElementList garrison = setting.GetChildNodes();
|
|
|
|
|
Garrison.reserve(garrison.size());
|
|
|
|
|
for (const XMBElement& garr_ent : garrison)
|
|
|
|
|
{
|
2020-11-26 14:28:50 -08:00
|
|
|
XMBAttributeList garrisonAttrs = garr_ent.GetAttributes();
|
|
|
|
|
Garrison.push_back(garrisonAttrs.GetNamedItem(at_uid).ToInt());
|
2020-03-15 06:54:50 -07:00
|
|
|
}
|
|
|
|
|
}
|
2020-11-11 11:40:44 -08:00
|
|
|
// <turrets>
|
|
|
|
|
else if (element_name == el_turrets)
|
|
|
|
|
{
|
|
|
|
|
XMBElementList turrets = setting.GetChildNodes();
|
|
|
|
|
Turrets.reserve(turrets.size());
|
|
|
|
|
for (const XMBElement& turretPoint : turrets)
|
|
|
|
|
{
|
2020-11-26 14:28:50 -08:00
|
|
|
XMBAttributeList turretAttrs = turretPoint.GetAttributes();
|
2021-01-11 03:26:31 -08:00
|
|
|
Turrets.emplace_back(
|
2020-11-26 14:28:50 -08:00
|
|
|
turretAttrs.GetNamedItem(at_turret),
|
|
|
|
|
turretAttrs.GetNamedItem(at_uid).ToInt()
|
2021-01-11 03:26:31 -08:00
|
|
|
);
|
2020-11-11 11:40:44 -08:00
|
|
|
}
|
|
|
|
|
}
|
2013-02-02 18:16:52 -08:00
|
|
|
// <actor>
|
|
|
|
|
else if (element_name == el_actor)
|
|
|
|
|
{
|
|
|
|
|
XMBAttributeList attrs = setting.GetAttributes();
|
2013-03-11 09:42:41 -07:00
|
|
|
CStr seedStr = attrs.GetNamedItem(at_seed);
|
|
|
|
|
if (!seedStr.empty())
|
|
|
|
|
{
|
|
|
|
|
Seed = seedStr.ToLong();
|
|
|
|
|
ENSURE(Seed >= 0);
|
|
|
|
|
}
|
2013-02-02 18:16:52 -08:00
|
|
|
}
|
2010-01-09 11:20:14 -08:00
|
|
|
else
|
|
|
|
|
debug_warn(L"Invalid map XML data");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
entity_id_t ent = sim.AddEntity(TemplateName, EntityUid);
|
2011-06-13 16:32:41 -07:00
|
|
|
entity_id_t player = cmpPlayerManager->GetPlayerByID(PlayerID);
|
|
|
|
|
if (ent == INVALID_ENTITY || player == INVALID_ENTITY)
|
|
|
|
|
{ // Don't add entities with invalid player IDs
|
2015-01-22 12:37:38 -08:00
|
|
|
LOGERROR("Failed to load entity template '%s'", utf8_from_wstring(TemplateName));
|
2011-06-09 16:47:20 -07:00
|
|
|
}
|
2011-06-13 16:32:41 -07:00
|
|
|
else
|
|
|
|
|
{
|
2010-01-09 11:20:14 -08:00
|
|
|
CmpPtr<ICmpPosition> cmpPosition(sim, ent);
|
2012-02-07 18:46:15 -08:00
|
|
|
if (cmpPosition)
|
2010-01-09 11:20:14 -08:00
|
|
|
{
|
|
|
|
|
cmpPosition->JumpTo(Position.X, Position.Z);
|
|
|
|
|
cmpPosition->SetYRotation(Orientation.Y);
|
2010-01-22 12:03:14 -08:00
|
|
|
// TODO: other parts of the position
|
2010-01-09 11:20:14 -08:00
|
|
|
}
|
2010-01-22 12:03:14 -08:00
|
|
|
|
2020-03-15 06:54:50 -07:00
|
|
|
if (!Garrison.empty())
|
|
|
|
|
{
|
|
|
|
|
CmpPtr<ICmpGarrisonHolder> cmpGarrisonHolder(sim, ent);
|
|
|
|
|
if (cmpGarrisonHolder)
|
2021-01-11 03:26:31 -08:00
|
|
|
cmpGarrisonHolder->SetInitEntities(std::move(Garrison));
|
2020-03-15 06:54:50 -07:00
|
|
|
else
|
|
|
|
|
LOGERROR("CXMLMapReader::ReadEntities() entity '%d' of player '%d' has no GarrisonHolder component and thus cannot garrison units.", ent, PlayerID);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-04 22:22:25 -07:00
|
|
|
// Needs to be before ownership changes to prevent initialising
|
|
|
|
|
// subunits too soon.
|
2020-11-11 11:40:44 -08:00
|
|
|
if (!Turrets.empty())
|
|
|
|
|
{
|
|
|
|
|
CmpPtr<ICmpTurretHolder> cmpTurretHolder(sim, ent);
|
|
|
|
|
if (cmpTurretHolder)
|
2021-01-11 03:26:31 -08:00
|
|
|
cmpTurretHolder->SetInitEntities(std::move(Turrets));
|
2020-11-11 11:40:44 -08:00
|
|
|
else
|
|
|
|
|
LOGERROR("CXMLMapReader::ReadEntities() entity '%d' of player '%d' has no TurretHolder component and thus cannot use turrets.", ent, PlayerID);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-04 22:22:25 -07:00
|
|
|
CmpPtr<ICmpOwnership> cmpOwnership(sim, ent);
|
|
|
|
|
if (cmpOwnership)
|
|
|
|
|
cmpOwnership->SetOwner(PlayerID);
|
|
|
|
|
|
2012-08-01 14:38:13 -07:00
|
|
|
CmpPtr<ICmpObstruction> cmpObstruction(sim, ent);
|
|
|
|
|
if (cmpObstruction)
|
|
|
|
|
{
|
|
|
|
|
if (ControlGroup != INVALID_ENTITY)
|
|
|
|
|
cmpObstruction->SetControlGroup(ControlGroup);
|
|
|
|
|
if (ControlGroup2 != INVALID_ENTITY)
|
|
|
|
|
cmpObstruction->SetControlGroup2(ControlGroup2);
|
|
|
|
|
|
|
|
|
|
cmpObstruction->ResolveFoundationCollisions();
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-02 18:16:52 -08:00
|
|
|
CmpPtr<ICmpVisual> cmpVisual(sim, ent);
|
|
|
|
|
if (cmpVisual)
|
|
|
|
|
{
|
|
|
|
|
if (Seed != -1)
|
|
|
|
|
cmpVisual->SetActorSeed((u32)Seed);
|
|
|
|
|
// TODO: variation/selection strings
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-13 16:32:41 -07:00
|
|
|
if (PlayerID == m_MapReader.m_PlayerID && (boost::algorithm::ends_with(TemplateName, L"civil_centre") || m_MapReader.m_StartingCameraTarget == INVALID_ENTITY))
|
2010-07-03 06:15:57 -07:00
|
|
|
{
|
2011-06-13 16:32:41 -07:00
|
|
|
// Focus on civil centre or first entity owned by player
|
|
|
|
|
m_MapReader.m_StartingCameraTarget = ent;
|
2010-07-03 06:15:57 -07:00
|
|
|
}
|
2010-01-09 11:20:14 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
completed_jobs++;
|
|
|
|
|
LDR_CHECK_TIMEOUT(completed_jobs, total_jobs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-01 11:08:11 -07:00
|
|
|
void CXMLReader::ReadXML()
|
2005-05-03 14:42:09 -07:00
|
|
|
{
|
2015-05-31 17:29:35 -07:00
|
|
|
for (XMBElement node : nodes)
|
2005-05-03 14:42:09 -07:00
|
|
|
{
|
2007-05-02 05:07:08 -07:00
|
|
|
CStr name = xmb_file.GetElementString(node.GetNodeName());
|
2010-05-03 12:13:58 -07:00
|
|
|
if (name == "Terrain")
|
|
|
|
|
{
|
|
|
|
|
ReadTerrain(node);
|
|
|
|
|
}
|
|
|
|
|
else if (name == "Environment")
|
2005-05-10 20:07:08 -07:00
|
|
|
{
|
|
|
|
|
ReadEnvironment(node);
|
|
|
|
|
}
|
# Housekeeping and pathfinder enhancements / optimization when dealing with ranged actions.
- Modified Xeromyces to no longer automatically convert element and
attribute names to lowercase, so that we can have camelCase names. We
should now be able to convert all the multi-word entity properties, like
pass_through_allies, to camelCase, like passThroughAllies, which is more
consistent with the rest of our JavaScript naming conventions. To
support the existing code that assumes lowercase element names, I made
the getElementID and getAttributeID methods (used in the EL and AT
macros) ignore case, and I changed any code that directly accessed
element names to use the right case. CEntityTemplate now converts
Names_LikeThis to names_likeThis (changing each separate "word" in the
name to camelCase). Changed the version letter in XMB filenames from A
to B to support this without requiring people to delete old XMBs.
- Enhanced the pathfinder's handling of contact paths, resulting in a
very large speedup for actions like attacking, construction, etc. The
problem was that the pathfinder used to not count a given state as the
goal unless it was exactly coincident with the target location. This is
fine when you order a unit to go exactly to a certain spot, but if
you're ordering a unit to build, gather or attack something, then the
target tile is impassable (because your target is there) and therefore
the pathfinder never declares a state final. As a result, the pathfinder
tries hundreds of extra tiles in case there is a long path that gets to
the goal, and after failing to find any path that reaches the goal, it
gives you one to the closest point it got to. To fix it, I made the
pathfinder take into account a radius around the goal in which it's OK
to be, which depends on the size of the target unit and the range of
your action.
This was SVN commit r4186.
2006-07-31 20:41:21 -07:00
|
|
|
else if (name == "Camera")
|
2006-03-21 12:55:45 -08:00
|
|
|
{
|
|
|
|
|
ReadCamera(node);
|
|
|
|
|
}
|
2010-08-04 14:15:41 -07:00
|
|
|
else if (name == "ScriptSettings")
|
|
|
|
|
{
|
2014-06-01 11:08:11 -07:00
|
|
|
// Already loaded - this is to prevent an assertion
|
2010-08-04 14:15:41 -07:00
|
|
|
}
|
2010-01-09 11:20:14 -08:00
|
|
|
else if (name == "Entities")
|
|
|
|
|
{
|
2014-06-01 11:08:11 -07:00
|
|
|
// Handled by ProgressiveReadEntities instead
|
2010-01-09 11:20:14 -08:00
|
|
|
}
|
2007-02-26 18:14:18 -08:00
|
|
|
else if (name == "Paths")
|
2006-08-21 19:24:44 -07:00
|
|
|
{
|
2016-01-03 04:41:04 -08:00
|
|
|
ReadPaths(node);
|
2006-08-21 19:24:44 -07:00
|
|
|
}
|
2006-11-24 11:45:04 -08:00
|
|
|
else if (name == "Triggers")
|
|
|
|
|
{
|
|
|
|
|
ReadTriggers(node);
|
|
|
|
|
}
|
2010-04-29 16:22:18 -07:00
|
|
|
else if (name == "Script")
|
|
|
|
|
{
|
2011-10-24 07:31:05 -07:00
|
|
|
if (m_MapReader.pSimulation2)
|
2012-05-04 14:48:46 -07:00
|
|
|
m_MapReader.pSimulation2->SetStartupScript(node.GetText());
|
2010-04-29 16:22:18 -07:00
|
|
|
}
|
2005-05-03 14:42:09 -07:00
|
|
|
else
|
2007-04-21 18:09:50 -07:00
|
|
|
{
|
2015-02-13 17:45:13 -08:00
|
|
|
debug_printf("Invalid XML element in map file: %s\n", name.c_str());
|
2009-11-03 13:46:35 -08:00
|
|
|
debug_warn(L"Invalid map XML data");
|
2007-04-21 18:09:50 -07:00
|
|
|
}
|
2014-06-01 11:08:11 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int CXMLReader::ProgressiveReadEntities()
|
|
|
|
|
{
|
|
|
|
|
// yield after this time is reached. balances increased progress bar
|
|
|
|
|
// smoothness vs. slowing down loading.
|
|
|
|
|
const double end_time = timer_Time() + 200e-3;
|
|
|
|
|
|
|
|
|
|
int ret;
|
|
|
|
|
|
2015-05-31 17:29:35 -07:00
|
|
|
while (node_idx < nodes.size())
|
2014-06-01 11:08:11 -07:00
|
|
|
{
|
2015-05-31 17:29:35 -07:00
|
|
|
XMBElement node = nodes[node_idx];
|
2014-06-01 11:08:11 -07:00
|
|
|
CStr name = xmb_file.GetElementString(node.GetNodeName());
|
|
|
|
|
if (name == "Entities")
|
|
|
|
|
{
|
|
|
|
|
if (!m_MapReader.m_SkipEntities)
|
|
|
|
|
{
|
|
|
|
|
ret = ReadEntities(node, end_time);
|
|
|
|
|
if (ret != 0) // error or timed out
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-05-03 14:42:09 -07:00
|
|
|
|
|
|
|
|
node_idx++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-29 21:02:42 -07:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// load script settings from map
|
|
|
|
|
int CMapReader::LoadScriptSettings()
|
|
|
|
|
{
|
|
|
|
|
if (!xml_reader)
|
|
|
|
|
xml_reader = new CXMLReader(filename_xml, *this);
|
|
|
|
|
|
|
|
|
|
// parse the script settings
|
2011-10-24 07:31:05 -07:00
|
|
|
if (pSimulation2)
|
|
|
|
|
pSimulation2->SetMapSettings(xml_reader->ReadScriptSettings());
|
2010-10-29 21:02:42 -07:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// load player settings script
|
|
|
|
|
int CMapReader::LoadPlayerSettings()
|
|
|
|
|
{
|
2011-10-24 07:31:05 -07:00
|
|
|
if (pSimulation2)
|
|
|
|
|
pSimulation2->LoadPlayerSettings(true);
|
2010-10-29 21:02:42 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// load map settings script
|
|
|
|
|
int CMapReader::LoadMapSettings()
|
|
|
|
|
{
|
2011-10-24 07:31:05 -07:00
|
|
|
if (pSimulation2)
|
|
|
|
|
pSimulation2->LoadMapSettings();
|
2010-10-29 21:02:42 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
2005-05-03 14:42:09 -07:00
|
|
|
|
|
|
|
|
int CMapReader::ReadXML()
|
|
|
|
|
{
|
2005-05-10 20:07:08 -07:00
|
|
|
if (!xml_reader)
|
|
|
|
|
xml_reader = new CXMLReader(filename_xml, *this);
|
2005-05-03 14:42:09 -07:00
|
|
|
|
2014-06-01 11:08:11 -07:00
|
|
|
xml_reader->ReadXML();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// progressive
|
|
|
|
|
int CMapReader::ReadXMLEntities()
|
|
|
|
|
{
|
|
|
|
|
if (!xml_reader)
|
|
|
|
|
xml_reader = new CXMLReader(filename_xml, *this);
|
|
|
|
|
|
|
|
|
|
int ret = xml_reader->ProgressiveReadEntities();
|
2005-05-04 16:12:46 -07:00
|
|
|
// finished or failed
|
2005-05-10 20:07:08 -07:00
|
|
|
if (ret <= 0)
|
2005-05-03 14:42:09 -07:00
|
|
|
{
|
2011-04-09 22:31:18 -07:00
|
|
|
SAFE_DELETE(xml_reader);
|
2005-05-03 14:42:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-21 18:34:45 -07:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int CMapReader::LoadRMSettings()
|
|
|
|
|
{
|
|
|
|
|
// copy random map settings over to sim
|
Implements skirmish maps, based on patch by sanderd17, fixes #1198. Skirmish maps are like scenarios, except the player can choose their civ during match setup. To create a skirmish map: place some skirmish entities for each player in Atlas (see templates/skirmish/* for examples), uncheck the player's civ in Atlas' player panel if desired, and save in the maps/skirmishes directory. The map will appear in match setup under the "Skirmish" match type.
Implements custom, VFS-based map load/save dialogs for Atlas (replaces
broken native file dialogs), fixes #631, #889.
Fixes map loading/saving to handle arbitrary subdirectories for better
organization.
Adds default settings to Atlas player panel, fixes #1872. Each setting
now has a checkbox to choose whether it should be saved with the map
(avoids writing lots of useless default data for each map).
Adds map preview setting to Atlas, refs #1745.
Cleans up and simplifies some duplicate code.
Fixes optional serialization performance test.
This was SVN commit r13938.
2013-10-03 19:29:16 -07:00
|
|
|
ENSURE(pSimulation2);
|
2016-09-02 09:53:22 -07:00
|
|
|
pSimulation2->SetMapSettings(m_ScriptSettings);
|
2011-03-21 18:34:45 -07:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-19 11:19:32 -08:00
|
|
|
struct CMapReader::GeneratorState
|
2011-03-21 18:34:45 -07:00
|
|
|
{
|
2023-11-19 11:19:32 -08:00
|
|
|
std::atomic<int> progress{1};
|
|
|
|
|
Future<Script::StructuredClone> task;
|
|
|
|
|
};
|
2011-04-09 22:31:18 -07:00
|
|
|
|
2023-11-19 11:19:32 -08:00
|
|
|
int CMapReader::StartMapGeneration(const CStrW& scriptFile)
|
|
|
|
|
{
|
|
|
|
|
ScriptRequest rq(pSimulation2->GetScriptInterface());
|
2016-01-13 16:04:32 -08:00
|
|
|
|
2023-11-19 11:19:32 -08:00
|
|
|
m_GeneratorState = std::make_unique<GeneratorState>();
|
2011-04-09 22:31:18 -07:00
|
|
|
|
2023-11-19 11:19:32 -08:00
|
|
|
// The settings are stringified to pass them to the task.
|
|
|
|
|
m_GeneratorState->task = Threading::TaskManager::Instance().PushTask(
|
|
|
|
|
[&progress = m_GeneratorState->progress, scriptFile,
|
|
|
|
|
settings = Script::StringifyJSON(rq, &m_ScriptSettings)]
|
|
|
|
|
{
|
|
|
|
|
PROFILE2("Map Generation");
|
2016-01-13 16:04:32 -08:00
|
|
|
|
2023-11-19 11:19:32 -08:00
|
|
|
const CStrW scriptPath{scriptFile.empty() ? L"" : L"maps/random/" + scriptFile};
|
2011-03-21 18:34:45 -07:00
|
|
|
|
2023-11-19 11:19:32 -08:00
|
|
|
const std::shared_ptr<ScriptContext> mapgenContext{ScriptContext::CreateContext(
|
|
|
|
|
MAP_GENERATION_CONTEXT_SIZE)};
|
|
|
|
|
ScriptInterface mapgenInterface{"Engine", "MapGenerator", mapgenContext};
|
2011-03-21 18:34:45 -07:00
|
|
|
|
2023-11-19 11:19:32 -08:00
|
|
|
return RunMapGenerationScript(progress, mapgenInterface, scriptPath, settings);
|
|
|
|
|
});
|
2016-01-13 16:04:32 -08:00
|
|
|
|
2023-11-19 11:19:32 -08:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[noreturn]] void ThrowMapGenerationError()
|
|
|
|
|
{
|
|
|
|
|
throw PSERROR_Game_World_MapLoadFailed{
|
|
|
|
|
"Error generating random map.\nCheck application log for details."};
|
|
|
|
|
};
|
2016-01-13 16:04:32 -08:00
|
|
|
|
2023-11-19 11:19:32 -08:00
|
|
|
int CMapReader::PollMapGeneration()
|
|
|
|
|
{
|
|
|
|
|
ENSURE(m_GeneratorState);
|
|
|
|
|
|
|
|
|
|
if (!m_GeneratorState->task.IsReady())
|
|
|
|
|
return m_GeneratorState->progress.load();
|
|
|
|
|
|
|
|
|
|
const Script::StructuredClone results{m_GeneratorState->task.Get()};
|
|
|
|
|
if (!results)
|
|
|
|
|
ThrowMapGenerationError();
|
|
|
|
|
|
|
|
|
|
// Parse data into simulation context
|
|
|
|
|
ScriptRequest rq(pSimulation2->GetScriptInterface());
|
|
|
|
|
JS::RootedValue data{rq.cx};
|
|
|
|
|
Script::ReadStructuredClone(rq, results, &data);
|
|
|
|
|
|
|
|
|
|
if (data.isUndefined())
|
|
|
|
|
ThrowMapGenerationError();
|
|
|
|
|
|
|
|
|
|
m_MapData.init(rq.cx, data);
|
|
|
|
|
|
|
|
|
|
return 0;
|
2011-03-21 18:34:45 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int CMapReader::ParseTerrain()
|
|
|
|
|
{
|
2011-04-06 19:32:16 -07:00
|
|
|
TIMER(L"ParseTerrain");
|
Improve JS Exception handling.
- Check for pending exceptions after function calls and script
executions.
- Call LOGERROR instead of JS_ReportError when there is a conversion
error in FromJSVal, since that can only be called from C++ (where JS
errors don't really make sense). Instead, C++ callers of FromJSVal
should handle the failure and, themselves, either report an error or
simply do something else.
- Wrap JS_ReportError since that makes updating it later easier.
This isn't a systematical fix since ToJSVal also ought return a boolean
for failures, and we probably should trigger errors instead of warnings
on 'implicit' conversions, rather a preparation diff.
Part of the SM52 migration, stage: SM45 compatible (actually SM52
incompatible, too).
Based on a patch by: Itms
Comments by: Vladislavbelov, Stan`
Refs #742, #4893
Differential Revision: https://code.wildfiregames.com/D3093
This was SVN commit r24187.
2020-11-15 10:29:17 -08:00
|
|
|
ScriptRequest rq(pSimulation2->GetScriptInterface());
|
2016-01-13 16:04:32 -08:00
|
|
|
|
2011-04-06 19:32:16 -07:00
|
|
|
// parse terrain from map data
|
|
|
|
|
// an error here should stop the loading process
|
2011-06-25 19:56:54 -07:00
|
|
|
#define GET_TERRAIN_PROPERTY(val, prop, out)\
|
2021-05-13 10:23:52 -07:00
|
|
|
if (!Script::GetProperty(rq, val, #prop, out))\
|
2015-01-22 12:36:24 -08:00
|
|
|
{ LOGERROR("CMapReader::ParseTerrain() failed to get '%s' property", #prop);\
|
2011-04-06 19:32:16 -07:00
|
|
|
throw PSERROR_Game_World_MapLoadFailed("Error parsing terrain data.\nCheck application log for details"); }
|
2011-03-21 18:34:45 -07:00
|
|
|
|
2011-04-16 15:57:00 -07:00
|
|
|
u32 size;
|
2016-09-02 09:53:22 -07:00
|
|
|
GET_TERRAIN_PROPERTY(m_MapData, size, size)
|
2011-03-21 18:34:45 -07:00
|
|
|
|
|
|
|
|
m_PatchesPerSide = size / PATCH_SIZE;
|
2011-03-22 11:46:39 -07:00
|
|
|
|
2011-03-21 18:34:45 -07:00
|
|
|
// flat heightmap of u16 data
|
2016-09-02 09:53:22 -07:00
|
|
|
GET_TERRAIN_PROPERTY(m_MapData, height, m_Heightmap)
|
2011-03-21 18:34:45 -07:00
|
|
|
|
|
|
|
|
// load textures
|
|
|
|
|
std::vector<std::string> textureNames;
|
2016-09-02 09:53:22 -07:00
|
|
|
GET_TERRAIN_PROPERTY(m_MapData, textureNames, textureNames)
|
2011-03-22 11:46:39 -07:00
|
|
|
num_terrain_tex = textureNames.size();
|
2011-03-21 18:34:45 -07:00
|
|
|
|
|
|
|
|
while (cur_terrain_tex < num_terrain_tex)
|
|
|
|
|
{
|
2022-01-29 00:22:28 -08:00
|
|
|
if (CTerrainTextureManager::IsInitialised())
|
|
|
|
|
{
|
|
|
|
|
CTerrainTextureEntry* texentry = g_TexMan.FindTexture(textureNames[cur_terrain_tex]);
|
|
|
|
|
m_TerrainTextures.push_back(texentry);
|
|
|
|
|
}
|
2011-03-21 18:34:45 -07:00
|
|
|
|
|
|
|
|
cur_terrain_tex++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// build tile data
|
|
|
|
|
m_Tiles.resize(SQR(size));
|
|
|
|
|
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue tileData(rq.cx);
|
2016-09-02 09:53:22 -07:00
|
|
|
GET_TERRAIN_PROPERTY(m_MapData, tileData, &tileData)
|
2011-03-21 18:34:45 -07:00
|
|
|
|
2011-06-25 19:56:54 -07:00
|
|
|
// parse tile data object into flat arrays
|
|
|
|
|
std::vector<u16> tileIndex;
|
|
|
|
|
std::vector<u16> tilePriority;
|
2014-07-26 15:33:16 -07:00
|
|
|
GET_TERRAIN_PROPERTY(tileData, index, tileIndex);
|
|
|
|
|
GET_TERRAIN_PROPERTY(tileData, priority, tilePriority);
|
2011-06-25 19:56:54 -07:00
|
|
|
|
|
|
|
|
ENSURE(SQR(size) == tileIndex.size() && SQR(size) == tilePriority.size());
|
2011-04-15 21:04:06 -07:00
|
|
|
|
|
|
|
|
// reorder by patches and store
|
|
|
|
|
for (size_t x = 0; x < size; ++x)
|
2011-03-21 18:34:45 -07:00
|
|
|
{
|
2011-04-15 21:04:06 -07:00
|
|
|
size_t patchX = x / PATCH_SIZE;
|
|
|
|
|
size_t offX = x % PATCH_SIZE;
|
|
|
|
|
for (size_t y = 0; y < size; ++y)
|
|
|
|
|
{
|
|
|
|
|
size_t patchY = y / PATCH_SIZE;
|
|
|
|
|
size_t offY = y % PATCH_SIZE;
|
2016-01-13 16:04:32 -08:00
|
|
|
|
2011-06-25 19:56:54 -07:00
|
|
|
STileDesc tile;
|
|
|
|
|
tile.m_Tex1Index = tileIndex[y*size + x];
|
2011-06-26 14:45:58 -07:00
|
|
|
tile.m_Tex2Index = 0xFFFF;
|
2011-06-25 19:56:54 -07:00
|
|
|
tile.m_Priority = tilePriority[y*size + x];
|
|
|
|
|
|
|
|
|
|
m_Tiles[(patchY * m_PatchesPerSide + patchX) * SQR(PATCH_SIZE) + (offY * PATCH_SIZE + offX)] = tile;
|
2011-04-15 21:04:06 -07:00
|
|
|
}
|
2011-03-21 18:34:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// reset generator state
|
|
|
|
|
cur_terrain_tex = 0;
|
|
|
|
|
|
|
|
|
|
#undef GET_TERRAIN_PROPERTY
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int CMapReader::ParseEntities()
|
|
|
|
|
{
|
2011-04-06 19:32:16 -07:00
|
|
|
TIMER(L"ParseEntities");
|
Improve JS Exception handling.
- Check for pending exceptions after function calls and script
executions.
- Call LOGERROR instead of JS_ReportError when there is a conversion
error in FromJSVal, since that can only be called from C++ (where JS
errors don't really make sense). Instead, C++ callers of FromJSVal
should handle the failure and, themselves, either report an error or
simply do something else.
- Wrap JS_ReportError since that makes updating it later easier.
This isn't a systematical fix since ToJSVal also ought return a boolean
for failures, and we probably should trigger errors instead of warnings
on 'implicit' conversions, rather a preparation diff.
Part of the SM52 migration, stage: SM45 compatible (actually SM52
incompatible, too).
Based on a patch by: Itms
Comments by: Vladislavbelov, Stan`
Refs #742, #4893
Differential Revision: https://code.wildfiregames.com/D3093
This was SVN commit r24187.
2020-11-15 10:29:17 -08:00
|
|
|
ScriptRequest rq(pSimulation2->GetScriptInterface());
|
2011-04-06 19:32:16 -07:00
|
|
|
|
2011-03-21 18:34:45 -07:00
|
|
|
// parse entities from map data
|
|
|
|
|
std::vector<Entity> entities;
|
|
|
|
|
|
2021-05-13 10:23:52 -07:00
|
|
|
if (!Script::GetProperty(rq, m_MapData, "entities", entities))
|
2015-01-22 12:31:30 -08:00
|
|
|
LOGWARNING("CMapReader::ParseEntities() failed to get 'entities' property");
|
2011-03-21 18:34:45 -07:00
|
|
|
|
2011-06-13 16:32:41 -07:00
|
|
|
CSimulation2& sim = *pSimulation2;
|
|
|
|
|
CmpPtr<ICmpPlayerManager> cmpPlayerManager(sim, SYSTEM_ENTITY);
|
|
|
|
|
|
2011-03-21 18:34:45 -07:00
|
|
|
size_t entity_idx = 0;
|
|
|
|
|
size_t num_entities = entities.size();
|
2016-01-13 16:04:32 -08:00
|
|
|
|
2011-03-21 18:34:45 -07:00
|
|
|
Entity currEnt;
|
|
|
|
|
|
|
|
|
|
while (entity_idx < num_entities)
|
|
|
|
|
{
|
|
|
|
|
// Get current entity struct
|
|
|
|
|
currEnt = entities[entity_idx];
|
|
|
|
|
|
|
|
|
|
entity_id_t ent = pSimulation2->AddEntity(currEnt.templateName, currEnt.entityID);
|
2011-06-13 16:32:41 -07:00
|
|
|
entity_id_t player = cmpPlayerManager->GetPlayerByID(currEnt.playerID);
|
|
|
|
|
if (ent == INVALID_ENTITY || player == INVALID_ENTITY)
|
|
|
|
|
{ // Don't add entities with invalid player IDs
|
2015-01-22 12:37:38 -08:00
|
|
|
LOGERROR("Failed to load entity template '%s'", utf8_from_wstring(currEnt.templateName));
|
2011-03-21 18:34:45 -07:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2011-06-13 16:32:41 -07:00
|
|
|
CmpPtr<ICmpPosition> cmpPosition(sim, ent);
|
2012-02-07 18:46:15 -08:00
|
|
|
if (cmpPosition)
|
2011-03-21 18:34:45 -07:00
|
|
|
{
|
2017-11-01 15:59:27 -07:00
|
|
|
cmpPosition->JumpTo(currEnt.position.X * (int)TERRAIN_TILE_SIZE, currEnt.position.Z * (int)TERRAIN_TILE_SIZE);
|
2011-09-26 14:36:33 -07:00
|
|
|
cmpPosition->SetYRotation(currEnt.rotation.Y);
|
2011-03-21 18:34:45 -07:00
|
|
|
// TODO: other parts of the position
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-07 18:46:15 -08:00
|
|
|
CmpPtr<ICmpOwnership> cmpOwnership(sim, ent);
|
|
|
|
|
if (cmpOwnership)
|
|
|
|
|
cmpOwnership->SetOwner(currEnt.playerID);
|
2011-03-21 18:34:45 -07:00
|
|
|
|
2012-08-01 14:38:13 -07:00
|
|
|
// Detect and fix collisions between foundation-blocking entities.
|
|
|
|
|
// This presently serves to copy wall tower control groups to wall
|
|
|
|
|
// segments, allowing players to expand RMS-generated walls.
|
|
|
|
|
CmpPtr<ICmpObstruction> cmpObstruction(sim, ent);
|
|
|
|
|
if (cmpObstruction)
|
|
|
|
|
cmpObstruction->ResolveFoundationCollisions();
|
|
|
|
|
|
2011-06-13 16:32:41 -07:00
|
|
|
if (currEnt.playerID == m_PlayerID && (boost::algorithm::ends_with(currEnt.templateName, L"civil_centre") || m_StartingCameraTarget == INVALID_ENTITY))
|
2011-03-21 18:34:45 -07:00
|
|
|
{
|
2011-06-13 16:32:41 -07:00
|
|
|
// Focus on civil centre or first entity owned by player
|
|
|
|
|
m_StartingCameraTarget = currEnt.entityID;
|
2011-03-21 18:34:45 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
entity_idx++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int CMapReader::ParseEnvironment()
|
|
|
|
|
{
|
|
|
|
|
// parse environment settings from map data
|
Improve JS Exception handling.
- Check for pending exceptions after function calls and script
executions.
- Call LOGERROR instead of JS_ReportError when there is a conversion
error in FromJSVal, since that can only be called from C++ (where JS
errors don't really make sense). Instead, C++ callers of FromJSVal
should handle the failure and, themselves, either report an error or
simply do something else.
- Wrap JS_ReportError since that makes updating it later easier.
This isn't a systematical fix since ToJSVal also ought return a boolean
for failures, and we probably should trigger errors instead of warnings
on 'implicit' conversions, rather a preparation diff.
Part of the SM52 migration, stage: SM45 compatible (actually SM52
incompatible, too).
Based on a patch by: Itms
Comments by: Vladislavbelov, Stan`
Refs #742, #4893
Differential Revision: https://code.wildfiregames.com/D3093
This was SVN commit r24187.
2020-11-15 10:29:17 -08:00
|
|
|
ScriptRequest rq(pSimulation2->GetScriptInterface());
|
2011-03-21 18:34:45 -07:00
|
|
|
|
|
|
|
|
#define GET_ENVIRONMENT_PROPERTY(val, prop, out)\
|
2021-05-13 10:23:52 -07:00
|
|
|
if (!Script::GetProperty(rq, val, #prop, out))\
|
2015-01-22 12:36:24 -08:00
|
|
|
LOGWARNING("CMapReader::ParseEnvironment() failed to get '%s' property", #prop);
|
2011-03-21 18:34:45 -07:00
|
|
|
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue envObj(rq.cx);
|
2016-09-02 09:53:22 -07:00
|
|
|
GET_ENVIRONMENT_PROPERTY(m_MapData, Environment, &envObj)
|
2011-03-21 18:34:45 -07:00
|
|
|
|
2014-07-26 15:33:16 -07:00
|
|
|
if (envObj.isUndefined())
|
2011-03-21 18:34:45 -07:00
|
|
|
{
|
2015-01-22 12:31:30 -08:00
|
|
|
LOGWARNING("CMapReader::ParseEnvironment(): Environment settings not found");
|
2011-03-21 18:34:45 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-15 03:34:23 -07:00
|
|
|
if (pPostproc)
|
|
|
|
|
pPostproc->SetPostEffect(L"default");
|
2011-03-26 13:17:21 -07:00
|
|
|
|
2011-03-21 18:34:45 -07:00
|
|
|
std::wstring skySet;
|
2014-07-26 15:33:16 -07:00
|
|
|
GET_ENVIRONMENT_PROPERTY(envObj, SkySet, skySet)
|
2011-11-29 12:29:06 -08:00
|
|
|
if (pSkyMan)
|
|
|
|
|
pSkyMan->SetSkySet(skySet);
|
2011-03-21 18:34:45 -07:00
|
|
|
|
2011-03-23 01:12:04 -07:00
|
|
|
CColor sunColor;
|
2015-03-15 16:59:48 -07:00
|
|
|
GET_ENVIRONMENT_PROPERTY(envObj, SunColor, sunColor)
|
2011-03-23 01:12:04 -07:00
|
|
|
m_LightEnv.m_SunColor = RGBColor(sunColor.r, sunColor.g, sunColor.b);
|
|
|
|
|
|
2014-07-26 15:33:16 -07:00
|
|
|
GET_ENVIRONMENT_PROPERTY(envObj, SunElevation, m_LightEnv.m_Elevation)
|
|
|
|
|
GET_ENVIRONMENT_PROPERTY(envObj, SunRotation, m_LightEnv.m_Rotation)
|
2016-01-13 16:04:32 -08:00
|
|
|
|
2021-01-17 05:10:00 -08:00
|
|
|
CColor ambientColor;
|
|
|
|
|
GET_ENVIRONMENT_PROPERTY(envObj, AmbientColor, ambientColor)
|
|
|
|
|
m_LightEnv.m_AmbientColor = RGBColor(ambientColor.r, ambientColor.g, ambientColor.b);
|
2011-03-21 18:34:45 -07:00
|
|
|
|
|
|
|
|
// Water properties
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue waterObj(rq.cx);
|
2014-07-26 15:33:16 -07:00
|
|
|
GET_ENVIRONMENT_PROPERTY(envObj, Water, &waterObj)
|
2011-03-21 18:34:45 -07:00
|
|
|
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue waterBodyObj(rq.cx);
|
2014-07-26 15:33:16 -07:00
|
|
|
GET_ENVIRONMENT_PROPERTY(waterObj, WaterBody, &waterBodyObj)
|
2011-03-21 18:34:45 -07:00
|
|
|
|
|
|
|
|
// Water level - necessary
|
|
|
|
|
float waterHeight;
|
2014-07-26 15:33:16 -07:00
|
|
|
GET_ENVIRONMENT_PROPERTY(waterBodyObj, Height, waterHeight)
|
2011-03-21 18:34:45 -07:00
|
|
|
|
2012-02-07 18:46:15 -08:00
|
|
|
CmpPtr<ICmpWaterManager> cmpWaterManager(*pSimulation2, SYSTEM_ENTITY);
|
|
|
|
|
ENSURE(cmpWaterManager);
|
|
|
|
|
cmpWaterManager->SetWaterLevel(entity_pos_t::FromFloat(waterHeight));
|
2011-03-21 18:34:45 -07:00
|
|
|
|
|
|
|
|
// If we have graphics, get rest of settings
|
|
|
|
|
if (pWaterMan)
|
|
|
|
|
{
|
2014-07-26 15:33:16 -07:00
|
|
|
GET_ENVIRONMENT_PROPERTY(waterBodyObj, Type, pWaterMan->m_WaterType)
|
2014-07-03 13:07:15 -07:00
|
|
|
if (pWaterMan->m_WaterType == L"default")
|
|
|
|
|
pWaterMan->m_WaterType = L"ocean";
|
2015-03-15 16:59:48 -07:00
|
|
|
GET_ENVIRONMENT_PROPERTY(waterBodyObj, Color, pWaterMan->m_WaterColor)
|
2014-07-26 15:33:16 -07:00
|
|
|
GET_ENVIRONMENT_PROPERTY(waterBodyObj, Tint, pWaterMan->m_WaterTint)
|
|
|
|
|
GET_ENVIRONMENT_PROPERTY(waterBodyObj, Waviness, pWaterMan->m_Waviness)
|
|
|
|
|
GET_ENVIRONMENT_PROPERTY(waterBodyObj, Murkiness, pWaterMan->m_Murkiness)
|
|
|
|
|
GET_ENVIRONMENT_PROPERTY(waterBodyObj, WindAngle, pWaterMan->m_WindAngle)
|
2011-03-21 18:34:45 -07:00
|
|
|
}
|
|
|
|
|
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue fogObject(rq.cx);
|
2014-07-26 15:33:16 -07:00
|
|
|
GET_ENVIRONMENT_PROPERTY(envObj, Fog, &fogObject);
|
2013-11-14 06:33:55 -08:00
|
|
|
|
2014-07-26 15:33:16 -07:00
|
|
|
GET_ENVIRONMENT_PROPERTY(fogObject, FogFactor, m_LightEnv.m_FogFactor);
|
|
|
|
|
GET_ENVIRONMENT_PROPERTY(fogObject, FogThickness, m_LightEnv.m_FogMax);
|
2013-11-14 06:33:55 -08:00
|
|
|
|
|
|
|
|
CColor fogColor;
|
2014-07-26 15:33:16 -07:00
|
|
|
GET_ENVIRONMENT_PROPERTY(fogObject, FogColor, fogColor);
|
2013-11-14 06:33:55 -08:00
|
|
|
m_LightEnv.m_FogColor = RGBColor(fogColor.r, fogColor.g, fogColor.b);
|
|
|
|
|
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue postprocObject(rq.cx);
|
2014-07-26 15:33:16 -07:00
|
|
|
GET_ENVIRONMENT_PROPERTY(envObj, Postproc, &postprocObject);
|
2013-11-14 06:33:55 -08:00
|
|
|
|
|
|
|
|
std::wstring postProcEffect;
|
2014-07-26 15:33:16 -07:00
|
|
|
GET_ENVIRONMENT_PROPERTY(postprocObject, PostprocEffect, postProcEffect);
|
2013-11-14 06:33:55 -08:00
|
|
|
|
|
|
|
|
if (pPostproc)
|
|
|
|
|
pPostproc->SetPostEffect(postProcEffect);
|
|
|
|
|
|
2014-07-26 15:33:16 -07:00
|
|
|
GET_ENVIRONMENT_PROPERTY(postprocObject, Brightness, m_LightEnv.m_Brightness);
|
|
|
|
|
GET_ENVIRONMENT_PROPERTY(postprocObject, Contrast, m_LightEnv.m_Contrast);
|
|
|
|
|
GET_ENVIRONMENT_PROPERTY(postprocObject, Saturation, m_LightEnv.m_Saturation);
|
|
|
|
|
GET_ENVIRONMENT_PROPERTY(postprocObject, Bloom, m_LightEnv.m_Bloom);
|
2013-11-14 06:33:55 -08:00
|
|
|
|
2011-03-21 18:34:45 -07:00
|
|
|
m_LightEnv.CalculateSunDirection();
|
|
|
|
|
|
|
|
|
|
#undef GET_ENVIRONMENT_PROPERTY
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int CMapReader::ParseCamera()
|
|
|
|
|
{
|
Improve JS Exception handling.
- Check for pending exceptions after function calls and script
executions.
- Call LOGERROR instead of JS_ReportError when there is a conversion
error in FromJSVal, since that can only be called from C++ (where JS
errors don't really make sense). Instead, C++ callers of FromJSVal
should handle the failure and, themselves, either report an error or
simply do something else.
- Wrap JS_ReportError since that makes updating it later easier.
This isn't a systematical fix since ToJSVal also ought return a boolean
for failures, and we probably should trigger errors instead of warnings
on 'implicit' conversions, rather a preparation diff.
Part of the SM52 migration, stage: SM45 compatible (actually SM52
incompatible, too).
Based on a patch by: Itms
Comments by: Vladislavbelov, Stan`
Refs #742, #4893
Differential Revision: https://code.wildfiregames.com/D3093
This was SVN commit r24187.
2020-11-15 10:29:17 -08:00
|
|
|
ScriptRequest rq(pSimulation2->GetScriptInterface());
|
2020-11-13 05:18:22 -08:00
|
|
|
|
2011-03-21 18:34:45 -07:00
|
|
|
// parse camera settings from map data
|
2011-06-13 16:32:41 -07:00
|
|
|
// defaults if we don't find player starting camera
|
2011-03-21 18:34:45 -07:00
|
|
|
float declination = DEGTORAD(30.f), rotation = DEGTORAD(-45.f);
|
|
|
|
|
CVector3D translation = CVector3D(100, 150, -100);
|
|
|
|
|
|
|
|
|
|
#define GET_CAMERA_PROPERTY(val, prop, out)\
|
2021-05-13 10:23:52 -07:00
|
|
|
if (!Script::GetProperty(rq, val, #prop, out))\
|
2015-01-22 12:36:24 -08:00
|
|
|
LOGWARNING("CMapReader::ParseCamera() failed to get '%s' property", #prop);
|
2011-03-21 18:34:45 -07:00
|
|
|
|
2020-11-13 05:18:22 -08:00
|
|
|
JS::RootedValue cameraObj(rq.cx);
|
2016-09-02 09:53:22 -07:00
|
|
|
GET_CAMERA_PROPERTY(m_MapData, Camera, &cameraObj)
|
2011-03-21 18:34:45 -07:00
|
|
|
|
2014-07-26 15:33:16 -07:00
|
|
|
if (!cameraObj.isUndefined())
|
2011-03-21 18:34:45 -07:00
|
|
|
{ // If camera property exists, read values
|
|
|
|
|
CFixedVector3D pos;
|
2014-07-26 15:33:16 -07:00
|
|
|
GET_CAMERA_PROPERTY(cameraObj, Position, pos)
|
2011-03-21 18:34:45 -07:00
|
|
|
translation = pos;
|
|
|
|
|
|
2014-07-26 15:33:16 -07:00
|
|
|
GET_CAMERA_PROPERTY(cameraObj, Rotation, rotation)
|
|
|
|
|
GET_CAMERA_PROPERTY(cameraObj, Declination, declination)
|
2011-03-21 18:34:45 -07:00
|
|
|
}
|
|
|
|
|
#undef GET_CAMERA_PROPERTY
|
|
|
|
|
|
|
|
|
|
if (pGameView)
|
|
|
|
|
{
|
|
|
|
|
pGameView->GetCamera()->m_Orientation.SetXRotation(declination);
|
|
|
|
|
pGameView->GetCamera()->m_Orientation.RotateY(rotation);
|
|
|
|
|
pGameView->GetCamera()->m_Orientation.Translate(translation);
|
|
|
|
|
pGameView->GetCamera()->UpdateFrustum();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2011-04-09 22:31:18 -07:00
|
|
|
|
|
|
|
|
CMapReader::~CMapReader()
|
|
|
|
|
{
|
|
|
|
|
// Cleaup objects
|
2011-11-28 16:14:34 -08:00
|
|
|
delete xml_reader;
|
2011-04-09 22:31:18 -07:00
|
|
|
}
|