Skip to content

Commit 125e5e6

Browse files
committed
Include elevated platform with entity collider creation.
Need to also update the body position when the raised platform gets deleted by a spell.
1 parent a8f4e99 commit 125e5e6

File tree

6 files changed

+50
-24
lines changed

6 files changed

+50
-24
lines changed

OpenTESArena/src/Entities/EntityChunkManager.cpp

+29-8
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ namespace
3737
VoxelDouble2 point;
3838
WorldDouble3 bboxMin, bboxMax; // Centered on the entity in model space
3939
double animMaxHeight;
40+
double feetY;
4041
char initialAnimStateIndex;
4142
bool isSensorCollider;
4243
std::optional<Double2> direction;
@@ -50,14 +51,15 @@ namespace
5051
{
5152
this->defID = -1;
5253
this->animMaxHeight = 0.0;
54+
this->feetY = 0.0;
5355
this->initialAnimStateIndex = -1;
5456
this->isSensorCollider = false;
5557
this->hasInventory = false;
5658
this->hasCreatureSound = false;
5759
}
5860
};
5961

60-
bool TryCreatePhysicsCollider(const CoordDouble2 &coord, double colliderHeight, double ceilingScale, bool isSensor, JPH::PhysicsSystem &physicsSystem, JPH::BodyID *outBodyID)
62+
bool TryCreatePhysicsCollider(const CoordDouble2 &coord, double colliderHeight, double feetY, bool isSensor, JPH::PhysicsSystem &physicsSystem, JPH::BodyID *outBodyID)
6163
{
6264
JPH::BodyInterface &bodyInterface = physicsSystem.GetBodyInterface();
6365

@@ -82,7 +84,7 @@ namespace
8284
const WorldDouble2 capsuleWorldPointXZ = VoxelUtils::coordToWorldPoint(coord); // @todo: use getEntityCorrectedY()
8385
const JPH::RVec3 capsuleJoltPos(
8486
static_cast<float>(capsuleWorldPointXZ.x),
85-
static_cast<float>(ceilingScale + capsuleHalfTotalHeight),
87+
static_cast<float>(feetY + capsuleHalfTotalHeight),
8688
static_cast<float>(capsuleWorldPointXZ.y));
8789
const JPH::Quat capsuleJoltQuat = JPH::Quat::sRotation(JPH::Vec3Arg::sAxisY(), 0.0f);
8890
const JPH::ObjectLayer capsuleObjectLayer = isSensor ? PhysicsLayers::SENSOR : PhysicsLayers::MOVING;
@@ -133,6 +135,17 @@ namespace
133135

134136
return animTextureRefs;
135137
}
138+
139+
double GetElevatedPlatformHeight(const VoxelShapeDefinition &voxelShapeDef)
140+
{
141+
if (!voxelShapeDef.isElevatedPlatform)
142+
{
143+
return 0.0;
144+
}
145+
146+
DebugAssert(voxelShapeDef.type == VoxelShapeType::Box);
147+
return voxelShapeDef.box.yOffset + voxelShapeDef.box.height;
148+
}
136149
}
137150

