Libprimis
Imprimis' 3D destroyable world engine
Loading...
Searching...
No Matches
prop.h
Go to the documentation of this file.
1
10#ifndef PROP_H_
11#define PROP_H_
12
13#include <any>
14#include <variant>
15
16#include "cube.h"
17
18namespace prop
19{
20
28typedef std::variant<int, float, bvec, ivec, vec, std::string> PropertyValue;
29
35typedef std::function<void(std::any argument)> OnChangeCallback;
36
43enum class PropertyType
44{
45 NoType = -1,
46
47 Int,
48 Float,
49 Color,
50 IntVec,
51 FloatVec,
52 String,
53
54 Count
55};
56
68{
69private:
70 std::string name;
71 PropertyType type;
72 PropertyValue min, def, max;
73 OnChangeCallback on_change;
74
75public:
76 PropertyType get_type() const;
77 PropertyValue get_min() const;
78 PropertyValue get_def() const;
79 PropertyValue get_max() const;
80 std::string get_name() const;
81
82 void changed(std::any argument) const;
83
84 template<class T> PropertyMeta(std::string _name, PropertyType _type, T _min, T _def, T _max,
85 OnChangeCallback _on_change = nullptr) :
86 name(_name), type(_type), min(_min), def(_def), max(_max), on_change(_on_change) {}
87 template<class T> PropertyMeta(std::string _name, PropertyType _type, T _def,
88 OnChangeCallback _on_change = nullptr) :
89 name(_name), type(_type), def(_def), on_change(_on_change) {}
90
91 PropertyMeta(const PropertyMeta&) = delete;
92};
93
101template<typename PropertyMetaT = PropertyMeta>
103{
104private:
105 PropertyValue value;
106 const PropertyMetaT& meta;
107
108 bool set_check_type(PropertyType type) const;
109 void set_clamped(PropertyValue value);
110
111public:
112 const PropertyValue& get_value() const;
113 int get_int() const;
114 float get_float() const;
115 const bvec& get_color() const;
116 const ivec& get_ivec() const;
117 const vec& get_fvec() const;
118 const std::string& get_string() const;
119 size_t get_size() const;
120 std::string get_name() const;
121 PropertyType get_type() const;
122
123 std::string to_string() const;
124
125 void copy(const Property& prop);
126
127 void set(PropertyValue value, std::any on_change_argument = std::any());
128 void set_no_cb(PropertyValue value);
129
130 void reset();
131
132 void cmd_result() const;
133 void cmd_result_min() const;
134 void cmd_result_def() const;
135 void cmd_result_max() const;
136
137 virtual void pack(std::vector<uint8_t>& buf) const;
138 virtual size_t unpack(const uint8_t* buf, size_t len);
139
140 Property(const PropertyMetaT& _meta);
141 virtual ~Property() = default;
142};
143
144
145
147// Implementation //
149
150
151
160template<typename PropertyMetaT>
162{
163 return std::get<int>(value);
164}
165
174template<typename PropertyMetaT>
176{
177 return std::get<float>(value);
178}
179
188template<typename PropertyMetaT>
190{
191 return std::get<bvec>(value);
192}
193
202template<typename PropertyMetaT>
204{
205 return std::get<ivec>(value);
206}
207
216template<typename PropertyMetaT>
218{
219 return std::get<vec>(value);
220}
221
230template<typename PropertyMetaT>
231const std::string& Property<PropertyMetaT>::get_string() const
232{
233 return std::get<std::string>(value);
234}
235
244template<typename PropertyMetaT>
246{
247 switch(get_type())
248 {
249 case PropertyType::Int:
250 return sizeof(int);
251 case PropertyType::Float:
252 return sizeof(float);
253 case PropertyType::Color:
254 return sizeof(bvec);
255 case PropertyType::IntVec:
256 return sizeof(ivec);
257 case PropertyType::FloatVec:
258 return sizeof(vec);
259 case PropertyType::String:
260 return get_string().size();
261 default:
262 return 0;
263 }
264}
265
266template<typename PropertyMetaT>
267std::string Property<PropertyMetaT>::to_string() const
268{
269 switch(get_type())
270 {
271 case PropertyType::Int:
272 return std::to_string(get_int());
273
274 case PropertyType::Float:
275 return std::to_string(get_float());
276
277 case PropertyType::Color:
278 return std::to_string(get_color().r) + " " + std::to_string(get_color().g) + " " + std::to_string(get_color().b);
279
280 case PropertyType::IntVec:
281 return std::to_string(get_ivec().x) + " " + std::to_string(get_ivec().y) + " " + std::to_string(get_ivec().z);
282
283 case PropertyType::FloatVec:
284 return std::to_string(get_fvec().x) + " " + std::to_string(get_fvec().y) + " " + std::to_string(get_fvec().z);
285
286 case PropertyType::String:
287 return get_string();
288
289 default:
290 return "";
291 }
292}
293
294template<typename PropertyMetaT>
295bool Property<PropertyMetaT>::set_check_type(PropertyType type) const
296{
297 // typename used in debug printout below
298 //static constexpr std::string_view typenames[] =
299 //{
300 // "int", "float", "color", "int vector", "float vector", "string"
301 //};
302
303 if(get_type() != type)
304 {
305 // conoutf("Error: %s, incorrect property assignment type: got %s, expected %s",
306 // meta.get_name().c_str(), std::string(typenames[static_cast<size_t>(type)]).c_str(),
307 // std::string(typenames[static_cast<size_t>(get_type())]).c_str());
308
309 return false;
310 }
311
312 return true;
313}
314
323template<typename PropertyMetaT>
325{
326 return meta.get_name();
327}
328
337template<typename PropertyMetaT>
339{
340 return meta.get_type();
341}
342
353template<typename PropertyMetaT>
355{
356 set_no_cb(prop.value);
357}
358
359template<typename PropertyMetaT>
361{
362 switch(get_type())
363 {
364 case PropertyType::Int:
365 {
366 int v = std::get<int>(value);
367 this->value = std::clamp(v, std::get<int>(meta.get_min()), std::get<int>(meta.get_max()));
368 break;
369 }
370
371 case PropertyType::Float:
372 {
373 float v = std::get<float>(value);
374 this->value = std::clamp(v, std::get<float>(meta.get_min()), std::get<float>(meta.get_max()));
375 break;
376 }
377
378 case PropertyType::IntVec:
379 {
380 ivec v = std::get<ivec>(value);
381 this->value = ivec(v).min(std::get<ivec>(meta.get_max()))
382 .max(std::get<ivec>(meta.get_min()));
383 break;
384 }
385
386 case PropertyType::FloatVec:
387 {
388 vec v = std::get<vec>(value);
389 this->value = vec(v).min(std::get<vec>(meta.get_max()))
390 .max(std::get<vec>(meta.get_min()));
391 break;
392 }
393
394 default:
395 this->value = value;
396 break;
397 }
398}
399
410template<typename PropertyMetaT>
411void Property<PropertyMetaT>::set(PropertyValue value, std::any on_change_arg)
412{
413 if(set_check_type(static_cast<PropertyType>(value.index())))
414 {
415 set_clamped(value);
416 meta.changed(on_change_arg);
417 }
418}
419
429template<typename PropertyMetaT>
431{
432 if(set_check_type(static_cast<PropertyType>(value.index())))
433 {
434 set_clamped(value);
435 }
436}
437
443template<typename PropertyMetaT>
445{
446 this->value = meta.get_def();
447}
448
449static void _prop_cmd_result_value(PropertyValue value, PropertyType type)
450{
451 switch(type)
452 {
453 case PropertyType::Int:
454 intret(std::get<int>(value));
455 break;
456
457 case PropertyType::Float:
458 floatret(std::get<float>(value));
459 break;
460
461 case PropertyType::Color:
462 intret(std::get<bvec>(value).tohexcolor());
463 break;
464
465 case PropertyType::IntVec:
466 {
467 const ivec& v = std::get<ivec>(value);
468 result(tempformatstring("%d %d %d", v.x, v.y, v.z));
469 break;
470 }
471
472 case PropertyType::FloatVec:
473 {
474 const vec& v = std::get<vec>(value);
475 result(tempformatstring("%f %f %f", v.x, v.y, v.z));
476 break;
477 }
478
479 case PropertyType::String:
480 result(std::get<std::string>(value).c_str());
481 break;
482
483 default: break;
484 }
485}
486
492template<typename PropertyMetaT>
494{
495 _prop_cmd_result_value(value, get_type());
496}
497
503template<typename PropertyMetaT>
505{
506 _prop_cmd_result_value(meta.get_min(), get_type());
507}
508
514template<typename PropertyMetaT>
516{
517 _prop_cmd_result_value(meta.get_def(), get_type());
518}
519
525template<typename PropertyMetaT>
527{
528 _prop_cmd_result_value(meta.get_max(), get_type());
529}
530
537template<typename PropertyMetaT>
538void Property<PropertyMetaT>::pack(std::vector<uint8_t>& buf) const
539{
540 size_t data_size = get_size();
541
542 vectorput(buf, data_size);
543
544 switch(get_type())
545 {
546 case PropertyType::Int:
547 {
548 vectorput(buf, get_int());
549 break;
550 }
551
552 case PropertyType::Float:
553 {
554 vectorput(buf, get_float());
555 break;
556 }
557
558 case PropertyType::Color:
559 {
560 vectorput(buf, get_color());
561 break;
562 }
563
564 case PropertyType::IntVec:
565 {
566 vectorput(buf, get_ivec());
567 break;
568 }
569
570 case PropertyType::FloatVec:
571 {
572 vectorput(buf, get_fvec());
573 break;
574 }
575
576 case PropertyType::String:
577 {
578 std::string data = get_string();
579 // Null-terminator not needed, since we know the size
580 vectorput(buf, reinterpret_cast<const uint8_t*>(data.data()), data.size());
581 break;
582 }
583
584 default: break;
585 }
586}
587
597template<typename PropertyMetaT>
598size_t Property<PropertyMetaT>::unpack(const uint8_t* buf, size_t buf_size)
599{
600 size_t buf_read = 0;
601 const size_t* data_size_packed = nullptr;
602
603 if(buf_size <= sizeof(*data_size_packed))
604 {
605 // conoutf("Error unpacking prop '%s': not enough data to get the size!", meta.get_name().c_str());
606 return 0;
607 }
608
609 data_size_packed = reinterpret_cast<const size_t*>(buf);
610
611 buf_read += sizeof(*data_size_packed);
612
613 static auto size_check = [&](size_t needed_size)
614 {
615 if(buf_size - buf_read < needed_size)
616 {
617 // conoutf("Error unpacking prop '%s': not enough data!", meta.get_name().c_str());
618 return false;
619 }
620
621 return true;
622 };
623
624 switch(get_type())
625 {
626 case PropertyType::Int:
627 case PropertyType::Color:
628 case PropertyType::Float:
629 if(*data_size_packed != get_size())
630 {
631 // conoutf("Error unpacking prop '%s': unexpected data size! Wanted: %lu, got: %lu",
632 // meta.get_name().c_str(), get_size(), *data_size_packed);
633
634 return 0;
635 }
636 break;
637
638 default: break;
639 }
640
641 switch(get_type())
642 {
643 case PropertyType::Int:
644 {
645 if(!size_check(get_size()))
646 {
647 return 0;
648 }
649
650 int ival;
651 memcpy(&ival, buf + buf_read, get_size());
652 buf_read += get_size();
653 value = ival;
654 break;
655 }
656
657 case PropertyType::Float:
658 {
659 if(!size_check(get_size()))
660 {
661 return 0;
662 }
663
664 float fval;
665 memcpy(&fval, buf + buf_read, get_size());
666 buf_read += get_size();
667 value = fval;
668 break;
669 }
670
671 case PropertyType::Color:
672 {
673 if(!size_check(get_size()))
674 {
675 return 0;
676 }
677
678 bvec cval;
679 memcpy(&cval, buf + buf_read, get_size());
680 buf_read += get_size();
681 value = cval;
682 break;
683 }
684
685 case PropertyType::IntVec:
686 {
687 if(!size_check(get_size()))
688 {
689 return 0;
690 }
691
692 ivec ivecval;
693 memcpy(&ivecval, buf + buf_read, get_size());
694 buf_read += get_size();
695 value = ivecval;
696 break;
697 }
698
699 case PropertyType::FloatVec:
700 {
701 if(!size_check(get_size()))
702 {
703 return 0;
704 }
705
706 vec vecval;
707 memcpy(&vecval, buf + buf_read, get_size());
708 buf_read += get_size();
709 value = vecval;
710 break;
711 }
712
713 case PropertyType::String:
714 {
715 if(!size_check(*data_size_packed))
716 {
717 return 0;
718 }
719
720 std::string sval(reinterpret_cast<const char*>(buf + buf_read), *data_size_packed);
721 buf_read += *data_size_packed;
722 value = sval;
723 break;
724 }
725
726 default: break;
727 }
728
729 return buf_read;
730}
731
738template<typename PropertyMetaT>
739Property<PropertyMetaT>::Property(const PropertyMetaT& _meta) : meta(_meta)
740{
741 reset();
742}
743
750{
751 return type;
752}
753
760{
761 return min;
762}
763
770{
771 return def;
772}
773
780{
781 return max;
782}
783
789std::string PropertyMeta::get_name() const
790{
791 return name;
792}
793
794void PropertyMeta::changed(std::any argument) const
795{
796 if(on_change)
797 {
798 on_change(argument);
799 }
800}
801
802
803
805// Helper functions //
807
808
809
819template<typename PropertyT, std::size_t N>
820PropertyT* find_prop(std::string name, std::array<PropertyT, N>& props)
821{
822 for(PropertyT& prop : props)
823 {
824 if(prop.get_name() == name)
825 {
826 return &prop;
827 }
828 }
829
830 return nullptr;
831}
832
842template<typename PropertyT, std::size_t N>
843const PropertyT* find_prop(std::string name, const std::array<PropertyT, N>& props)
844{
845 for(const PropertyT& prop : props)
846 {
847 if(prop.get_name() == name)
848 {
849 return &prop;
850 }
851 }
852
853 return nullptr;
854}
855
867template<typename PropertyT, std::size_t N>
868bool set_prop(std::string name, PropertyValue value, std::array<PropertyT, N>& props,
869 std::any on_change_arg = std::any())
870{
871 PropertyT* prop = find_prop(name, props);
872 if(!prop)
873 {
874 // conoutf("Property %s not found!", name.c_str());
875 return false;
876 }
877
878 prop->set(value, on_change_arg);
879 return true;
880}
881
891template<typename PropertyMetaT, std::size_t N>
892const PropertyMetaT* find_prop_meta(std::string name, const std::array<PropertyMetaT, N>& prop_metas)
893{
894 for(const PropertyMetaT& prop_meta : prop_metas)
895 {
896 if(prop_meta.get_name() == name)
897 {
898 return &prop_meta;
899 }
900 }
901
902 return nullptr;
903}
904
913template<typename PropertyT, std::size_t N>
914void pack_props(const std::array<PropertyT, N>& props, std::vector<uint8_t>& buf)
915{
916 for(const PropertyT& prop : props)
917 {
918 prop.pack(buf);
919 }
920}
921
931template<typename PropertyT, std::size_t N>
932size_t unpack_props(const std::vector<uint8_t>& buf, std::array<PropertyT, N>& props)
933{
934 size_t prop_idx = 0;
935 size_t read_pos = 0;
936
937 while(read_pos < buf.size())
938 {
939 if(prop_idx >= N)
940 {
941 break;
942 }
943
944 PropertyT &prop = props[prop_idx];
945
946 int unpacked_size = prop.unpack(buf.data() + read_pos, buf.size() - read_pos);
947 if(!unpacked_size)
948 {
949 break;
950 }
951
952 read_pos += unpacked_size;
953 prop_idx++;
954 }
955
956 return prop_idx;
957}
958
959template<std::size_t N, typename PropertyT, std::size_t... Is, typename PropertyMetaT>
960std::array<PropertyT, N> _make_props_array_impl(std::index_sequence<Is...>,
961 const PropertyMetaT (&prop_meta)[N])
962{
963 return { PropertyT(prop_meta[Is])... };
964}
965
976template<std::size_t N, typename PropertyT, std::size_t... Is, typename PropertyMetaT>
977std::array<PropertyT, N> make_props_array(const PropertyMetaT (&prop_meta)[N])
978{
979 return _make_props_array_impl<N, PropertyT>(std::make_index_sequence<N>{}, prop_meta);
980}
981
982}; // namespace prop
983
984#endif // PROP_H_
Meta information about a property.
Definition prop.h:68
PropertyType get_type() const
Gets the type of the property definition.
Definition prop.h:749
PropertyValue get_min() const
Gets the minimum value of the property definition.
Definition prop.h:759
PropertyValue get_def() const
Gets the default value of the property definition.
Definition prop.h:769
std::string get_name() const
Gets the name of the property definition.
Definition prop.h:789
PropertyValue get_max() const
Gets the maximum value of the property definition.
Definition prop.h:779
A property.
Definition prop.h:103
void reset()
Reset the value of the property to the default value.
Definition prop.h:444
size_t get_size() const
Get the size of the property.
Definition prop.h:245
void cmd_result_def() const
Results the default value of the property.
Definition prop.h:515
const vec & get_fvec() const
Get the float vector value of the property.
Definition prop.h:217
void cmd_result_max() const
Results the maximum value of the property.
Definition prop.h:526
void set(PropertyValue value, std::any on_change_argument=std::any())
Set the value of the property.
Definition prop.h:411
const ivec & get_ivec() const
Get the integer vector value of the property.
Definition prop.h:203
PropertyType get_type() const
Get the type of the property.
Definition prop.h:338
void cmd_result() const
Results the value of the property.
Definition prop.h:493
const bvec & get_color() const
Get the color value of the property.
Definition prop.h:189
void copy(const Property &prop)
Copy the value of another property, will not invoke callback.
Definition prop.h:354
void set_no_cb(PropertyValue value)
Set the value of the property without invoking callback.
Definition prop.h:430
void cmd_result_min() const
Results the minimum value of the property.
Definition prop.h:504
float get_float() const
Get the float value of the property.
Definition prop.h:175
int get_int() const
Get the integer value of the property.
Definition prop.h:161
Property(const PropertyMetaT &_meta)
Creates a new property with the given meta class.
Definition prop.h:739
virtual void pack(std::vector< uint8_t > &buf) const
Packs the property into a buffer.
Definition prop.h:538
const std::string & get_string() const
Get the string value of the property.
Definition prop.h:231
virtual size_t unpack(const uint8_t *buf, size_t len)
Unpacks the property from a buffer.
Definition prop.h:598
std::string get_name() const
Get the name of the property.
Definition prop.h:324
void result(const char *s)
Returns an alias' name from a Cubescript command.
void intret(int v)
Returns an integer value from a Cubescript command.
void floatret(float v)
Returns a float value from a Cubescript command.
Needed for making games, along with iengine.h.
std::function< void(std::any argument)> OnChangeCallback
Callback type for property changes.
Definition prop.h:35
bool set_prop(std::string name, PropertyValue value, std::array< PropertyT, N > &props, std::any on_change_arg=std::any())
Sets the value of a property with the given name in the given array.
Definition prop.h:868
void pack_props(const std::array< PropertyT, N > &props, std::vector< uint8_t > &buf)
Packs the given properties into the given buffer.
Definition prop.h:914
std::variant< int, float, bvec, ivec, vec, std::string > PropertyValue
Storage for a property value.
Definition prop.h:28
PropertyType
Type of a property.
Definition prop.h:44
std::array< PropertyT, N > make_props_array(const PropertyMetaT(&prop_meta)[N])
Creates an array of properties from the given property definitions.
Definition prop.h:977
PropertyT * find_prop(std::string name, std::array< PropertyT, N > &props)
Finds a property with the given name in the given array.
Definition prop.h:820
size_t unpack_props(const std::vector< uint8_t > &buf, std::array< PropertyT, N > &props)
Unpacks the given buffer into the given properties.
Definition prop.h:932
const PropertyMetaT * find_prop_meta(std::string name, const std::array< PropertyMetaT, N > &prop_metas)
Finds a property definition with the given name in the given array.
Definition prop.h:892
three dimensional Cartesian byte vector
Definition geom.h:637
Definition geom.h:2075
three dimensional Cartesian vector object
Definition geom.h:185