summaryrefslogtreecommitdiff
path: root/src/KingSystem/Physics/System/physRayCastRequestMgr.cpp
blob: cbae2dac2ebf062958417ca043f3bd7662b6d530 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include "KingSystem/Physics/System/physRayCastRequestMgr.h"
#include <cmath>
#include <prim/seadScopedLock.h>
#include "KingSystem/Framework/frmWorkerSupportThreadMgr.h"
#include "KingSystem/Physics/System/physRayCastForRequest.h"
#include "KingSystem/ksys.h"

namespace ksys::phys {

RayCastRequestMgr::RayCastRequestMgr() = default;

RayCastRequestMgr::~RayCastRequestMgr() = default;

void RayCastRequestMgr::init(sead::Heap* heap, int pool_size) {
    mLargestRecordedQueueSize = 0;
    for (auto it = mQueuedList.robustBegin(); it != mQueuedList.robustEnd(); it++)
        mQueuedList.erase(&*it);

    for (int i = 0; i < pool_size; ++i) {
        auto* ray_cast = new (heap, 0x10) RayCastForRequest(this);
        mFreeList.pushBack(&ray_cast->mListNode);
    }

    mWorkerFunction.bind(this, &RayCastRequestMgr::processRequests);
}

bool RayCastRequestMgr::processRequests(void*) {
    for (int i = 0; i < mBatchSize; ++i) {
        mCS.lock();
        auto* request = mQueuedList.popFront();
        if (!request) {
            mCS.unlock();
            return true;
        }
        request->mList = nullptr;
        mCS.unlock();

        request->mData->worldRayCast(request->mData->mRequestContactLayerType);
    }

    return true;
}

void RayCastRequestMgr::clearRequests() {
    {
        auto lock = sead::makeScopedLock(mCS);
        while (!mQueuedList.isEmpty()) {
            auto* request = mQueuedList.popFront();
            if (!request)
                continue;

            auto* ray_cast = request->mData;
            request->mList = nullptr;
            releaseRequest(*ray_cast);
        }
    }
    mLargestRecordedQueueSize = 0;
}

void RayCastRequestMgr::releaseRequest(RayCastForRequest& ray_cast) {
    auto lock = sead::makeScopedLock(mCS);
    ray_cast.mRigidBodyHitCallback = nullptr;
    mFreeList.pushBack(&ray_cast.mListNode);
}

RayCastForRequest* RayCastRequestMgr::allocRequest(SystemGroupHandler* group_handler,
                                                   GroundHit ground_hit) {
    auto lock = sead::makeScopedLock(mCS);

    auto* request = mFreeList.popFront();
    if (!request)
        return nullptr;

    request->mList = nullptr;

    if (request->mData->_98) {
        mFreeList.pushBack(request);
        return nullptr;
    }

    request->mData->reset();
    request->mData->mGroupHandler = group_handler;
    request->mData->setGroundHit(ground_hit);
    request->mData->mNormalCheckingMode = RayCast::NormalCheckingMode::_0;
    return request->mData;
}

static bool isVectorInvalid(const sead::Vector3f& vec) {
    for (int i = 0; i < 3; ++i) {
        if (std::isnan(vec.e[i]))
            return true;
    }
    return false;
}

bool RayCastRequestMgr::submitRequest(RayCastForRequest& ray_cast, ContactLayerType layer_type) {
    if (isVectorInvalid(ray_cast.mFrom) || isVectorInvalid(ray_cast.mTo))
        return false;

    if (ray_cast.mListNode.isLinked())
        return false;

    auto lock = sead::makeScopedLock(mCS);

    ray_cast.mRequestContactLayerType = layer_type;
    mQueuedList.pushBack(&ray_cast.mListNode);

    if (mQueuedList.size() > mLargestRecordedQueueSize)
        mLargestRecordedQueueSize = mQueuedList.size();

    return true;
}

bool RayCastRequestMgr::isRequestQueued(const RayCastForRequest& ray_cast) const {
    return ray_cast.mListNode.mList == &mQueuedList;
}

bool RayCastRequestMgr::isRequestFinished(const RayCastForRequest& ray_cast) const {
    return ray_cast.mListNode.mList == &mFreeList;
}

void RayCastRequestMgr::scheduleRequestProcessing() {
    if (!isGameOver())
        frm::WorkerSupportThreadMgr::instance()->submitRequest(5, &mWorkerFunction);
}

}  // namespace ksys::phys