1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-10-06 09:07:19 +02:00

Game objects as unique ptrs

This commit is contained in:
Filip Gawin 2018-09-05 00:14:27 +02:00 committed by Daniel Evans
parent d1c31952b5
commit 0ae2a836ca
13 changed files with 118 additions and 88 deletions

View File

@ -208,8 +208,8 @@ bool CharacterController::checkForObstacles()
// Try to stop before pedestrians
for (const auto &obj : character->engine->pedestrianPool.objects) {
// Verify that the character isn't the driver and is walking
if (obj.second != character &&
static_cast<CharacterObject *>(obj.second)->getCurrentVehicle() ==
if (obj.second.get() != character &&
static_cast<CharacterObject *>(obj.second.get())->getCurrentVehicle() ==
nullptr) {
// Only check characters that are near our vehicle
if (glm::distance(vehicle->getPosition(),
@ -228,7 +228,7 @@ bool CharacterController::checkForObstacles()
// Brake when a car is in front of us and change lanes when possible
for (const auto &obj : character->engine->vehiclePool.objects) {
// Verify that the vehicle isn't our vehicle
if (obj.second != vehicle) {
if (obj.second.get() != vehicle) {
// Only check vehicles that are near our vehicle
if (glm::distance(vehicle->getPosition(),
obj.second->getPosition()) <= minColDist) {
@ -247,18 +247,18 @@ bool CharacterController::checkForObstacles()
if (maxLanes > 1) {
// Change the lane, firstly check if there is an
// occupant
if (static_cast<VehicleObject *>(obj.second)
if (static_cast<VehicleObject *>(obj.second.get())
->getDriver() != nullptr) {
// @todo for now we don't know the lane where the
// player is currently driving so just slow down, in
// the future calculate the lane
if (static_cast<VehicleObject *>(obj.second)
if (static_cast<VehicleObject *>(obj.second.get())
->getDriver()
->isPlayer()) {
return true;
} else {
int avoidLane =
static_cast<VehicleObject *>(obj.second)
static_cast<VehicleObject *>(obj.second.get())
->getDriver()
->controller->getLane();

View File

@ -46,7 +46,7 @@ void PlayerController::enterNearestVehicle() {
float d = 10.f;
for (auto& p : world->vehiclePool.objects) {
auto object = p.second;
auto object = p.second.get();
float vd =
glm::length(character->getPosition() - object->getPosition());
if (vd < d) {

View File

@ -94,9 +94,13 @@ GameWorld::GameWorld(Logger* log, GameData* dat)
}
GameWorld::~GameWorld() {
for (auto& p : allObjects) {
delete p;
}
// Bullet requires to remove each object before all physic world
pedestrianPool.clear();
instancePool.clear();
vehiclePool.clear();
pickupPool.clear();
cutscenePool.clear();
projectilePool.clear();
}
bool GameWorld::placeItems(const std::string& name) {
@ -145,14 +149,16 @@ InstanceObject* GameWorld::createInstance(const uint16_t id,
}
auto instance =
new InstanceObject(this, pos, rot, glm::vec3(1.f), oi, dydata);
std::make_unique<InstanceObject>(this, pos, rot, glm::vec3(1.f), oi, dydata);
instancePool.insert(instance);
allObjects.push_back(instance);
auto ptr = instance.get();
modelInstances.insert({oi->name, instance});
instancePool.insert(std::move(instance));
allObjects.push_back(ptr);
return instance;
modelInstances.emplace(oi->name, ptr);
return ptr;
}
return nullptr;
@ -173,7 +179,7 @@ void GameWorld::cleanupTraffic(const ViewCamera& focus) {
if (glm::distance(focus.position, p.second->getPosition()) >=
kMaxTrafficCleanupRadius) {
if (!focus.frustum.intersects(p.second->getPosition(), 1.f)) {
destroyObjectQueued(p.second);
destroyObjectQueued(p.second.get());
}
}
}
@ -185,7 +191,7 @@ void GameWorld::cleanupTraffic(const ViewCamera& focus) {
if (glm::distance(focus.position, p.second->getPosition()) >=
kMaxTrafficCleanupRadius) {
if (!focus.frustum.intersects(p.second->getPosition(), 1.f)) {
destroyObjectQueued(p.second);
destroyObjectQueued(p.second.get());
}
}
}
@ -216,12 +222,13 @@ CutsceneObject* GameWorld::createCutsceneObject(const uint16_t id,
}
}
auto instance = new CutsceneObject(this, pos, rot, model, modelinfo);
auto instance = std::make_unique<CutsceneObject>(this, pos, rot, model, modelinfo);
auto ptr = instance.get();
cutscenePool.insert(instance);
allObjects.push_back(instance);
cutscenePool.insert(std::move(instance));
allObjects.push_back(ptr);
return instance;
return ptr;
}
VehicleObject* GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos,
@ -299,13 +306,14 @@ VehicleObject* GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos,
}
auto vehicle =
new VehicleObject{this, pos, rot, vti, info->second, prim, sec};
std::make_unique<VehicleObject>(this, pos, rot, vti, info->second, prim, sec);
auto ptr = vehicle.get();
vehicle->setGameObjectID(gid);
vehiclePool.insert(vehicle);
allObjects.push_back(vehicle);
vehiclePool.insert(std::move(vehicle));
allObjects.push_back(ptr);
return vehicle;
return ptr;
}
CharacterObject* GameWorld::createPedestrian(const uint16_t id,
@ -323,11 +331,12 @@ CharacterObject* GameWorld::createPedestrian(const uint16_t id,
}
auto controller = new DefaultAIController();
auto ped = new CharacterObject(this, pos, rot, pt, controller);
auto ped = std::make_unique<CharacterObject>(this, pos, rot, pt, controller);
auto ptr = ped.get();
ped->setGameObjectID(gid);
pedestrianPool.insert(ped);
allObjects.push_back(ped);
return ped;
pedestrianPool.insert(std::move(ped));
allObjects.push_back(ptr);
return ptr;
}
CharacterObject* GameWorld::createPlayer(const glm::vec3& pos,
@ -350,13 +359,14 @@ CharacterObject* GameWorld::createPlayer(const glm::vec3& pos,
}
auto controller = new PlayerController();
auto ped = new CharacterObject(this, pos, rot, pt, controller);
auto ped = std::make_unique<CharacterObject>(this, pos, rot, pt, controller);
auto ptr = ped.get();
ped->setGameObjectID(gid);
ped->setLifetime(GameObject::PlayerLifetime);
players.push_back(controller);
pedestrianPool.insert(ped);
allObjects.push_back(ped);
return ped;
pedestrianPool.insert(std::move(ped));
allObjects.push_back(ptr);
return ptr;
}
PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) {
@ -371,7 +381,7 @@ PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) {
data->loadModel(id);
}
PickupObject* pickup = nullptr;
std::unique_ptr<PickupObject> pickup;
auto pickuptype = static_cast<PickupObject::PickupType>(type);
auto it = std::find_if(
@ -380,34 +390,36 @@ PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) {
// If nothing, create a generic pickup instead of an item pickup
if (it != data->weaponData.end()) {
pickup = new ItemPickup(this, pos, modelInfo, pickuptype, it->get());
pickup = std::make_unique<ItemPickup>(this, pos, modelInfo, pickuptype, it->get());
} else if (modelInfo->name == "info" || modelInfo->name == "briefcase" ||
modelInfo->name == "floatpackge1") {
pickup = new DummyPickup(this, pos, modelInfo, pickuptype);
pickup = std::make_unique<DummyPickup>(this, pos, modelInfo, pickuptype);
} else if (modelInfo->name == "killfrenzy") {
pickup = new RampagePickup(this, pos, modelInfo, pickuptype);
pickup = std::make_unique<RampagePickup>(this, pos, modelInfo, pickuptype);
} else if (modelInfo->name == "health") {
pickup = new HealthPickup(this, pos, modelInfo, pickuptype);
pickup = std::make_unique<HealthPickup>(this, pos, modelInfo, pickuptype);
} else if (modelInfo->name == "bodyarmour") {
pickup = new ArmourPickup(this, pos, modelInfo, pickuptype);
pickup = std::make_unique<ArmourPickup>(this, pos, modelInfo, pickuptype);
} else if (modelInfo->name == "package1") {
pickup = new CollectablePickup(this, pos, modelInfo, pickuptype);
pickup = std::make_unique<CollectablePickup>(this, pos, modelInfo, pickuptype);
} else if (modelInfo->name == "adrenaline") {
pickup = new AdrenalinePickup(this, pos, modelInfo, pickuptype);
pickup = std::make_unique<AdrenalinePickup>(this, pos, modelInfo, pickuptype);
} else if (modelInfo->name == "Money") {
pickup = new MoneyPickup(this, pos, modelInfo, pickuptype, 0);
pickup = std::make_unique<MoneyPickup>(this, pos, modelInfo, pickuptype, 0);
} else if (modelInfo->name == "donkeymag") {
pickup = new BigNVeinyPickup(this, pos, modelInfo, pickuptype);
pickup = std::make_unique<BigNVeinyPickup>(this, pos, modelInfo, pickuptype);
pickup->setBehaviourFlags(PickupObject::BehaviourFlags::PickupInVehicle);
} else {
RW_UNIMPLEMENTED("Non-weapon pickups");
pickup = new PickupObject(this, pos, modelInfo, pickuptype);
pickup = std::make_unique<PickupObject>(this, pos, modelInfo, pickuptype);
}
pickupPool.insert(pickup);
allObjects.push_back(pickup);
auto ptr = pickup.get();
return pickup;
pickupPool.insert(std::move(pickup));
allObjects.push_back(ptr);
return ptr;
}
Garage* GameWorld::createGarage(const glm::vec3 coord0, const glm::vec3 coord1,
@ -423,7 +435,7 @@ Payphone* GameWorld::createPayphone(const glm::vec2 coord) {
return payphones.back().get();
}
void GameWorld::ObjectPool::insert(GameObject* object) {
void GameWorld::ObjectPool::insert(std::unique_ptr<GameObject> object) {
if (object->getGameObjectID() == 0) {
// Find the lowest free GameObjectID.
GameObjectID availID = 1;
@ -433,12 +445,12 @@ void GameWorld::ObjectPool::insert(GameObject* object) {
object->setGameObjectID(availID);
}
objects[object->getGameObjectID()] = object;
objects[object->getGameObjectID()] = std::move(object);
}
GameObject* GameWorld::ObjectPool::find(GameObjectID id) const {
auto it = objects.find(id);
return (it == objects.end()) ? nullptr : it->second;
return (it == objects.end()) ? nullptr : it->second.get();
}
void GameWorld::ObjectPool::remove(GameObject* object) {
@ -450,6 +462,10 @@ void GameWorld::ObjectPool::remove(GameObject* object) {
}
}
void GameWorld::ObjectPool::clear() {
objects.clear();
}
GameWorld::ObjectPool& GameWorld::getTypeObjectPool(GameObject* object) {
switch (object->type()) {
case GameObject::Character:
@ -500,8 +516,6 @@ void GameWorld::destroyObject(GameObject* object) {
if (it != allObjects.end()) {
allObjects.erase(it);
}
delete object;
}
void GameWorld::destroyObjectQueued(GameObject* object) {
@ -712,20 +726,20 @@ void GameWorld::PhysicsTickCallback(btDynamicsWorld* physWorld,
RW_PROFILE_COUNTER_SET("physicsTick/vehiclePool", world->vehiclePool.objects.size());
for (auto& p : world->vehiclePool.objects) {
RW_PROFILE_SCOPEC("VehicleObject", MP_THISTLE1);
VehicleObject* object = static_cast<VehicleObject*>(p.second);
auto object = static_cast<VehicleObject*>(p.second.get());
object->tickPhysics(timeStep);
}
RW_PROFILE_COUNTER_SET("physicsTick/pedestrianPool", world->pedestrianPool.objects.size());
for (auto& p : world->pedestrianPool.objects) {
RW_PROFILE_SCOPEC("CharacterObject", MP_THISTLE1);
CharacterObject* object = static_cast<CharacterObject*>(p.second);
auto object = static_cast<CharacterObject*>(p.second.get());
object->tickPhysics(timeStep);
}
RW_PROFILE_COUNTER_SET("physicsTick/instancePool", world->instancePool.objects.size());
for (auto& p : world->instancePool.objects) {
InstanceObject* object = static_cast<InstanceObject*>(p.second);
auto object = static_cast<InstanceObject*>(p.second.get());
object->tickPhysics(timeStep);
}
}
@ -771,7 +785,7 @@ void GameWorld::startCutscene() {
void GameWorld::clearCutscene() {
for (auto& p : cutscenePool.objects) {
destroyObjectQueued(p.second);
destroyObjectQueued(p.second.get());
}
if (cutsceneAudio.length() > 0) {
@ -968,7 +982,7 @@ void GameWorld::clearObjectsWithinArea(const glm::vec3 center,
// Check if we have any important objects in a vehicle, if we do - don't
// erase it
for (auto& seat :
static_cast<VehicleObject*>(obj.second)->seatOccupants) {
static_cast<VehicleObject*>(obj.second.get())->seatOccupants) {
auto character = static_cast<CharacterObject*>(seat.second);
if (character->getLifetime() == GameObject::PlayerLifetime ||
@ -982,7 +996,7 @@ void GameWorld::clearObjectsWithinArea(const glm::vec3 center,
}
if (glm::distance(center, obj.second->getPosition()) < radius) {
destroyObjectQueued(obj.second);
destroyObjectQueued(obj.second.get());
}
}
@ -995,7 +1009,7 @@ void GameWorld::clearObjectsWithinArea(const glm::vec3 center,
}
if (glm::distance(center, obj.second->getPosition()) < radius) {
destroyObjectQueued(obj.second);
destroyObjectQueued(obj.second.get());
}
}

View File

@ -253,13 +253,13 @@ public:
* the individual pools.
*/
struct ObjectPool {
std::map<GameObjectID, GameObject*> objects;
std::map<GameObjectID, std::unique_ptr<GameObject>> objects;
/**
* Allocates the game object a GameObjectID and inserts it into
* the pool
*/
void insert(GameObject* object);
void insert(std::unique_ptr<GameObject> object);
/**
* Removes a game object from this pool
@ -270,6 +270,11 @@ public:
* Finds a game object if it exists in this pool
*/
GameObject* find(GameObjectID id) const;
/**
* Removes all stored objects
*/
void clear();
};
/**

View File

@ -37,8 +37,8 @@ Garage::Garage(GameWorld* engine_, size_t id_, const glm::vec3& coord0,
midpoint.y = (min.y + max.y) / 2;
// Find door objects for this garage
for (const auto p : engine->instancePool.objects) {
const auto inst = static_cast<InstanceObject*>(p.second);
for (const auto& p : engine->instancePool.objects) {
const auto inst = static_cast<InstanceObject*>(p.second.get());
if (!inst->getModel()) {
continue;

View File

@ -15,7 +15,7 @@ Payphone::Payphone(GameWorld* engine_, size_t id_, const glm::vec2& coord)
: engine(engine_), id(id_) {
// Find payphone object, original game does this differently
for (const auto& p : engine->instancePool.objects) {
auto o = p.second;
auto o = p.second.get();
if (!o->getModel()) {
continue;
}

View File

@ -33,13 +33,15 @@ void Weapon::fireProjectile(WeaponData* weapon, CharacterObject* owner,
force = std::max(0.1f, force);
auto projectile = new ProjectileObject(
auto projectile = std::make_unique<ProjectileObject>(
owner->engine, fireOrigin,
{pt, direction,
ProjectileObject::ProjectileInfo{
pt, direction,
17.f * force, /// @todo pull a better velocity from somewhere
3.5f, weapon});
auto ptr = projectile.get();
auto& pool = owner->engine->getTypeObjectPool(projectile);
pool.insert(projectile);
owner->engine->allObjects.push_back(projectile);
auto& pool = owner->engine->getTypeObjectPool(ptr);
pool.insert(std::move(projectile));
owner->engine->allObjects.push_back(ptr);
}

View File

@ -25,6 +25,14 @@ public:
};
struct ProjectileInfo {
ProjectileInfo(ProjectileType p_type, glm::vec3 p_direction,
float p_velocity, float p_time, WeaponData* p_weapon)
: type(p_type)
, direction(p_direction)
, velocity(p_velocity)
, time(p_time)
, weapon(p_weapon) {
}
ProjectileType type;
glm::vec3 direction{};
float velocity;

View File

@ -7442,7 +7442,7 @@ void opcode_02c5(const ScriptArguments& args, ScriptInt& collected) {
*/
void opcode_02c6(const ScriptArguments& args) {
for (auto& p : args.getWorld()->pickupPool.objects) {
auto pickup = static_cast<BigNVeinyPickup*>(p.second);
auto pickup = static_cast<BigNVeinyPickup*>(p.second.get());
if (pickup->isBigNVeinyPickup()) {
script::destroyObject(args, pickup);
}
@ -7720,7 +7720,7 @@ void opcode_02dd(const ScriptArguments& args, const ScriptString areaName, Scrip
// Create a list of candidate characters by iterating and checking if the char is in this zone
std::vector<std::pair<GameObjectID, GameObject*>> candidates;
for (auto& p : args.getWorld()->pedestrianPool.objects) {
auto character = static_cast<CharacterObject*>(p.second);
auto character = static_cast<CharacterObject*>(p.second.get());
// We only consider characters walking around normally
// @todo not sure if we are able to grab script objects or players too
@ -7735,7 +7735,7 @@ void opcode_02dd(const ScriptArguments& args, const ScriptString areaName, Scrip
auto& max = zone->max;
if (cp.x > min.x && cp.y > min.y && cp.z > min.z &&
cp.x < max.x && cp.y < max.y && cp.z < max.z) {
candidates.push_back(p);
candidates.emplace_back(p.first, p.second.get());
}
}
@ -9056,7 +9056,7 @@ bool opcode_0339(const ScriptArguments& args, ScriptVec3 coord0, ScriptVec3 coor
if (actors) {
auto& actors = args.getWorld()->pedestrianPool.objects;
for (const auto& o : actors) {
if (script::objectInBounds(o.second, coord0, coord1)) {
if (script::objectInBounds(o.second.get(), coord0, coord1)) {
return true;
}
}
@ -9064,7 +9064,7 @@ bool opcode_0339(const ScriptArguments& args, ScriptVec3 coord0, ScriptVec3 coor
if (cars) {
auto& cars = args.getWorld()->vehiclePool.objects;
for (const auto& o : cars) {
if (script::objectInBounds(o.second, coord0, coord1)) {
if (script::objectInBounds(o.second.get(), coord0, coord1)) {
return true;
}
}
@ -9072,7 +9072,7 @@ bool opcode_0339(const ScriptArguments& args, ScriptVec3 coord0, ScriptVec3 coor
if (objects) {
auto& objects = args.getWorld()->instancePool.objects;
for (const auto& o : objects) {
if (script::objectInBounds(o.second, coord0, coord1)) {
if (script::objectInBounds(o.second.get(), coord0, coord1)) {
return true;
}
}
@ -9622,7 +9622,7 @@ void opcode_0363(const ScriptArguments& args, ScriptVec3 coord, const ScriptFloa
InstanceObject* closestObject = nullptr;
float closestDistance = radius;
for(auto& i : args.getWorld()->instancePool.objects) {
InstanceObject* object = static_cast<InstanceObject*>(i.second);
InstanceObject* object = static_cast<InstanceObject*>(i.second.get());
// Check if this instance has the correct model id, early out if it isn't
auto modelinfo = object->getModelInfo<BaseModelInfo>();
@ -10887,8 +10887,8 @@ void opcode_03b6(const ScriptArguments& args, ScriptVec3 coord, const ScriptFloa
auto newobjectid = args.getWorld()->data->findModelObject(newmodel);
auto nobj = args.getWorld()->data->findModelInfo<SimpleModelInfo>(newobjectid);
for(auto p : args.getWorld()->instancePool.objects) {
auto o = p.second;
for(auto& p : args.getWorld()->instancePool.objects) {
auto o = p.second.get();
if( !o->getModel() ) continue;
if( o->getModelInfo<BaseModelInfo>()->name != oldmodel ) continue;
float d = glm::distance(coord, o->getPosition());

View File

@ -771,7 +771,7 @@ void RWGame::renderDebugPaths(float time) {
// Draw the targetNode if a character is driving a vehicle
for (auto& p : world->pedestrianPool.objects) {
auto v = static_cast<CharacterObject*>(p.second);
auto v = static_cast<CharacterObject*>(p.second.get());
static const btVector3 color(1.f, 1.f, 0.f);
@ -831,8 +831,8 @@ void RWGame::renderDebugObjects(float time, ViewCamera& camera) {
};
for (auto& p : world->vehiclePool.objects) {
if (!isnearby(p.second)) continue;
auto v = static_cast<VehicleObject*>(p.second);
if (!isnearby(p.second.get())) continue;
auto v = static_cast<VehicleObject*>(p.second.get());
std::stringstream ss;
ss << v->getVehicle()->vehiclename_ << "\n"
@ -843,8 +843,8 @@ void RWGame::renderDebugObjects(float time, ViewCamera& camera) {
showdata(v, ss);
}
for (auto& p : world->pedestrianPool.objects) {
if (!isnearby(p.second)) continue;
auto c = static_cast<CharacterObject*>(p.second);
if (!isnearby(p.second.get())) continue;
auto c = static_cast<CharacterObject*>(p.second.get());
const auto& state = c->getCurrentState();
auto act = c->controller->getCurrentActivity();

View File

@ -129,7 +129,7 @@ std::shared_ptr<Menu> DebugState::createMapMenu() {
auto gw = game->getWorld();
for (auto& i : gw->instancePool.objects) {
auto obj = static_cast<InstanceObject*>(i.second);
auto obj = static_cast<InstanceObject*>(i.second.get());
if (std::find(garageDoorModels.begin(),
garageDoorModels.end(),
obj->getModelInfo<BaseModelInfo>()->name) !=

View File

@ -8,7 +8,7 @@ BOOST_AUTO_TEST_SUITE(GameWorldTests)
#if RW_TEST_WITH_DATA
BOOST_AUTO_TEST_CASE(test_gameobject_id) {
GameWorld gw(&Global::get().log, Global::get().d);
auto& gw = *Global::get().e;
auto object1 = gw.createInstance(1337, glm::vec3(100.f, 0.f, 0.f));
auto object2 = gw.createInstance(1337, glm::vec3(100.f, 0.f, 100.f));
@ -17,7 +17,7 @@ BOOST_AUTO_TEST_CASE(test_gameobject_id) {
}
BOOST_AUTO_TEST_CASE(test_offsetgametime) {
GameWorld gw(&Global::get().log, Global::get().d);
auto& gw = *Global::get().e;
gw.state = new GameState();
BOOST_CHECK_EQUAL(0, gw.getHour());

View File

@ -16,6 +16,7 @@
#include <engine/GameData.hpp>
#include <engine/GameState.hpp>
#include <engine/GameWorld.hpp>
#include <objects/GameObject.hpp>
#include <glm/gtx/string_cast.hpp>
std::ostream& operator<<(std::ostream& stream, glm::vec3 const& v);