summaryrefslogtreecommitdiff
path: root/src/KingSystem/Physics/System/physGroupFilter.h
blob: d40f29bf3e408359d4f4fbea605c31716e4fc4e8 (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
#pragma once

#include <Havok/Physics2012/Collide/Filter/Group/hkpGroupFilter.h>
#include <basis/seadTypes.h>
#include <container/seadOffsetList.h>
#include <container/seadSafeArray.h>
#include <prim/seadRuntimeTypeInfo.h>
#include <thread/seadCriticalSection.h>
#include "KingSystem/Physics/physDefines.h"

namespace ksys::phys {

class SystemGroupHandler {
    SEAD_RTTI_BASE(SystemGroupHandler)
public:
    explicit SystemGroupHandler(int index, ContactLayerType layer_type)
        : mIndex(index), mLayerType(layer_type) {}

    virtual ~SystemGroupHandler() = default;
    virtual u32 makeCollisionFilterInfo(u32 info, ContactLayer layer, GroundHit ground_hit) = 0;
    virtual u32 makeQueryCollisionMask(u32 layer_mask, GroundHit ground_hit, bool unk) = 0;
    virtual u32 makeRagdollCollisionFilterInfo(GroundHit ground_hit);
    virtual bool m8() = 0;

    int getIndex() const { return mIndex; }
    ContactLayerType getLayerType() const { return mLayerType; }

    const char* getActorName() const { return mActorName; }
    void setActorName(const char* name) { mActorName = name; }

    const char* getActorProfile() const { return mActorProfile; }
    void setActorProfile(const char* name) { mActorProfile = name; }

    /// Remove this handler from the filter it's attached to.
    void removeThis();

    static constexpr auto getFreeListNodeOffset() {
        return offsetof(SystemGroupHandler, mFreeListNode);
    }

    static constexpr auto getUsedListNodeOffset() {
        return offsetof(SystemGroupHandler, mUsedListNode);
    }

protected:
    const char* mActorName = nullptr;
    const char* mActorProfile = nullptr;
    int mIndex = 0;
    ContactLayerType mLayerType{};
    sead::ListNode mFreeListNode;
    sead::ListNode mUsedListNode;
};

class GroupFilter : public hkpGroupFilter {
    SEAD_RTTI_BASE(GroupFilter)
public:
    GroupFilter(ContactLayerType type, ContactLayer::ValueType layer_first,
                ContactLayer::ValueType layer_last);
    ~GroupFilter() override;

    ContactLayer::ValueType getLayerFirst() const { return mLayerFirst; }
    ContactLayer::ValueType getLayerLast() const { return mLayerLast; }
    int getNumLayers() const { return getLayerLast() - getLayerFirst() + 1; }
    ContactLayerType getLayerType() const { return mLayerType; }

    void initFilter(sead::Heap* heap);
    /// Frees all memory associated with this instance and then self-destructs.
    /// @warning Do not use this filter after a call to destroy!
    void destroy();

    SystemGroupHandler* addSystemGroupHandler(int free_list_idx);
    void removeSystemGroupHandler(SystemGroupHandler* handler);

    void setLayerCollisionEnabledMask(ContactLayer layer, u32 mask) {
        m_collisionLookupTable[layer - getLayerFirst()] = mask;
    }

    /// Indicates whether contact between layerA and layerB should never be ignored,
    /// even if the corresponding rigid bodies are configured to ignore each other's layer.
    virtual bool shouldContactNeverBeIgnored(ContactLayer layerA, ContactLayer layerB) {
        return true;
    }

    /// Make a collision filter mask with the specified layer and ground hit type.
    virtual u32 makeCollisionFilterInfo(ContactLayer layer, GroundHit ground_hit) = 0;

    /// Get the layer from a collision filter mask.
    virtual ContactLayer getCollisionFilterInfoLayer(u32 info) = 0;

    /// Make a query collision mask with the specified layer mask, ground hit type and flag.
    virtual u32 makeQueryCollisionMask(u32 layer_mask, GroundHit ground_hit, bool unk) = 0;

    /// Get the ground hit type from a query collision mask.
    virtual GroundHit getQueryCollisionMaskGroundHit(u32 info) = 0;

    /// Get the layer and ground hit type from a collision filter mask.
    virtual void getCollisionFilterInfoLayerAndGroundHit(u32 info, ContactLayer* layer,
                                                         GroundHit* ground_hit) = 0;

    /// Get the layer from a collision filter mask.
    virtual const char* getCollisionFilterInfoLayerText(u32 info) = 0;

    virtual void setLayerCustomMask(ContactLayer layer, u32 mask) {}

    /// Get the group handler index from a collision filter mask.
    virtual u32 getCollisionFilterInfoGroupHandlerIdx(u32 info) = 0;

protected:
    virtual void doInitSystemGroupHandlerLists_(sead::Heap* heap) = 0;
    virtual int getFreeListIndex(const SystemGroupHandler* handler) = 0;

    /// Initialises internal state.
    virtual void doInit_(sead::Heap* heap) {}

    ContactLayer::ValueType mLayerFirst{};
    ContactLayer::ValueType mLayerLast{};
    ContactLayerType mLayerType{};
    bool mInhibitCollisions{};
    sead::SafeArray<sead::OffsetList<SystemGroupHandler>, 2> mFreeLists;
    sead::CriticalSection mCS;
    sead::OffsetList<SystemGroupHandler> mUsedList;
};

}  // namespace ksys::phys