138151
const EntityDefinition &EntityChunkManager::getEntityDef(EntityDefID defID) const
@@ -231,7 +244,7 @@ void EntityChunkManager::populateChunkEntities(EntityChunk &entityChunk, const V
231244

232245
animInst.setStateIndex(initInfo.initialAnimStateIndex);
233246

234-
if (!TryCreatePhysicsCollider(entityCoord, initInfo.animMaxHeight, ceilingScale, initInfo.isSensorCollider, physicsSystem, &entityInst.physicsBodyID))
247+
if (!TryCreatePhysicsCollider(entityCoord, initInfo.animMaxHeight, initInfo.feetY, initInfo.isSensorCollider, physicsSystem, &entityInst.physicsBodyID))
235248
{
236249
DebugLogError("Couldn't allocate entity Jolt physics body.");
237250
}
@@ -316,10 +329,11 @@ void EntityChunkManager::populateChunkEntities(EntityChunk &entityChunk, const V
316329
DebugAssert(initialAnimStateIndex.has_value());
317330

318331
std::optional<EntityDefID> entityDefID; // Global entity def ID (shared across all active chunks).
319-
for (const WorldDouble3 &position : placementDef.positions)
332+
for (const WorldDouble2 &worldPosition : placementDef.positions)
320333
{
321-
const WorldInt3 voxelPosition = VoxelUtils::pointToVoxel(position, ceilingScale);
322-
if (!ChunkUtils::IsInWritingRange(voxelPosition, startX, endX, startY, endY, startZ, endZ))
334+
const WorldInt2 worldVoxelXZ = VoxelUtils::pointToVoxel(worldPosition);
335+
const WorldInt3 worldVoxel(worldVoxelXZ.x, 1, worldVoxelXZ.y);
336+
if (!ChunkUtils::IsInWritingRange(worldVoxel, startX, endX, startY, endY, startZ, endZ))
323337
{
324338
continue;
325339
}
@@ -329,21 +343,27 @@ void EntityChunkManager::populateChunkEntities(EntityChunk &entityChunk, const V
329343
entityDefID = this->getOrAddEntityDefID(entityDef, entityDefLibrary);
330344
}
331345

332-
const VoxelDouble3 point = ChunkUtils::MakeChunkPointFromLevel(position, startX, startY, startZ);
346+
const VoxelDouble2 point = ChunkUtils::MakeChunkPointFromLevel(worldPosition, startX, startZ);
347+
const VoxelInt3 voxel = VoxelUtils::worldVoxelToCoord(worldVoxel).voxel;
333348

334349
double animMaxWidth, animMaxHeight;
335350
EntityUtils::getAnimationMaxDims(animDef, &animMaxWidth, &animMaxHeight);
336351
const double halfAnimMaxWidth = animMaxWidth * 0.50;
337352

338353
EntityInitInfo initInfo;
339354
initInfo.defID = *entityDefID;
340-
initInfo.point = VoxelDouble2(point.x, point.z);
355+
initInfo.point = point;
341356

342357
// Bounding box is centered on the entity in model space.
343358
initInfo.bboxMin = WorldDouble3(-halfAnimMaxWidth, 0.0, -halfAnimMaxWidth);
344359
initInfo.bboxMax = WorldDouble3(halfAnimMaxWidth, animMaxHeight, halfAnimMaxWidth);
345360

346361
initInfo.animMaxHeight = animMaxHeight;
362+
363+
const VoxelShapeDefID voxelShapeDefID = voxelChunk.getShapeDefID(voxel.x, voxel.y, voxel.z);
364+
const VoxelShapeDefinition &voxelShapeDef = voxelChunk.getShapeDef(voxelShapeDefID);
365+
initInfo.feetY = ceilingScale + GetElevatedPlatformHeight(voxelShapeDef);
366+
347367
initInfo.initialAnimStateIndex = *initialAnimStateIndex;
348368
initInfo.isSensorCollider = !EntityUtils::hasCollision(entityDef);
349369

@@ -424,6 +444,7 @@ void EntityChunkManager::populateChunkEntities(EntityChunk &entityChunk, const V
424444
citizenInitInfo.bboxMax = WorldDouble3(halfAnimMaxWidth, animMaxHeight, halfAnimMaxWidth);
425445

426446
citizenInitInfo.animMaxHeight = animMaxHeight;
447+
citizenInitInfo.feetY = ceilingScale;
427448
citizenInitInfo.initialAnimStateIndex = *initialCitizenAnimStateIndex;
428449
citizenInitInfo.isSensorCollider = true;
429450
citizenInitInfo.citizenDirectionIndex = CitizenUtils::getRandomCitizenDirectionIndex(random);

OpenTESArena/src/World/ChunkUtils.cpp

+10-4
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,16 @@ VoxelInt3 ChunkUtils::MakeChunkVoxelFromLevel(const WorldInt3 &levelPosition, SN
140140
levelPosition.z - chunkStartZ);
141141
}
142142

143-
VoxelDouble3 ChunkUtils::MakeChunkPointFromLevel(const WorldDouble3 &levelPosition, SNInt chunkStartX, int chunkStartY, WEInt chunkStartZ)
143+
VoxelInt2 ChunkUtils::MakeChunkVoxelFromLevel(const WorldInt2 &levelPosition, SNInt chunkStartX, WEInt chunkStartZ)
144144
{
145-
return VoxelDouble3(
145+
return VoxelInt2(
146+
levelPosition.x - chunkStartX,
147+
levelPosition.y - chunkStartZ);
148+
}
149+
150+
VoxelDouble2 ChunkUtils::MakeChunkPointFromLevel(const WorldDouble2 &levelPosition, SNInt chunkStartX, WEInt chunkStartZ)
151+
{
152+
return VoxelDouble2(
146153
levelPosition.x - static_cast<SNDouble>(chunkStartX),
147-
levelPosition.y - static_cast<double>(chunkStartY),
148-
levelPosition.z - static_cast<WEDouble>(chunkStartZ));
154+
levelPosition.y - static_cast<WEDouble>(chunkStartZ));
149155
}

OpenTESArena/src/World/ChunkUtils.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ namespace ChunkUtils
5555
WEInt startZ, WEInt endZ);
5656

5757
VoxelInt3 MakeChunkVoxelFromLevel(const WorldInt3 &levelPosition, SNInt chunkStartX, int chunkStartY, WEInt chunkStartZ);
58-
VoxelDouble3 MakeChunkPointFromLevel(const WorldDouble3 &levelPosition, SNInt chunkStartX, int chunkStartY, WEInt chunkStartZ);
58+
VoxelInt2 MakeChunkVoxelFromLevel(const WorldInt2 &levelPosition, SNInt chunkStartX, WEInt chunkStartZ);
59+
VoxelDouble2 MakeChunkPointFromLevel(const WorldDouble2 &levelPosition, SNInt chunkStartX, WEInt chunkStartZ);
5960
}
6061

6162
#endif

OpenTESArena/src/World/LevelDefinition.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
#include "LevelDefinition.h"
44

5-
LevelEntityPlacementDefinition::LevelEntityPlacementDefinition(LevelVoxelEntityDefID id, std::vector<WorldDouble3> &&positions)
5+
LevelEntityPlacementDefinition::LevelEntityPlacementDefinition(LevelVoxelEntityDefID id, std::vector<WorldDouble2> &&positions)
66
: positions(std::move(positions))
77
{
88
this->id = id;
@@ -226,7 +226,7 @@ const LevelChasmPlacementDefinition &LevelDefinition::getChasmPlacementDef(int i
226226
return this->chasmPlacementDefs[index];
227227
}
228228

229-
void LevelDefinition::addEntity(LevelVoxelEntityDefID id, const WorldDouble3 &position)
229+
void LevelDefinition::addEntity(LevelVoxelEntityDefID id, const WorldDouble2 &position)
230230
{
231231
const auto iter = std::find_if(this->entityPlacementDefs.begin(), this->entityPlacementDefs.end(),
232232
[id](const LevelEntityPlacementDefinition &def)
@@ -236,12 +236,12 @@ void LevelDefinition::addEntity(LevelVoxelEntityDefID id, const WorldDouble3 &po
236236

237237
if (iter != this->entityPlacementDefs.end())
238238
{
239-
std::vector<WorldDouble3> &positions = iter->positions;
239+
std::vector<WorldDouble2> &positions = iter->positions;
240240
positions.emplace_back(position);
241241
}
242242
else
243243
{
244-
this->entityPlacementDefs.emplace_back(id, std::vector<WorldDouble3> { position });
244+
this->entityPlacementDefs.emplace_back(id, std::vector<WorldDouble2> { position });
245245
}
246246
}
247247

OpenTESArena/src/World/LevelDefinition.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ using LevelVoxelChasmDefID = int;
2525
struct LevelEntityPlacementDefinition
2626
{
2727
LevelVoxelEntityDefID id;
28-
std::vector<WorldDouble3> positions;
28+
std::vector<WorldDouble2> positions;
2929

30-
LevelEntityPlacementDefinition(LevelVoxelEntityDefID id, std::vector<WorldDouble3> &&positions);
30+
LevelEntityPlacementDefinition(LevelVoxelEntityDefID id, std::vector<WorldDouble2> &&positions);
3131
};
3232

3333
struct LevelLockPlacementDefinition
@@ -137,7 +137,7 @@ class LevelDefinition
137137
int getChasmPlacementDefCount() const;
138138
const LevelChasmPlacementDefinition &getChasmPlacementDef(int index) const;
139139

140-
void addEntity(LevelVoxelEntityDefID id, const WorldDouble3 &position);
140+
void addEntity(LevelVoxelEntityDefID id, const WorldDouble2 &position);
141141
void addLock(LevelVoxelLockDefID id, const WorldInt3 &position);
142142
void addTrigger(LevelVoxelTriggerDefID id, const WorldInt3 &position);
143143
void addTransition(LevelVoxelTransitionDefID id, const WorldInt3 &position);

OpenTESArena/src/World/MapGeneration.cpp

+2-4
Original file line numberDiff line numberDiff line change
@@ -1211,9 +1211,8 @@ namespace MapGeneration
12111211
entityCache->emplace(florVoxel, entityDefID);
12121212
}
12131213

1214-
const WorldDouble3 entityPos(
1214+
const WorldDouble2 entityPos(
12151215
static_cast<SNDouble>(levelX) + 0.50,
1216-
1.0, // Will probably be ignored in favor of raised platform top face.
12171216
static_cast<WEDouble>(levelZ) + 0.50);
12181217
outLevelDef->addEntity(entityDefID, entityPos);
12191218
}
@@ -1412,9 +1411,8 @@ namespace MapGeneration
14121411
entityCache->emplace(map1Voxel, entityDefID);
14131412
}
14141413

1415-
const WorldDouble3 entityPos(
1414+
const WorldDouble2 entityPos(
14161415
static_cast<SNDouble>(levelX) + 0.50,
1417-
1.0,
14181416
static_cast<WEDouble>(levelZ) + 0.50);
14191417
outLevelDef->addEntity(entityDefID, entityPos);
14201418
}

0 commit comments

Comments
 (0)