177 lines
4.1 KiB
C++
177 lines
4.1 KiB
C++
#include "obj/universe.h"
|
|
#include "empire.h"
|
|
#include "compat/misc.h"
|
|
#include "util/random.h"
|
|
#include "main/references.h"
|
|
#include "network/network_manager.h"
|
|
#include "physics/physics_world.h"
|
|
#include <assert.h>
|
|
#include <unordered_set>
|
|
|
|
void Universe::doQueued() {
|
|
threads::Lock qlock(queueLock);
|
|
threads::WriteLock lock(childLock);
|
|
|
|
//Remove queued objects
|
|
unsigned offset = 0;
|
|
if(!removeQueue.empty()) {
|
|
for(unsigned i = 0, cnt = (unsigned)children.size(); i < cnt; ++i) {
|
|
Object* child = children[i];
|
|
if(removeQueue.find(child) != removeQueue.end()) {
|
|
++offset;
|
|
removeTargetsTo(child); //TODO: better
|
|
child->drop();
|
|
}
|
|
else if(offset != 0) {
|
|
children[i - offset] = children[i];
|
|
}
|
|
}
|
|
if(offset != 0)
|
|
children.resize(children.size() - (size_t)offset);
|
|
removeQueue.clear();
|
|
}
|
|
|
|
//Add queued objects
|
|
foreach(it, addQueue)
|
|
children.push_back(*it);
|
|
addQueue.clear();
|
|
}
|
|
|
|
void Universe::addChild(Object* obj) {
|
|
threads::Lock qlock(queueLock);
|
|
|
|
auto it = removeQueue.find(obj);
|
|
if(it != removeQueue.end())
|
|
removeQueue.erase(obj);
|
|
else
|
|
addQueue.insert(obj);
|
|
obj->grab();
|
|
}
|
|
|
|
void Universe::removeChild(Object* obj) {
|
|
threads::Lock qlock(queueLock);
|
|
auto it = addQueue.find(obj);
|
|
if(it != addQueue.end()) {
|
|
addQueue.erase(obj);
|
|
for(unsigned i = 0; i < OBJ_TARGETS; ++i)
|
|
obj->targets[i] = nullptr;
|
|
}
|
|
else
|
|
removeQueue.insert(obj);
|
|
}
|
|
|
|
void Universe::destroyAll() {
|
|
foreach(child, children) {
|
|
(*child)->destroy(true);
|
|
(*child)->drop();
|
|
}
|
|
children.clear();
|
|
}
|
|
|
|
Object* Universe::getRandomTarget(unsigned randVal) {
|
|
//No child lock needed, guaranteed through lock ticking
|
|
if(children.empty())
|
|
return 0;
|
|
if(randVal == 0)
|
|
randVal = randomi();
|
|
return children[randVal % children.size()];
|
|
}
|
|
|
|
void Universe::setRandomTarget(heldPointer<Object>& targ, unsigned randVal) {
|
|
//No child lock needed, guaranteed through lock ticking
|
|
if(children.empty())
|
|
return;
|
|
|
|
if(randVal == 0)
|
|
randVal = randomi();
|
|
|
|
Object* child = children[randVal % children.size()];
|
|
|
|
if(child->isValid()) {
|
|
auto& other = child->targets[randVal % OBJ_TARGETS];
|
|
if(!other->getFlag(objNoPhysics))
|
|
other.swap(targ);
|
|
}
|
|
}
|
|
|
|
void Universe::removeTargetsTo(Object* obj) {
|
|
//No child lock needed, guaranteed through lock ticking
|
|
unsigned remaining = OBJ_TARGETS;
|
|
unsigned i = 0;
|
|
unsigned cnt = (unsigned)children.size();
|
|
|
|
for(unsigned t = 0; t < OBJ_TARGETS; ++t)
|
|
if(obj->targets[t] == obj)
|
|
--remaining;
|
|
|
|
if(remaining == 0)
|
|
goto clearTargets;
|
|
|
|
for(; i < cnt; ++i) {
|
|
Object* child = children[i];
|
|
|
|
for(unsigned j = 0; j < OBJ_TARGETS; ++j) {
|
|
if(child->targets[j] == obj && child != obj) {
|
|
for(unsigned t = 0; t < OBJ_TARGETS; ++t) {
|
|
if(obj->targets[t] != obj) {
|
|
child->targets[j].swap(obj->targets[t]);
|
|
break;
|
|
}
|
|
}
|
|
assert(children[i]->targets[j] != obj);
|
|
--remaining;
|
|
if(remaining == 0)
|
|
goto clearTargets;
|
|
}
|
|
}
|
|
}
|
|
|
|
clearTargets:;
|
|
for(unsigned i = 0; i < OBJ_TARGETS; ++i)
|
|
obj->targets[i] = 0;
|
|
}
|
|
|
|
const double coneSlope = 0.02;
|
|
|
|
Object* Universe::getClosestOnLine(const line3dd& line) const {
|
|
threads::ReadLock lock(childLock);
|
|
|
|
Empire* empire = Empire::getPlayerEmpire();
|
|
auto lineDir = line.getDirection();
|
|
double closest_d = 9e32;
|
|
double closest_p = 1.0;
|
|
Object* closest_o = 0;
|
|
|
|
//TODO: This should handle the cone more accurately, possibly in multiple steps?
|
|
//Bound should hold the line, and a considerable radius around it to handle the cone
|
|
AABBoxd bound(line.start);
|
|
bound.addBox( AABBoxd::fromCircle(line.end, 1500.0) );
|
|
|
|
devices.physics->findInBox(line, [&](const PhysicsItem& item) {
|
|
Object* obj = item.object;
|
|
if(!obj || !obj->isVisibleTo(empire))
|
|
return;
|
|
|
|
double distOnLine = (obj->position - line.start).dot(lineDir);
|
|
if(distOnLine <= 0)
|
|
return;
|
|
|
|
auto p = line.start + (lineDir * distOnLine);
|
|
double p_d = p.distanceTo(obj->position);
|
|
double c_d = obj->radius + distOnLine * coneSlope;
|
|
if(p_d >= c_d)
|
|
return;
|
|
|
|
double pct = p_d / c_d;
|
|
|
|
auto dist = p.getLength();
|
|
if(dist < closest_d && pct < closest_p) {
|
|
closest_o = obj;
|
|
closest_d = dist;
|
|
closest_p = pct;
|
|
}
|
|
});
|
|
|
|
return closest_o;
|
|
}
|