EnTT 4.0.0
Loading...
Searching...
No Matches
davey.hpp
1#ifndef ENTT_TOOLS_DAVEY_HPP
2#define ENTT_TOOLS_DAVEY_HPP
3
4#include "../config/config.h"
5#include "../entity/mixin.hpp"
6#include "../entity/registry.hpp"
7#include "../entity/sparse_set.hpp"
8#include "../entity/storage.hpp"
9#include "../locator/locator.hpp"
10#include "../meta/container.hpp"
11#include "../meta/context.hpp"
12#include "../meta/meta.hpp"
13#include "../meta/pointer.hpp"
14#include "../meta/resolve.hpp"
15#include "../stl/cstdint.hpp"
16#include "../stl/ios.hpp"
17#include "../stl/sstream.hpp"
18#include "../stl/string.hpp"
19
20#if __has_include(<imgui.h>)
21# include <imgui.h>
22#endif
23
24namespace entt {
25
27namespace internal {
28
29template<typename Entity, typename OnEntity>
30static void present_element(const meta_any &obj, OnEntity on_entity) {
31 for([[maybe_unused]] const auto [id, data]: obj.type().data()) {
32 const auto elem = data.get(obj);
33 const stl::string name = data.name().empty() ? stl::string{data.type().info().name()} : stl::string{data.name()};
34 const char *const label = name.c_str();
35
36 if(auto type = data.type(); type.info() == type_id<const char *>()) {
37 ImGui::Text("%s: %s", label, elem.template cast<const char *>());
38 } else if(type.info() == type_id<stl::string>()) {
39 ImGui::Text("%s: %s", label, elem.template cast<const stl::string &>().data());
40 } else if(type.info() == type_id<Entity>()) {
41 if(const auto entt = elem.template cast<Entity>(); entt == null) {
42 ImGui::Text("%s: %s", label, "null");
43 } else {
44 on_entity(label, entt);
45 }
46 } else if(type.is_enum()) {
47 const char *as_string = nullptr;
48
49 for(auto [id, curr]: type.data()) {
50 if(curr.get({}) == elem) {
51 as_string = curr.name().data();
52 break;
53 }
54 }
55
56 if(as_string) {
57 ImGui::Text("%s: %s", label, as_string);
58 } else {
59 ImGui::Text("%s: %zu", label, elem.template allow_cast<stl::uint64_t>().template cast<stl::uint64_t>());
60 }
61 } else if(type.is_arithmetic()) {
62 if(type.info() == type_id<bool>()) {
63 stl::stringstream buffer{};
64 buffer << stl::boolalpha << elem.template cast<bool>();
65 ImGui::Text("%s: %s", label, buffer.str().data());
66 } else if(type.info() == type_id<char>()) {
67 ImGui::Text("%s: %c", label, elem.template cast<char>());
68 } else if(type.is_integral()) {
69 ImGui::Text("%s: %zu", label, elem.template allow_cast<stl::uint64_t>().template cast<stl::uint64_t>());
70 } else {
71 ImGui::Text("%s: %f", label, elem.template allow_cast<double>().template cast<double>());
72 }
73 } else if(type.is_pointer_like()) {
74 if(auto deref = *obj; deref) {
75 if(ImGui::TreeNode(label)) {
76 present_element<Entity>(*obj, on_entity);
77 ImGui::TreePop();
78 }
79 } else {
80 ImGui::Text("%s: %s", label, "null");
81 }
82 } else if(type.is_sequence_container()) {
83 if(ImGui::TreeNode(label)) {
84 meta_sequence_container view = elem.as_sequence_container();
85
86 for(stl::size_t pos{}, last = view.size(); pos < last; ++pos) {
87 ImGui::PushID(static_cast<int>(pos));
88
89 if(ImGui::TreeNode(label, "%zu", pos)) {
90 present_element<Entity>(view[pos], on_entity);
91 ImGui::TreePop();
92 }
93
94 ImGui::PopID();
95 }
96
97 ImGui::TreePop();
98 }
99 } else if(type.is_associative_container()) {
100 if(ImGui::TreeNode(label)) {
101 meta_associative_container view = elem.as_associative_container();
102 auto it = view.begin();
103
104 for(stl::size_t pos{}, last = view.size(); pos < last; ++pos, ++it) {
105 ImGui::PushID(static_cast<int>(pos));
106
107 if(ImGui::TreeNode(label, "%zu", pos)) {
108 const auto [key, value] = *it;
109
110 if(ImGui::TreeNode("key")) {
111 present_element<Entity>(key, on_entity);
112 ImGui::TreePop();
113 }
114
115 if(ImGui::TreeNode("value")) {
116 present_element<Entity>(value, on_entity);
117 ImGui::TreePop();
118 }
119
120 ImGui::TreePop();
121 }
122
123 ImGui::PopID();
124 }
125
126 ImGui::TreePop();
127 }
128 } else if(type.is_class()) {
129 if(ImGui::TreeNode(label)) {
130 present_element<Entity>(elem, on_entity);
131 ImGui::TreePop();
132 }
133 } else {
134 const stl::string underlying_type{data.type().info().name()};
135 ImGui::Text("%s: %s", label, underlying_type.data());
136 }
137 }
138
139 for([[maybe_unused]] const auto [id, base]: obj.type().base()) {
140 present_element<Entity>(obj.allow_cast(base.type()), on_entity);
141 }
142}
143
144template<typename Entity, typename Allocator>
145static void present_storage(const meta_ctx &ctx, const basic_sparse_set<Entity, Allocator> &storage) {
146 if(auto type = resolve(ctx, storage.info()); type) {
147 for(auto entt: storage) {
148 ImGui::PushID(static_cast<int>(to_entity(entt)));
149
150 if(ImGui::TreeNode(&storage.info(), "%d [%d/%d]", to_integral(entt), to_entity(entt), to_version(entt))) {
151 if(const auto obj = type.from_void(storage.value(entt)); obj) {
152 present_element<typename stl::decay_t<decltype(storage)>::entity_type>(obj, [](const char *name, const Entity entt) {
153 ImGui::Text("%s: %d [%d/%d]", name, to_integral(entt), to_entity(entt), to_version(entt));
154 });
155 }
156
157 ImGui::TreePop();
158 }
159
160 ImGui::PopID();
161 }
162 } else {
163 for(auto entt: storage) {
164 ImGui::Text("%d [%d/%d]", to_integral(entt), to_entity(entt), to_version(entt));
165 }
166 }
167}
168
169template<typename Entity, typename It>
170static void present_entity(const meta_ctx &ctx, const Entity entt, const It from, const It to) {
171 for(auto it = from; it != to; ++it) {
172 if(const auto &storage = it->second; storage.contains(entt)) {
173 if(auto type = resolve(ctx, storage.info()); type) {
174 const stl::string name = type.name().empty() ? stl::string{storage.info().name()} : stl::string{type.name()};
175 const char *const label = name.c_str();
176
177 if(ImGui::TreeNode(&storage.info(), "%s", label)) {
178 if(const auto obj = type.from_void(storage.value(entt)); obj) {
179 present_element<Entity>(obj, [&ctx, from, to](const char *name, const Entity other) {
180 if(ImGui::TreeNode(name, "%s: %d [%d/%d]", name, to_integral(other), to_entity(other), to_version(other))) {
181 present_entity<Entity>(ctx, other, from, to);
182 ImGui::TreePop();
183 }
184 });
185 }
186
187 ImGui::TreePop();
188 }
189 } else {
190 const stl::string name{storage.info().name()};
191 ImGui::Text("%s", name.data());
192 }
193 }
194 }
195}
196
197template<typename... Get, typename... Exclude, stl::size_t... Index>
198static void present_view(const meta_ctx &ctx, const basic_view<get_t<Get...>, exclude_t<Exclude...>> &view, stl::index_sequence<Index...>) {
199 using view_type = basic_view<get_t<Get...>, exclude_t<Exclude...>>;
200 const stl::array<const typename view_type::common_type *, sizeof...(Index)> range{view.template storage<Index>()...};
201
202 for(auto tup: view.each()) {
203 const auto entt = stl::get<0>(tup);
204 ImGui::PushID(static_cast<int>(to_entity(entt)));
205
206 if(ImGui::TreeNode(&type_id<typename view_type::entity_type>(), "%d [%d/%d]", to_integral(entt), to_entity(entt), to_version(entt))) {
207 for(const auto *storage: range) {
208 if(auto type = resolve(ctx, storage->info()); type) {
209 const stl::string name = type.name().empty() ? stl::string{storage->info().name()} : stl::string{type.name()};
210 const char *const label = name.c_str();
211
212 if(ImGui::TreeNode(&storage->info(), "%s", label)) {
213 if(const auto obj = type.from_void(storage->value(entt)); obj) {
214 present_element<typename view_type::entity_type>(obj, [](const char *name, const view_type::entity_type entt) {
215 ImGui::Text("%s: %d [%d/%d]", name, to_integral(entt), to_entity(entt), to_version(entt));
216 });
217 }
218
219 ImGui::TreePop();
220 }
221 } else {
222 const stl::string name{storage->info().name()};
223 ImGui::Text("%s", name.data());
224 }
225 }
226
227 ImGui::TreePop();
228 }
229
230 ImGui::PopID();
231 }
232}
233
234} // namespace internal
236
245template<typename Type, typename Entity, typename Allocator>
247 internal::present_storage(ctx, storage);
248}
249
257template<typename Type, typename Entity, typename Allocator>
261
269template<typename... Get, typename... Exclude>
271 internal::present_view(ctx, view, stl::index_sequence_for<Get...>{});
272}
273
280template<typename... Get, typename... Exclude>
284
292template<typename Entity, typename Allocator>
294 ImGui::BeginTabBar("#tabs");
295
296 if(ImGui::BeginTabItem("Entity")) {
297 for(const auto [entt]: registry.template storage<Entity>()->each()) {
298 ImGui::PushID(static_cast<int>(to_entity(entt)));
299
300 if(ImGui::TreeNode(&type_id<Entity>(), "%d [%d/%d]", to_integral(entt), to_entity(entt), to_version(entt))) {
301 const auto range = registry.storage();
302 internal::present_entity(ctx, entt, range.begin(), range.end());
303 ImGui::TreePop();
304 }
305
306 ImGui::PopID();
307 }
308
309 ImGui::EndTabItem();
310 }
311
312 if(ImGui::BeginTabItem("Storage")) {
313 for([[maybe_unused]] auto [id, storage]: registry.storage()) {
314 const auto type = resolve(ctx, storage.info());
315 const stl::string name = type.name().empty() ? stl::string{storage.info().name()} : stl::string{type.name()};
316 const char *const label = name.c_str();
317
318 if(ImGui::TreeNode(&storage.info(), "%s (%zu)", label, storage.size())) {
319 internal::present_storage(ctx, storage);
320 ImGui::TreePop();
321 }
322 }
323
324 ImGui::EndTabItem();
325 }
326
327 ImGui::EndTabBar();
328}
329
336template<typename Entity, typename Allocator>
340
341} // namespace entt
342
343#endif
Fast and reliable entity-component system.
Definition registry.hpp:211
bool contains(const entity_type entt) const noexcept
Checks if a sparse set contains an entity.
const void * value(const entity_type entt) const noexcept
Returns the element assigned to an entity, if any.
const type_info & info() const noexcept
Returns a type info object for the value type, if any.
Storage implementation.
Definition storage.hpp:208
View implementation.
Definition fwd.hpp:48
static Service & value_or(Args &&...args)
Returns a service if available or sets it from a fallback type.
Definition locator.hpp:90
EnTT default namespace.
Definition dense_map.hpp:25
basic_view(Type &...storage) -> basic_view< get_t< Type... >, exclude_t<> >
Deduction guide.
constexpr entt_traits< Entity >::entity_type to_entity(const Entity value) noexcept
Returns the entity part once converted to the underlying type.
Definition entity.hpp:202
basic_view< type_list_transform_t< Get, storage_for >, type_list_transform_t< Exclude, storage_for > > view
Alias declaration for the most common use case.
Definition fwd.hpp:278
constexpr entt_traits< Entity >::version_type to_version(const Entity value) noexcept
Returns the version part once converted to the underlying type.
Definition entity.hpp:213
void davey(const meta_ctx &ctx, const basic_storage< Type, Entity, Allocator > &storage)
ImGui-based introspection tool for storage types.
Definition davey.hpp:246
meta_type resolve() noexcept
Returns the meta type associated with a given type.
Definition resolve.hpp:32
basic_registry<> registry
Alias declaration for the most common use case.
Definition fwd.hpp:96
constexpr entt_traits< Entity >::entity_type to_integral(const Entity value) noexcept
Converts an entity to its underlying type.
Definition entity.hpp:191
meta_type resolve(const meta_ctx &ctx) noexcept
Returns the meta type associated with a given type.
Definition resolve.hpp:21
const type_info & type_id() noexcept
Returns the type info object associated to a given type.
basic_storage< Type > storage
Alias declaration for the most common use case.
Definition fwd.hpp:79
Alias for exclusion lists.
Definition fwd.hpp:141
Alias for lists of observed elements.
Definition fwd.hpp:158
Opaque meta context type.
Definition context.hpp:30
constexpr stl::string_view name() const noexcept
Type name.