summaryrefslogtreecommitdiff
path: root/src/engine/registry/Registry.h
blob: 86b3528943f370b760ccc162dfb4561b9118f720 (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
128
129
130
131
132
133
134
135
#pragma once

#include <libultraship.h>
#include <string>
#include <unordered_map>
#include <functional>
#include <set>

struct TrackInfo {
    uint32_t Id;
    std::string Path; // Path to the custom track
    std::string ResourceName;
    std::string Name;
    std::string DebugName;
    std::string Length;
    const char* MinimapTexture;
    // std::string PreviewTexture;
};

struct ActorInfo {
    uint32_t Id;
    std::string ResourceName;
    std::string Name;
    std::set<std::string> Tags; // Category for filtering
};

struct ItemInfo {
    uint32_t Id;
    std::string ResourceName;
    std::string Name;
};

/**
 * TInfo must have a ResourceName member of type std::string
 * This should be a unique string such as hm:cloud or hm:harbour
 * user_name:my_mod
 * 
 * TArgs the parameters passed into the callback function
 * 
 * Example Usage:
 * 
 * Registry<ActorInfo> gActorRegistry;
 * 
 * ActorInfo actorInfo {
 *     .ResourceName = "hm:cloud",
 * };
 * SpawnParams params;
 * params.Location = FVector(0, 0, 0);
 * 
 * gActorRegistry.Add(actorInfo, [](params) {
 *     GetWorld()->AddActor(new ACloud(params));
 * });
 * 
 * gActorRegistry.Invoke("hm:cloud", params);
 * 
 */

template<typename TInfo, typename... TArgs>
// ^ Scary template key word
class Registry {
public:
    /**
     * Callback explanation
     * 
     * This is just a lambda function.
     * 
     * Usage: gRegistry.Add("hm:harbour", [](parameters) { // My code here })
     */
    using Callback = std::function<void(TArgs...)>;

    void Add(TInfo& info, Callback func) {
        info.Id = mCounter++;
        // Needs to allow overwriting to support mod hot-reloading
        mMap[info.ResourceName] = Entry{info, std::move(func)};
    }

    const TInfo* GetInfo(const std::string& resourceName) const {
        auto it = mMap.find(resourceName);
        return (it != mMap.end()) ? &it->second.Info : nullptr;
    }

    void Invoke(const std::string& resourceName, TArgs... args) {
        auto it = mMap.find(resourceName);
        if (it != mMap.end() && it->second.Func) {
            // Using C++ variadic template expansion to call the function
            printf("[Registry] Invoking %s\n", resourceName.c_str());
            it->second.Func(std::forward<TArgs>(args)...);
        } else {
            printf("[Registry] Error: %s not found or function is null.\n", resourceName.c_str());
        }
    }

    bool Find(const std::string& resourceName) const {
        return mMap.find(resourceName) != mMap.end();
    }

    size_t Size() {
        return mMap.size();
    }

    std::vector<const TInfo*> GetAllInfo() const {
        std::vector<const TInfo*> list;
        list.reserve(mMap.size());
        for (auto& pair : mMap) {
            list.push_back(&pair.second.Info);
        }
        return list;
    }

    // Returns true if item succesfully removed
    // Note that mCounter is not decremented on remove
    bool Remove(const std::string& resourceName) {
        auto it = mMap.find(resourceName);
        if (it != mMap.end()) {
            mMap.erase(it);
            return true;
        }
        return false;
    }

    void Clear() {
        mMap.clear();
        mCounter = 0;
    }

private:
    int32_t mCounter;
    struct Entry {
        TInfo Info;
        Callback Func;
    };

    // key: str, value: lambda function
    std::unordered_map<std::string, Registry::Entry> mMap;
};