Files
starruler-linux/source/game/obj/obj_group.cpp
T
2018-07-17 14:15:37 +02:00

264 lines
5.3 KiB
C++

#include "obj_group.h"
#include "object.h"
#include "physics/physics_world.h"
#include "main/references.h"
#include "main/logging.h"
#include "util/save_file.h"
#include <map>
threads::ReadWriteMutex groupIDsLock;
threads::atomic_int nextGroupID(1);
std::map<int,ObjectGroup*> groups;
void registerObjectGroup(ObjectGroup* group, int id = -1) {
groupIDsLock.writeLock();
group->grab();
if(id == -1) {
group->id = nextGroupID++;
}
else {
group->id = id;
nextGroupID = id+1;
}
groups[group->id] = group;
groupIDsLock.release();
}
void unregisterObjectGroup(ObjectGroup* group) {
groupIDsLock.writeLock();
groups.erase(group->id);
group->drop();
groupIDsLock.release();
}
ObjectGroup* ObjectGroup::byID(int id) {
ObjectGroup* group = 0;
groupIDsLock.readLock();
auto iter = groups.find(id);
if(iter != groups.end())
group = iter->second;
if(group)
group->grab();
groupIDsLock.release();
return group;
}
ObjectGroup::ObjectGroup(unsigned count, int id) : objectCount(count), origObjectCount(count), objects(new Object*[count]), physItem(new PhysicsItem), owner(0) {
PhysicsGroup* physGroup = new PhysicsGroup;
physGroup->itemCount = count;
physGroup->items = new PhysicsItem[count];
physItem->type = PhysItemType(PIT_Group | PIT_Object);
physItem->group = physGroup;
memset(objects, 0, sizeof(Object*) * count);
registerObjectGroup(this, id);
}
bool ObjectGroup::postLoad() {
//Remove invalid objects
unsigned off = 0;
for(unsigned i = 0; i < objectCount; ++i) {
Object* obj = objects[i];
if(!obj->isValid() || !obj->isInitialized()) {
physItem->group->items[i].object = 0;
++off;
}
else {
if(off != 0)
objects[i-off] = obj;
}
obj->drop();
}
objectCount -= off;
//Check if the group should die
if(objectCount == 0) {
owner = nullptr;
return false;
}
//Check if the owner is valid
if(!owner->isValid() || !owner->isInitialized())
owner = objects[0];
return true;
}
void ObjectGroup::postInit() {
//Update physics item
physItem->bound.reset(objects[0]->physItem->bound);
for(unsigned i = 1; i < objectCount; ++i)
physItem->bound.addBox(objects[i]->physItem->bound);
devices.physics->registerItem(*physItem);
}
ObjectGroup::~ObjectGroup() {
devices.physics->unregisterItem(*physItem);
delete[] physItem->group->items;
delete physItem;
delete[] objects;
}
unsigned ObjectGroup::getObjectCount() const {
return objectCount;
}
unsigned ObjectGroup::getMaxObjectCount() const {
return origObjectCount;
}
Object* ObjectGroup::getObject(unsigned index) {
return objects[index];
}
const Object* ObjectGroup::getObject(unsigned index) const {
return objects[index];
}
void ObjectGroup::setObject(unsigned index, Object* obj) {
objects[index] = obj;
if(index == 0 && owner == 0)
owner = obj;
if(obj)
obj->grab();
}
unsigned ObjectGroup::setNextObject(Object* obj) {
for(unsigned i = 0; i < objectCount; ++i) {
if(objects[i] != 0)
continue;
objects[i] = obj;
if(i == 0 && owner == nullptr)
owner = obj;
return i;
}
return 0;
}
Object* ObjectGroup::getOwner() {
return owner;
}
void ObjectGroup::setOwner(Object* obj) {
owner = obj;
}
vec3d ObjectGroup::getCenter() const {
return physItem->bound.getCenter();
}
PhysicsItem* ObjectGroup::getPhysicsItem() {
return physItem;
}
PhysicsItem* ObjectGroup::getPhysicsItem(unsigned index) const {
return &physItem->group->items[index];
}
bool ObjectGroup::removeOwner() {
Object* newOwner = 0;
double nearest = 9.0e40;
//Move objects down to the lower indices, and find the nearest object to the previous owner to be the new owner
unsigned j = 0;
for(unsigned i = 0; i < objectCount; ++i) {
Object*& obj = objects[i];
if(!obj) {
++j;
}
else if(obj->isValid() && obj != owner) {
double dist = owner->position.distanceToSQ(obj->position);
if(dist < nearest) {
nearest = dist;
newOwner = obj;
}
if(j != i) {
objects[j] = obj;
obj = 0;
}
++j;
}
}
objectCount = j;
if(objectCount != 0) {
if(newOwner)
owner = newOwner;
else
owner = objects[0];
return false;
}
else {
owner = 0;
unregisterObjectGroup(this);
drop();
return true;
}
}
void ObjectGroup::update() {
AABBoxd box;
box.reset(owner->physItem->bound);
unsigned j = 1;
for(unsigned i = 1; i < objectCount; ++i) {
if(!objects[i]) {
++j;
} else if(objects[i]->isValid()) {
box.addBox(objects[i]->physItem->bound);
if(j != i) {
objects[j] = objects[i];
objects[i] = 0;
}
++j;
}
}
objectCount = j;
devices.physics->updateItem(*physItem, box);
}
ObjectGroup::ObjectGroup(SaveFile& file) {
file >> id >> objectCount >> formationFacing;
objects = new Object*[objectCount];
for(unsigned i = 0; i < objectCount; ++i)
file >> objects[i];
owner = objects[(unsigned short)file];
PhysicsGroup* physGroup = new PhysicsGroup;
physGroup->itemCount = objectCount;
physGroup->items = new PhysicsItem[objectCount];
physItem = new PhysicsItem;
physItem->type = PhysItemType(PIT_Group | PIT_Object);
physItem->group = physGroup;
registerObjectGroup(this);
}
void ObjectGroup::save(SaveFile& file) {
file << id;
file << objectCount;
file << formationFacing;
unsigned ownerIndex = 0;
for(unsigned i = 0; i < objectCount; ++i) {
file << objects[i];
if(objects[i] == owner)
ownerIndex = i;
}
file << (unsigned short)ownerIndex;
}