#pragma once #include "vec3.h" #include "vec2.h" #include "quaternion.h" #include "line3d.h" #include "util/refcount.h" #include "util/link_container.h" #include "threads.h" #include "general_states.h" #include "util/random.h" #include #include #ifndef OBJ_TARGETS #define OBJ_TARGETS 3 #endif const unsigned ObjectTypeBitOffset = 26; const unsigned ObjectTypeMask = (unsigned)(0xFF << ObjectTypeBitOffset); const unsigned ObjectIDMask = 0xFFFFFFFF >> (32 - ObjectTypeBitOffset); extern unsigned ObjectTypeCount; class Object; class ObjectGroup; struct PhysicsItem; struct ObjectMessage; class asIScriptFunction; class asIScriptObject; class asITypeInfo; class SaveFile; enum ScriptObjectCallback { SOC_init, SOC_postInit, SOC_destroy, SOC_groupDestroyed, SOC_tick, SOC_ownerChange, SOC_damage, SOC_repair, SOC_syncInitial, SOC_syncDetailed, SOC_syncDelta, SOC_recvInitial, SOC_recvDetailed, SOC_recvDelta, SOC_save, SOC_load, SOC_postLoad, SOC_COUNT }; struct ScriptObjectType { unsigned id; std::string name; std::string script; mutable threads::atomic_int nextID; asITypeInfo* scriptType; asIScriptFunction* functions[SOC_COUNT]; const StateDefinition* states; std::vector componentOffsets; std::vector optionalComponents; size_t blueprintOffset; scripts::GenericType* refType; scripts::GenericType* handleType; ScriptObjectType(); void bind(const char* module, const char* decl); asIScriptObject* create() const; }; void prepScriptObjectTypes(); void addObjectStateValueTypes(); void setScriptObjectStates(); void bindScriptObjectTypes(); ScriptObjectType* getScriptObjectType(const std::string& name); ScriptObjectType* getScriptObjectType(int index); unsigned getScriptObjectTypeCount(); //Retrieve the object referred to by the given id. // Grabs the object before returning it, so it needs // to be dropped afterwards Object* getObjectByID(unsigned id, bool create = false); ScriptObjectType* getObjectTypeFromID(unsigned id); void invalidateUninitializedObjects(); enum ObjectFlag : unsigned { //Object is not in the process of being deleted objValid = 0x1, //Object needs to go to sleep (going invalid) objStopTicking = 0x2, //Object has something to do and should ignore timeout delay objWakeUp = 0x4, //Object has been allocated as a reference-only object, and does not yet have data objUninitialized = 0x8, //Object has been flagged to send a data delta the next time it can objSendDelta = 0x10, //Object has been flagged as a focus object, this has various //effects for interpolation and multiplayer objFocus = 0x20, //Object is currently engaged in combat objEngaged = 0x40, //Object does not have physics objNoPhysics = 0x80, //Object is selected objSelected = 0x100, //Object is considered as in combat objCombat = 0x200, //Multiplayer clients should be able to get information even out of vision objMemorable = 0x400, //Whether it has been given a name objNamed = 0x800, //Whether the object should nudge movable objects (enforced by scripts) objNoCollide = 0x1000, //Whether the object can not receive damage by being hit by projectiles objNoDamage = 0x2000, objQueueDestroy = 0x80000000 }; const unsigned objFlagSaveMask = ~(objSelected); namespace net { struct Message; }; namespace scene { class Node; }; class Empire; struct LockGroup; class TimedEffect; class DamageEvent; struct DeferredObjMessage { DeferredObjMessage* next, *prev; ObjectMessage* msg; }; class Object { public: static bool GALAXY_CREATION; mutable threads::atomic_int references; heldPointer targets[OBJ_TARGETS]; //Object tree unsigned id; ObjectGroup* group; //Locking LockGroup* lockGroup; LockGroup* originalLock; unsigned lockHint; //Messages DeferredObjMessage* deferredMessages; void queueDeferredMessage(ObjectMessage* msg); DeferredObjMessage* fetchMessages(); //Ownership Empire* owner; //Vision bool alwaysVisible; float sightRange; float seeableRange; unsigned char visionTimes[32]; unsigned visibleMask, donatedVision, prevVisibleMask, sightedMask, sightDelay; //State variables threads::atomic_int flags; //Object spatial variables PhysicsItem* physItem; vec3d position, velocity, acceleration; quaterniond rotation; double radius; //The last time this Object ran its think() // - the parent is responsible for updating this double lastTick; double nextTick; //Effects std::vector effects; void addTimedEffect(const TimedEffect& eff); //Generic stats LinkMap stats; //Graphics tree scene::Node* node; std::string name; asIScriptObject* script; const ScriptObjectType* type; void init(); void postInit(); void setOwner(Empire* newOwner); bool isLocked() const; static Object* create(ScriptObjectType* type, LockGroup* lock = 0, int id = 0); void grab() const; void drop() const; inline const ScriptObjectType* GetType() const { return type; } void setFlag(ObjectFlag flag, bool val); bool getFlag(ObjectFlag flag) const; //Like set flag, but only succeeds if this call set the flag to that value bool setFlagSecure(ObjectFlag flag, bool val); //Flag access wrappers bool isValid() const; bool isInitialized() const; void wake(); void sleep(double seconds); //Focus is an object property to indicate //priority syncing and calculations. //The focus flag decays after a while and needs to //be set repeatedly on accessed objects. bool isFocus() const; void focus(); bool isVisibleTo(Empire* emp) const; bool isKnownTo(Empire* emp) const; unsigned updateVision(Object* target, unsigned depth); //Damage events void damage(DamageEvent& evt, double position, const vec2d& direction); void repair(double amount); //Targeting void updateTargets(); template bool findTargets(T& cb, int depth) { for(unsigned i = 0; i < OBJ_TARGETS; ++i) { Object* targ = targets[i].ptr; if(targ == this) continue; if(cb.result(targ)) return true; if(depth != 0) { if(targ->findTargets(cb, depth-1)) return true; } } return false; } static const unsigned char RANDOMIZE_TARGETS = 0; template bool findTargets(T& cb, int depth, unsigned char randomizer) { if(randomizer == RANDOMIZE_TARGETS) randomizer = (unsigned char)randomi(); else randomizer ^= (unsigned char)id; unsigned index = randomizer % OBJ_TARGETS; for(unsigned i = 0; i < OBJ_TARGETS; ++i, index = (index+1) % OBJ_TARGETS) { Object* targ = targets[index].ptr; if(targ == this) continue; if(cb.result(targ)) return true; if(depth != 0) { if(targ->findTargets(cb, depth-1, randomizer)) return true; } } return false; } //Network syncing void sendInitial(net::Message& msg); void sendDetailed(net::Message& msg); bool sendDelta(net::Message& msg); void recvDetailed(net::Message& msg, double fromTime); void recvDelta(net::Message& msg, double fromTime); //Saving & loading void save(SaveFile& file); void load(SaveFile& file); void postLoad(); //Management Object(ScriptObjectType* Type, LockGroup* group = 0, int id = 0); ~Object(); double think(double seconds); void flagDestroy() { setFlag(objQueueDestroy, true); setFlag(objWakeUp, true); } friend class Universe; void clearScripts(); private: void destroy(bool fromUniverse = false); }; Object* recvObjectInitial(net::Message& msg, double fromTime); void clearObjects(); struct ObjectLock { LockGroup* group; bool released; ObjectLock(Object* Obj, bool priority = false); void release(); ~ObjectLock(); };