Skip to content

Commit

Permalink
Support reading SOC game.graph and level.gct (OpenXRay#392)
Browse files Browse the repository at this point in the history
  • Loading branch information
Xottab-DUTY committed Jun 25, 2019
1 parent 18f4090 commit 6b30ac3
Show file tree
Hide file tree
Showing 13 changed files with 163 additions and 46 deletions.
27 changes: 25 additions & 2 deletions src/Common/LevelStructure.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,15 @@ struct NodeCompressed
friend class CNodeRenumberer;
friend class CRenumbererConverter;
};

struct NodeCompressedOld
{
u8 data[12];
NodeCompressed::SCover cover;
u16 plane;
NodePosition p;
};

#endif

#ifdef AI_COMPILER
Expand Down Expand Up @@ -263,10 +272,24 @@ struct SNodePositionOld
typedef SNodePositionOld NodePosition;
#endif

const char LEVEL_GRAPH_NAME[] = "level.ai";
constexpr cpcstr LEVEL_GRAPH_NAME = "level.ai";

const u32 XRCL_CURRENT_VERSION = 18; // input
const u32 XRCL_PRODUCTION_VERSION = 14; // output
const u32 CFORM_CURRENT_VERSION = 4;
const u32 MAX_NODE_BIT_COUNT = 23;
const u32 XRAI_CURRENT_VERSION = 10;

enum xrAI_Versions
{
XRAI_VERSION_SOC = 8,
XRAI_VERSION_CS = 9,
XRAI_VERSION_COP = 10,

XRAI_VERSION_ALLOWED = XRAI_VERSION_SOC,
XRAI_VERSION_OPENXRAY = XRAI_VERSION_COP,

XRAI_CURRENT_VERSION = XRAI_VERSION_OPENXRAY
};

#define ASSERT_XRAI_VERSION_MATCH(version, description)\
R_ASSERT2((version) >= XRAI_VERSION_ALLOWED && (version) <= XRAI_CURRENT_VERSION, description);
2 changes: 2 additions & 0 deletions src/xrAICore/Navigation/game_graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "xrAICore/Navigation/game_graph_space.h"
#include "xrAICore/Navigation/game_level_cross_table.h"

constexpr cpcstr GRAPH_NAME = "game.graph";

class CGameGraph
{
private:
Expand Down
42 changes: 29 additions & 13 deletions src/xrAICore/Navigation/game_graph_inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,22 @@ inline void CGameGraph::Initialize(IReader& stream, bool own)
ownReader = own;
m_reader = &stream;
m_header.load(m_reader);
R_ASSERT2(header().version() == XRAI_CURRENT_VERSION, "Graph version mismatch!");
ASSERT_XRAI_VERSION_MATCH(header().version(), "Game graph version mismatch!");
m_nodes = (CVertex*)m_reader->pointer();
m_current_level_some_vertex_id = _GRAPH_ID(-1);
m_enabled.assign(header().vertex_count(), true);

if (header().version() <= XRAI_VERSION_SOC)
{
m_cross_tables = nullptr;
m_current_level_cross_table = nullptr;
return;
}

u8* temp = (u8*)(m_nodes + header().vertex_count());
temp += header().edge_count() * sizeof(CGameGraph::CEdge);
m_cross_tables = (u32*)(((CLevelPoint*)temp) + header().death_point_count());
m_current_level_cross_table = 0;
m_current_level_cross_table = nullptr;
}

