/* ZPropertyBuffer.hpp Author: author_name Created: 8/30/2015 Purpose: The property buffer system is an allocator which holds entity property data in contiguous blocks of memory that can then be synchronized across the network when properties change, though properties can be kept in non-synchronized buffers for local use. The buffer keeps both a read and write copy of the properties which can be updated on call. This allocator does not lock, so any locking that would be required must be handled by the caller. In order to have proper synchronization, each entity that has properties allocated should have it's synchronized variables created in the same order on all machines. This will ensure that the data layouts are identical and proper synchronization can occur. License: TODO */ #pragma once #ifndef _ZPROPERTYBUFFER_HPP #define _ZPROPERTYBUFFER_HPP #include "ZSimulationDefs.hpp" #include "ZPropertyBufferUpdate.hpp" // forward decl struct PropertyPage; class ZNetworkUpdateStream; // class decl class ZPropertyBuffer { public: // key used to look up allocated data in the property buffer typedef uint64_t PropertyKey; // used to flag synchronization type (none, send, or receive) enum SyncMode { SYNC_NONE = 0, SYNC_SEND = 1, SYNC_RECV = 2, SYNC_ENUM_SIZE }; // data struct for property data struct Property { void* Read; // pointer to the read property void* Write; // pointer to the write property size_t Size; // size of the property PropertyKey Key; // the property key }; // c'tor ZPropertyBuffer(); // d'tor ~ZPropertyBuffer(); /* Allocates a chunk of memory in the property buffer given the entity id, the entity size, and whether or not the property should be synchronized. The read buffer for the property is returned. Allocations from these methods return static sized properties - they will not ever be able to increase in size - alloc a new property and remove the old one in order to increase size. The size limit on a synchronized property is 1024 bytes. In order to have proper synchronization, each entity that has properties allocated should have its synchronized variables created in the same order on all machines. This will ensure that the data layouts are identical and proper synchronization can occur. */ Property AllocProperty(eID id, size_t size, SyncMode mode = SYNC_NONE ); /* Deallocation methods, which deallocate previously allocated property data. The version which takes an entity id deallocates all data associated with that entity id. The version which takes a property key merely deallocates that particular property. Deallocating individual properties is not terribly fast, so avoid it where possible. */ void DeallocEntity(eID id); void DeallocProperty(PropertyKey key, size_t size); /* Flags a previously allocated property as modified. The size (in bytes) of the property is required. */ void FlagModified(PropertyKey key, size_t size); /* Updates the read properties from the write properties where modifications have happened. The version which takes an entity id will update a single entities properties. If told to synchronize, the buffer will queue up the network updates needed to sync the buffer state. */ void UpdateModified(bool sync, ZNetworkUpdateStream& stream); void UpdateModified(eID id, bool sync, ZNetworkUpdateStream& stream); /* Applies buffer updates that have been read from the network. These are applied directly to the read value of the property. */ void ApplyBufferUpdates(const ZArray& updates); private: /* synchronized and non-synchronized data storage */ ZArray Pages[2]; // the individual buffer pages (synchronized and local) ZHashMap IdPageMap; // maps the entity id to its page number ZArray Avail; // available indices from dealloc'd entities // given the property key will get the data, page, and synchronization flag void* GetData(PropertyKey key, int rw, PropertyPage** page_out = NULL, SyncMode* mode_out = NULL); // will alloc data for the property (searches page, otherwise makes new pages) Property AllocData(PropertyPage* page, eID id, uint32_t page_idx, size_t size, SyncMode mode); }; #endif