Sq Plus Instances With Script Object Handle
Last changed: -66.139.76.17

.

coacel

Change code in SqPlus.h from line

#define DECLARE_INSTANCE_TYPE_NAME_(TYPE,NAME) namespace SqPlus { \

to line

#define SQPLUS_DECLARE_INSTANCE_TYPE_CONST

#include "SqPlusConst.h"

#endif

(lines 532-583 in sqplus.h v20)

to following

#define SQPLUS_DECLARE_TYPE_INFO(TYPE, NAME) \
  inline const SQChar * GetTypeName(const TYPE & /*n*/) { return _T(#NAME); } \
  template<> \
  struct TypeInfo<TYPE> { \
    const SQChar * typeName; \
    TypeInfo() : typeName(_T(#NAME)) {} \
    enum {TypeID=VAR_TYPE_INSTANCE,Size=sizeof(TYPE)}; \
    operator ScriptVarType() { return ScriptVarType(TypeID); } \
  };

#define SQPLUS_DECLARE_TYPE_OPERATIONS(TYPE, NAME) \
  inline bool Match(TypeWrapper<TYPE &>,HSQUIRRELVM v,int idx) { \
    return GetInstance<TYPE,false>(v,idx) != NULL; } \
  inline bool Match(TypeWrapper<TYPE *>,HSQUIRRELVM v,int idx) { \
    return (sq_gettype(v,idx)==OT_NULL) || (GetInstance<TYPE,false>(v,idx) != NULL); } \
  inline TYPE & Get(TypeWrapper<TYPE &>,HSQUIRRELVM v,int idx) { \
    return *GetInstance<TYPE,true>(v,idx); } \
  inline TYPE * Get(TypeWrapper<TYPE *>,HSQUIRRELVM v,int idx) { \
    if (sq_gettype(v,idx)==OT_NULL) return NULL;\
    return  GetInstance<TYPE,true>(v,idx); } \
  inline void PushNative(HSQUIRRELVM v,TYPE * value) { \
    if (!value) sq_pushnull(v); \
    else if (!CreateNativeClassInstance(v,GetTypeName(*value),value,0)) \
       throw SquirrelError(_T("Push(): could not create INSTANCE (check registration name)")); } \
  inline void PushNative(HSQUIRRELVM /*v*/,TYPE & value) { \
    if (!CreateCopyInstance(GetTypeName(value),value)) \
      throw SquirrelError(_T("Push(): could not create INSTANCE copy (check registration name)")); }

#define SQPLUS_DECLARE_TYPE_PUSH_NATIVE(TYPE, NAME) \
  inline void Push(HSQUIRRELVM v,TYPE * value) { PushNative(v, value); } \
  inline void Push(HSQUIRRELVM v,TYPE & value) { PushNative(v, value); }

#define SQPLUS_DECLARE_TYPE_PUSH_SCRIPTED(TYPE, NAME) \
  inline void Push(HSQUIRRELVM v,TYPE * value) { \
    if (!value) sq_pushnull(v); \
    else if (value->scriptObjHandle._type != OT_NULL)  Push(v, SquirrelObject(value->scriptObjHandle)); \
    else PushNative(v, value); } \
  inline void Push(HSQUIRRELVM v,TYPE & value) { \
    if (value.scriptObjHandle._type != OT_NULL) Push(v, SquirrelObject(value.scriptObjHandle)); \
    else PushNative(v, value); }

#define DECLARE_INSTANCE_TYPE_NAME_(TYPE,NAME) \
namespace SqPlus { \
  SQPLUS_DECLARE_TYPE_INFO(TYPE,NAME) \
  SQPLUS_DECLARE_TYPE_OPERATIONS(TYPE,NAME) \
  SQPLUS_DECLARE_TYPE_PUSH_NATIVE(TYPE,NAME) \
} // nameSpace SqPlus

#define DECLARE_INSTANCE_TYPE_NAME_SCRIPTED_(TYPE,NAME) \
namespace SqPlus { \
  SQPLUS_DECLARE_TYPE_INFO(TYPE,NAME) \
  SQPLUS_DECLARE_TYPE_OPERATIONS(TYPE,NAME) \
  SQPLUS_DECLARE_TYPE_PUSH_SCRIPTED(TYPE,NAME) \
} // nameSpace SqPlus

#ifndef SQPLUS_CONST_OPT
#define DECLARE_INSTANCE_TYPE(TYPE) DECLARE_INSTANCE_TYPE_NAME_(TYPE,TYPE)
#define DECLARE_INSTANCE_TYPE_NAME(TYPE,NAME) DECLARE_INSTANCE_TYPE_NAME_(TYPE,NAME)
#define DECLARE_INSTANCE_TYPE_SCRIPTED(TYPE) DECLARE_INSTANCE_TYPE_NAME_SCRIPTED_(TYPE,TYPE)
#define DECLARE_INSTANCE_TYPE_NAME_SCRIPTED(TYPE,NAME) DECLARE_INSTANCE_TYPE_NAME_SCRIPTED_(TYPE,NAME)
#else
#define SQPLUS_DECLARE_INSTANCE_TYPE_CONST
#include "SqPlusConst.h"
#endif

and in in SqPlusConst.h all DECLARE_INSTANCE_TYPE_NAME_SCRIPTED-related code to

#define SQPLUS_DECLARE_TYPE_OPERATIONS_CONST(TYPE, NAME) \
  inline bool		Match(TypeWrapper<const TYPE &>,HSQUIRRELVM v,int idx) { \
    return  GetInstance<TYPE,false>(v,idx) != NULL; } \
  inline const TYPE & Get(TypeWrapper<const TYPE &>,HSQUIRRELVM v,int idx) { \
    return *GetInstance<TYPE,true>(v,idx); } \
  inline void PushNative(HSQUIRRELVM v,const TYPE * value) { \
    if (!value)  sq_pushnull(v); \
    else if (!CreateNativeClassInstance(v,GetTypeName(*value),(TYPE*)value,0)) \
      throw SquirrelError(_T("Push(): could not create INSTANCE (check registration name)")); } \
  inline void PushNative(HSQUIRRELVM /*v*/,const TYPE & value) { \
    if (!CreateCopyInstance(GetTypeName(value),value)) \
      throw SquirrelError(_T("Push(): could not create INSTANCE copy (check registration name)")); }

#define SQPLUS_DECLARE_TYPE_PUSH_NATIVE_CONST(TYPE, NAME) \
  inline void Push(HSQUIRRELVM v,const TYPE * value) { PushNative(v, value); } \
  inline void Push(HSQUIRRELVM v,const TYPE & value) { PushNative(v, value); }

#define SQPLUS_DECLARE_TYPE_PUSH_SCRIPTED_CONST(TYPE, NAME) \
  inline void Push(HSQUIRRELVM v, const TYPE * value) { \
    if (!value) sq_pushnull(v); \
    else if (value->scriptObjHandle._type != OT_NULL)  Push(v, SquirrelObject(value->scriptObjHandle)); \
    else PushNative(v, value); } \
  inline void Push(HSQUIRRELVM v, const TYPE & value) { \
    if (value.scriptObjHandle._type != OT_NULL) Push(v, SquirrelObject(value.scriptObjHandle)); \
    else PushNative(v, value); }

#undef SQPLUS_DECLARE_INSTANCE_TYPE_CONST

#define DECLARE_INSTANCE_TYPE_NAME_CONST(TYPE,NAME) \
DECLARE_INSTANCE_TYPE_NAME_(TYPE,NAME) \
namespace SqPlus { \
  SQPLUS_DECLARE_TYPE_OPERATIONS_CONST(TYPE, NAME) \
  SQPLUS_DECLARE_TYPE_PUSH_NATIVE_CONST(TYPE, NAME) \
} // nameSpace SqPlus

#define DECLARE_INSTANCE_TYPE_NAME_SCRIPTED_CONST(TYPE,NAME) \
DECLARE_INSTANCE_TYPE_NAME_SCRIPTED_(TYPE,NAME) \
namespace SqPlus { \
  SQPLUS_DECLARE_TYPE_OPERATIONS_CONST(TYPE, NAME) \
  SQPLUS_DECLARE_TYPE_PUSH_SCRIPTED_CONST(TYPE, NAME) \
} // nameSpace SqPlus

#define DECLARE_INSTANCE_TYPE(TYPE) DECLARE_INSTANCE_TYPE_NAME_CONST(TYPE,TYPE)
#define DECLARE_INSTANCE_TYPE_NAME(TYPE,NAME) DECLARE_INSTANCE_TYPE_NAME_CONST(TYPE,NAME)
#define DECLARE_INSTANCE_TYPE_SCRIPTED(TYPE) DECLARE_INSTANCE_TYPE_NAME_SCRIPTED_CONST(TYPE,TYPE)
#define DECLARE_INSTANCE_TYPE_NAME_SCRIPTED(TYPE,NAME) DECLARE_INSTANCE_TYPE_NAME_SCRIPTED_CONST(TYPE,NAME)

Then it is possible to declare class with DECLARE_INSTANCE_TYPE_SCRIPTED(). Note that it must have member variable

HSQOBJECT scriptObjHandle;

It can be use like

class Walker
{

HSQOBJECT scriptObjHandle;
				
int construct(HSQUIRRELVM v)
{
  StackHandler sa(v);

  Walker *self = new Walker();
  self->scriptObjHandle = sa.GetObjectHandle(1);
  self->dieHandler = SqPlus::SquirrelFunction<void>(self->scriptObjHandle, _T("onDie"));

  int result = SqPlus::PostConstruct<Walker>(v, self, release);

  sq_addref(v, &self->scriptObjHandle);

  return result;
}

~Walker()
{
  if (!destroyed)
  {
    destroyed = true;

    G_ASSERT(SquirrelVM::GetVMPtr());

    onDieHandler.reset();
    sq_release(SquirrelVM::GetVMPtr(), &scriptObjHandle);
  }
}

}

DECLARE_INSTANCE_TYPE_SCRIPTED(Walker)

Now it is possible to subclass this class in script and when passed to script functions it will be exactly the same instance as one that was created.