#pragma once #include #include #include #include "common/ICriticalSection.h" struct SKSESerializationInterface; class TESForm; class VMClassRegistry; // Serializable classes deriving from ISKSEObject must define a // serialization constructor that takes SerializationTag as the single argument. // After it has been called, either Load() is used to fill in the data, // or in case the load failed, the instance is destroyed again. struct SerializationTag {}; /// /// ISKSEObject - Interface for a heap allocated, co-save serializable object. /// class ISKSEObject { public: virtual ~ISKSEObject() {} virtual const char* ClassName() const = 0; virtual UInt32 ClassVersion() const = 0; virtual bool Save(SKSESerializationInterface* intfc) = 0; virtual bool Load(SKSESerializationInterface* intfc, UInt32 version) = 0; }; /// /// SKSEObjectFactory /// class ISKSEObjectFactory { public: virtual ~ISKSEObjectFactory() {} virtual ISKSEObject* Create() const = 0; virtual const char* ClassName() const = 0; }; template class ConcreteSKSEObjectFactory : public ISKSEObjectFactory { public: virtual ISKSEObject* Create() const { SerializationTag tag; return new T( tag ); } virtual const char* ClassName() const { SerializationTag tag; T tempInstance(tag); return tempInstance.ClassName(); } }; /// /// SKSEObjectRegistry /// class SKSEObjectRegistry { private: typedef std::map FactoryMapT; public: template bool RegisterClass() { ConcreteSKSEObjectFactory factory; RegisterFactory(&factory); return true; } virtual void RegisterFactory(ISKSEObjectFactory * factory); virtual const ISKSEObjectFactory* GetFactoryByName(const char* name) const; private: // Stores the vtables directly FactoryMapT factoryMap_; }; /// /// SKSEPersistentObjectStorage /// class SKSEPersistentObjectStorage { struct Entry; // Note: handle = index + 1 // +1, because in previous versions the invalid handle was 0 so people // might test for != 0 public: // Transfer ownership to registry template SInt32 StoreObject(T* obj, UInt32 owningStackId) {// lock_ return Store(obj, owningStackId); }// ~lock_ // Access object while keeping in storage template T* AccessObject(SInt32 handle) {// lock_ return reinterpret_cast(Access(handle)); }// ~lock_ // Remove object from storage and take ownership of the pointer template T* TakeObject(SInt32 handle) {// lock_ return reinterpret_cast(Take(handle)); }// lock_ virtual SInt32 Store(ISKSEObject* obj, UInt32 owningStackId); virtual ISKSEObject* Access(SInt32 handle); virtual ISKSEObject* Take(SInt32 handle); bool Save(SKSESerializationInterface* intfc); bool Load(SKSESerializationInterface* intfc, UInt32 version); void CleanDroppedStacks(); void ClearAndRelease(); enum { kSaveVersion = 1 }; private: struct Entry { ISKSEObject* obj; UInt32 owningStackId; }; typedef std::vector DataT; typedef std::vector IndexCacheT; ICriticalSection lock_; DataT data_; IndexCacheT freeIndices_; }; /// /// Serialization helpers /// bool WriteSKSEObject(SKSESerializationInterface* intfc, ISKSEObject* obj); bool ReadSKSEObject(SKSESerializationInterface* intfc, ISKSEObject*& objOut); /// /// Global instances /// SKSEObjectRegistry& SKSEObjectRegistryInstance(); SKSEPersistentObjectStorage& SKSEObjectStorageInstance();