Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
269 changes: 147 additions & 122 deletions Engine/source/T3D/assets/SoundAsset.cpp

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Engine/source/T3D/assets/SoundAsset.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ class SoundAsset : public AssetBase

/// Declare Console Object.
DECLARE_CONOBJECT(SoundAsset);

// asset Base load
static bool slotVisible(void* object, const char* index);
U32 load() override;

void setSoundFile(StringTableEntry pSoundFile, U32 slot = 0);
Expand Down
97 changes: 97 additions & 0 deletions Engine/source/console/consoleObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,83 @@ static char* suppressSpaces(const char* in_pname)
return replacebuf;
}

static U32 sg_currentArrayElementCount = 1;

void ConsoleObject::registerField(const char* name, U32 type, dsize_t offset, const FieldDescriptor& desc)
{
AbstractClassRep::Field f;

const bool isCollection = desc.isArrayBegin || desc.isArrayEnd || desc.isGroupBegin || desc.isGroupEnd;

if (isCollection)
{
char* pFieldNameBuf = suppressSpaces(name);
if (desc.isGroupBegin)
{
// Append group begin type to fieldname.
dStrcat(pFieldNameBuf, "_begingroup", 1024);
f.type = AbstractClassRep::StartGroupFieldType;
}

if (desc.isGroupEnd)
{
// Append group end type to fieldname.
dStrcat(pFieldNameBuf, "_endgroup", 1024);
f.type = AbstractClassRep::EndGroupFieldType;
}

if (desc.isArrayBegin)
{
// Append array type to fieldname.
dStrcat(pFieldNameBuf, "_beginarray", 1024);
f.type = AbstractClassRep::StartArrayFieldType;
}

if (desc.isArrayEnd)
{
// Append array end type to fieldname.
dStrcat(pFieldNameBuf, "_endarray", 1024);
f.type = AbstractClassRep::EndArrayFieldType;
}

f.pFieldname = StringTable->insert(pFieldNameBuf);
f.pGroupname = StringTable->insert(name);
f.elementCount = desc.elementCount;
}
else
{
ConsoleBaseType* conType = ConsoleBaseType::getType(desc._type);
AssertFatal(conType, avar("ConsoleObject::addProtectedField[%s] - invalid console type", name));
f.pFieldname = StringTable->insert(name);
f.type = desc._type;
f.table = conType->getEnumTable();
}

if (desc.isArrayBegin)
sg_currentArrayElementCount = desc.elementCount;

if (desc.isArrayEnd)
sg_currentArrayElementCount = 1;

if (desc.docs)
f.pFieldDocs = desc.docs;

if (!isCollection)
f.elementCount = desc.elementCount > 1 ? desc.elementCount : sg_currentArrayElementCount;

f.offset = desc._offset;
f.validator = desc.validator;
f.setDataFn = desc.setFn;
f.getDataFn = desc.getFn;
f.writeDataFn = desc.writeFn;
f.visibilityFn = desc.visibilityFn;
f.groupExpand = desc.isExpanded;
f.networkMask = desc.networkMask;
f.flag = desc.flags;

sg_tempFieldList.push_back(f);
}

