OdysseyDecomp/lib/al/Library/LiveActor/ActorCollisionFunction.cpp

692 lines
23 KiB
C++

#include "Library/LiveActor/ActorCollisionFunction.h"
#include "Library/Base/StringUtil.h"
#include "Library/Collision/Collider.h"
#include "Library/Collision/CollisionDirector.h"
#include "Library/Collision/CollisionParts.h"
#include "Library/Collision/CollisionPartsKeeperUtil.h"
#include "Library/Collision/CollisionPartsTriangle.h"
#include "Library/Collision/ICollisionPartsKeeper.h"
#include "Library/Collision/KCollisionServer.h"
#include "Library/LiveActor/ActorMovementFunction.h"
#include "Library/LiveActor/ActorPoseUtil.h"
#include "Library/LiveActor/LiveActor.h"
#include "Library/Math/MathUtil.h"
#include "Project/Collision/ActorCollisionController.h"
namespace al {
Collider* getActorCollider(const LiveActor* actor) {
return actor->getCollider();
}
bool isExistActorCollider(const LiveActor* actor) {
return actor->getCollider() != nullptr;
}
const HitSensor* getActorCollisionPartsSensor(const LiveActor* actor) {
return actor->getCollisionParts()->getConnectedSensor();
}
bool isExistCollisionParts(const LiveActor* actor) {
return actor->getCollisionParts() != nullptr;
}
bool isEqualCollisionParts(const LiveActor* actor, const CollisionParts* collisionParts) {
return collisionParts && actor->getCollisionParts() == collisionParts;
}
void validateCollisionParts(LiveActor* actor) {
CollisionParts* collisionParts = actor->getCollisionParts();
if (collisionParts->getSyncCollisonMtx()) {
collisionParts->resetAllMtx();
} else {
sead::Matrix34f mtx;
makeMtxSRT(&mtx, actor);
collisionParts->resetAllMtx(mtx);
}
collisionParts->validateByUser();
}
void invalidateCollisionParts(LiveActor* actor) {
actor->getCollisionParts()->invalidateByUser();
}
void validateCollisionPartsBySystem(LiveActor* actor) {
CollisionParts* collisionParts = actor->getCollisionParts();
collisionParts->validateBySystem();
if (collisionParts->getSyncCollisonMtx()) {
collisionParts->resetAllMtx();
} else {
sead::Matrix34f mtx;
makeMtxSRT(&mtx, actor);
collisionParts->resetAllMtx(mtx);
}
}
void invalidateCollisionPartsBySystem(LiveActor* actor) {
actor->getCollisionParts()->invalidateBySystem();
}
bool isValidCollisionParts(const LiveActor* actor) {
return actor->getCollisionParts()->isValidCollision();
}
void setCollisionPartsSpecialPurposeName(LiveActor* actor, const char* name) {
actor->getCollisionParts()->setSpecialPurpose(name);
}
void resetAllCollisionMtx(LiveActor* actor) {
CollisionParts* collisionParts = actor->getCollisionParts();
if (collisionParts->getSyncCollisonMtx()) {
collisionParts->resetAllMtx();
} else {
sead::Matrix34f mtx;
makeMtxSRT(&mtx, actor);
collisionParts->resetAllMtx(mtx);
}
alCollisionUtil::getCollisionPartsKeeper(actor)->resetToCollisionPartsList(collisionParts);
}
void syncCollisionMtx(LiveActor* actor, const sead::Matrix34f* mtx) {
syncCollisionMtx(actor, actor->getCollisionParts(), mtx);
}
void syncCollisionMtx(LiveActor* actor, CollisionParts* collisionParts,
const sead::Matrix34f* mtx) {
if (!collisionParts->isValidCollision())
return;
if (collisionParts->getSyncCollisonMtx()) {
collisionParts->syncMtx();
} else if (mtx) {
collisionParts->syncMtx(*mtx);
} else {
sead::Matrix34f newMtx;
makeMtxSRT(&newMtx, actor);
collisionParts->syncMtx(newMtx);
}
}
void setSyncCollisionMtxPtr(LiveActor* actor, const sead::Matrix34f* mtx) {
actor->getCollisionParts()->setSyncCollisionMtx(mtx);
}
bool isOnGround(const LiveActor* actor, u32 coyoteTime) {
Collider* collider = actor->getCollider();
if (!isCollidedGround(actor) && collider->getNoGroundCounter() > coyoteTime)
return false;
return !(getVelocity(actor).dot(collider->getRecentOnGroundNormal(coyoteTime)) > 0.0f);
}
bool isOnGroundFace(const LiveActor* actor) {
return isOnGround(actor, 0) && !isCollidedGroundEdgeOrCorner(actor);
}
bool isCollidedGroundEdgeOrCorner(const LiveActor* actor) {
return isCollidedGround(actor) && !actor->getCollider()->getFloorHit().isCollisionAtFace();
}
bool isOnGroundNoVelocity(const LiveActor* actor, u32 coyoteTime) {
if (!isExistActorCollider(actor))
return getTrans(actor).y <= 0.0f;
if (isCollidedGround(actor))
return true;
return actor->getCollider()->getNoGroundCounter() <= coyoteTime;
}
bool isOnGroundDegree(const LiveActor* actor, f32 angle, u32 coyoteTime) {
Collider* collider = actor->getCollider();
if (!(isCollidedGround(actor) || collider->getNoGroundCounter() <= coyoteTime))
return false;
if (sead::Mathf::abs(
(*collider->getActorGravityPtr()).dot(collider->getRecentOnGroundNormal(coyoteTime))) <
sead::Mathf::cos(sead::Mathf::deg2rad(angle)))
return false;
return !(getVelocity(actor).dot(collider->getRecentOnGroundNormal(coyoteTime)) > 0.0f);
}
bool isOnGroundFaceDegree(const LiveActor* actor, f32 angle) {
return isOnGroundDegree(actor, angle, 0) && !isCollidedGroundEdgeOrCorner(actor);
}
bool isOnGroundNoVelocityDegree(const LiveActor* actor, f32 angle, u32 coyoteTime) {
Collider* collider = actor->getCollider();
if (!collider)
return getTrans(actor).y <= 0.0;
if (!(isCollidedGround(actor) || collider->getNoGroundCounter() <= coyoteTime))
return false;
if (sead::Mathf::abs(
(*collider->getActorGravityPtr()).dot(collider->getRecentOnGroundNormal(coyoteTime))) <
sead::Mathf::cos(sead::Mathf::deg2rad(angle)))
return false;
return true;
}
const sead::Vector3f& getOnGroundNormal(const LiveActor* actor, u32 offset) {
return actor->getCollider()->getRecentOnGroundNormal(offset);
}
void setColliderRadius(LiveActor* actor, f32 radius) {
actor->getCollider()->setRadius(radius);
}
void setColliderOffsetY(LiveActor* actor, f32 offsety) {
actor->getCollider()->setOffsetY(offsety);
}
f32 getColliderRadius(const LiveActor* actor) {
return actor->getCollider()->getRadius();
}
f32 getColliderOffsetY(const LiveActor* actor) {
return actor->getCollider()->getOffsetY();
}
const sead::Vector3f& getColliderFixReaction(const LiveActor* actor) {
return actor->getCollider()->getFixReaction();
}
void calcColliderPos(sead::Vector3f* outPos, const LiveActor* actor) {
actor->getCollider()->calcCheckPos(outPos);
}
void validateColliderRobustCheck(LiveActor* actor) {
actor->getCollider()->validateRobustCheck();
}
void invalidateColliderRobustCheck(LiveActor* actor) {
actor->getCollider()->invalidateRobustCheck();
}
void setColliderReactMovePower(LiveActor* actor, bool isEnabled) {
actor->getCollider()->setReactMovePower(isEnabled);
}
void calcColliderFloorRotatePower(sead::Quatf* outRotatePower, LiveActor* actor) {
actor->getCollider()->getFloorHit().triangle.calcForceRotatePower(outRotatePower);
}
void calcJumpInertia(sead::Vector3f* outJumpInertia, LiveActor* actor,
const sead::Vector3f& velocityDir, f32 force) {
if (!isCollidedGround(actor)) {
outJumpInertia->set({0.0f, 0.0f, 0.0f});
return;
}
sead::Vector3f movePower = {0.0f, 0.0f, 0.0f};
const HitInfo& floorHit = actor->getCollider()->getFloorHit();
if (floorHit.triangle.getCollisionParts() && floorHit.triangle.isHostMoved())
floorHit.triangle.calcForceMovePower(&movePower, getTrans(actor));
verticalizeVec(&movePower, getGravity(actor), movePower);
sead::Vector3f hMoveDir = movePower;
tryNormalizeOrZero(&hMoveDir);
sead::Vector3f hVelDir = {0.0f, 0.0f, 0.0f};
verticalizeVec(&hVelDir, getGravity(actor), velocityDir);
if (!tryNormalizeOrZero(&hVelDir)) {
outJumpInertia->set(movePower * force);
return;
}
force *= sead::Mathf::clampMin(hMoveDir.dot(hVelDir), 0.0f);
outJumpInertia->set(movePower * force);
}
bool isCollidedGround(const LiveActor* actor) {
return actor->getCollider()->get_110() >= 0.0f;
}
void calcJumpInertiaWall(sead::Vector3f* outJumpInertia, LiveActor* actor, f32 force) {
if (!isCollidedWall(actor)) {
outJumpInertia->set({0.0f, 0.0f, 0.0f});
return;
}
sead::Vector3f movePower = {0.0f, 0.0f, 0.0f};
const sead::Vector3f& trans = getTrans(actor);
const HitInfo& floorHit = actor->getCollider()->getWallHit();
if (floorHit.triangle.getCollisionParts() && alCollisionUtil::isCollisionMoving(&floorHit))
floorHit.triangle.calcForceMovePower(&movePower, trans);
verticalizeVec(&movePower, getGravity(actor), movePower);
outJumpInertia->set(movePower * force);
}
bool isCollidedWall(const LiveActor* actor) {
return actor->getCollider()->get_1b8() >= 0.0f;
}
// TODO: probably a sead function?
inline f32 normalize2(sead::Vector3f* v, f32 scalar) {
const f32 len = v->length();
if (len > 0) {
const f32 inv_len = scalar / len;
v->x *= inv_len;
v->y *= inv_len;
v->z *= inv_len;
}
return len;
}
void scaleVelocityInertiaWallHit(LiveActor* actor, f32 velocityScaleH, f32 maxVelocityH,
f32 maxScaledVelocityH) {
if (!isCollidedWall(actor))
return;
sead::Vector3f faceNormal = getCollidedWallNormal(actor);
verticalizeVec(&faceNormal, getGravity(actor), faceNormal);
if (!tryNormalizeOrZero(&faceNormal))
return;
sead::Vector3f jumpInertia = {0.0f, 0.0f, 0.0f};
calcJumpInertiaWall(&jumpInertia, actor, 1.0f);
sead::Vector3f velocityH = {0.0f, 0.0f, 0.0f};
sead::Vector3f velocityV = {0.0f, 0.0f, 0.0f};
separateVelocityHV(&velocityH, &velocityV, actor);
sead::Vector3f velocityDirH = {0.0f, 0.0f, 0.0f};
tryNormalizeOrZero(&velocityDirH, velocityH);
if (velocityDirH.dot(faceNormal) < -0.5f) {
f32 speedH = velocityH.length();
f32 scaledVelocity = speedH * velocityScaleH;
f32 newSpeedH = sead::Mathf::clamp(scaledVelocity, sead::Mathf::min(speedH, maxVelocityH),
maxScaledVelocityH);
normalize2(&velocityH, newSpeedH);
f32 newVelocityH = jumpInertia.dot(velocityDirH);
if (-newVelocityH < faceNormal.dot(velocityDirH))
normalize2(&velocityH, newVelocityH);
}
setVelocity(actor, velocityH + velocityV);
}
const sead::Vector3f& getCollidedWallNormal(const LiveActor* actor) {
return actor->getCollider()->getWallHit().triangle.getFaceNormal();
}
void calcCollidedNormalSum(const LiveActor* actor, sead::Vector3f* outNormal) {
outNormal->set({0.0f, 0.0f, 0.0f});
Collider* collider = actor->getCollider();
if (collider->get_110() >= 0.0f)
outNormal->add(collider->getFloorHit().triangle.getFaceNormal());
if (collider->get_1b8() >= 0.0f)
outNormal->add(collider->getWallHit().triangle.getFaceNormal());
if (collider->get_260() >= 0.0f)
outNormal->add(collider->getCeilingHit().triangle.getFaceNormal());
*outNormal *= 1.0f / 3.0f;
}
void calcGroundNormalOrUpDir(sead::Vector3f* outDir, const LiveActor* actor) {
if (isCollidedGround(actor))
*outDir = getCollidedGroundNormal(actor);
else
calcUpDir(outDir, actor);
}
const sead::Vector3f& getCollidedGroundNormal(const LiveActor* actor) {
return actor->getCollider()->getFloorHit().triangle.getFaceNormal();
}
void calcGroundNormalOrGravityDir(sead::Vector3f* outDir, const LiveActor* actor) {
if (isCollidedGround(actor))
*outDir = getCollidedGroundNormal(actor);
else
*outDir = -getGravity(actor);
}
void setColliderFilterTriangle(LiveActor* actor, const TriangleFilterBase* triangleFilter) {
actor->getCollider()->setTriangleFilter(triangleFilter);
}
void setColliderFilterCollisionParts(LiveActor* actor,
const CollisionPartsFilterBase* collisionPartsFilter) {
actor->getCollider()->setCollisionPartsFilter(collisionPartsFilter);
}
void createAndSetColliderFilterExistActor(LiveActor* actor) {
createAndSetColliderFilterExistActor(actor, actor);
}
void createAndSetColliderFilterExistActor(LiveActor* actor, LiveActor* filterActor) {
CollisionPartsFilterActor* collisionPartsFilter = new CollisionPartsFilterActor(filterActor);
setColliderFilterCollisionParts(actor, collisionPartsFilter);
}
void createAndSetColliderFilterSubActor(LiveActor* actor) {
CollisionPartsFilterSubActor* collisionPartsFilter = new CollisionPartsFilterSubActor(actor);
setColliderFilterCollisionParts(actor, collisionPartsFilter);
}
void createAndSetColliderSpecialPurpose(LiveActor* actor, const char* name) {
CollisionPartsFilterSpecialPurpose* collisionPartsFilter =
new CollisionPartsFilterSpecialPurpose(name);
setColliderFilterCollisionParts(actor, collisionPartsFilter);
}
void createAndSetColliderSpecialPurposeForCollisionActor(LiveActor* actor, const char* name) {
CollisionPartsFilterMergePair* collisionPartsFilter = new CollisionPartsFilterMergePair(
new CollisionPartsFilterSpecialPurpose(name), new CollisionPartsFilterActor(actor));
setColliderFilterCollisionParts(actor, collisionPartsFilter);
}
void createAndSetColliderIgnoreOptionalPurpose(LiveActor* actor, const char* name) {
CollisionPartsFilterIgnoreOptionalPurpose* collisionPartsFilter =
new CollisionPartsFilterIgnoreOptionalPurpose(name);
setColliderFilterCollisionParts(actor, collisionPartsFilter);
}
void createAndSetColliderSpecialAndIgnoreOptionalPurpose(LiveActor* actor, const char* name,
const char* ignoreName) {
CollisionPartsFilterMergePair* collisionPartsFilter = new CollisionPartsFilterMergePair(
new CollisionPartsFilterSpecialPurpose(name),
new CollisionPartsFilterIgnoreOptionalPurpose(ignoreName));
setColliderFilterCollisionParts(actor, collisionPartsFilter);
}
ActorCollisionController* createActorCollisionController(LiveActor* actor) {
return new ActorCollisionController(actor);
}
void setColliderRadius(ActorCollisionController* collisionController, f32 radius) {
collisionController->setColliderRadius(radius);
}
void setColliderRadiusScale(ActorCollisionController* collisionController, f32 scale) {
collisionController->setColliderRadiusScale(scale);
}
void setColliderOffsetY(ActorCollisionController* collisionController, f32 offsetY) {
collisionController->setColliderOffsetY(offsetY);
}
void resetActorCollisionController(ActorCollisionController* collisionController, s32 delay) {
collisionController->resetToOrigin(delay);
}
void updateActorCollisionController(ActorCollisionController* collisionController) {
collisionController->update();
}
const char* getCollidedFloorMaterialCodeName(const LiveActor* actor) {
return getCollidedFloorMaterialCodeName(actor->getCollider());
}
const char* getCollidedFloorMaterialCodeName(const Collider* collider) {
return getMaterialCodeName(collider->getFloorHit().triangle);
}
const char* getCollidedWallMaterialCodeName(const LiveActor* actor) {
return getMaterialCodeName(actor->getCollider()->getWallHit().triangle);
}
const char* getCollidedCeilingMaterialCodeName(const LiveActor* actor) {
return getMaterialCodeName(actor->getCollider()->getCeilingHit().triangle);
}
bool isCollidedFloorCode(const LiveActor* actor, const char* name) {
return isCollidedCollisionCode(actor, "FloorCode", name);
}
bool isCollidedCollisionCode(const LiveActor* actor, const char* sensorName, const char* name) {
Collider* collider = actor->getCollider();
if (collider->getPlaneNum() == 0) {
if (collider->get_110() >= 0.0f) {
if (isEqualString(name,
getCollisionCodeName(collider->getFloorHit().triangle, sensorName))) {
return true;
}
}
if (collider->get_1b8() >= 0.0f) {
if (isEqualString(name,
getCollisionCodeName(collider->getWallHit().triangle, sensorName))) {
return true;
}
}
if (collider->get_260() >= 0.0f) {
if (isEqualString(
name, getCollisionCodeName(collider->getCeilingHit().triangle, sensorName))) {
return true;
}
}
return false;
}
u32 size = collider->getStoredPlaneNum();
for (u32 i = 0; i < size; i++)
if (isEqualString(name, getCollisionCodeName(*collider->getPlane(i), sensorName)))
return true;
return false;
}
bool isCollidedWallCode(const LiveActor* actor, const char* name) {
return isCollidedCollisionCode(actor, "WallCode", name);
}
bool isCollidedCameraCode(const LiveActor* actor, const char* name) {
return isCollidedCollisionCode(actor, "CameraCode", name);
}
bool isCollidedMaterialCode(const LiveActor* actor, const char* name) {
return isCollidedCollisionCode(actor, "MaterialCode", name);
}
bool isCollidedGroundFloorCode(const LiveActor* actor, const char* name) {
return isCollidedGroundCollisionCode(actor, "FloorCode", name);
}
bool isCollidedGroundCollisionCode(const LiveActor* actor, const char* sensorName,
const char* name) {
if (!isCollidedGround(actor))
return false;
return isEqualString(
name, getCollisionCodeName(actor->getCollider()->getFloorHit().triangle, sensorName));
}
bool isCollided(const LiveActor* actor) {
return isCollidedGround(actor) || isCollidedWall(actor) || isCollidedCeiling(actor);
}
bool isCollidedCeiling(const LiveActor* actor) {
return actor->getCollider()->get_260() >= 0.0f;
}
bool isCollidedWallFace(const LiveActor* actor) {
if (!isCollidedWall(actor))
return false;
return actor->getCollider()->isCollidedWallFace();
}
bool isCollidedVelocity(const LiveActor* actor) {
if (isOnGround(actor, 0))
return true;
return isCollidedWallVelocity(actor) || isCollidedCeilingVelocity(actor);
}
bool isCollidedWallVelocity(const LiveActor* actor) {
return isCollidedWall(actor) && getVelocity(actor).dot(getCollidedWallNormal(actor)) < 0.0f;
}
bool isCollidedCeilingVelocity(const LiveActor* actor) {
return isCollidedCeiling(actor) &&
getVelocity(actor).dot(getCollidedCeilingNormal(actor)) < 0.0f;
}
const sead::Vector3f& getCollidedCeilingNormal(const LiveActor* actor) {
return actor->getCollider()->getCeilingHit().triangle.getFaceNormal();
}
const sead::Vector3f& getCollidedGroundPos(const LiveActor* actor) {
return actor->getCollider()->getFloorHit().collisionHitPos;
}
const sead::Vector3f& getCollidedWallPos(const LiveActor* actor) {
return actor->getCollider()->getWallHit().collisionHitPos;
}
const sead::Vector3f& getCollidedCeilingPos(const LiveActor* actor) {
return actor->getCollider()->getCeilingHit().collisionHitPos;
}
f32 calcSpeedCollideWall(const LiveActor* actor) {
if (!isCollidedWall(actor))
return 0.0f;
sead::Vector3f wallNormal = getCollidedWallNormal(actor);
return -sead::Mathf::min(wallNormal.dot(getVelocity(actor)), 0.0f);
}
f32 calcSpeedCollideGround(const LiveActor* actor) {
if (!isCollidedGround(actor))
return 0.0f;
sead::Vector3f groundNormal = getCollidedGroundNormal(actor);
return -sead::Mathf::min(groundNormal.dot(getVelocity(actor)), 0.0f);
}
f32 calcSpeedCollideCeiling(const LiveActor* actor) {
if (!isCollidedCeiling(actor))
return 0.0f;
sead::Vector3f ceilingNormal = getCollidedCeilingNormal(actor);
return -sead::Mathf::min(ceilingNormal.dot(getVelocity(actor)), 0.0f);
}
const CollisionParts* getCollidedGroundCollisionParts(const LiveActor* actor) {
return tryGetCollidedGroundCollisionParts(actor);
}
const CollisionParts* tryGetCollidedGroundCollisionParts(const LiveActor* actor) {
if (!isCollidedGround(actor))
return nullptr;
return actor->getCollider()->getFloorHit().triangle.getCollisionParts();
}
const CollisionParts* getCollidedWallCollisionParts(const LiveActor* actor) {
return tryGetCollidedWallCollisionParts(actor);
}
const CollisionParts* tryGetCollidedWallCollisionParts(const LiveActor* actor) {
if (!isCollidedWall(actor))
return nullptr;
return actor->getCollider()->getWallHit().triangle.getCollisionParts();
}
const CollisionParts* getCollidedCeilingCollisionParts(const LiveActor* actor) {
return tryGetCollidedCeilingCollisionParts(actor);
}
const CollisionParts* tryGetCollidedCeilingCollisionParts(const LiveActor* actor) {
if (!isCollidedCeiling(actor))
return nullptr;
return actor->getCollider()->getCeilingHit().triangle.getCollisionParts();
}
HitSensor* getCollidedGroundSensor(const LiveActor* actor) {
return tryGetCollidedGroundSensor(actor);
}
HitSensor* tryGetCollidedGroundSensor(const LiveActor* actor) {
if (!isCollidedGround(actor))
return nullptr;
return actor->getCollider()->getFloorHit().triangle.getCollisionParts()->getConnectedSensor();
}
HitSensor* getCollidedWallSensor(const LiveActor* actor) {
return tryGetCollidedWallSensor(actor);
}
HitSensor* tryGetCollidedWallSensor(const LiveActor* actor) {
if (!isCollidedWall(actor))
return nullptr;
return actor->getCollider()->getWallHit().triangle.getCollisionParts()->getConnectedSensor();
}
HitSensor* getCollidedCeilingSensor(const LiveActor* actor) {
return tryGetCollidedCeilingSensor(actor);
}
HitSensor* tryGetCollidedCeilingSensor(const LiveActor* actor) {
if (!isCollidedCeiling(actor))
return nullptr;
return actor->getCollider()->getCeilingHit().triangle.getCollisionParts()->getConnectedSensor();
}
HitSensor* tryGetCollidedSensor(const LiveActor* actor) {
return tryGetCollidedWallSensor(actor) ?:
tryGetCollidedGroundSensor(actor) ?:
tryGetCollidedCeilingSensor(actor);
}
bool tryGetCollidedPos(sead::Vector3f* outPos, const LiveActor* actor) {
if (isCollidedWall(actor)) {
outPos->set(getCollidedWallPos(actor));
return true;
}
if (isCollidedGround(actor)) {
outPos->set(getCollidedGroundPos(actor));
return true;
}
if (isCollidedCeiling(actor)) {
outPos->set(getCollidedCeilingPos(actor));
return true;
}
return false;
}
void setForceCollisionScaleOne(const LiveActor* actor) {
actor->getCollisionParts()->setForceCollisionScaleOne();
}
void followRotateFrontAxisUpGround(LiveActor* actor) {
const CollisionParts* collisionParts = tryGetCollidedGroundCollisionParts(actor);
if (collisionParts)
followRotateFrontAxisUp(actor, collisionParts);
}
void followRotateFrontAxisUp(LiveActor* actor, const CollisionParts* collisionParts) {
sead::Vector3f frontDir = {0.0f, 0.0f, 0.0f};
calcFrontDir(&frontDir, actor);
sead::Vector3f sideDir = frontDir;
sideDir.rotate(collisionParts->getPrevBaseInvMtx());
sideDir.rotate(collisionParts->getBaseMtx());
sead::Vector3f upDir = {0.0f, 0.0f, 0.0f};
calcUpDir(&upDir, actor);
sead::Vector3f newFrontDir = {0.0f, 0.0f, 0.0f};
turnVecToVecCosOnPlane(&newFrontDir, frontDir, sideDir, upDir, -1.0f);
sead::Quatf quat = sead::Quatf::unit;
makeQuatUpFront(&quat, upDir, newFrontDir);
updatePoseQuat(actor, quat);
}
} // namespace al