convert line ends
[canaan.git] / prj / cam / src / object / propert_.h
blob8e466647a420963fc2874a2797417e214c8eac05
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 // $Header: r:/t2repos/thief2/src/object/propert_.h,v 1.31 2000/01/29 13:24:24 adurant Exp $
7 #pragma once
9 #ifndef PROPERT__H
10 #define PROPERT__H
12 #include <propstor.h>
13 #include <propman.h>
14 #include <propknow.h>
15 #include <dbtype.h>
16 #include <propbase.h>
17 #include <dynarray.h>
18 #include <pstordel.h>
19 #include <traittyp.h>
20 #include <prpstats.h>
21 #include <propnet.h>
22 #include <propinst.h>
24 F_DECLARE_INTERFACE(ITrait);
25 F_DECLARE_INTERFACE(IPropertyStore);
26 F_DECLARE_INTERFACE(INetManager);
27 F_DECLARE_INTERFACE(IObjectNetworking);
29 template <class T> class cSimpleDList;
31 ////////////////////////////////////////////////////////////
33 // cPropertyBase
35 // Basic support for constraints, listeners with no property store.
37 // Not a COM object
39 ////////////////////////////////////////////////////////////
41 class cPropertyBase: public cPropertyManagerKnower
43 struct Listener
45 static PropListenerHandle gNextHandle;
47 PropertyListenMsgSet interests;
48 PropertyListenFunc func;
49 PropListenerData data;
50 PropListenerHandle handle;
52 Listener(PropertyListenMsgSet i, PropertyListenFunc f,
53 PropListenerData d)
54 :interests(i),func(f),data(d),handle(gNextHandle++) {};
58 typedef cSimpleDList<PropertyID> PropIDList;
61 public:
62 // Destructor
63 virtual ~cPropertyBase ();
65 // Describe myself
66 const sPropertyDesc* Describe () const {return &mDesc;};
68 // Return my id
69 PropertyID GetID() const { return mID; } ;
71 // Add a listener
72 PropListenerHandle Listen(PropertyListenMsgSet interests, PropertyListenFunc func, PropListenerData data);
74 void Unlisten(PropListenerHandle handle);
77 // Notify the property system that the object no longer exists
78 void Notify (ePropertyNotifyMsg msg, PropNotifyData data);
81 // Call property listeners
82 void CallListeners(ePropertyListenMsg msg, ObjID obj, sDatum value, ObjID donor = OBJ_NULL);
84 // Recompile constraints
85 void CompileConstraints(void);
87 // Enforce constraints
88 void EnforceRequirements(ObjID obj);
89 void EnforceImplications(ObjID obj);
91 void CreateEditor(IProperty* prop);
94 // Overridables
97 // A built-in listener for the property's own use
98 virtual void OnListenMsg(ePropertyListenMsg , ObjID , uPropListenerValue ) {};
100 // Create the property's editor
102 protected:
103 // Constructor; tell it the name of your property and the implementation.
104 // pimpl must be constructed first, but the cProperty then takes over
105 // management of it.
106 cPropertyBase (const sPropertyDesc *desc);
108 sPropertyDesc mDesc; // Descriptor
109 PropertyID mID; // unique to each cProperty
110 cDynArray<Listener> mListeners; // listener set
111 PropIDList* mpImplied; // Properties I imply
112 PropIDList* mpRequired; // Properties I require
115 ////////////////////////////////////////////////////////////
117 // cStoredProperty
119 // Common code for properties that use IPropertyStore, and
120 // Have ITraits for inheritance/instantiation.
122 // Not a COM object.
124 ////////////////////////////////////////////////////////////
126 // Forward decl of our classes used for side interfaces.
127 class cStoredPropertyStats;
128 class cStoredPropertyNetworking;
130 // Stored property instrumentation macros
131 #define STOREDPROP_AUTO_BLAME() PROP_AUTO_BLAME(mAllocName)
132 #define STOREDPROP_TIMER(x) PROP_TIMER_STATS_IDX(mStoreStats,kProp##x##Time)
133 #define STOREDPROP_TIMER_RESTART(x) PROP_TIMER_RESTART(mStoreStats,kProp##x##Time)
135 class cStoredProperty: public cPropertyBase
138 public:
140 // Query Interface
141 HRESULT QI(IUnknown* me, REFIID id, void ** ppI);
143 // Make the property relevant for this object
144 HRESULT Create(ObjID obj);
146 // Decide that this property is irrelevant for the object
147 HRESULT Delete (ObjID obj);
149 // Copy the property
150 HRESULT Copy(ObjID targ, ObjID src);
152 // Notify the property of database changes
153 void Notify (ePropertyNotifyMsg msg, PropNotifyData data);
155 // Is this property relevant to the given object?
156 BOOL IsSimplyRelevant(ObjID obj) const
158 STOREDPROP_TIMER(Relevant);
159 return mpStore->Relevant (obj);
162 // Is this property relevant to the given object?
163 BOOL IsRelevant(ObjID obj) const
165 STOREDPROP_TIMER(Relevant);
166 if (mpStore->Relevant(obj))
167 return TRUE;
169 PROP_TIMER_STOP();
170 obj = GetDonor(obj);
171 PROP_TIMER_START();
173 return mpStore->Relevant(obj);
176 HRESULT Set(ObjID obj,sDatum val);
178 // modify a property in place, call listeners
179 BOOL Touch(ObjID obj,sDatum* val);
181 // Iteration
182 void IterStart (sPropertyObjIter* iter) const
184 STOREDPROP_TIMER(IterStart);
186 mpStore->IterStart(iter);
189 BOOL IterNext (sPropertyObjIter* iter, ObjID* next) const
191 sDatum dummy;
192 STOREDPROP_TIMER(IterNext);
193 return mpStore->IterNext(iter,next,&dummy);
196 void IterStop(sPropertyObjIter* iter) const
198 STOREDPROP_TIMER(IterStop);
199 mpStore->IterStop(iter);
202 // Find the object an object inherits from
203 ObjID GetDonor(ObjID obj) const;
205 // Find the object that the property would be copied from on create
206 ObjID GetExemplar(ObjID obj) const;
208 PropListenerHandle Listen(PropertyListenMsgSet interests, PropertyListenFunc func, PropListenerData data);
210 ~cStoredProperty();
212 // Swap out for a new store
213 void SetStore(IPropertyStore* store) ;
215 void SetOps(IDataOps* ops) { mpStore->SetOps(ops); };
217 // Concrete requirements enforcement
218 void SetRebuildConcretes(BOOL fRebuild);
219 void RebuildConcretes(ObjID obj);
220 void RebuildOneConcrete(ObjID obj);
221 static void LGAPI RebuildHierarchyListener(const sHierarchyMsg* msg,
222 HierarchyListenerData data);
224 // Return the mpStats structure pointer.
225 sPropTimeStats* GetStoreTimeStats(){return &mStoreStats;};
228 // Overridables
231 // A built-in listener for the property's own use
232 virtual void OnListenMsg(ePropertyListenMsg , ObjID , uPropListenerValue );
235 virtual void RebuildConcrete(ObjID obj, BOOL fIsRelevant, uPropListenerValue, ObjID donor) {};
237 protected:
238 friend class cStoredPropertyNetworking;
240 enum eFlags
242 kListeningHierarchy = 0x01,
243 kRebuildConcretes = 0x02
246 // Call property listeners, possibly doing our own updating
247 void CallListeners(ePropertyListenMsg msg, ObjID obj, sDatum value, ObjID donor = OBJ_NULL);
250 cStoredProperty (const sPropertyDesc *desc, IPropertyStore * pStore);
253 void InitTraits(void);
254 void Save(ITagFile* file, edbFiletype filetype);
255 void Load(ITagFile* file, edbFiletype filetype);
256 void write_obj(ObjID obj, IDataOpsFile* file, edbFiletype filetype);
257 void read_obj(IDataOpsFile* file, edbFiletype filetype, uint version);
259 IPropertyStore *mpStore; // Property store
260 ITrait* mpDonors; // My trait for inheritance
261 ITrait* mpExemplars; // My trait for creation
262 unsigned mFlags;
264 // This is for the IPropertyNetworking interface, which handles network messages.
265 // NULL for properties that don't require networking (kPropertyChangeLocally).
266 cStoredPropertyNetworking* mpNetProp;
268 // This should be #Ifndef SHIP or something
269 cStoredPropertyStats* mpStats; // our stat interface
270 sPropTimeStats mStoreStats; // actual gather stats
271 const char* mAllocName; // our name for lgalloc blame
273 // Interfaces that are needed by & shared by all properties.
274 static INetManager *gmNetMan;
275 static IObjectNetworking *gmObjNet;
279 ////////////////////////////////////////////////////////////
281 // cUnknownProperty
283 // Has only IUnknown methods
285 ////////////////////////////////////////////////////////////
287 template <class IFACE, const GUID* pIID>
288 class cUnknownProperty : public cCTUnaggregated<IFACE,pIID,kCTU_Default>
290 public:
292 virtual ~cUnknownProperty() {};
297 ////////////////////////////////////////////////////////////
299 // cProperty
301 // Templatized on interface, but only implements IProperty methods
302 // If you want to roll your own (slow) accessors, use this
304 ////////////////////////////////////////////////////////////
306 template <class IFACE, const GUID *pIID>
307 class cProperty: public cUnknownProperty<IFACE,pIID>,
308 public cStoredProperty
310 typedef cStoredProperty cBase;
312 public:
315 // Describe myself
316 STDMETHOD_(const sPropertyDesc*, Describe) () const { return cBase::Describe(); };
318 // Return my id
319 STDMETHOD_(PropertyID,GetID)() const { return cBase::GetID(); } ;
321 // Make this property relevant for this object
322 STDMETHOD(Create) (ObjID obj) { return cBase::Create(obj); } ;
324 // Decide that this property is irrelevant for the object
325 STDMETHOD(Delete) (ObjID obj) { return cBase::Delete(obj); } ;
327 // Copy the prop from one obj to another
328 STDMETHOD(Copy) (ObjID targ,ObjID src) { return cBase::Copy(targ,src); } ;
330 // Notify the property system that the object no longer exists
331 STDMETHOD_(void,Notify) (ePropertyNotifyMsg msg, PropNotifyData data)
333 // @TODO: move this someplace more appropriate!
334 if (!mCalledCreateEditor)
336 CreateEditor();
337 mCalledCreateEditor = TRUE;
339 cBase::Notify(msg,data);
342 // Is this property relevant to the given object?
343 STDMETHOD_(BOOL,IsRelevant)(ObjID obj) const {return cBase::IsRelevant(obj); } ;
344 STDMETHOD_(BOOL,IsSimplyRelevant)(ObjID obj) const {return cBase::IsSimplyRelevant(obj); } ;
346 // modify an object in place
347 STDMETHOD_(BOOL,Touch)(ObjID obj) {return cBase::Touch(obj,NULL); } ;
349 // Add a listener
350 STDMETHOD_(PropListenerHandle, Listen)(PropertyListenMsgSet interests, PropertyListenFunc func, PropListenerData data) { return cBase::Listen(interests,func,data); } ;
352 STDMETHOD(Unlisten)(PropListenerHandle handle) { cBase::Unlisten(handle); return S_OK; };
354 STDMETHOD_(void, IterStart) (sPropertyObjIter* iter) const { cBase::IterStart(iter);} ;
355 STDMETHOD_(BOOL, IterNext) (sPropertyObjIter* iter, ObjID* next) const
356 { return cBase::IterNext(iter,next);};
357 STDMETHOD_(void, IterStop) (sPropertyObjIter* iter) const { cBase::IterStop(iter);} ;
359 STDMETHOD_(const sPropertyTypeDesc*, DescribeType)() const
360 { static sPropertyTypeDesc desc = { "Unknown", 0}; return &desc; };
362 STDMETHOD(QueryInterface)(REFIID id, void ** ppI)
364 if (id == *pIID)
366 *ppI = this;
367 AddRef();
368 return S_OK;
370 if (id == IID_IPropertyStore)
372 *ppI = &mStoreDel;
373 AddRef();
374 return S_OK;
376 else
377 return cBase::QI((IUnknown*)this,id,ppI);
380 void SetStore(IPropertyStore* store)
382 cBase::SetStore(store);
383 mStoreDel.SetStore(mpStore);
386 protected:
387 // Create the property editor
388 virtual void CreateEditor() { cPropertyBase::CreateEditor(this); };
390 // constructor
391 cProperty(const sPropertyDesc *desc, IPropertyStore *store)
392 : cBase(desc,store),
393 mStoreDel(mpStore,this),
394 mCalledCreateEditor(FALSE)
396 GetManager()->AddProperty (this, &mID);
397 if (mpStore)
398 mpStore->SetID(mID);
401 // Destructor
402 virtual ~cProperty () { GetManager()->DelProperty(this); };
405 cDelegatingPropertyStore mStoreDel; // the store I hand out when QI'd for one.
406 BOOL mCalledCreateEditor; // have I created an editor yet? (sigh)
409 ////////////////////////////////////////////////////////////
411 // cGenericProperty
413 // Generic property, with (slow) accessors, templatized on type
414 // Accessors must be by 32-bit (or smaller) value.
416 ////////////////////////////////////////////////////////////
418 template <class IFACE, const GUID* IID, class TYPE>
419 class cGenericProperty : public cProperty<IFACE,IID>
421 protected:
422 // We use this to do type-conversion
423 union uPropVal
425 TYPE t;
426 void* d;
428 uPropVal(const TYPE& tt) : t(tt) {};
431 public:
432 cGenericProperty(const sPropertyDesc* desc, IPropertyStore* store = NULL, IDataOps* ops = NULL)
433 : cProperty<IFACE,IID>(desc,store)
435 AssertMsg(sizeof(TYPE) == sizeof(sDatum),"Can't make property accessors for non-32 bit type");
436 if (ops)
437 store->SetOps(ops);
440 STDMETHOD_(BOOL,Get)(ObjID obj, TYPE (*pval)) const
442 STOREDPROP_TIMER(Get);
444 sDatum* pdat = (sDatum*)pval;
445 BOOL result = mpStore->Get(obj,pdat);
446 if (!result)
448 PROP_TIMER_STOP();
449 ObjID donor = GetDonor(obj);
450 PROP_TIMER_START();
451 if (donor != OBJ_NULL)
452 result = mpStore->Get(donor,pdat);
454 return result;
457 STDMETHOD_ (BOOL, GetSimple) (ObjID obj, TYPE (*ptr)) const
459 STOREDPROP_TIMER(Get);
460 sDatum* pdat = (sDatum*)ptr;
461 return mpStore->Get(obj,pdat);
464 STDMETHOD(Set) (ObjID obj, TYPE val)
466 uPropVal dat = val;
467 return cBase::Set(obj, dat.d);
470 STDMETHOD_ (BOOL, IterNextValue) (sPropertyObjIter* iter,ObjID* next, TYPE (*val)) const
472 STOREDPROP_TIMER(IterNext);
473 sDatum* pdat = (sDatum*)val;
474 return mpStore->IterNext(iter,next,pdat);
477 STDMETHOD_(BOOL,TouchValue)(ObjID obj, TYPE val)
479 uPropVal dat = val;
480 sDatum d = dat.d;
481 return cBase::Touch(obj,&d);
486 ////////////////////////////////////////////////////////////
488 // cSpecificProperty
490 // Generic property, templatized on type and on store type for speed
491 // Accessors must be by 32-bit value.
493 ////////////////////////////////////////////////////////////
496 // Keep my store from deleting itself
499 template<class STORE>
500 class cNonDeletingStore : public STORE
502 void OnFinalRelease() {};
506 template <class IFACE, const GUID* IID, class TYPE, class STORE>
507 class cSpecificProperty : public cProperty<IFACE,IID>
509 protected:
510 // We use this to do type-conversion
511 union uPropVal
513 TYPE t;
514 void* d;
516 uPropVal(const TYPE& tt) : t(tt) {};
519 public:
522 cSpecificProperty(const sPropertyDesc* desc)
523 : cProperty<IFACE,IID>(desc,NULL)
525 AssertMsg(sizeof(TYPE) == sizeof(sDatum),"Can't make property accessors for non-32 bit type");
527 // Since we circumvent the mpStore a lot, we can't deal with the auto-mixing
528 // done by kpropertyconcrete
529 Assert_(!(desc->flags & kPropertyConcrete));
531 // We can't pass &mStore into the constructor, because it hasn't been initialized
532 // yet, so we set it up here instead.
533 SetStore(&mStore);
536 ~cSpecificProperty()
538 mStore.Reset();
539 // unset the store before it goes away
540 SetStore(NULL);
544 // Store accessor
547 STORE& Store() { return mStore; };
550 // METHODS
553 STDMETHOD_(BOOL,Get)(ObjID obj, TYPE (*pval)) const
555 STOREDPROP_TIMER(Get);
556 sDatum* pdat = (sDatum*)pval;
557 BOOL result = mStore.Get(obj,pdat);
558 if (!result)
560 PROP_TIMER_STOP();
561 ObjID donor = GetDonor(obj);
562 PROP_TIMER_START();
564 if (donor != OBJ_NULL)
565 result = mStore.Get(donor,pdat);
567 return result;
570 STDMETHOD_ (BOOL, GetSimple) (ObjID obj, TYPE (*ptr)) const
572 STOREDPROP_TIMER(Get);
573 sDatum* pdat = (sDatum*)ptr;
574 return mStore.Get(obj,pdat);
577 STDMETHOD(Set) (ObjID obj, TYPE val)
579 uPropVal dat = val;
580 return cBase::Set(obj, dat.d);
583 STDMETHOD_ (BOOL, IterNextValue) (sPropertyObjIter* iter,ObjID* next, TYPE (*val)) const
585 STOREDPROP_TIMER(IterNext);
586 sDatum* pdat = (sDatum*)val;
587 return mStore.IterNext(iter,next,pdat);
590 STDMETHOD_(BOOL,TouchValue)(ObjID obj, TYPE val)
592 uPropVal dat = val;
593 sDatum d = dat.d;
594 return cBase::Touch(obj,&d);
597 protected:
598 cNonDeletingStore<STORE> mStore;
605 // Use this macro to create the standard DescribeType method for a type
608 #define STANDARD_DESCRIBE_TYPE(type) \
609 STDMETHOD_(const sPropertyTypeDesc*, DescribeType)() const \
610 { static sPropertyTypeDesc desc = { #type, sizeof(type)}; return &desc; }
613 #endif // PROPERT__H