IC CGameGraph::CGameGraph(LPCSTR file_name, u32 current_version)
Expand Down Expand Up @@ -250,21 +258,29 @@ IC void GameGraph::CHeader::save(IWriter* writer)
IC void CGameGraph::set_current_level(u32 const level_id)
{
xr_delete(m_current_level_cross_table);
u32* current_cross_table = m_cross_tables;
GameGraph::LEVEL_MAP::const_iterator I = header().levels().begin();
GameGraph::LEVEL_MAP::const_iterator E = header().levels().end();
for (; I != E; ++I)
if (m_cross_tables)
{
if (level_id != (*I).first)
u32* current_cross_table = m_cross_tables;
GameGraph::LEVEL_MAP::const_iterator I = header().levels().begin();
GameGraph::LEVEL_MAP::const_iterator E = header().levels().end();
for (; I != E; ++I)
{
current_cross_table = (u32*)((u8*)current_cross_table + *current_cross_table);
continue;
if (level_id != (*I).first)
{
current_cross_table = (u32*)((u8*)current_cross_table + *current_cross_table);
continue;
}

m_current_level_cross_table = new CGameLevelCrossTable(current_cross_table + 1, *current_cross_table);
break;
}

m_current_level_cross_table = new CGameLevelCrossTable(current_cross_table + 1, *current_cross_table);
break;
}

else
{
string_path fName;
FS.update_path(fName, "$level$", CROSS_TABLE_NAME);
m_current_level_cross_table = new CGameLevelCrossTable(fName);
}
VERIFY(m_current_level_cross_table);

m_current_level_some_vertex_id = _GRAPH_ID(-1);
Expand Down
4 changes: 0 additions & 4 deletions src/xrAICore/Navigation/game_level_cross_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,17 +71,13 @@ class CGameLevelCrossTable
CHeader m_tCrossTableHeader;
CCell* m_tpaCrossTable;

#ifdef AI_COMPILER
private:
IReader* m_tpCrossTableVFS;
IReader* m_chunk;
#endif // AI_COMPILER

public:
IC CGameLevelCrossTable(const void* buffer, const u32& buffer_size);
#ifdef AI_COMPILER
IC CGameLevelCrossTable(LPCSTR fName);
#endif // AI_COMPILER

public:
IC virtual ~CGameLevelCrossTable();
Expand Down
13 changes: 8 additions & 5 deletions src/xrAICore/Navigation/game_level_cross_table_inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

#pragma once

#ifdef AI_COMPILER
IC CGameLevelCrossTable::CGameLevelCrossTable(LPCSTR fName)
{
m_tpCrossTableVFS = FS.r_open(fName);
Expand All @@ -19,25 +18,29 @@ IC CGameLevelCrossTable::CGameLevelCrossTable(LPCSTR fName)
chunk->r(&m_tCrossTableHeader, sizeof(m_tCrossTableHeader));
chunk->close();

R_ASSERT2(m_tCrossTableHeader.version() == XRAI_CURRENT_VERSION, "Cross table version mismatch!");
ASSERT_XRAI_VERSION_MATCH(m_tCrossTableHeader.version(), "Cross table version mismatch!");

m_chunk = m_tpCrossTableVFS->open_chunk(CROSS_TABLE_CHUNK_DATA);
R_ASSERT2(m_chunk, "Cross table is corrupted!");
m_tpaCrossTable = (CCell*)m_chunk->pointer();
}
#endif // AI_COMPILER

IC CGameLevelCrossTable::CGameLevelCrossTable(const void* buffer, const u32& /*buffer_size*/)
{
memcpy(&m_tCrossTableHeader, buffer, sizeof(m_tCrossTableHeader));
buffer = (const u8*)buffer + sizeof(m_tCrossTableHeader);

R_ASSERT2(m_tCrossTableHeader.version() == XRAI_CURRENT_VERSION, "Cross table version mismatch!");
ASSERT_XRAI_VERSION_MATCH(m_tCrossTableHeader.version(), "Cross table version mismatch!");

m_tpaCrossTable = (CCell*)buffer;
}

IC CGameLevelCrossTable::~CGameLevelCrossTable(){};
IC CGameLevelCrossTable::~CGameLevelCrossTable()
{
if (m_chunk)
m_chunk->close();
FS.r_close(m_tpCrossTableVFS);
}

IC const CGameLevelCrossTable::CCell& CGameLevelCrossTable::vertex(u32 level_vertex_id) const
{
Expand Down
13 changes: 6 additions & 7 deletions src/xrAICore/Navigation/level_graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,13 @@ CLevelGraph::CLevelGraph()

void CLevelGraph::Initialize(const char* filePath)
{

m_reader = FS.r_open(filePath);
// m_header & data
m_header = (CHeader*)m_reader->pointer();
R_ASSERT(header().version() == XRAI_CURRENT_VERSION);
ASSERT_XRAI_VERSION_MATCH(header().version(), "Level graph version mismatch");
m_reader->advance(sizeof(CHeader));
const auto& box = header().box();
m_nodes = (CVertex*)m_reader->pointer();
m_nodes = new CLevelGraphManager(m_reader, header().vertex_count(), header().version());
m_row_length = iFloor((box.vMax.z - box.vMin.z) / header().cell_size() + EPS_L + 1.5f);
m_column_length = iFloor((box.vMax.x - box.vMin.x) / header().cell_size() + EPS_L + 1.5f);
m_access_mask.assign(header().vertex_count(), true);
Expand Down Expand Up @@ -198,8 +197,8 @@ u32 CLevelGraph::vertex_id(const Fvector& position) const
make_string("invalid position for CLevelGraph::vertex_id specified: [%f][%f][%f]", VPUSH(position)));

CPosition _vertex_position = vertex_position(position);
CVertex* B = m_nodes;
CVertex* E = m_nodes + header().vertex_count();
CVertex* B = m_nodes->begin();
CVertex* E = m_nodes->end();
CVertex* I = std::lower_bound(B, E, _vertex_position.xz());
if ((I == E) || ((*I).position().xz() != _vertex_position.xz()))
return (u32(-1));
Expand Down Expand Up @@ -269,8 +268,8 @@ u32 CLevelGraph::guess_vertex_id(u32 const& current_vertex_id, Fvector const& po
float result_distance = nearest(best_point, position, vertex_contour);
u32 result_vertex_id = current_vertex_id;

CVertex const* B = m_nodes;
CVertex const* E = m_nodes + header().vertex_count();
CVertex const* B = m_nodes->begin();
CVertex const* E = m_nodes->end();
u32 start_x = (u32)std::max(0, int(x) - max_guess_vertex_count);
u32 stop_x = std::min(max_x(), x + (u32)max_guess_vertex_count);
u32 start_z = (u32)std::max(0, int(z) - max_guess_vertex_count);
Expand Down
7 changes: 5 additions & 2 deletions src/xrAICore/Navigation/level_graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "Common/LevelStructure.hpp"
#include "xrAICore/Navigation/level_graph_space.h"
#include "xrAICore/Navigation/game_graph_space.h"
#include "xrAICore/Navigation/level_graph_manager.h"

namespace LevelGraph
{
Expand Down Expand Up @@ -43,10 +44,12 @@ class XRAICORE_API CLevelGraph
typedef LevelGraph::SContour SContour;
typedef LevelGraph::ELineIntersections ELineIntersections;

using CLevelGraphManager = LevelGraph::CLevelGraphManager;

private:
IReader* m_reader; // level graph virtual storage
CHeader* m_header; // level graph header
CVertex* m_nodes; // nodes array
CLevelGraphManager* m_nodes; // contains nodes array
xr_vector<bool> m_access_mask;
GameGraph::_LEVEL_ID m_level_id; // unique level identifier
u32 m_row_length;
Expand Down Expand Up @@ -240,7 +243,7 @@ class XRAICORE_API CLevelGraph
IC bool valid_vertex_position(const Fvector& position) const;
bool neighbour_in_direction(const Fvector& direction, u32 start_vertex_id) const;

IC CVertex* vertices() { return m_nodes; }
IC CVertex* vertices() { return m_nodes->begin(); }
};

IC bool operator<(const CLevelGraph::CVertex& vertex, const u32& vertex_xz);
Expand Down
24 changes: 12 additions & 12 deletions src/xrAICore/Navigation/level_graph_inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
#pragma once
#include "xrCore/_fbox2.h"

IC CLevelGraph::const_vertex_iterator CLevelGraph::begin() const { return (m_nodes); }
IC CLevelGraph::const_vertex_iterator CLevelGraph::end() const { return (m_nodes + header().vertex_count()); }
IC CLevelGraph::const_vertex_iterator CLevelGraph::begin() const { return (m_nodes->begin()); }
IC CLevelGraph::const_vertex_iterator CLevelGraph::end() const { return (m_nodes->end()); }
IC const CLevelGraph::CHeader& CLevelGraph::header() const { return (*m_header); }
ICF bool CLevelGraph::valid_vertex_id(u32 id) const
{
Expand All @@ -21,13 +21,13 @@ ICF bool CLevelGraph::valid_vertex_id(u32 id) const
ICF CLevelGraph::CVertex* CLevelGraph::vertex(const u32 vertex_id) const
{
VERIFY(valid_vertex_id(vertex_id));
return (m_nodes + vertex_id);
return m_nodes->at(vertex_id);
}

ICF u32 CLevelGraph::vertex(const CVertex* vertex_p) const
{
VERIFY((vertex_p >= m_nodes) && valid_vertex_id(u32(vertex_p - m_nodes)));
return (u32(vertex_p - m_nodes));
VERIFY((vertex_p >= m_nodes->begin()) && valid_vertex_id(u32(vertex_p - m_nodes->begin())));
return (u32(vertex_p - m_nodes->begin()));
}

ICF u32 CLevelGraph::vertex(const CVertex& vertex_r) const { return (vertex(&vertex_r)); }
Expand Down Expand Up @@ -293,8 +293,8 @@ IC void CLevelGraph::set_invalid_vertex(u32& vertex_id, CVertex** vertex) const

IC const u32 CLevelGraph::vertex_id(const CLevelGraph::CVertex* vertex) const
{
VERIFY(valid_vertex_id(u32(vertex - m_nodes)));
return (u32(vertex - m_nodes));
VERIFY(valid_vertex_id(u32(vertex - m_nodes->begin())));
return (u32(vertex - m_nodes->begin()));
}

IC Fvector CLevelGraph::v3d(const Fvector2& vector2d) const { return (Fvector().set(vector2d.x, 0.f, vector2d.y)); }
Expand Down Expand Up @@ -560,19 +560,19 @@ IC void CLevelGraph::iterate_vertices(

if (valid_vertex_position(min_position))
I = std::lower_bound(
m_nodes, m_nodes + header().vertex_count(), vertex_position(min_position).xz(), &vertex::predicate2);
m_nodes->begin(), m_nodes->end(), vertex_position(min_position).xz(), &vertex::predicate2);
else
I = m_nodes;
I = m_nodes->begin();

if (valid_vertex_position(max_position))
{
E = std::upper_bound(
m_nodes, m_nodes + header().vertex_count(), vertex_position(max_position).xz(), &vertex::predicate);
if (E != (m_nodes + header().vertex_count()))
m_nodes->begin(), m_nodes->end(), vertex_position(max_position).xz(), &vertex::predicate);
if (E != (m_nodes->end()))
++E;
}
else
E = m_nodes + header().vertex_count();
E = m_nodes->end();

for (; I != E; ++I)
predicate(*I);
Expand Down
65 changes: 65 additions & 0 deletions src/xrAICore/Navigation/level_graph_manager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#pragma once

#include "xrAICore/Navigation/level_graph_space.h"

namespace LevelGraph
{
class CLevelGraphManager
{
bool compatibilityMode;
xr_vector<CVertex*> m_nodes; // nodes array

public:
CLevelGraphManager(IReader* stream, u32 vertex_count, u32 version)
{
m_nodes.resize(vertex_count);
if (version <= 8)
{
compatibilityMode = true;
NodeCompressedOld* nodes = static_cast<NodeCompressedOld*>(stream->pointer());
for (u32 i = 0; i < vertex_count; ++i)
{
CVertex* vertex = new CVertex();

NodeCompressed& newNode = *vertex;
NodeCompressedOld& oldNode = nodes[i];
CopyMemory(newNode.data, oldNode.data, sizeof(oldNode.data) / sizeof(u8));
newNode.high = oldNode.cover;
newNode.low = oldNode.cover;
newNode.plane = oldNode.plane;
newNode.p = oldNode.p;

m_nodes[i] = vertex;
}
}
else
{
compatibilityMode = false;
CVertex* begin = static_cast<CVertex*>(stream->pointer());
CVertex* end = begin + vertex_count;
for (size_t i = 0; begin != end; ++begin, ++i)
{
m_nodes[i] = begin;
}
}
}

~CLevelGraphManager()
{
if (compatibilityMode)
{
for (auto& node : m_nodes)
xr_delete(node);
}
m_nodes.clear();
}

CVertex* begin() { return m_nodes.front(); }
CVertex* end() { return m_nodes.back(); }

CVertex* at(size_t id) { return m_nodes[id]; }
CVertex* operator[](size_t id) { return m_nodes[id]; }

CVertex* operator+(size_t id) { return m_nodes[id]; }
};
} // namespace LevelGraph
1 change: 1 addition & 0 deletions src/xrAICore/xrAICore.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@
<ClInclude Include="Navigation\graph_vertex_inline.h" />
<ClInclude Include="Navigation\level_graph.h" />
<ClInclude Include="Navigation\level_graph_inline.h" />
<ClInclude Include="Navigation\level_graph_manager.h" />
<ClInclude Include="Navigation\level_graph_space.h" />
<ClInclude Include="Navigation\level_graph_vertex_inline.h" />
<ClInclude Include="Navigation\PathManagers\path_manager.h" />
Expand Down
3 changes: 3 additions & 0 deletions src/xrAICore/xrAICore.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,9 @@
<ClInclude Include="pch.hpp">
<Filter>Kernel</Filter>
</ClInclude>
<ClInclude Include="Navigation\level_graph_manager.h">
<Filter>AI\Navigation\LevelGraph</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Navigation\game_graph_script.cpp">
Expand Down
Loading

0 comments on commit 6b30ac3

Please sign in to comment.