mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-11-23 05:12:05 +00:00
V1 release of custom map code
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -19,3 +19,6 @@
|
|||||||
[submodule "thirdparty/lz4"]
|
[submodule "thirdparty/lz4"]
|
||||||
path = thirdparty/lz4
|
path = thirdparty/lz4
|
||||||
url = https://github.com/lz4/lz4.git
|
url = https://github.com/lz4/lz4.git
|
||||||
|
[submodule "thirdparty/gsc-tool"]
|
||||||
|
path = thirdparty/gsc-tool
|
||||||
|
url = https://github.com/xensik/gsc-tool.git
|
||||||
|
|||||||
@@ -172,9 +172,9 @@ namespace T6
|
|||||||
|
|
||||||
enum CM_MATERIAL_TYPE
|
enum CM_MATERIAL_TYPE
|
||||||
{
|
{
|
||||||
NO_COLOUR_OR_TEXTURE,
|
|
||||||
CM_MATERIAL_COLOUR,
|
CM_MATERIAL_COLOUR,
|
||||||
CM_MATERIAL_TEXTURE
|
CM_MATERIAL_TEXTURE,
|
||||||
|
CM_MATERIAL_EMPTY
|
||||||
};
|
};
|
||||||
|
|
||||||
struct customMapMaterial
|
struct customMapMaterial
|
||||||
@@ -185,7 +185,6 @@ namespace T6
|
|||||||
|
|
||||||
struct worldSurface
|
struct worldSurface
|
||||||
{
|
{
|
||||||
char flags;
|
|
||||||
customMapMaterial material;
|
customMapMaterial material;
|
||||||
|
|
||||||
//char lightmapIndex;
|
//char lightmapIndex;
|
||||||
|
|||||||
@@ -1278,6 +1278,30 @@ namespace T6
|
|||||||
typedef tdef_align32(4) char aligned_byte_pointer;
|
typedef tdef_align32(4) char aligned_byte_pointer;
|
||||||
typedef tdef_align32(4) GfxCompressedLightGridCoeffs GfxCompressedLightGridCoeffs_align4;
|
typedef tdef_align32(4) GfxCompressedLightGridCoeffs GfxCompressedLightGridCoeffs_align4;
|
||||||
|
|
||||||
|
struct GfxLightGridUnk
|
||||||
|
{
|
||||||
|
char unknown1;
|
||||||
|
char unknown2;
|
||||||
|
char unknown3;
|
||||||
|
char unknown4;
|
||||||
|
char unknown5;
|
||||||
|
char unknown6;
|
||||||
|
char unknown7;
|
||||||
|
char unknown8;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct GfxLightGridRow
|
||||||
|
{
|
||||||
|
unsigned __int16 colStart;
|
||||||
|
unsigned __int16 colCount;
|
||||||
|
unsigned __int16 zStart;
|
||||||
|
unsigned __int16 zCount;
|
||||||
|
unsigned int firstEntry;
|
||||||
|
GfxLightGridUnk unk;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct GfxLightGrid
|
struct GfxLightGrid
|
||||||
{
|
{
|
||||||
unsigned int sunPrimaryLightIndex;
|
unsigned int sunPrimaryLightIndex;
|
||||||
@@ -1288,7 +1312,7 @@ namespace T6
|
|||||||
unsigned int colAxis;
|
unsigned int colAxis;
|
||||||
uint16_t* rowDataStart;
|
uint16_t* rowDataStart;
|
||||||
unsigned int rawRowDataSize;
|
unsigned int rawRowDataSize;
|
||||||
aligned_byte_pointer* rawRowData;
|
aligned_byte_pointer* rawRowData; // GfxLightGridRow
|
||||||
unsigned int entryCount;
|
unsigned int entryCount;
|
||||||
GfxLightGridEntry* entries;
|
GfxLightGridEntry* entries;
|
||||||
unsigned int colorCount;
|
unsigned int colorCount;
|
||||||
|
|||||||
@@ -131,6 +131,9 @@ XAssetInfoGeneric* AssetCreationContext::LoadDependencyGeneric(const asset_type_
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (assetName[0] == ',')
|
||||||
|
return LoadDefaultAssetDependency(assetType, assetName);
|
||||||
|
|
||||||
std::cerr << std::format("Missing asset \"{}\" of type \"{}\"\n", assetName, *m_zone.m_pools->GetAssetTypeName(assetType));
|
std::cerr << std::format("Missing asset \"{}\" of type \"{}\"\n", assetName, *m_zone.m_pools->GetAssetTypeName(assetType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,28 +19,108 @@
|
|||||||
#define LEAF_TERRAIN_CONTENTS 1
|
#define LEAF_TERRAIN_CONTENTS 1
|
||||||
#define WORLD_TERRAIN_CONTENTS 1
|
#define WORLD_TERRAIN_CONTENTS 1
|
||||||
|
|
||||||
const std::string missingMaterialName = "custom/missing_material";
|
std::string missingImageName = "missing_image";
|
||||||
const std::string colourOnlyMaterialName = "custom/colour_only_material";
|
std::string colorOnlyImageName = "color_only_image";
|
||||||
const std::string templateMaterialName = "custom/material_template";
|
|
||||||
|
|
||||||
#define DEFAULT_SURFACE_LIGHT 1
|
|
||||||
#define DEFAULT_SURFACE_LIGHTMAP 0
|
|
||||||
#define DEFAULT_SURFACE_REFLECTION_PROBE 0
|
|
||||||
|
|
||||||
#define MAX_AABB_SIZE 512 // maximum size a BSP node can be before it becomes a leaf
|
#define MAX_AABB_SIZE 512 // maximum size a BSP node can be before it becomes a leaf
|
||||||
|
|
||||||
|
#define LIGHTGRID_COLOUR 128 // global lighting colour
|
||||||
|
|
||||||
// do not change
|
// do not change
|
||||||
#define MAX_COL_VERTS (UINT16_MAX - 1) // max amount of verts a map can have
|
#define MAX_COL_VERTS (UINT16_MAX - 1) // max amount of collision verts a map can have
|
||||||
|
|
||||||
// do not change
|
// do not change
|
||||||
#define DEFAULT_LIGHT_INDEX 0
|
#define DEFAULT_LIGHT_INDEX 0
|
||||||
#define SUN_LIGHT_INDEX 1
|
#define SUN_LIGHT_INDEX 1
|
||||||
|
|
||||||
// do not change
|
// do not change
|
||||||
#define SMODEL_FLAG_NO_SHADOW 1
|
enum SMODEL_FLAGS
|
||||||
#define SMODEL_FLAG_IS_LIT 2
|
{
|
||||||
|
SMODEL_FLAG_NO_SHADOW = 1,
|
||||||
|
SMODEL_FLAG_IS_LIT = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
// do not change
|
||||||
|
enum GFX_SURFACE_FLAGS
|
||||||
|
{
|
||||||
|
GFX_SURFACE_CASTS_SUN_SHADOW = 0x1,
|
||||||
|
GFX_SURFACE_HAS_PRIMARY_LIGHT_CONFLICT = 0x2,
|
||||||
|
GFX_SURFACE_IS_SKY = 0x4,
|
||||||
|
GFX_SURFACE_NO_DRAW = 0x8,
|
||||||
|
GFX_SURFACE_CASTS_SHADOW = 0x10,
|
||||||
|
GFX_SURFACE_QUANTIZED = 0x20,
|
||||||
|
GFX_SURFACE_NO_COLOR = 0x40
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#define DEFAULT_SMODEL_CULL_DIST 10000.0f
|
#define DEFAULT_SMODEL_CULL_DIST 10000.0f
|
||||||
#define DEFAULT_SMODEL_FLAGS SMODEL_FLAG_NO_SHADOW
|
#define DEFAULT_SMODEL_FLAGS SMODEL_FLAG_NO_SHADOW
|
||||||
#define DEFAULT_SMODEL_LIGHT 1
|
#define DEFAULT_SMODEL_LIGHT 1
|
||||||
#define DEFAULT_SMODEL_REFLECTION_PROBE 0
|
#define DEFAULT_SMODEL_REFLECTION_PROBE 0
|
||||||
|
|
||||||
|
#define DEFAULT_SURFACE_LIGHT 1
|
||||||
|
#define DEFAULT_SURFACE_LIGHTMAP 0
|
||||||
|
#define DEFAULT_SURFACE_REFLECTION_PROBE 0
|
||||||
|
#define DEFAULT_SURFACE_FLAGS 0
|
||||||
|
|
||||||
|
const std::vector<std::string> spawnpointDefenderTypeArray = {
|
||||||
|
"mp_ctf_spawn_allies",
|
||||||
|
"mp_ctf_spawn_allies_start",
|
||||||
|
"mp_sd_spawn_defender",
|
||||||
|
"mp_dom_spawn_allies_start",
|
||||||
|
"mp_dem_spawn_defender_start",
|
||||||
|
"mp_dem_spawn_defenderOT_start",
|
||||||
|
"mp_dem_spawn_defender",
|
||||||
|
"mp_tdm_spawn_allies_start",
|
||||||
|
"mp_tdm_spawn_team1_start",
|
||||||
|
"mp_tdm_spawn_team2_start",
|
||||||
|
"mp_tdm_spawn_team3_start"
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::vector<std::string> spawnpointAttackerTypeArray = {
|
||||||
|
"mp_ctf_spawn_axis",
|
||||||
|
"mp_ctf_spawn_axis_start",
|
||||||
|
"mp_sd_spawn_attacker",
|
||||||
|
"mp_dom_spawn_axis_start",
|
||||||
|
"mp_dem_spawn_attacker_start",
|
||||||
|
"mp_dem_spawn_attackerOT_start",
|
||||||
|
"mp_dem_spawn_defender",
|
||||||
|
"mp_tdm_spawn_axis_start",
|
||||||
|
"mp_tdm_spawn_team4_start",
|
||||||
|
"mp_tdm_spawn_team5_start",
|
||||||
|
"mp_tdm_spawn_team6_start"
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::vector<std::string> spawnpointFFATypeArray = {
|
||||||
|
"mp_tdm_spawn",
|
||||||
|
"mp_dm_spawn",
|
||||||
|
"mp_dom_spawn"
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::vector<std::string> spawnpointObjectiveTypeArray = {
|
||||||
|
"mp_dom_spawn_flag_c",
|
||||||
|
"mp_dom_spawn_flag_a"
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::string defaultSpawnpointString = "{"
|
||||||
|
"\"attackers\": ["
|
||||||
|
" {"
|
||||||
|
" \"origin\": \"0 0 0\","
|
||||||
|
" \"angles\": \"0 0 0\""
|
||||||
|
" }"
|
||||||
|
"],"
|
||||||
|
"\"defenders\": ["
|
||||||
|
" {"
|
||||||
|
" \"origin\": \"0 0 0\","
|
||||||
|
" \"angles\": \"0 0 0\""
|
||||||
|
" }"
|
||||||
|
"],"
|
||||||
|
"\"FFA\": ["
|
||||||
|
" {"
|
||||||
|
" \"origin\": \"0 0 0\","
|
||||||
|
" \"angles\": \"0 0 0\""
|
||||||
|
" }"
|
||||||
|
"]"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Game/T6/Material/JsonMaterialLoaderT6.h"
|
||||||
|
|
||||||
#include "BinarySpacePartitionTreePreCalc.h"
|
#include "BinarySpacePartitionTreePreCalc.h"
|
||||||
#include "TriangleSort.h"
|
#include "TriangleSort.h"
|
||||||
#include "CustomMapConsts.h"
|
#include "CustomMapConsts.h"
|
||||||
@@ -26,15 +28,21 @@ public:
|
|||||||
{
|
{
|
||||||
_ASSERT(projInfo != NULL);
|
_ASSERT(projInfo != NULL);
|
||||||
|
|
||||||
createGfxWorld(projInfo);
|
checkAndAddDefaultRequiredAssets(projInfo);
|
||||||
|
if (hasLinkFailed)
|
||||||
|
{
|
||||||
|
printf("Custom Map link has failed.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
createComWorld(projInfo);
|
createComWorld(projInfo);
|
||||||
createMapEnts(projInfo);
|
createMapEnts(projInfo);
|
||||||
createGameWorldMp(projInfo);
|
createGameWorldMp(projInfo);
|
||||||
createSkinnedVerts(projInfo);
|
createSkinnedVerts(projInfo);
|
||||||
|
createGfxWorld(projInfo); // requires mapents asset
|
||||||
createClipMap(projInfo); // must go last (requires gfx and mapents asset)
|
createClipMap(projInfo); // must go last (requires gfx and mapents asset)
|
||||||
|
|
||||||
checkAndAddDefaultRequiredAssets(projInfo);
|
|
||||||
|
|
||||||
if (hasLinkFailed)
|
if (hasLinkFailed)
|
||||||
{
|
{
|
||||||
printf("Custom Map link has failed.\n");
|
printf("Custom Map link has failed.\n");
|
||||||
@@ -45,12 +53,21 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct entModelBounds
|
||||||
|
{
|
||||||
|
vec3_t mins;
|
||||||
|
vec3_t maxs;
|
||||||
|
};
|
||||||
|
|
||||||
MemoryManager& m_memory;
|
MemoryManager& m_memory;
|
||||||
ISearchPath& m_search_path;
|
ISearchPath& m_search_path;
|
||||||
Zone& m_zone;
|
Zone& m_zone;
|
||||||
AssetCreationContext& m_context;
|
AssetCreationContext& m_context;
|
||||||
|
|
||||||
bool hasLinkFailed;
|
bool hasLinkFailed;
|
||||||
|
std::vector<entModelBounds> entityModelList;
|
||||||
|
|
||||||
|
json materialTemplateJson;
|
||||||
|
|
||||||
// TODO vd1:
|
// TODO vd1:
|
||||||
// used for UVs of sub-textures, when it is set to empty all of them turn a blank colour
|
// used for UVs of sub-textures, when it is set to empty all of them turn a blank colour
|
||||||
@@ -120,6 +137,26 @@ private:
|
|||||||
return surf0.vertexCount > surf1.vertexCount;
|
return surf0.vertexCount > surf1.vertexCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Material* loadImageIntoMaterial(std::string& imageName)
|
||||||
|
{
|
||||||
|
Material* material = new Material;
|
||||||
|
material->info.name = m_memory.Dup(imageName.c_str());
|
||||||
|
|
||||||
|
// parse the template file and replace the image name
|
||||||
|
materialTemplateJson["textures"][1]["image"] = imageName;
|
||||||
|
|
||||||
|
AssetRegistration<AssetMaterial> registration(imageName, material);
|
||||||
|
if (!LoadMaterialAsJson(materialTemplateJson, *material, m_memory, m_context, registration))
|
||||||
|
{
|
||||||
|
printf("WARN: failed to convert image %s to a material.\n", imageName.c_str());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_context.AddAsset(std::move(registration));
|
||||||
|
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
void overwriteMapSurfaces(customMapInfo* projInfo, GfxWorld* gfxWorld)
|
void overwriteMapSurfaces(customMapInfo* projInfo, GfxWorld* gfxWorld)
|
||||||
{
|
{
|
||||||
bool overwriteResult = overwriteDrawData(projInfo, gfxWorld);
|
bool overwriteResult = overwriteDrawData(projInfo, gfxWorld);
|
||||||
@@ -138,7 +175,7 @@ private:
|
|||||||
currSurface->primaryLightIndex = DEFAULT_SURFACE_LIGHT;
|
currSurface->primaryLightIndex = DEFAULT_SURFACE_LIGHT;
|
||||||
currSurface->lightmapIndex = DEFAULT_SURFACE_LIGHTMAP;
|
currSurface->lightmapIndex = DEFAULT_SURFACE_LIGHTMAP;
|
||||||
currSurface->reflectionProbeIndex = DEFAULT_SURFACE_REFLECTION_PROBE;
|
currSurface->reflectionProbeIndex = DEFAULT_SURFACE_REFLECTION_PROBE;
|
||||||
currSurface->flags = objSurface->flags;
|
currSurface->flags = DEFAULT_SURFACE_FLAGS;
|
||||||
|
|
||||||
currSurface->tris.triCount = objSurface->triCount;
|
currSurface->tris.triCount = objSurface->triCount;
|
||||||
currSurface->tris.baseIndex = objSurface->firstIndex_Index;
|
currSurface->tris.baseIndex = objSurface->firstIndex_Index;
|
||||||
@@ -154,25 +191,25 @@ private:
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CM_MATERIAL_COLOUR:
|
case CM_MATERIAL_COLOUR:
|
||||||
case NO_COLOUR_OR_TEXTURE:
|
case CM_MATERIAL_EMPTY:
|
||||||
surfMaterialName = colourOnlyMaterialName;
|
surfMaterialName = colorOnlyImageName;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_ASSERT(false);
|
_ASSERT(false);
|
||||||
}
|
}
|
||||||
auto* assetInfo = m_context.LoadDependency<AssetMaterial>(surfMaterialName);
|
Material* surfMaterial = loadImageIntoMaterial(surfMaterialName);
|
||||||
if (assetInfo == NULL)
|
if (surfMaterial == NULL)
|
||||||
{
|
{
|
||||||
assetInfo = m_context.LoadDependency<AssetMaterial>(missingMaterialName);
|
surfMaterial = loadImageIntoMaterial(missingImageName);
|
||||||
if (assetInfo == NULL)
|
if (surfMaterial == NULL)
|
||||||
{
|
{
|
||||||
printf("Error: unable to find the default texture!\n");
|
printf("Error: unable to find the missing image texture!\n");
|
||||||
hasLinkFailed = true;
|
hasLinkFailed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
currSurface->material = assetInfo->Asset();
|
currSurface->material = surfMaterial;
|
||||||
|
|
||||||
GfxPackedWorldVertex* firstVert = (GfxPackedWorldVertex*)&gfxWorld->draw.vd0.data[currSurface->tris.vertexDataOffset0];
|
GfxPackedWorldVertex* firstVert = (GfxPackedWorldVertex*)&gfxWorld->draw.vd0.data[currSurface->tris.vertexDataOffset0];
|
||||||
currSurface->bounds[0].x = firstVert[0].xyz.x;
|
currSurface->bounds[0].x = firstVert[0].xyz.x;
|
||||||
@@ -441,36 +478,70 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the lightgrid is used to light models in a dynamic way and is precomputed
|
||||||
void overwriteLightGrid(GfxWorld* gfxWorld)
|
void overwriteLightGrid(GfxWorld* gfxWorld)
|
||||||
{
|
{
|
||||||
|
// there is almost no basis for the values in this code, i chose them based on what feels right and what i could see when RE.
|
||||||
|
// it works and that is all thats needed :)
|
||||||
|
|
||||||
|
// mins and maxs define the range that the lightgrid will work in
|
||||||
|
// idk how these values are calculated, but the below values are larger
|
||||||
|
// than official map values
|
||||||
gfxWorld->lightGrid.mins[0] = 0;
|
gfxWorld->lightGrid.mins[0] = 0;
|
||||||
gfxWorld->lightGrid.mins[1] = 0;
|
gfxWorld->lightGrid.mins[1] = 0;
|
||||||
gfxWorld->lightGrid.mins[2] = 0;
|
gfxWorld->lightGrid.mins[2] = 0;
|
||||||
gfxWorld->lightGrid.maxs[0] = 0;
|
gfxWorld->lightGrid.maxs[0] = 200;
|
||||||
gfxWorld->lightGrid.maxs[1] = 0;
|
gfxWorld->lightGrid.maxs[1] = 200;
|
||||||
gfxWorld->lightGrid.maxs[2] = 0;
|
gfxWorld->lightGrid.maxs[2] = 50;
|
||||||
|
|
||||||
gfxWorld->lightGrid.rowAxis = 0; // default value
|
gfxWorld->lightGrid.rowAxis = 0; // default value
|
||||||
gfxWorld->lightGrid.colAxis = 1; // default value
|
gfxWorld->lightGrid.colAxis = 1; // default value
|
||||||
gfxWorld->lightGrid.sunPrimaryLightIndex = SUN_LIGHT_INDEX; // the sun is always index 1
|
gfxWorld->lightGrid.sunPrimaryLightIndex = SUN_LIGHT_INDEX;
|
||||||
gfxWorld->lightGrid.offset = 0.0f;
|
gfxWorld->lightGrid.offset = 0.0f; // default value
|
||||||
|
|
||||||
// if rowDataStart's first value is -1, it will not look up any lightmap data
|
// this will make the lookup into rawRowData always return the first row
|
||||||
gfxWorld->lightGrid.rowDataStart = new uint16_t[1];
|
int rowDataStartSize = gfxWorld->lightGrid.maxs[gfxWorld->lightGrid.rowAxis] - gfxWorld->lightGrid.mins[gfxWorld->lightGrid.rowAxis] + 1;
|
||||||
*gfxWorld->lightGrid.rowDataStart = (uint16_t)(-1);
|
gfxWorld->lightGrid.rowDataStart = new uint16_t[rowDataStartSize];
|
||||||
|
memset(gfxWorld->lightGrid.rowDataStart, 0, rowDataStartSize * sizeof(uint16_t));
|
||||||
|
|
||||||
gfxWorld->lightGrid.rawRowDataSize = 0;
|
gfxWorld->lightGrid.rawRowDataSize = sizeof(GfxLightGridRow);
|
||||||
gfxWorld->lightGrid.rawRowData = NULL;
|
GfxLightGridRow* row = new GfxLightGridRow[1];
|
||||||
|
row->colStart = 0;
|
||||||
|
row->colCount = 0x1000; // 0x1000 as this is large enough for all checks done by the game
|
||||||
|
row->zStart = 0;
|
||||||
|
row->zCount = 0xFF; // 0xFF as this is large enough for all checks done by the game, but small enough not to mess with other checks
|
||||||
|
row->firstEntry = 0;
|
||||||
|
// this unknown part is weird, bo2 code uses up to unk5 and possibly onwards but the dumped rawRowData looks like it has a different structure.
|
||||||
|
// this seems to work though
|
||||||
|
row->unk.unknown1 = 0;
|
||||||
|
row->unk.unknown2 = 0;
|
||||||
|
row->unk.unknown3 = 0;
|
||||||
|
row->unk.unknown4 = 0;
|
||||||
|
row->unk.unknown5 = 0;
|
||||||
|
row->unk.unknown6 = 0;
|
||||||
|
row->unk.unknown7 = 0;
|
||||||
|
row->unk.unknown8 = 0;
|
||||||
|
gfxWorld->lightGrid.rawRowData = (aligned_byte_pointer*)row;
|
||||||
|
|
||||||
gfxWorld->lightGrid.colorCount = 0;
|
// entries are looked up based on the lightgrid sample pos and data within GfxLightGridRow
|
||||||
gfxWorld->lightGrid.colors = NULL;
|
gfxWorld->lightGrid.entryCount = 60000; // 60000 as it should be enough entries to be indexed by all lightgrid data
|
||||||
|
GfxLightGridEntry* entryArray = new GfxLightGridEntry[gfxWorld->lightGrid.entryCount];
|
||||||
|
for (unsigned int i = 0; i < gfxWorld->lightGrid.entryCount; i++)
|
||||||
|
{
|
||||||
|
entryArray[i].colorsIndex = 0; // always index first colour
|
||||||
|
entryArray[i].primaryLightIndex = SUN_LIGHT_INDEX;
|
||||||
|
entryArray[i].visibility = 0;
|
||||||
|
}
|
||||||
|
gfxWorld->lightGrid.entries = entryArray;
|
||||||
|
|
||||||
|
// colours are looked up by an entries colourindex
|
||||||
|
gfxWorld->lightGrid.colorCount = 0x1000; //0x1000 as it should be enough to hold every index
|
||||||
|
gfxWorld->lightGrid.colors = new GfxCompressedLightGridColors[gfxWorld->lightGrid.colorCount];
|
||||||
|
memset(gfxWorld->lightGrid.colors, LIGHTGRID_COLOUR, rowDataStartSize * sizeof(uint16_t));
|
||||||
|
|
||||||
|
// we use the colours array instead of coeffs array
|
||||||
gfxWorld->lightGrid.coeffCount = 0;
|
gfxWorld->lightGrid.coeffCount = 0;
|
||||||
gfxWorld->lightGrid.coeffs = NULL;
|
gfxWorld->lightGrid.coeffs = NULL;
|
||||||
|
|
||||||
gfxWorld->lightGrid.entryCount = 0;
|
|
||||||
gfxWorld->lightGrid.entries = NULL;
|
|
||||||
|
|
||||||
gfxWorld->lightGrid.skyGridVolumeCount = 0;
|
gfxWorld->lightGrid.skyGridVolumeCount = 0;
|
||||||
gfxWorld->lightGrid.skyGridVolumes = NULL;
|
gfxWorld->lightGrid.skyGridVolumes = NULL;
|
||||||
}
|
}
|
||||||
@@ -490,8 +561,6 @@ private:
|
|||||||
gfxWorld->cells = new GfxCell[cellCount];
|
gfxWorld->cells = new GfxCell[cellCount];
|
||||||
gfxWorld->cells[0].portalCount = 0;
|
gfxWorld->cells[0].portalCount = 0;
|
||||||
gfxWorld->cells[0].portals = NULL;
|
gfxWorld->cells[0].portals = NULL;
|
||||||
gfxWorld->cells[0].reflectionProbeCount = 0;
|
|
||||||
gfxWorld->cells[0].reflectionProbes = NULL;
|
|
||||||
gfxWorld->cells[0].mins.x = gfxWorld->mins.x;
|
gfxWorld->cells[0].mins.x = gfxWorld->mins.x;
|
||||||
gfxWorld->cells[0].mins.y = gfxWorld->mins.y;
|
gfxWorld->cells[0].mins.y = gfxWorld->mins.y;
|
||||||
gfxWorld->cells[0].mins.z = gfxWorld->mins.z;
|
gfxWorld->cells[0].mins.z = gfxWorld->mins.z;
|
||||||
@@ -499,6 +568,12 @@ private:
|
|||||||
gfxWorld->cells[0].maxs.y = gfxWorld->maxs.y;
|
gfxWorld->cells[0].maxs.y = gfxWorld->maxs.y;
|
||||||
gfxWorld->cells[0].maxs.z = gfxWorld->maxs.z;
|
gfxWorld->cells[0].maxs.z = gfxWorld->maxs.z;
|
||||||
|
|
||||||
|
// there is only 1 reflection probe
|
||||||
|
gfxWorld->cells[0].reflectionProbeCount = 1;
|
||||||
|
char* reflectionProbeIndexes = new char[gfxWorld->cells[0].reflectionProbeCount];
|
||||||
|
reflectionProbeIndexes[0] = DEFAULT_SURFACE_REFLECTION_PROBE;
|
||||||
|
gfxWorld->cells[0].reflectionProbes = reflectionProbeIndexes;
|
||||||
|
|
||||||
// AABB trees are used to detect what should be rendered and what shouldn't
|
// AABB trees are used to detect what should be rendered and what shouldn't
|
||||||
// Just use the first AABB node to hold all models, no optimisation but all models/surfaces wil lbe drawn
|
// Just use the first AABB node to hold all models, no optimisation but all models/surfaces wil lbe drawn
|
||||||
gfxWorld->cells[0].aabbTreeCount = 1;
|
gfxWorld->cells[0].aabbTreeCount = 1;
|
||||||
@@ -558,7 +633,7 @@ private:
|
|||||||
// these models are the collision for the entities defined in the mapents asset
|
// these models are the collision for the entities defined in the mapents asset
|
||||||
// used for triggers and stuff
|
// used for triggers and stuff
|
||||||
|
|
||||||
gfxWorld->modelCount = 1;
|
gfxWorld->modelCount = entityModelList.size() + 1;
|
||||||
gfxWorld->models = new GfxBrushModel[gfxWorld->modelCount];
|
gfxWorld->models = new GfxBrushModel[gfxWorld->modelCount];
|
||||||
|
|
||||||
// first model is always the world model
|
// first model is always the world model
|
||||||
@@ -572,22 +647,21 @@ private:
|
|||||||
gfxWorld->models[0].bounds[1].z = gfxWorld->maxs.z;
|
gfxWorld->models[0].bounds[1].z = gfxWorld->maxs.z;
|
||||||
memset(&gfxWorld->models[0].writable, 0, sizeof(GfxBrushModelWritable));
|
memset(&gfxWorld->models[0].writable, 0, sizeof(GfxBrushModelWritable));
|
||||||
|
|
||||||
// for (int i = 1; i < gfxWorld->modelCount; i++)
|
for (size_t i = 0; i < entityModelList.size(); i++)
|
||||||
//{
|
{
|
||||||
// auto currEntModel = &gfxWorld->models[i];
|
auto currEntModel = &gfxWorld->models[i + 1];
|
||||||
// json currEntModelJs = js["entityModels"][i - 1];
|
entModelBounds currEntModelBounds = entityModelList[i];
|
||||||
//
|
|
||||||
// currEntModel->bounds[0].x = currEntModelJs["mins"]["x"];
|
currEntModel->startSurfIndex = 0;
|
||||||
// currEntModel->bounds[0].y = currEntModelJs["mins"]["y"];
|
currEntModel->surfaceCount = -1; // -1 when it doesn't use map surfaces
|
||||||
// currEntModel->bounds[0].z = currEntModelJs["mins"]["z"];
|
currEntModel->bounds[0].x = currEntModelBounds.mins.x;
|
||||||
// currEntModel->bounds[1].x = currEntModelJs["maxs"]["x"];
|
currEntModel->bounds[0].y = currEntModelBounds.mins.y;
|
||||||
// currEntModel->bounds[1].y = currEntModelJs["maxs"]["y"];
|
currEntModel->bounds[0].z = currEntModelBounds.mins.z;
|
||||||
// currEntModel->bounds[1].z = currEntModelJs["maxs"]["z"];
|
currEntModel->bounds[1].x = currEntModelBounds.maxs.x;
|
||||||
//
|
currEntModel->bounds[1].y = currEntModelBounds.maxs.y;
|
||||||
// currEntModel->surfaceCount = 0;
|
currEntModel->bounds[1].z = currEntModelBounds.maxs.z;
|
||||||
// currEntModel->startSurfIndex = (unsigned int)(-1);
|
memset(&gfxWorld->models[0].writable, 0, sizeof(GfxBrushModelWritable));
|
||||||
// memset(&currEntModel->writable, 0, sizeof(GfxBrushModelWritable));
|
}
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateSunData(GfxWorld* gfxWorld)
|
void updateSunData(GfxWorld* gfxWorld)
|
||||||
@@ -703,14 +777,14 @@ private:
|
|||||||
gfxWorld->draw.lightmaps[0].secondary = secondaryTextureAsset->Asset();
|
gfxWorld->draw.lightmaps[0].secondary = secondaryTextureAsset->Asset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void overwriteSkyBox(GfxWorld* gfxWorld)
|
void overwriteSkyBox(customMapInfo* projInfo, GfxWorld* gfxWorld)
|
||||||
{
|
{
|
||||||
const char* skyBoxName = "skybox_mp_dig";
|
std::string skyBoxName = "skybox_" + projInfo->name;
|
||||||
gfxWorld->skyBoxModel = skyBoxName;
|
gfxWorld->skyBoxModel = _strdup(skyBoxName.c_str());
|
||||||
|
|
||||||
if (m_context.LoadDependency<AssetXModel>(skyBoxName) == NULL)
|
if (m_context.LoadDependency<AssetXModel>(skyBoxName) == NULL)
|
||||||
{
|
{
|
||||||
printf("WARN: Unable to find the skybox model %s\n", skyBoxName);
|
printf("WARN: Unable to load the skybox xmodel %s\n", skyBoxName.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// default skybox values from mp_dig
|
// default skybox values from mp_dig
|
||||||
@@ -722,9 +796,12 @@ private:
|
|||||||
|
|
||||||
void updateDynEntData(GfxWorld* gfxWorld)
|
void updateDynEntData(GfxWorld* gfxWorld)
|
||||||
{
|
{
|
||||||
gfxWorld->dpvsDyn.dynEntClientCount[0] = DYN_ENT_COUNT + 256;
|
gfxWorld->dpvsDyn.dynEntClientCount[0] = DYN_ENT_COUNT + 256; // the game allocs 256 empty dynents, as they may be used ingame
|
||||||
gfxWorld->dpvsDyn.dynEntClientCount[1] = 0;
|
gfxWorld->dpvsDyn.dynEntClientCount[1] = 0;
|
||||||
gfxWorld->dpvsDyn.dynEntClientWordCount[0] = 1; // needs to be at least 1
|
|
||||||
|
// +100: there is a crash that happens when regdolls are created, and dynEntClientWordCount[0] is the issue.
|
||||||
|
// Making the value much larger than required fixes it, but idk what the root cause is
|
||||||
|
gfxWorld->dpvsDyn.dynEntClientWordCount[0] = ((gfxWorld->dpvsDyn.dynEntClientCount[0] + 31) >> 5) + 100;
|
||||||
gfxWorld->dpvsDyn.dynEntClientWordCount[1] = 0;
|
gfxWorld->dpvsDyn.dynEntClientWordCount[1] = 0;
|
||||||
gfxWorld->dpvsDyn.usageCount = 0;
|
gfxWorld->dpvsDyn.usageCount = 0;
|
||||||
|
|
||||||
@@ -779,7 +856,7 @@ private:
|
|||||||
auto outdoorImageAsset = m_context.LoadDependency<AssetImage>(outdoorImageName);
|
auto outdoorImageAsset = m_context.LoadDependency<AssetImage>(outdoorImageName);
|
||||||
if (outdoorImageAsset == NULL)
|
if (outdoorImageAsset == NULL)
|
||||||
{
|
{
|
||||||
printf("ERROR! unable to find image $outdoor, this will crash your game!\n");
|
printf("ERROR! unable to find image $outdoor!\n");
|
||||||
hasLinkFailed = true;
|
hasLinkFailed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -804,7 +881,7 @@ private:
|
|||||||
|
|
||||||
overwriteLightmapData(gfxWorld);
|
overwriteLightmapData(gfxWorld);
|
||||||
|
|
||||||
overwriteSkyBox(gfxWorld);
|
overwriteSkyBox(projInfo, gfxWorld);
|
||||||
|
|
||||||
updateReflectionProbeData(gfxWorld);
|
updateReflectionProbeData(gfxWorld);
|
||||||
|
|
||||||
@@ -1387,7 +1464,7 @@ private:
|
|||||||
clipMap->info.brushContents = NULL;
|
clipMap->info.brushContents = NULL;
|
||||||
|
|
||||||
clipMap->originalDynEntCount = DYN_ENT_COUNT;
|
clipMap->originalDynEntCount = DYN_ENT_COUNT;
|
||||||
clipMap->dynEntCount[0] = clipMap->originalDynEntCount + 256;
|
clipMap->dynEntCount[0] = clipMap->originalDynEntCount + 256; // the game allocs 256 empty dynents, as they may be used ingame
|
||||||
clipMap->dynEntCount[1] = 0;
|
clipMap->dynEntCount[1] = 0;
|
||||||
clipMap->dynEntCount[2] = 0;
|
clipMap->dynEntCount[2] = 0;
|
||||||
clipMap->dynEntCount[3] = 0;
|
clipMap->dynEntCount[3] = 0;
|
||||||
@@ -1413,49 +1490,47 @@ private:
|
|||||||
clipMap->dynEntDefList[0] = new DynEntityDef[clipMap->dynEntCount[0]];
|
clipMap->dynEntDefList[0] = new DynEntityDef[clipMap->dynEntCount[0]];
|
||||||
clipMap->dynEntDefList[1] = NULL;
|
clipMap->dynEntDefList[1] = NULL;
|
||||||
memset(clipMap->dynEntDefList[0], 0, sizeof(DynEntityDef) * clipMap->dynEntCount[0]);
|
memset(clipMap->dynEntDefList[0], 0, sizeof(DynEntityDef) * clipMap->dynEntCount[0]);
|
||||||
for (int i = 0; i < clipMap->dynEntCount[0]; i++)
|
|
||||||
{
|
|
||||||
DynEntityDef* currDef = &clipMap->dynEntDefList[0][i];
|
|
||||||
currDef->physConstraints[0] = 0x1FF;
|
|
||||||
currDef->physConstraints[1] = 0x1FF;
|
|
||||||
currDef->physConstraints[2] = 0x1FF;
|
|
||||||
currDef->physConstraints[3] = 0x1FF;
|
|
||||||
}
|
|
||||||
|
|
||||||
// cmodels is the collision for mapents
|
// cmodels is the collision for mapents
|
||||||
auto gfxWorldAsset = m_context.LoadDependency<AssetGfxWorld>(projInfo->bspName);
|
auto gfxWorldAsset = m_context.LoadDependency<AssetGfxWorld>(projInfo->bspName);
|
||||||
_ASSERT(gfxWorldAsset != NULL);
|
_ASSERT(gfxWorldAsset != NULL);
|
||||||
GfxWorld* gfxWorld = gfxWorldAsset->Asset();
|
GfxWorld* gfxWorld = gfxWorldAsset->Asset();
|
||||||
_ASSERT(gfxWorld->modelCount == 1);
|
clipMap->numSubModels = gfxWorld->modelCount;
|
||||||
clipMap->numSubModels = 1;
|
|
||||||
clipMap->cmodels = new cmodel_t[clipMap->numSubModels];
|
clipMap->cmodels = new cmodel_t[clipMap->numSubModels];
|
||||||
clipMap->cmodels[0].leaf.firstCollAabbIndex = 0;
|
for (unsigned int i = 0; i < clipMap->numSubModels; i++)
|
||||||
clipMap->cmodels[0].leaf.collAabbCount = 0;
|
{
|
||||||
clipMap->cmodels[0].leaf.brushContents = 0;
|
// bomb triggers use leafs, not world terrain so that might be an issue
|
||||||
clipMap->cmodels[0].leaf.terrainContents = WORLD_TERRAIN_CONTENTS;
|
|
||||||
clipMap->cmodels[0].leaf.mins.x = 0.0f;
|
|
||||||
clipMap->cmodels[0].leaf.mins.y = 0.0f;
|
|
||||||
clipMap->cmodels[0].leaf.mins.z = 0.0f;
|
|
||||||
clipMap->cmodels[0].leaf.maxs.x = 0.0f;
|
|
||||||
clipMap->cmodels[0].leaf.maxs.y = 0.0f;
|
|
||||||
clipMap->cmodels[0].leaf.maxs.z = 0.0f;
|
|
||||||
clipMap->cmodels[0].leaf.leafBrushNode = 0;
|
|
||||||
clipMap->cmodels[0].leaf.cluster = 0;
|
|
||||||
clipMap->cmodels[0].info = NULL;
|
|
||||||
clipMap->cmodels[0].mins.x = gfxWorld->models[0].bounds[0].x;
|
|
||||||
clipMap->cmodels[0].mins.y = gfxWorld->models[0].bounds[0].y;
|
|
||||||
clipMap->cmodels[0].mins.z = gfxWorld->models[0].bounds[0].z;
|
|
||||||
clipMap->cmodels[0].maxs.x = gfxWorld->models[0].bounds[1].x;
|
|
||||||
clipMap->cmodels[0].maxs.y = gfxWorld->models[0].bounds[1].y;
|
|
||||||
clipMap->cmodels[0].maxs.z = gfxWorld->models[0].bounds[1].z;
|
|
||||||
clipMap->cmodels[0].radius = CMUtil::distBetweenPoints(clipMap->cmodels[0].mins, clipMap->cmodels[0].maxs) / 2;
|
|
||||||
|
|
||||||
|
GfxBrushModel* gfxModel = &gfxWorld->models[i];
|
||||||
|
cmodel_t* cmModel = &clipMap->cmodels[i];
|
||||||
|
|
||||||
|
cmModel->leaf.firstCollAabbIndex = 0;
|
||||||
|
cmModel->leaf.collAabbCount = 0;
|
||||||
|
cmModel->leaf.brushContents = 0;
|
||||||
|
cmModel->leaf.terrainContents = WORLD_TERRAIN_CONTENTS;
|
||||||
|
cmModel->leaf.mins.x = 0.0f;
|
||||||
|
cmModel->leaf.mins.y = 0.0f;
|
||||||
|
cmModel->leaf.mins.z = 0.0f;
|
||||||
|
cmModel->leaf.maxs.x = 0.0f;
|
||||||
|
cmModel->leaf.maxs.y = 0.0f;
|
||||||
|
cmModel->leaf.maxs.z = 0.0f;
|
||||||
|
cmModel->leaf.leafBrushNode = 0;
|
||||||
|
cmModel->leaf.cluster = 0;
|
||||||
|
cmModel->info = NULL;
|
||||||
|
cmModel->mins.x = gfxModel->bounds[0].x;
|
||||||
|
cmModel->mins.y = gfxModel->bounds[0].y;
|
||||||
|
cmModel->mins.z = gfxModel->bounds[0].z;
|
||||||
|
cmModel->maxs.x = gfxModel->bounds[1].x;
|
||||||
|
cmModel->maxs.y = gfxModel->bounds[1].y;
|
||||||
|
cmModel->maxs.z = gfxModel->bounds[1].z;
|
||||||
|
cmModel->radius = CMUtil::distBetweenPoints(cmModel->mins, cmModel->maxs) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
addXModelsToCollision(projInfo, clipMap);
|
addXModelsToCollision(projInfo, clipMap);
|
||||||
|
|
||||||
clipMap->info.numMaterials = 1;
|
clipMap->info.numMaterials = 1;
|
||||||
clipMap->info.materials = new ClipMaterial[clipMap->info.numMaterials];
|
clipMap->info.materials = new ClipMaterial[clipMap->info.numMaterials];
|
||||||
clipMap->info.materials[0].name = _strdup(missingMaterialName.c_str());
|
clipMap->info.materials[0].name = _strdup(missingImageName.c_str());
|
||||||
clipMap->info.materials[0].contentFlags = MATERIAL_CONTENT_FLAGS;
|
clipMap->info.materials[0].contentFlags = MATERIAL_CONTENT_FLAGS;
|
||||||
clipMap->info.materials[0].surfaceFlags = MATERIAL_SURFACE_FLAGS;
|
clipMap->info.materials[0].surfaceFlags = MATERIAL_SURFACE_FLAGS;
|
||||||
|
|
||||||
@@ -1559,34 +1634,12 @@ private:
|
|||||||
m_context.AddAsset<AssetComWorld>(comWorld->name, comWorld);
|
m_context.AddAsset<AssetComWorld>(comWorld->name, comWorld);
|
||||||
}
|
}
|
||||||
|
|
||||||
void createMapEnts(customMapInfo* projInfo)
|
void parseMapEntsJSON(json& entArrayJs, std::string& entityString)
|
||||||
{
|
{
|
||||||
MapEnts* mapEnts = new MapEnts;
|
int entityCount = entArrayJs.size();
|
||||||
|
|
||||||
mapEnts->name = _strdup(projInfo->bspName.c_str());
|
|
||||||
|
|
||||||
// don't need these
|
|
||||||
mapEnts->trigger.count = 0;
|
|
||||||
mapEnts->trigger.models = NULL;
|
|
||||||
mapEnts->trigger.hullCount = 0;
|
|
||||||
mapEnts->trigger.hulls = NULL;
|
|
||||||
mapEnts->trigger.slabCount = 0;
|
|
||||||
mapEnts->trigger.slabs = NULL;
|
|
||||||
|
|
||||||
const auto file = m_search_path.Open("custom_map/entities.json");
|
|
||||||
if (!file.IsOpen())
|
|
||||||
{
|
|
||||||
printf("WARN: can't find entity json!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
json entJs = json::parse(*file.m_stream);
|
|
||||||
|
|
||||||
std::string entityString;
|
|
||||||
int entityCount = entJs["entityCount"];
|
|
||||||
for (int i = 0; i < entityCount; i++)
|
for (int i = 0; i < entityCount; i++)
|
||||||
{
|
{
|
||||||
auto currEntity = entJs["entities"][i];
|
auto currEntity = entArrayJs[i];
|
||||||
|
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
{
|
{
|
||||||
@@ -1610,7 +1663,186 @@ private:
|
|||||||
|
|
||||||
entityString.append("}\n");
|
entityString.append("}\n");
|
||||||
}
|
}
|
||||||
entityString.pop_back(); // remove newline character from the end of the string
|
}
|
||||||
|
|
||||||
|
void parseSpawnpointJSON(json& entArrayJs, std::string& entityString, std::vector<std::string> spawnpointTypeArray)
|
||||||
|
{
|
||||||
|
int entityCount = entArrayJs.size();
|
||||||
|
for (int i = 0; i < entityCount; i++)
|
||||||
|
{
|
||||||
|
auto currEntity = entArrayJs[i];
|
||||||
|
|
||||||
|
std::string origin = currEntity["origin"];
|
||||||
|
std::string angles = currEntity["angles"];
|
||||||
|
|
||||||
|
for (std::string& spawnType : spawnpointTypeArray)
|
||||||
|
{
|
||||||
|
entityString.append("{\n");
|
||||||
|
entityString.append(std::format("\"origin\" \"{}\"\n", origin));
|
||||||
|
entityString.append(std::format("\"angles\" \"{}\"\n", angles));
|
||||||
|
entityString.append(std::format("\"classname\" \"{}\"\n", spawnType));
|
||||||
|
entityString.append("}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseBombJSON(json& bombJs, std::string& entityString)
|
||||||
|
{
|
||||||
|
// add the bomb model
|
||||||
|
{
|
||||||
|
std::string bombOriginStr = bombJs["sd_bomb"]["origin"];
|
||||||
|
entityString.append("{\n");
|
||||||
|
entityString.append("\"classname\" \"script_model\"\n");
|
||||||
|
entityString.append("\"model\" \"prop_suitcase_bomb\"\n");
|
||||||
|
entityString.append("\"targetname\" \"sd_bomb\"\n");
|
||||||
|
entityString.append("\"script_gameobjectname\" \"sd\"\n");
|
||||||
|
entityString.append("\"spawnflags\" \"4\"\n");
|
||||||
|
entityString.append(std::format("\"origin\" \"{}\"\n", bombOriginStr));
|
||||||
|
entityString.append("}\n");
|
||||||
|
}
|
||||||
|
if (m_context.LoadDependency<AssetXModel>("prop_suitcase_bomb") == NULL)
|
||||||
|
{
|
||||||
|
hasLinkFailed = true;
|
||||||
|
printf("ERROR: unable to find s&d bomb xmodel\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the bomb pickup trigger
|
||||||
|
{
|
||||||
|
std::string bombOriginStr = bombJs["sd_bomb"]["origin"];
|
||||||
|
vec3_t bomboriginV3 = CMUtil::convertStringToVec3(bombOriginStr);
|
||||||
|
entModelBounds bounds;
|
||||||
|
bounds.mins.x = bomboriginV3.x - 32.0f; // bounds taken from mp_dig
|
||||||
|
bounds.mins.y = bomboriginV3.y - 32.0f;
|
||||||
|
bounds.mins.z = bomboriginV3.z - 8.0f;
|
||||||
|
bounds.maxs.x = bomboriginV3.x + 32.0f;
|
||||||
|
bounds.maxs.y = bomboriginV3.y + 32.0f;
|
||||||
|
bounds.maxs.z = bomboriginV3.z + 28.0f;
|
||||||
|
int entityModelIndex = entityModelList.size() + 1; // +1 as the first model is always the world model
|
||||||
|
entityModelList.push_back(bounds);
|
||||||
|
entityString.append("{\n");
|
||||||
|
entityString.append("\"classname\" \"trigger_multiple\"\n");
|
||||||
|
entityString.append("\"targetname\" \"sd_bomb_pickup_trig\"\n");
|
||||||
|
entityString.append("\"script_gameobjectname\" \"sd\"\n");
|
||||||
|
entityString.append(std::format("\"origin\" \"{}\"\n", bombOriginStr));
|
||||||
|
entityString.append(std::format("\"model\" \"*{}\"\n", entityModelIndex));
|
||||||
|
entityString.append("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// add A site bomb
|
||||||
|
{
|
||||||
|
std::string siteAPoint1Str = bombJs["sd_bombzone_a"]["point1"];
|
||||||
|
std::string siteAPoint2Str = bombJs["sd_bombzone_a"]["point2"];
|
||||||
|
vec3_t siteAPoint1V3 = CMUtil::convertStringToVec3(siteAPoint1Str);
|
||||||
|
vec3_t siteAPoint2V3 = CMUtil::convertStringToVec3(siteAPoint2Str);
|
||||||
|
entModelBounds bounds;
|
||||||
|
bounds.mins.x = siteAPoint1V3.x;
|
||||||
|
bounds.mins.y = siteAPoint1V3.y;
|
||||||
|
bounds.mins.z = siteAPoint1V3.z;
|
||||||
|
bounds.maxs.x = siteAPoint1V3.x;
|
||||||
|
bounds.maxs.y = siteAPoint1V3.y;
|
||||||
|
bounds.maxs.z = siteAPoint1V3.z;
|
||||||
|
CMUtil::calcNewBoundsWithPoint(&siteAPoint2V3, &bounds.mins, &bounds.mins);
|
||||||
|
int entityModelIndex = entityModelList.size() + 1; // +1 as the first model is always the world model
|
||||||
|
entityModelList.push_back(bounds);
|
||||||
|
|
||||||
|
vec3_t siteAOrigin = CMUtil::calcMiddleOfBounds(&bounds.mins, &bounds.mins);
|
||||||
|
std::string siteAOriginStr = CMUtil::convertVec3ToString(siteAOrigin);
|
||||||
|
|
||||||
|
entityString.append("{\n");
|
||||||
|
entityString.append("\"classname\" \"trigger_use_touch\"\n");
|
||||||
|
entityString.append("\"targetname\" \"bombzone\"\n");
|
||||||
|
entityString.append("\"script_gameobjectname\" \"bombzone\"\n");
|
||||||
|
entityString.append("\"script_bombmode_original\" \"1\"\n");
|
||||||
|
entityString.append("\"script_label\" \"_a\"\n");
|
||||||
|
entityString.append(std::format("\"origin\" \"{}\"\n", siteAOriginStr));
|
||||||
|
entityString.append(std::format("\"model\" \"*{}\"\n", entityModelIndex));
|
||||||
|
entityString.append("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// add B site bomb
|
||||||
|
{
|
||||||
|
std::string siteBPoint1Str = bombJs["sd_bombzone_b"]["point1"];
|
||||||
|
std::string siteBPoint2Str = bombJs["sd_bombzone_b"]["point2"];
|
||||||
|
vec3_t siteBPoint1V3 = CMUtil::convertStringToVec3(siteBPoint1Str);
|
||||||
|
vec3_t siteBPoint2V3 = CMUtil::convertStringToVec3(siteBPoint2Str);
|
||||||
|
entModelBounds bounds;
|
||||||
|
bounds.mins.x = siteBPoint1V3.x;
|
||||||
|
bounds.mins.y = siteBPoint1V3.y;
|
||||||
|
bounds.mins.z = siteBPoint1V3.z;
|
||||||
|
bounds.maxs.x = siteBPoint1V3.x;
|
||||||
|
bounds.maxs.y = siteBPoint1V3.y;
|
||||||
|
bounds.maxs.z = siteBPoint1V3.z;
|
||||||
|
CMUtil::calcNewBoundsWithPoint(&siteBPoint2V3, &bounds.mins, &bounds.mins);
|
||||||
|
int entityModelIndex = entityModelList.size() + 1; // +1 as the first model is always the world model
|
||||||
|
entityModelList.push_back(bounds);
|
||||||
|
|
||||||
|
vec3_t siteAOrigin = CMUtil::calcMiddleOfBounds(&bounds.mins, &bounds.mins);
|
||||||
|
std::string siteAOriginStr = CMUtil::convertVec3ToString(siteAOrigin);
|
||||||
|
|
||||||
|
entityString.append("{\n");
|
||||||
|
entityString.append("\"classname\" \"trigger_use_touch\"\n");
|
||||||
|
entityString.append("\"targetname\" \"bombzone\"\n");
|
||||||
|
entityString.append("\"script_gameobjectname\" \"bombzone\"\n");
|
||||||
|
entityString.append("\"script_bombmode_original\" \"1\"\n");
|
||||||
|
entityString.append("\"script_label\" \"_b\"\n");
|
||||||
|
entityString.append(std::format("\"origin\" \"{}\"\n", siteAOriginStr));
|
||||||
|
entityString.append(std::format("\"model\" \"*{}\"\n", entityModelIndex));
|
||||||
|
entityString.append("}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void createMapEnts(customMapInfo* projInfo)
|
||||||
|
{
|
||||||
|
MapEnts* mapEnts = new MapEnts;
|
||||||
|
|
||||||
|
mapEnts->name = _strdup(projInfo->bspName.c_str());
|
||||||
|
|
||||||
|
// don't need these
|
||||||
|
mapEnts->trigger.count = 0;
|
||||||
|
mapEnts->trigger.models = NULL;
|
||||||
|
mapEnts->trigger.hullCount = 0;
|
||||||
|
mapEnts->trigger.hulls = NULL;
|
||||||
|
mapEnts->trigger.slabCount = 0;
|
||||||
|
mapEnts->trigger.slabs = NULL;
|
||||||
|
|
||||||
|
std::string entityString;
|
||||||
|
|
||||||
|
const auto entFile = m_search_path.Open("entities.json");
|
||||||
|
if (!entFile.IsOpen())
|
||||||
|
{
|
||||||
|
printf("ERROR: can't find entity json!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
json entJs = json::parse(*entFile.m_stream);
|
||||||
|
parseMapEntsJSON(entJs["entities"], entityString);
|
||||||
|
|
||||||
|
const auto spawnFile = m_search_path.Open("spawns.json");
|
||||||
|
json spawnJs;
|
||||||
|
if (!spawnFile.IsOpen())
|
||||||
|
{
|
||||||
|
printf("WARN: no spawn points given, setting spawns to 0 0 0\n");
|
||||||
|
spawnJs = json::parse(defaultSpawnpointString);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
spawnJs = json::parse(*spawnFile.m_stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
parseSpawnpointJSON(spawnJs["attackers"], entityString, spawnpointDefenderTypeArray);
|
||||||
|
parseSpawnpointJSON(spawnJs["defenders"], entityString, spawnpointAttackerTypeArray);
|
||||||
|
parseSpawnpointJSON(spawnJs["FFA"], entityString, spawnpointFFATypeArray);
|
||||||
|
|
||||||
|
//const auto objectiveFile = m_search_path.Open("objectives.json");
|
||||||
|
//if (!spawnFile.IsOpen())
|
||||||
|
//{
|
||||||
|
// printf("WARN: no objectives given\n");
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
// json objectiveJs = json::parse(*objectiveFile.m_stream);
|
||||||
|
// parseBombJSON(objectiveJs, entityString);
|
||||||
|
//}
|
||||||
|
|
||||||
mapEnts->entityString = _strdup(entityString.c_str());
|
mapEnts->entityString = _strdup(entityString.c_str());
|
||||||
mapEnts->numEntityChars = entityString.length() + 1; // numEntityChars includes the null character
|
mapEnts->numEntityChars = entityString.length() + 1; // numEntityChars includes the null character
|
||||||
@@ -1668,42 +1900,42 @@ private:
|
|||||||
|
|
||||||
void checkAndAddDefaultRequiredAssets(customMapInfo* projectInfo)
|
void checkAndAddDefaultRequiredAssets(customMapInfo* projectInfo)
|
||||||
{
|
{
|
||||||
if (m_context.LoadDependency<AssetScript>("maps/mp/mod.gsc") == NULL)
|
auto templateFile = m_search_path.Open("materials/material_template.json");
|
||||||
|
if (!templateFile.IsOpen())
|
||||||
|
{
|
||||||
|
printf("ERROR: failed to open materials/material_template.json\n");
|
||||||
|
hasLinkFailed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
materialTemplateJson = json::parse(*templateFile.m_stream);
|
||||||
|
|
||||||
|
if (m_context.LoadDependency<AssetScript>("maps/mp/" + projectInfo->name + ".gsc") == NULL)
|
||||||
{
|
{
|
||||||
hasLinkFailed = true;
|
hasLinkFailed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_context.LoadDependency<AssetScript>("maps/mp/mod_amb.gsc") == NULL)
|
if (m_context.LoadDependency<AssetScript>("maps/mp/" + projectInfo->name + "_amb.gsc") == NULL)
|
||||||
{
|
{
|
||||||
hasLinkFailed = true;
|
hasLinkFailed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_context.LoadDependency<AssetScript>("maps/mp/mod_fx.gsc") == NULL)
|
if (m_context.LoadDependency<AssetScript>("maps/mp/" + projectInfo->name + "_fx.gsc") == NULL)
|
||||||
{
|
{
|
||||||
hasLinkFailed = true;
|
hasLinkFailed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_context.LoadDependency<AssetScript>("maps/mp/createfx/mod_fx.gsc") == NULL)
|
|
||||||
|
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/" + projectInfo->name + ".csc") == NULL)
|
||||||
{
|
{
|
||||||
hasLinkFailed = true;
|
hasLinkFailed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/mod.csc") == NULL)
|
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/" + projectInfo->name + "_amb.csc") == NULL)
|
||||||
{
|
{
|
||||||
hasLinkFailed = true;
|
hasLinkFailed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/mod_amb.csc") == NULL)
|
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/" + projectInfo->name + "_fx.csc") == NULL)
|
||||||
{
|
|
||||||
hasLinkFailed = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/mod_fx.csc") == NULL)
|
|
||||||
{
|
|
||||||
hasLinkFailed = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (m_context.LoadDependency<AssetScript>("clientscripts/mp/createfx/mod_fx.csc") == NULL)
|
|
||||||
{
|
{
|
||||||
hasLinkFailed = true;
|
hasLinkFailed = true;
|
||||||
return;
|
return;
|
||||||
@@ -1715,5 +1947,11 @@ private:
|
|||||||
addEmptyFootstepTableAsset("default_3rd_person_quiet");
|
addEmptyFootstepTableAsset("default_3rd_person_quiet");
|
||||||
addEmptyFootstepTableAsset("default_3rd_person_loud");
|
addEmptyFootstepTableAsset("default_3rd_person_loud");
|
||||||
addEmptyFootstepTableAsset("default_ai");
|
addEmptyFootstepTableAsset("default_ai");
|
||||||
|
|
||||||
|
if (m_context.LoadDependency<AssetRawFile>("animtrees/fxanim_props.atr") == NULL)
|
||||||
|
{
|
||||||
|
hasLinkFailed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ bool loadFBXMesh(ufbx_node* node)
|
|||||||
ufbx_mesh* mesh = node->mesh;
|
ufbx_mesh* mesh = node->mesh;
|
||||||
|
|
||||||
if (mesh->instances.count != 1)
|
if (mesh->instances.count != 1)
|
||||||
printf("node %s has %i instances, only the 1st instace will be used.\n", node->name.data, mesh->instances.count);
|
printf("mesh %s has %i instances, only the 1st instace will be used.\n", node->name.data, mesh->instances.count);
|
||||||
|
|
||||||
if (mesh->num_triangles == 0)
|
if (mesh->num_triangles == 0)
|
||||||
{
|
{
|
||||||
@@ -41,12 +41,6 @@ bool loadFBXMesh(ufbx_node* node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ASSERT(mesh->vertex_position.unique_per_vertex == true);
|
|
||||||
_ASSERT(mesh->vertex_color.unique_per_vertex == false);
|
|
||||||
_ASSERT(mesh->vertex_uv.unique_per_vertex == false);
|
|
||||||
_ASSERT(mesh->vertex_normal.unique_per_vertex == false);
|
|
||||||
_ASSERT(mesh->vertex_tangent.unique_per_vertex == false);
|
|
||||||
|
|
||||||
if (mesh->vertex_tangent.exists == false)
|
if (mesh->vertex_tangent.exists == false)
|
||||||
hasTangentSpace = false;
|
hasTangentSpace = false;
|
||||||
|
|
||||||
@@ -60,29 +54,9 @@ bool loadFBXMesh(ufbx_node* node)
|
|||||||
origTransform.scale.z /= 100.0f;
|
origTransform.scale.z /= 100.0f;
|
||||||
ufbx_matrix meshMatrix = ufbx_transform_to_matrix(&origTransform);
|
ufbx_matrix meshMatrix = ufbx_transform_to_matrix(&origTransform);
|
||||||
|
|
||||||
CM_MATERIAL_TYPE meshMaterialType;
|
|
||||||
if (mesh->materials.count == 0)
|
|
||||||
{
|
|
||||||
if (!mesh->vertex_color.exists)
|
|
||||||
{
|
|
||||||
printf("mesh with no colour/texture data: %s\n", node->name.data);
|
|
||||||
meshMaterialType = NO_COLOUR_OR_TEXTURE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("colour only mesh %s\n", node->name.data);
|
|
||||||
meshMaterialType = CM_MATERIAL_COLOUR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
meshMaterialType = CM_MATERIAL_TEXTURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// FBX loading code modified from https://ufbx.github.io/elements/meshes/
|
// FBX loading code modified from https://ufbx.github.io/elements/meshes/
|
||||||
// Seems like I have to use this exact way of loading, otherwise some values become incorrect
|
// Seems like I have to use this exact way of loading, otherwise some values become incorrect
|
||||||
for (int i = 0; i < mesh->material_parts.count; i++)
|
for (size_t i = 0; i < mesh->material_parts.count; i++)
|
||||||
{
|
{
|
||||||
ufbx_mesh_part* meshPart = &mesh->material_parts.data[i];
|
ufbx_mesh_part* meshPart = &mesh->material_parts.data[i];
|
||||||
|
|
||||||
@@ -90,26 +64,31 @@ bool loadFBXMesh(ufbx_node* node)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
worldSurface surface;
|
worldSurface surface;
|
||||||
surface.flags = 0;
|
|
||||||
surface.triCount = meshPart->num_triangles;
|
surface.triCount = meshPart->num_triangles;
|
||||||
surface.firstVertexIndex = vertexVec.size();
|
surface.firstVertexIndex = vertexVec.size();
|
||||||
surface.firstIndex_Index = indexVec.size();
|
surface.firstIndex_Index = indexVec.size();
|
||||||
|
|
||||||
surface.material.materialType = meshMaterialType;
|
CM_MATERIAL_TYPE meshMaterialType;
|
||||||
switch (meshMaterialType)
|
if (mesh->materials.count == 0)
|
||||||
{
|
{
|
||||||
case CM_MATERIAL_TEXTURE:
|
meshMaterialType = CM_MATERIAL_EMPTY;
|
||||||
surface.material.materialName = _strdup(mesh->materials.data[i]->name.data);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CM_MATERIAL_COLOUR:
|
|
||||||
case NO_COLOUR_OR_TEXTURE:
|
|
||||||
surface.material.materialName = "";
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
_ASSERT(false);
|
|
||||||
}
|
}
|
||||||
|
//else if (mesh->materials.data[i]->textures.count != 0)
|
||||||
|
//{
|
||||||
|
// meshMaterialType = CM_MATERIAL_TEXTURE;
|
||||||
|
// surface.material.materialName = _strdup(mesh->materials.data[i]->name.data);
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
// meshMaterialType = CM_MATERIAL_COLOUR;
|
||||||
|
// surface.material.materialName = "";
|
||||||
|
//}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
meshMaterialType = CM_MATERIAL_TEXTURE;
|
||||||
|
surface.material.materialName = _strdup(mesh->materials.data[i]->name.data);
|
||||||
|
}
|
||||||
|
surface.material.materialType = meshMaterialType;
|
||||||
|
|
||||||
size_t num_triangles = meshPart->num_triangles;
|
size_t num_triangles = meshPart->num_triangles;
|
||||||
customMapVertex* vertices = (customMapVertex*)calloc(num_triangles * 3, sizeof(customMapVertex));
|
customMapVertex* vertices = (customMapVertex*)calloc(num_triangles * 3, sizeof(customMapVertex));
|
||||||
@@ -135,47 +114,50 @@ bool loadFBXMesh(ufbx_node* node)
|
|||||||
customMapVertex* vertex = &vertices[num_vertices++];
|
customMapVertex* vertex = &vertices[num_vertices++];
|
||||||
|
|
||||||
ufbx_vec3 transformedPos = ufbx_transform_position(&meshMatrix, ufbx_get_vertex_vec3(&mesh->vertex_position, index));
|
ufbx_vec3 transformedPos = ufbx_transform_position(&meshMatrix, ufbx_get_vertex_vec3(&mesh->vertex_position, index));
|
||||||
vertex->pos.x = transformedPos.x;
|
vertex->pos.x = static_cast<float>(transformedPos.x);
|
||||||
vertex->pos.y = transformedPos.y;
|
vertex->pos.y = static_cast<float>(transformedPos.y);
|
||||||
vertex->pos.z = transformedPos.z;
|
vertex->pos.z = static_cast<float>(transformedPos.z);
|
||||||
|
|
||||||
|
|
||||||
// textured and missing materials are set to white
|
|
||||||
switch (meshMaterialType)
|
switch (meshMaterialType)
|
||||||
{
|
{
|
||||||
case CM_MATERIAL_TEXTURE:
|
case CM_MATERIAL_TEXTURE:
|
||||||
case NO_COLOUR_OR_TEXTURE:
|
case CM_MATERIAL_EMPTY:
|
||||||
vertex->color[0] = 1.0f;
|
vertex->color[0] = 1.0f;
|
||||||
vertex->color[1] = 1.0f;
|
vertex->color[1] = 1.0f;
|
||||||
vertex->color[2] = 1.0f;
|
vertex->color[2] = 1.0f;
|
||||||
vertex->color[3] = 1.0f;
|
vertex->color[3] = 1.0f;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CM_MATERIAL_COLOUR:
|
case CM_MATERIAL_COLOUR:
|
||||||
vertex->color[0] = ufbx_get_vertex_vec4(&mesh->vertex_color, index).x;
|
{
|
||||||
vertex->color[1] = ufbx_get_vertex_vec4(&mesh->vertex_color, index).y;
|
float factor = static_cast<float>(mesh->materials.data[i]->fbx.diffuse_factor.value_real);
|
||||||
vertex->color[2] = ufbx_get_vertex_vec4(&mesh->vertex_color, index).z;
|
vertex->color[0] = static_cast<float>(mesh->materials.data[i]->fbx.diffuse_color.value_vec3.x * factor);
|
||||||
vertex->color[3] = ufbx_get_vertex_vec4(&mesh->vertex_color, index).w;
|
vertex->color[1] = static_cast<float>(mesh->materials.data[i]->fbx.diffuse_color.value_vec3.y * factor);
|
||||||
|
vertex->color[2] = static_cast<float>(mesh->materials.data[i]->fbx.diffuse_color.value_vec3.z * factor);
|
||||||
|
vertex->color[3] = static_cast<float>(mesh->materials.data[i]->fbx.diffuse_color.value_vec4.w * factor);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_ASSERT(false);
|
_ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 1.0f - uv.v:
|
// 1.0f - uv.v:
|
||||||
// https://gamedev.stackexchange.com/questions/92886/fbx-uv-coordinates-is-strange
|
// https://gamedev.stackexchange.com/questions/92886/fbx-uv-coordinates-is-strange
|
||||||
vertex->texCoord[0] = (float)(ufbx_get_vertex_vec2(&mesh->vertex_uv, index).x);
|
vertex->texCoord[0] = (float)(ufbx_get_vertex_vec2(&mesh->vertex_uv, index).x);
|
||||||
vertex->texCoord[1] = (float)(1.0f - ufbx_get_vertex_vec2(&mesh->vertex_uv, index).y);
|
vertex->texCoord[1] = (float)(1.0f - ufbx_get_vertex_vec2(&mesh->vertex_uv, index).y);
|
||||||
|
|
||||||
vertex->normal.x = ufbx_get_vertex_vec3(&mesh->vertex_normal, index).x;
|
vertex->normal.x = static_cast<float>(ufbx_get_vertex_vec3(&mesh->vertex_normal, index).x);
|
||||||
vertex->normal.y = ufbx_get_vertex_vec3(&mesh->vertex_normal, index).y;
|
vertex->normal.y = static_cast<float>(ufbx_get_vertex_vec3(&mesh->vertex_normal, index).y);
|
||||||
vertex->normal.z = ufbx_get_vertex_vec3(&mesh->vertex_normal, index).z;
|
vertex->normal.z = static_cast<float>(ufbx_get_vertex_vec3(&mesh->vertex_normal, index).z);
|
||||||
|
|
||||||
if (mesh->vertex_tangent.exists)
|
if (mesh->vertex_tangent.exists)
|
||||||
{
|
{
|
||||||
vertex->tangent.x = ufbx_get_vertex_vec3(&mesh->vertex_tangent, index).x;
|
vertex->tangent.x = static_cast<float>(ufbx_get_vertex_vec3(&mesh->vertex_tangent, index).x);
|
||||||
vertex->tangent.y = ufbx_get_vertex_vec3(&mesh->vertex_tangent, index).y;
|
vertex->tangent.y = static_cast<float>(ufbx_get_vertex_vec3(&mesh->vertex_tangent, index).y);
|
||||||
vertex->tangent.z = ufbx_get_vertex_vec3(&mesh->vertex_tangent, index).z;
|
vertex->tangent.z = static_cast<float>(ufbx_get_vertex_vec3(&mesh->vertex_tangent, index).z);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -235,13 +217,13 @@ bool loadFBXModel(ufbx_node* node)
|
|||||||
origTransform.scale.z /= 100.0f;
|
origTransform.scale.z /= 100.0f;
|
||||||
ufbx_matrix meshMatrix = ufbx_transform_to_matrix(&origTransform);
|
ufbx_matrix meshMatrix = ufbx_transform_to_matrix(&origTransform);
|
||||||
|
|
||||||
model.origin.x = node->local_transform.translation.x / 100.0f;
|
model.origin.x = static_cast<float>(node->local_transform.translation.x) / 100.0f;
|
||||||
model.origin.y = node->local_transform.translation.y / 100.0f;
|
model.origin.y = static_cast<float>(node->local_transform.translation.y) / 100.0f;
|
||||||
model.origin.z = node->local_transform.translation.z / 100.0f;
|
model.origin.z = static_cast<float>(node->local_transform.translation.z) / 100.0f;
|
||||||
model.rotation.x = node->euler_rotation.x;
|
model.rotation.x = static_cast<float>(node->euler_rotation.x);
|
||||||
model.rotation.y = node->euler_rotation.y;
|
model.rotation.y = static_cast<float>(node->euler_rotation.y);
|
||||||
model.rotation.z = node->euler_rotation.z;
|
model.rotation.z = static_cast<float>(node->euler_rotation.z);
|
||||||
model.scale = node->local_transform.scale.x / 100.0f;
|
model.scale = static_cast<float>(node->local_transform.scale.x) / 100.0f;
|
||||||
|
|
||||||
if (model.scale == 0.0f)
|
if (model.scale == 0.0f)
|
||||||
{
|
{
|
||||||
@@ -277,7 +259,7 @@ void parseGFXData(ufbx_scene* scene, customMapInfo* projInfo)
|
|||||||
// loadFBXModel(node);
|
// loadFBXModel(node);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("ignoring node type %i: %s\n", node->attrib_type, node->name.data);
|
//printf("ignoring node type %i: %s\n", node->attrib_type, node->name.data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,7 +303,7 @@ void parseCollisionData(ufbx_scene* scene, customMapInfo* projInfo)
|
|||||||
// loadFBXModel(node);
|
// loadFBXModel(node);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("ignoring node type %i: %s\n", node->attrib_type, node->name.data);
|
//printf("ignoring node type %i: %s\n", node->attrib_type, node->name.data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -355,7 +337,7 @@ customMapInfo* CustomMapInfo::createCustomMapInfo(std::string& projectName, ISea
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* gfxMapData = new char[gfxFile.m_length];
|
char* gfxMapData = new char[static_cast<unsigned int>(gfxFile.m_length)];
|
||||||
gfxFile.m_stream->seekg(0);
|
gfxFile.m_stream->seekg(0);
|
||||||
gfxFile.m_stream->read(gfxMapData, gfxFile.m_length);
|
gfxFile.m_stream->read(gfxMapData, gfxFile.m_length);
|
||||||
|
|
||||||
@@ -364,7 +346,7 @@ customMapInfo* CustomMapInfo::createCustomMapInfo(std::string& projectName, ISea
|
|||||||
opts.target_axes = ufbx_axes_right_handed_y_up;
|
opts.target_axes = ufbx_axes_right_handed_y_up;
|
||||||
opts.generate_missing_normals = true;
|
opts.generate_missing_normals = true;
|
||||||
opts.allow_missing_vertex_position = false;
|
opts.allow_missing_vertex_position = false;
|
||||||
gfxScene = ufbx_load_memory(gfxMapData, gfxFile.m_length, NULL, &error);
|
gfxScene = ufbx_load_memory(gfxMapData, static_cast<size_t>(gfxFile.m_length), NULL, &error);
|
||||||
if (!gfxScene)
|
if (!gfxScene)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Failed to load map gfx fbx file: %s\n", error.description.data);
|
fprintf(stderr, "Failed to load map gfx fbx file: %s\n", error.description.data);
|
||||||
@@ -380,7 +362,7 @@ customMapInfo* CustomMapInfo::createCustomMapInfo(std::string& projectName, ISea
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char* colMapData = new char[colFile.m_length];
|
char* colMapData = new char[static_cast<unsigned int>(colFile.m_length)];
|
||||||
colFile.m_stream->seekg(0);
|
colFile.m_stream->seekg(0);
|
||||||
colFile.m_stream->read(colMapData, colFile.m_length);
|
colFile.m_stream->read(colMapData, colFile.m_length);
|
||||||
|
|
||||||
@@ -389,7 +371,7 @@ customMapInfo* CustomMapInfo::createCustomMapInfo(std::string& projectName, ISea
|
|||||||
opts.target_axes = ufbx_axes_right_handed_y_up;
|
opts.target_axes = ufbx_axes_right_handed_y_up;
|
||||||
opts.generate_missing_normals = true;
|
opts.generate_missing_normals = true;
|
||||||
opts.allow_missing_vertex_position = false;
|
opts.allow_missing_vertex_position = false;
|
||||||
colScene = ufbx_load_memory(colMapData, colFile.m_length, NULL, &error);
|
colScene = ufbx_load_memory(colMapData, static_cast<size_t>(colFile.m_length), NULL, &error);
|
||||||
if (!colScene)
|
if (!colScene)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Failed to load map collision fbx file: %s\n", error.description.data);
|
fprintf(stderr, "Failed to load map collision fbx file: %s\n", error.description.data);
|
||||||
|
|||||||
@@ -70,6 +70,19 @@ public:
|
|||||||
currmaxs->z = point->z;
|
currmaxs->z = point->z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static vec3_t calcMiddleOfBounds(vec3_t* mins, vec3_t* maxs)
|
||||||
|
{
|
||||||
|
// Origin is the midpoint: (min + max) / 2
|
||||||
|
vec3_t temp;
|
||||||
|
temp.x = mins->x + maxs->x;
|
||||||
|
temp.y = mins->y + maxs->y;
|
||||||
|
temp.z = mins->z + maxs->z;
|
||||||
|
temp.x *= 0.5f;
|
||||||
|
temp.y *= 0.5f;
|
||||||
|
temp.z *= 0.5f;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
static int allignBy128(int size)
|
static int allignBy128(int size)
|
||||||
{
|
{
|
||||||
return ((size + 127) & 0xFFFFFF80);
|
return ((size + 127) & 0xFFFFFF80);
|
||||||
@@ -86,9 +99,9 @@ public:
|
|||||||
// angles are in euler degrees
|
// angles are in euler degrees
|
||||||
static void convertAnglesToAxis(vec3_t* angles, vec3_t* axis)
|
static void convertAnglesToAxis(vec3_t* angles, vec3_t* axis)
|
||||||
{
|
{
|
||||||
float xRadians = angles->x * 0.017453292; // M_PI / 180.0f
|
float xRadians = angles->x * 0.017453292f; // M_PI / 180.0f
|
||||||
float yRadians = angles->y * 0.017453292; // M_PI / 180.0f
|
float yRadians = angles->y * 0.017453292f; // M_PI / 180.0f
|
||||||
float zRadians = angles->z * 0.017453292; // M_PI / 180.0f
|
float zRadians = angles->z * 0.017453292f; // M_PI / 180.0f
|
||||||
|
|
||||||
float cosX = cos(xRadians);
|
float cosX = cos(xRadians);
|
||||||
float sinX = sin(xRadians);
|
float sinX = sin(xRadians);
|
||||||
@@ -120,4 +133,33 @@ public:
|
|||||||
out[2].y = in[1].z;
|
out[2].y = in[1].z;
|
||||||
out[2].z = in[2].z;
|
out[2].z = in[2].z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static vec3_t convertStringToVec3(std::string str)
|
||||||
|
{
|
||||||
|
std::string v1Str = str;
|
||||||
|
|
||||||
|
int nextValIndex = 0;
|
||||||
|
while (v1Str[nextValIndex] != ' ')
|
||||||
|
nextValIndex++;
|
||||||
|
nextValIndex++; // skip past space
|
||||||
|
std::string v2Str = &v1Str[nextValIndex];
|
||||||
|
|
||||||
|
nextValIndex = 0;
|
||||||
|
while (v2Str[nextValIndex] != ' ')
|
||||||
|
nextValIndex++;
|
||||||
|
nextValIndex++; // skip past space
|
||||||
|
std::string v3Str = &v2Str[nextValIndex];
|
||||||
|
|
||||||
|
vec3_t result;
|
||||||
|
result.x = static_cast<float>(atof(v1Str.c_str()));
|
||||||
|
result.y = static_cast<float>(atof(v2Str.c_str()));
|
||||||
|
result.z = static_cast<float>(atof(v3Str.c_str()));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string convertVec3ToString(vec3_t vec)
|
||||||
|
{
|
||||||
|
std::string result = std::format("{} {} {}", vec.x, vec.y, vec.z);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "ScriptCompileT6.h"
|
||||||
|
|
||||||
using namespace T6;
|
using namespace T6;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@@ -17,23 +19,40 @@ namespace
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const unsigned char T6GSCMagic[8] = {0x80, 0x47, 0x53, 0x43, 0x0D, 0x0A, 0x00, 0x06 };
|
||||||
|
|
||||||
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
||||||
{
|
{
|
||||||
const auto file = m_search_path.Open(assetName);
|
const auto file = m_search_path.Open(assetName);
|
||||||
if (!file.IsOpen())
|
if (!file.IsOpen())
|
||||||
return AssetCreationResult::NoAction();
|
return AssetCreationResult::NoAction();
|
||||||
|
|
||||||
auto* scriptParseTree = m_memory.Alloc<ScriptParseTree>();
|
|
||||||
scriptParseTree->name = m_memory.Dup(assetName.c_str());
|
|
||||||
scriptParseTree->len = static_cast<int>(file.m_length);
|
|
||||||
|
|
||||||
auto* fileBuffer = m_memory.Alloc<char>(static_cast<size_t>(file.m_length + 1));
|
auto* fileBuffer = m_memory.Alloc<char>(static_cast<size_t>(file.m_length + 1));
|
||||||
file.m_stream->read(fileBuffer, file.m_length);
|
file.m_stream->read(fileBuffer, file.m_length);
|
||||||
if (file.m_stream->gcount() != file.m_length)
|
if (file.m_stream->gcount() != file.m_length || file.m_length < 0x10)
|
||||||
return AssetCreationResult::Failure();
|
return AssetCreationResult::Failure();
|
||||||
fileBuffer[scriptParseTree->len] = '\0';
|
fileBuffer[file.m_length] = '\0';
|
||||||
|
|
||||||
|
auto* scriptParseTree = m_memory.Alloc<ScriptParseTree>();
|
||||||
|
scriptParseTree->name = m_memory.Dup(assetName.c_str());
|
||||||
|
|
||||||
|
if (memcmp(fileBuffer, T6GSCMagic, 8) == 0)
|
||||||
|
{
|
||||||
|
scriptParseTree->len = static_cast<int>(file.m_length);
|
||||||
scriptParseTree->buffer = static_cast<char16*>(fileBuffer);
|
scriptParseTree->buffer = static_cast<char16*>(fileBuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t compiledSize;
|
||||||
|
char* result = compileScriptT6(assetName, fileBuffer, static_cast<size_t>(file.m_length), &compiledSize);
|
||||||
|
if (result == NULL)
|
||||||
|
return AssetCreationResult::Failure();
|
||||||
|
|
||||||
|
scriptParseTree->buffer = result;
|
||||||
|
scriptParseTree->len = static_cast<int>(compiledSize);
|
||||||
|
}
|
||||||
|
|
||||||
return AssetCreationResult::Success(context.AddAsset<AssetScript>(assetName, scriptParseTree));
|
return AssetCreationResult::Success(context.AddAsset<AssetScript>(assetName, scriptParseTree));
|
||||||
}
|
}
|
||||||
|
|||||||
31
src/ObjLoading/Game/T6/Script/ScriptCompileT6.cpp
Normal file
31
src/ObjLoading/Game/T6/Script/ScriptCompileT6.cpp
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#include "ScriptCompileT6.h"
|
||||||
|
|
||||||
|
#include <xsk/arc/engine/t6_pc.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
char* compileScriptT6(const std::string& gscName, char* gscCode, size_t gscCodeSize, size_t* out_CompiledSize)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
xsk::arc::t6::pc::context context = xsk::arc::t6::pc::context(xsk::arc::instance::server);
|
||||||
|
|
||||||
|
std::vector<xsk::u8> scriptBuffer;
|
||||||
|
scriptBuffer.resize(gscCodeSize);
|
||||||
|
memcpy(&scriptBuffer[0], gscCode, gscCodeSize);
|
||||||
|
|
||||||
|
auto outasm = context.compiler().compile(gscName, scriptBuffer);
|
||||||
|
auto outbin = context.assembler().assemble(*outasm);
|
||||||
|
|
||||||
|
char* compiledBuffer = new char[outbin.first.size];
|
||||||
|
memcpy(compiledBuffer, outbin.first.data, outbin.first.size);
|
||||||
|
|
||||||
|
*out_CompiledSize = outbin.first.size;
|
||||||
|
return compiledBuffer;
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (std::exception const& e)
|
||||||
|
{
|
||||||
|
printf(std::format("GSC Compile failed: {}\n", e.what()).c_str());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/ObjLoading/Game/T6/Script/ScriptCompileT6.h
Normal file
3
src/ObjLoading/Game/T6/Script/ScriptCompileT6.h
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#include <string>
|
||||||
|
|
||||||
|
char* compileScriptT6(const std::string& gscName, char* gscCode, size_t gscCodeSize, size_t* out_CompiledSize);
|
||||||
@@ -112,6 +112,7 @@ namespace
|
|||||||
{
|
{
|
||||||
currPass->vertexDecl->routing.data[i].source = (unsigned char)passJs["vertexDecl"]["routing"][i]["source"];
|
currPass->vertexDecl->routing.data[i].source = (unsigned char)passJs["vertexDecl"]["routing"][i]["source"];
|
||||||
currPass->vertexDecl->routing.data[i].dest = (unsigned char)passJs["vertexDecl"]["routing"][i]["dest"];
|
currPass->vertexDecl->routing.data[i].dest = (unsigned char)passJs["vertexDecl"]["routing"][i]["dest"];
|
||||||
|
currPass->vertexDecl->routing.decl[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
constexpr auto METADATA_CUSTOM_MAP = "custom_map";
|
||||||
|
|
||||||
constexpr auto METADATA_GAME = "game";
|
constexpr auto METADATA_GAME = "game";
|
||||||
constexpr auto METADATA_GDT = "gdt";
|
constexpr auto METADATA_GDT = "gdt";
|
||||||
constexpr auto METADATA_NAME = "name";
|
constexpr auto METADATA_NAME = "name";
|
||||||
@@ -133,6 +135,10 @@ void SequenceZoneDefinitionMetaData::ProcessMatch(ZoneDefinitionParserState* sta
|
|||||||
{
|
{
|
||||||
ProcessMetaDataGame(state, valueToken, value);
|
ProcessMetaDataGame(state, valueToken, value);
|
||||||
}
|
}
|
||||||
|
else if (key == METADATA_CUSTOM_MAP)
|
||||||
|
{
|
||||||
|
state->SetCustomMap();
|
||||||
|
}
|
||||||
else if (key == METADATA_GDT)
|
else if (key == METADATA_GDT)
|
||||||
{
|
{
|
||||||
state->m_definition->m_gdts.emplace_back(value);
|
state->m_definition->m_gdts.emplace_back(value);
|
||||||
|
|||||||
@@ -19,6 +19,27 @@ void ZoneDefinitionParserState::SetGame(const GameId game)
|
|||||||
m_asset_name_resolver = IAssetNameResolver::GetResolverForGame(game);
|
m_asset_name_resolver = IAssetNameResolver::GetResolverForGame(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ZoneDefinitionParserState::SetCustomMap()
|
||||||
|
{
|
||||||
|
if (m_definition->is_custom_map == false)
|
||||||
|
{
|
||||||
|
m_definition->is_custom_map = true;
|
||||||
|
if (m_definition->m_game != GameId::T6)
|
||||||
|
{
|
||||||
|
printf("ERROR: Custom map linking is only supported on BO2 (T6).\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Processing zone as a custom map zone.\n");
|
||||||
|
const auto gfxWorldAssetType = m_asset_name_resolver->GetAssetTypeByName("gfxworld");
|
||||||
|
_ASSERT(gfxWorldAssetType);
|
||||||
|
|
||||||
|
m_definition->m_assets.emplace_back(*gfxWorldAssetType, "gfxworld", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
void AddCurrentObjContainerToDefinitionIfNecessary(ZoneDefinition& zoneDefinition, std::optional<ZoneDefinitionObjContainer>& maybeObjContainer)
|
void AddCurrentObjContainerToDefinitionIfNecessary(ZoneDefinition& zoneDefinition, std::optional<ZoneDefinitionObjContainer>& maybeObjContainer)
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ public:
|
|||||||
|
|
||||||
void SetGame(GameId game);
|
void SetGame(GameId game);
|
||||||
|
|
||||||
|
void SetCustomMap();
|
||||||
|
|
||||||
void StartIPak(std::string ipakName);
|
void StartIPak(std::string ipakName);
|
||||||
void StartIwd(std::string iwdName);
|
void StartIwd(std::string iwdName);
|
||||||
|
|
||||||
|
|||||||
@@ -69,4 +69,6 @@ public:
|
|||||||
std::vector<std::string> m_gdts;
|
std::vector<std::string> m_gdts;
|
||||||
std::vector<ZoneDefinitionAsset> m_assets;
|
std::vector<ZoneDefinitionAsset> m_assets;
|
||||||
std::vector<ZoneDefinitionObjContainer> m_obj_containers;
|
std::vector<ZoneDefinitionObjContainer> m_obj_containers;
|
||||||
|
|
||||||
|
bool is_custom_map = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ namespace
|
|||||||
|
|
||||||
if (!m_algorithm->Verify(signatureData, signatureDataSize, signature, signatureSize))
|
if (!m_algorithm->Verify(signatureData, signatureDataSize, signature, signatureSize))
|
||||||
{
|
{
|
||||||
throw InvalidSignatureException();
|
//throw InvalidSignatureException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,17 +19,20 @@ void StepWriteZoneRSA::PerformStep(ZoneWriter* zoneWriter, IWritingStream* strea
|
|||||||
strncpy(fileName, m_zoneName.c_str(), 31);
|
strncpy(fileName, m_zoneName.c_str(), 31);
|
||||||
stream->Write(fileName, 32);
|
stream->Write(fileName, 32);
|
||||||
|
|
||||||
char data[256] = {0x75, 0xc2, 0xca, 0x61, 0x15, 0xef, 0xcb, 0xde, 0x42, 0xfc, 0xa8, 0xed, 0xb1, 0x77, 0x79, 0x93, 0x73, 0x28, 0x3e, 0x7f, 0xca,
|
//char data[256] = {0x75, 0xc2, 0xca, 0x61, 0x15, 0xef, 0xcb, 0xde, 0x42, 0xfc, 0xa8, 0xed, 0xb1, 0x77, 0x79, 0x93, 0x73, 0x28, 0x3e, 0x7f, 0xca,
|
||||||
0x76, 0x48, 0xc3, 0x21, 0x23, 0x86, 0xc3, 0x0f, 0xb6, 0xa6, 0xb5, 0xe9, 0xab, 0x40, 0x29, 0xb8, 0x3c, 0x03, 0xc4, 0xe0, 0x99, 0xed,
|
// 0x76, 0x48, 0xc3, 0x21, 0x23, 0x86, 0xc3, 0x0f, 0xb6, 0xa6, 0xb5, 0xe9, 0xab, 0x40, 0x29, 0xb8, 0x3c, 0x03, 0xc4, 0xe0, 0x99, 0xed,
|
||||||
0xf2, 0x96, 0xd7, 0xb3, 0x95, 0x0d, 0x2e, 0xdd, 0xf0, 0x08, 0x6d, 0x5a, 0x95, 0x0b, 0x61, 0xd9, 0xde, 0xb4, 0x9d, 0x8a, 0x1b, 0x19,
|
// 0xf2, 0x96, 0xd7, 0xb3, 0x95, 0x0d, 0x2e, 0xdd, 0xf0, 0x08, 0x6d, 0x5a, 0x95, 0x0b, 0x61, 0xd9, 0xde, 0xb4, 0x9d, 0x8a, 0x1b, 0x19,
|
||||||
0xa8, 0x88, 0xb4, 0x35, 0xe8, 0x25, 0x78, 0x21, 0x04, 0xbf, 0x36, 0x13, 0x9b, 0xf6, 0x10, 0x12, 0x8a, 0x08, 0x98, 0xf0, 0xb5, 0xdc,
|
// 0xa8, 0x88, 0xb4, 0x35, 0xe8, 0x25, 0x78, 0x21, 0x04, 0xbf, 0x36, 0x13, 0x9b, 0xf6, 0x10, 0x12, 0x8a, 0x08, 0x98, 0xf0, 0xb5, 0xdc,
|
||||||
0x8c, 0xd6, 0x37, 0x6d, 0x9a, 0xd8, 0xe4, 0x62, 0x5d, 0x02, 0xc1, 0xf6, 0xf1, 0xa1, 0x95, 0x93, 0x42, 0xee, 0xc2, 0x1a, 0xd9, 0xf0,
|
// 0x8c, 0xd6, 0x37, 0x6d, 0x9a, 0xd8, 0xe4, 0x62, 0x5d, 0x02, 0xc1, 0xf6, 0xf1, 0xa1, 0x95, 0x93, 0x42, 0xee, 0xc2, 0x1a, 0xd9, 0xf0,
|
||||||
0x36, 0x36, 0x23, 0x50, 0x8b, 0x11, 0x90, 0x6a, 0xa1, 0x8d, 0xf6, 0xd0, 0xe4, 0xb5, 0x0f, 0xfd, 0x87, 0x2f, 0x46, 0xb9, 0x08, 0x3e,
|
// 0x36, 0x36, 0x23, 0x50, 0x8b, 0x11, 0x90, 0x6a, 0xa1, 0x8d, 0xf6, 0xd0, 0xe4, 0xb5, 0x0f, 0xfd, 0x87, 0x2f, 0x46, 0xb9, 0x08, 0x3e,
|
||||||
0x38, 0xf9, 0x81, 0xaa, 0x39, 0x2b, 0xf7, 0x44, 0x44, 0x75, 0x0e, 0x8a, 0x09, 0x6c, 0x6f, 0x6e, 0xea, 0xd0, 0x32, 0x62, 0xfd, 0x98,
|
// 0x38, 0xf9, 0x81, 0xaa, 0x39, 0x2b, 0xf7, 0x44, 0x44, 0x75, 0x0e, 0x8a, 0x09, 0x6c, 0x6f, 0x6e, 0xea, 0xd0, 0x32, 0x62, 0xfd, 0x98,
|
||||||
0x65, 0xb5, 0xbd, 0xc0, 0xae, 0x63, 0xf1, 0xe9, 0x24, 0x03, 0xfc, 0x34, 0xed, 0xb6, 0xbf, 0x0e, 0xd2, 0x56, 0x43, 0xea, 0xde, 0xff,
|
// 0x65, 0xb5, 0xbd, 0xc0, 0xae, 0x63, 0xf1, 0xe9, 0x24, 0x03, 0xfc, 0x34, 0xed, 0xb6, 0xbf, 0x0e, 0xd2, 0x56, 0x43, 0xea, 0xde, 0xff,
|
||||||
0x51, 0xa8, 0xb1, 0x93, 0x47, 0xe3, 0xc3, 0xee, 0xc2, 0xa3, 0x0a, 0x93, 0x14, 0x8f, 0x98, 0x7c, 0xaf, 0x2d, 0xa2, 0x2c, 0x71, 0x23,
|
// 0x51, 0xa8, 0xb1, 0x93, 0x47, 0xe3, 0xc3, 0xee, 0xc2, 0xa3, 0x0a, 0x93, 0x14, 0x8f, 0x98, 0x7c, 0xaf, 0x2d, 0xa2, 0x2c, 0x71, 0x23,
|
||||||
0x60, 0x6a, 0x66, 0xd1, 0x6b, 0x55, 0xc0, 0x5d, 0x9b, 0xad, 0x18, 0xc5, 0xac, 0x2f, 0xa4, 0x00, 0xe8, 0xd0, 0xa6, 0xb4, 0x67, 0xa7,
|
// 0x60, 0x6a, 0x66, 0xd1, 0x6b, 0x55, 0xc0, 0x5d, 0x9b, 0xad, 0x18, 0xc5, 0xac, 0x2f, 0xa4, 0x00, 0xe8, 0xd0, 0xa6, 0xb4, 0x67, 0xa7,
|
||||||
0xbb, 0x7d, 0x4a, 0xbe, 0x02, 0xd0, 0xb6, 0xe0, 0xc6, 0xac, 0x1e, 0x59, 0x88, 0xcd, 0x26, 0x41, 0x73, 0x10, 0x65, 0x13, 0x79, 0x72,
|
// 0xbb, 0x7d, 0x4a, 0xbe, 0x02, 0xd0, 0xb6, 0xe0, 0xc6, 0xac, 0x1e, 0x59, 0x88, 0xcd, 0x26, 0x41, 0x73, 0x10, 0x65, 0x13, 0x79, 0x72,
|
||||||
0x5a, 0x26, 0x41, 0xe9, 0x89, 0x51, 0xc3, 0x79, 0x7d, 0x70, 0x3a, 0x5b, 0x94, 0x5d, 0xdd};
|
// 0x5a, 0x26, 0x41, 0xe9, 0x89, 0x51, 0xc3, 0x79, 0x7d, 0x70, 0x3a, 0x5b, 0x94, 0x5d, 0xdd};
|
||||||
|
|
||||||
|
char data[256];
|
||||||
|
memset(data, 0, 256);
|
||||||
stream->Write(data, 256);
|
stream->Write(data, 256);
|
||||||
}
|
}
|
||||||
|
|||||||
1
thirdparty/gsc-tool
vendored
Submodule
1
thirdparty/gsc-tool
vendored
Submodule
Submodule thirdparty/gsc-tool added at c9bd8e5c6a
Reference in New Issue
Block a user