janwas
c0ed950657
this snowballed into a massive search+destroy of the hodgepodge of mostly equivalent types we had in use (int, uint, unsigned, unsigned int, i32, u32, ulong, uintN). it is more efficient to use 64-bit types in 64-bit mode, so the preferred default is size_t (for anything remotely resembling a size or index). tile coordinates are ssize_t to allow more efficient conversion to/from floating point. flags are int because we almost never need more than 15 distinct bits, bit test/set is not slower and int is fastest to type. finally, some data that is pretty much directly passed to OpenGL is now typed accordingly. after several hours, the code now requires fewer casts and less guesswork. other changes: - unit and player IDs now have an "invalid id" constant in the respective class to avoid casting and -1 - fix some endian/64-bit bugs in the map (un)packing. added a convenience function to write/read a size_t. - ia32: change CPUID interface to allow passing in ecx (required for cache topology detection, which I need at work). remove some unneeded functions from asm, replace with intrinsics where possible. This was SVN commit r5942.
151 lines
4.3 KiB
C++
151 lines
4.3 KiB
C++
/*
|
|
CSynchedJSObject
|
|
|
|
DESCRIPTION:
|
|
A helper class for CJSObject that enables a callback to be called
|
|
whenever an attribute of the class changes and enables all (synched)
|
|
properties to be set and retrieved as strings for network sync.
|
|
|
|
All string conversions are performed by specific functions that use a
|
|
strictly (hrm) defined format - or at least a format that is specific
|
|
for the type in question (which is why JSParseString can't be used -
|
|
the JS interface's ToString function is also not usable since it often
|
|
produces a human-readable format that doesn't parse well and might
|
|
change outside the control of the network protocol).
|
|
|
|
This replaces CAttributeMap for both player and game attributes.
|
|
|
|
USAGE:
|
|
First you must create your subclass, make it inherit from
|
|
CSynchedJSObject and implement the pure virtual method Update (see
|
|
prototype below)
|
|
|
|
Then you may use it just like CJSObject (see ScriptableObject.h) - with
|
|
one exception: Any property you want to be synchronized (i.e. have the
|
|
new property functionality including the update callback) is added using
|
|
the AddSynchedProperty method instead: AddSynchedProperty(name, &m_Property)
|
|
|
|
The extra arguments that exist in the AddProperty method haven't been
|
|
implemented (if you by any chance would need to, just do it ;-)
|
|
|
|
*/
|
|
|
|
#ifndef INCLUDED_SYNCHEDJSOBJECT
|
|
#define INCLUDED_SYNCHEDJSOBJECT
|
|
|
|
#include "ps/CStr.h"
|
|
#include "ScriptableObject.h"
|
|
|
|
template <typename T>
|
|
void SetFromNetString(T &data, const CStrW& string);
|
|
|
|
template <typename T>
|
|
CStrW ToNetString(const T &data);
|
|
|
|
#define TYPE(type) \
|
|
template <> CStrW ToNetString(const type &data); \
|
|
template <> void SetFromNetString(type &data, const CStrW& string);
|
|
|
|
TYPE(size_t)
|
|
TYPE(CStrW)
|
|
|
|
#undef TYPE
|
|
|
|
class ISynchedJSProperty: public IJSProperty
|
|
{
|
|
public:
|
|
virtual void FromString(const CStrW& value)=0;
|
|
virtual CStrW ToString()=0;
|
|
};
|
|
|
|
// non-templated base class
|
|
struct CSynchedJSObjectBase
|
|
{
|
|
typedef void (*UpdateFn)(CSynchedJSObjectBase *owner);
|
|
|
|
template <typename PropType, bool ReadOnly = false>
|
|
class CSynchedJSProperty: public ISynchedJSProperty
|
|
{
|
|
PropType *m_Data;
|
|
CStrW m_Name;
|
|
CSynchedJSObjectBase *m_Owner;
|
|
UpdateFn m_Update;
|
|
|
|
virtual void Set(JSContext* cx, IJSObject* UNUSED(owner), jsval value)
|
|
{
|
|
if (!ReadOnly)
|
|
{
|
|
if (ToPrimitive(cx, value, *m_Data))
|
|
{
|
|
m_Owner->Update(m_Name, this);
|
|
if (m_Update)
|
|
m_Update(m_Owner);
|
|
}
|
|
}
|
|
}
|
|
virtual jsval Get(JSContext* UNUSED(cx), IJSObject* UNUSED(owner))
|
|
{
|
|
return ToJSVal(*m_Data);
|
|
}
|
|
|
|
virtual void ImmediateCopy(IJSObject* UNUSED(CopyFrom), IJSObject* UNUSED(CopyTo), IJSProperty* other)
|
|
{
|
|
*m_Data = *( ((CSynchedJSProperty<PropType, ReadOnly>*)other)->m_Data );
|
|
}
|
|
|
|
virtual void FromString(const CStrW& value)
|
|
{
|
|
SetFromNetString(*m_Data, value);
|
|
if (m_Update)
|
|
m_Update(m_Owner);
|
|
}
|
|
|
|
virtual CStrW ToString()
|
|
{
|
|
return ToNetString(*m_Data);
|
|
}
|
|
|
|
public:
|
|
inline CSynchedJSProperty(const CStrW& name, PropType* native, CSynchedJSObjectBase *owner, UpdateFn update=NULL):
|
|
m_Data(native),
|
|
m_Name(name),
|
|
m_Owner(owner),
|
|
m_Update(update)
|
|
{
|
|
}
|
|
};
|
|
|
|
typedef STL_HASH_MAP<CStrW, ISynchedJSProperty *, CStrW_hash_compare> SynchedPropertyTable;
|
|
typedef SynchedPropertyTable::iterator SynchedPropertyIterator;
|
|
SynchedPropertyTable m_SynchedProperties;
|
|
|
|
protected:
|
|
virtual ~CSynchedJSObjectBase() { }
|
|
|
|
// Called every time a property changes.
|
|
// This is where the individual callbacks are dispatched from.
|
|
virtual void Update(const CStrW& name, ISynchedJSProperty *prop)=0;
|
|
|
|
public:
|
|
ISynchedJSProperty *GetSynchedProperty(const CStrW& name);
|
|
|
|
typedef void (IterateCB)(const CStrW& name, ISynchedJSProperty *prop, void *userdata);
|
|
void IterateSynchedProperties(IterateCB *cb, void *userdata);
|
|
};
|
|
|
|
template <typename Class>
|
|
class CSynchedJSObject: public CJSObject<Class>, public CSynchedJSObjectBase
|
|
{
|
|
protected:
|
|
// Add a property to the object; if desired, a callback is called every time it changes.
|
|
// Replaces CJSObject's AddProperty.
|
|
template <typename T> void AddSynchedProperty(const CStrW& name, T *native, UpdateFn update=NULL)
|
|
{
|
|
ISynchedJSProperty *prop=new CSynchedJSProperty<T>(name, native, this, update);
|
|
this->m_NonsharedProperties[name]=prop;
|
|
this->m_SynchedProperties[name]=prop;
|
|
}
|
|
};
|
|
|
|
#endif
|