void ConsoleObject::addGroup(const char* in_pGroupname, const char* in_pGroupDocs)
{
// Remove spaces.
Expand Down Expand Up @@ -1130,3 +1207,23 @@ DefineEngineFunction(linkNamespaces, bool, ( String childNSName, String parentNS
return true;
}

FieldDescriptor::~FieldDescriptor()
{
if (!_active)
return;

if (_name == NULL || _name[0] == '\0')
return;

_active = false;

// if we are a collection, sanitize some properties.
if (isGroupBegin || isGroupEnd || isArrayBegin || isArrayEnd)
{
elementCount = isArrayBegin ? elementCount : 0;
validator = NULL;
networkMask = 0;
}

ConsoleObject::registerField(_name, _type, _offset, *this);
}
204 changes: 188 additions & 16 deletions Engine/source/console/consoleObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,11 @@ class AbstractClassRep : public ConsoleBaseType
/// This is a function pointer typedef to support optional writing for fields.
typedef bool(*WriteDataNotify)(void* obj, StringTableEntry pFieldName);

/// <summary>
/// This is a function pointer typedef to support optional visibility of fields.
/// </summary>
typedef bool(*VisibilityNotify)(void* obj, const char* array);

/// These are special field type values used to mark
/// groups and arrays in the field list.
/// @see Field::type
Expand Down Expand Up @@ -517,27 +522,29 @@ class AbstractClassRep : public ConsoleBaseType
setDataFn( NULL ),
getDataFn( NULL ),
writeDataFn(NULL),
visibilityFn(NULL),
networkMask(0)
{
doNotSubstitute = keepClearSubsOnly = false;
}

StringTableEntry pFieldname; ///< Name of the field.
const char* pGroupname; ///< Optionally filled field containing the group name.
///
/// This is filled when type is StartField or EndField

const char* pFieldDocs; ///< Documentation about this field; see consoleDoc.cc.
bool groupExpand; ///< Flag to track expanded/not state of this group in the editor.
U32 type; ///< A data type ID or one of the special custom fields. @see ACRFieldTypes
U32 offset; ///< Memory offset from beginning of class for this field.
S32 elementCount; ///< Number of elements, if this is an array.
const EnumTable * table; ///< If this is an enum, this points to the table defining it.
BitSet32 flag; ///< Stores various flags
TypeValidator *validator; ///< Validator, if any.
SetDataNotify setDataFn; ///< Set data notify Fn
GetDataNotify getDataFn; ///< Get data notify Fn
WriteDataNotify writeDataFn; ///< Function to determine whether data should be written or not.
StringTableEntry pFieldname; ///< Name of the field.
const char* pGroupname; ///< Optionally filled field containing the group name.
///
/// This is filled when type is StartField or EndField

const char* pFieldDocs; ///< Documentation about this field; see consoleDoc.cc.
bool groupExpand; ///< Flag to track expanded/not state of this group in the editor.
U32 type; ///< A data type ID or one of the special custom fields. @see ACRFieldTypes
U32 offset; ///< Memory offset from beginning of class for this field.
S32 elementCount; ///< Number of elements, if this is an array.
const EnumTable * table; ///< If this is an enum, this points to the table defining it.
BitSet32 flag; ///< Stores various flags
TypeValidator *validator; ///< Validator, if any.
SetDataNotify setDataFn; ///< Set data notify Fn
GetDataNotify getDataFn; ///< Get data notify Fn
WriteDataNotify writeDataFn; ///< Function to determine whether data should be written or not.
VisibilityNotify visibilityFn; ///< Function to determine this field is visibile or not.
bool doNotSubstitute;
bool keepClearSubsOnly;

Expand Down Expand Up @@ -764,9 +771,173 @@ template< typename T > EnginePropertyTable& ConcreteAbstractClassRep< T >::smPro

//------------------------------------------------------------------------------
// Forward declaration of this function so it can be used in the class
bool defaultProtectedSetFn(void* object, const char* index, const char* data);
const char *defaultProtectedGetFn( void *obj, const char *data );
bool defaultProtectedWriteFn(void* obj, StringTableEntry pFieldName);

struct FieldDescriptor {
// Context for auto-registration
const char* _name = NULL;
U32 _type = 0;
dsize_t _offset = 0;
bool isExpanded = false;
bool isGroupBegin = false;
bool isGroupEnd = false;
bool isArrayBegin = false;
bool isArrayEnd = false;
bool _active = true;

// Field properties
const char* docs = NULL;
AbstractClassRep::SetDataNotify setFn = &defaultProtectedSetFn;
AbstractClassRep::GetDataNotify getFn = &defaultProtectedGetFn;
AbstractClassRep::WriteDataNotify writeFn = &defaultProtectedWriteFn;
TypeValidator* validator = NULL;
U32 elementCount = 1;
U32 flags = 0;
U32 networkMask = 0;
AbstractClassRep::VisibilityNotify visibilityFn = NULL;

// Add documentation to this field.
FieldDescriptor& doc(const char* d) { docs = d; return *this; }
// The number of elements for this field (U32 number)
FieldDescriptor& elements(U32 n) { elementCount = n; return *this; }
// The validator for this field.
FieldDescriptor& validate(TypeValidator* v) { validator = v; return *this; }
// The set data function.
FieldDescriptor& onSet(AbstractClassRep::SetDataNotify fn) { setFn = fn; return *this; }
// The get data function.
FieldDescriptor& onGet(AbstractClassRep::GetDataNotify fn) { getFn = fn; return *this; }
// The on write function
FieldDescriptor& onWrite(AbstractClassRep::WriteDataNotify fn) { writeFn = fn; return *this; }
// The visibility function
FieldDescriptor& showWhen(AbstractClassRep::VisibilityNotify fn) { visibilityFn = fn; return *this; }
// The network mask changes will trigger.
FieldDescriptor& network(U32 mask) { networkMask = mask; return *this; }
// The flags for this field.
FieldDescriptor& withFlags(U32 f) { flags = f; return *this; }
// This field marks the start of a group.
FieldDescriptor& startGroup() { isGroupBegin = true; return *this; }
// This field marks the end of a group.
FieldDescriptor& endGroup() { isGroupEnd = true; return *this; }
// This field marks the start of an array.
FieldDescriptor& startArray() { isArrayBegin = true; return *this; }
// This field marks the end of an array.
FieldDescriptor& endArray() { isArrayEnd = true; return *this; }
// This field should start expanded in the inspector.
FieldDescriptor& expanded() { isExpanded = true; return *this; }

FieldDescriptor(const char* name, U32 type = 0, dsize_t offset = 0)
: _name(name), _type(type), _offset(offset)
{}

FieldDescriptor(const FieldDescriptor&) = delete;
FieldDescriptor& operator=(const FieldDescriptor&) = delete;

FieldDescriptor(FieldDescriptor&& other) noexcept
{
moveFrom(std::move(other));
}

FieldDescriptor& operator=(FieldDescriptor&& other) noexcept
{
if (this != &other)
moveFrom(std::move(other));
return *this;
}

void moveFrom(FieldDescriptor&& other)
{
// transfer all data
_name = other._name;
_type = other._type;
_offset = other._offset;

docs = other.docs;
setFn = other.setFn;
getFn = other.getFn;
writeFn = other.writeFn;
validator = other.validator;
elementCount = other.elementCount;
flags = other.flags;
networkMask = other.networkMask;
visibilityFn = other.visibilityFn;

isExpanded = other.isExpanded;
isGroupBegin = other.isGroupBegin;
isGroupEnd = other.isGroupEnd;
isArrayBegin = other.isArrayBegin;
isArrayEnd = other.isArrayEnd;

// transfer ownership of "registration responsibility"
_active = other._active;

// CRITICAL: disable the source so its destructor does NOTHING
other._active = false;
}

~FieldDescriptor();

};


/// Registers a standard field.
/// Usage:
/// FIELD("health", TypeS32, Offset(mHealth, Player)).doc("Player health");
#define ADD_FIELD(name, type, offset) \
FieldDescriptor(name, type, offset)

/// Field with fixed element count.
/// Usage:
/// FIELD_ARRAY("color", TypeColorF, Offset(mColor, GuiControl), 4);
#define FIELD_ARRAY(name, type, offset, count) \
FieldDescriptor(name, type, offset).elements(count)

/// Begins a field group in the inspector.
/// All fields declared after this will belong to the group until GROUP_END().
/// Usage:
/// GROUP_BEGIN("Rendering").expanded();
#define GROUP_BEGIN(name) \
FieldDescriptor(name).startGroup()

/// Ends the current field group.
/// Must match a preceding GROUP_BEGIN().
/// Usage:
/// GROUP_END("Rendering");
#define GROUP_END(name) \
FieldDescriptor(name).endGroup()

/// Begins an array block in the inspector.
/// Usage:
/// ARRAY_BEGIN("Waypoints");
#define ARRAY_BEGIN(name, count) \
FieldDescriptor(name).startArray().elements(count)

/// Ends an array block.
/// Usage:
/// ARRAY_END("Waypoints");
#define ARRAY_END(name) \
FieldDescriptor(name).endArray()

/// Declares a scoped inspector group.
///
/// Provides a structured grouping of fields in the inspector UI using a scoped
/// block. Internally, this macro guarantees that a matching group end marker
/// is emitted, preventing mismatched begin/end pairs.
#define GROUP(name) \
for (bool _once = true; _once; _once = false) \
for (FieldDescriptor(name).startGroup(); _once; FieldDescriptor(name).endGroup(), _once = false)

/// Declares a scoped inspector array block.
///
/// Defines a logical array grouping in the inspector UI. Fields declared within
/// the block are treated as elements of the array. Like GROUP, this macro
/// ensures that the array begin/end markers are correctly paired using scoped
/// execution.
#define ARRAY(name, count) \
for (bool _once = true; _once; _once = false) \
for (FieldDescriptor(name).startArray().elements(count); _once; FieldDescriptor(name).endArray(), _once = false)

//=============================================================================
// ConsoleObject.
//=============================================================================
Expand Down Expand Up @@ -871,6 +1042,7 @@ class ConsoleObject : public EngineObject

/// @name Fields
/// @{
static void registerField(const char* name, U32 type, dsize_t offset, const FieldDescriptor& desc);

/// Mark the beginning of a group of fields.
///
Expand Down
Loading
Loading