mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-07 03:12:36 +01:00
Overhaul Model data handling to improve accuracy
This commit is contained in:
parent
479aaab666
commit
996a82c4bf
@ -179,7 +179,7 @@ bool Activities::EnterVehicle::update(CharacterObject *character,
|
||||
RW_UNUSED(controller);
|
||||
|
||||
// Boats don't have any kind of entry animation unless you're onboard.
|
||||
if (vehicle->vehicle->type == VehicleData::BOAT) {
|
||||
if (vehicle->getVehicle()->vehicletype_ == VehicleModelInfo::BOAT) {
|
||||
character->enterVehicle(vehicle, seat);
|
||||
return true;
|
||||
}
|
||||
@ -344,7 +344,7 @@ bool Activities::ExitVehicle::update(CharacterObject *character,
|
||||
anm_exit = character->animations.car_getout_rhs;
|
||||
}
|
||||
|
||||
if (vehicle->vehicle->type == VehicleData::BOAT) {
|
||||
if (vehicle->getVehicle()->vehicletype_ == VehicleModelInfo::BOAT) {
|
||||
auto ppos = character->getPosition();
|
||||
character->enterVehicle(nullptr, seat);
|
||||
character->setPosition(ppos);
|
||||
|
@ -1,10 +1 @@
|
||||
#include "data/ObjectData.hpp"
|
||||
|
||||
const ObjectInformation::ObjectClass ObjectData::class_id =
|
||||
ObjectInformation::_class("OBJS");
|
||||
const ObjectInformation::ObjectClass VehicleData::class_id =
|
||||
ObjectInformation::_class("CARS");
|
||||
const ObjectInformation::ObjectClass CharacterData::class_id =
|
||||
ObjectInformation::_class("PEDS");
|
||||
const ObjectInformation::ObjectClass CutsceneObjectData::class_id =
|
||||
ObjectInformation::_class("HIER");
|
||||
#include "data/ModelData.hpp"
|
||||
|
@ -4,109 +4,227 @@
|
||||
#include <glm/glm.hpp>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <data/Model.hpp>
|
||||
#include <data/PathData.hpp>
|
||||
#include <rw/defines.hpp>
|
||||
#ifdef RW_WINDOWS
|
||||
#include <rw_mingw.hpp>
|
||||
#endif
|
||||
|
||||
typedef uint16_t ObjectID;
|
||||
|
||||
/**
|
||||
* Stores basic information about an Object and it's real type.
|
||||
* 16-bit model ID identifier (from .ide)
|
||||
*/
|
||||
struct ObjectInformation {
|
||||
typedef size_t ObjectClass;
|
||||
static ObjectClass _class(const std::string& name) {
|
||||
return std::hash<std::string>()(name);
|
||||
}
|
||||
using ModelID = uint16_t;
|
||||
|
||||
ObjectID ID;
|
||||
const ObjectClass class_type;
|
||||
|
||||
ObjectInformation(const ObjectClass type) : class_type(type) {
|
||||
}
|
||||
|
||||
virtual ~ObjectInformation() {
|
||||
}
|
||||
enum class ModelDataType {
|
||||
SimpleInfo = 1,
|
||||
/** Unknown */
|
||||
MLoModelInfo = 2,
|
||||
/** Currently unused; data in SimpleInfo instead */
|
||||
TimeModelInfo = 3,
|
||||
ClumpInfo = 4,
|
||||
VehicleInfo = 5,
|
||||
PedInfo = 6
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<ObjectInformation> ObjectInformationPtr;
|
||||
|
||||
/**
|
||||
* Data used by Normal Objects
|
||||
* Base type for all model information
|
||||
*
|
||||
* @todo reference counting
|
||||
* @todo store collision model
|
||||
*/
|
||||
struct ObjectData : public ObjectInformation {
|
||||
static const ObjectClass class_id;
|
||||
class BaseModelInfo {
|
||||
public:
|
||||
std::string name;
|
||||
std::string textureslot;
|
||||
|
||||
ObjectData() : ObjectInformation(_class("OBJS")) {
|
||||
BaseModelInfo(ModelDataType type) : type_(type) {
|
||||
}
|
||||
|
||||
std::string modelName;
|
||||
std::string textureName;
|
||||
uint8_t numClumps;
|
||||
float drawDistance[3];
|
||||
int32_t flags;
|
||||
bool LOD;
|
||||
virtual ~BaseModelInfo() {
|
||||
}
|
||||
|
||||
short timeOn;
|
||||
short timeOff;
|
||||
ModelID id() const {
|
||||
return modelid_;
|
||||
}
|
||||
|
||||
void setModelID(ModelID id) {
|
||||
modelid_ = id;
|
||||
}
|
||||
|
||||
ModelDataType type() const {
|
||||
return type_;
|
||||
}
|
||||
|
||||
void addReference() {
|
||||
refcount_++;
|
||||
}
|
||||
|
||||
void removeReference() {
|
||||
refcount_--;
|
||||
}
|
||||
|
||||
int getReferenceCount() const {
|
||||
return refcount_;
|
||||
}
|
||||
|
||||
/// @todo replace with proper streaming implementation
|
||||
virtual bool isLoaded() const = 0;
|
||||
|
||||
static std::string getTypeName(ModelDataType type) {
|
||||
switch (type) {
|
||||
case ModelDataType::SimpleInfo:
|
||||
return "Simple";
|
||||
case ModelDataType::VehicleInfo:
|
||||
return "Vehicle";
|
||||
case ModelDataType::PedInfo:
|
||||
return "Pedestrian";
|
||||
case ModelDataType::ClumpInfo:
|
||||
return "Cutscene";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
private:
|
||||
ModelID modelid_ = 0;
|
||||
ModelDataType type_;
|
||||
int refcount_ = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Model data for simple types
|
||||
*
|
||||
* @todo replace Model* with librw types
|
||||
*/
|
||||
class SimpleModelInfo : public BaseModelInfo {
|
||||
public:
|
||||
static constexpr ModelDataType kType = ModelDataType::SimpleInfo;
|
||||
|
||||
/// @todo Use TimeModelInfo instead of hacking this in here
|
||||
int timeOn = 0;
|
||||
int timeOff = 24;
|
||||
int flags;
|
||||
/// @todo Remove this?
|
||||
bool LOD = false;
|
||||
/// Information loaded from PATH sections
|
||||
/// @todo remove this from here too :)
|
||||
std::vector<PathData> paths;
|
||||
|
||||
SimpleModelInfo() : BaseModelInfo(kType) {
|
||||
}
|
||||
SimpleModelInfo(ModelDataType type) : BaseModelInfo(type) {
|
||||
}
|
||||
|
||||
/// @todo change with librw
|
||||
void setAtomic(Model* model, int n, ModelFrame* atomic) {
|
||||
model_ = model;
|
||||
atomics_[n] = atomic;
|
||||
}
|
||||
|
||||
ModelFrame* getAtomic(int n) const {
|
||||
return atomics_[n];
|
||||
}
|
||||
|
||||
void setLodDistance(int n, float d) {
|
||||
RW_CHECK(n < 3, "Lod Index out of range");
|
||||
loddistances_[n] = d;
|
||||
}
|
||||
|
||||
float getLodDistance(int n) {
|
||||
RW_CHECK(n < 3, "Lod Index out of range");
|
||||
return loddistances_[n];
|
||||
}
|
||||
|
||||
void setNumAtomics(int num) {
|
||||
numatomics_ = num;
|
||||
}
|
||||
|
||||
int getNumAtomics() const {
|
||||
return numatomics_;
|
||||
}
|
||||
|
||||
enum {
|
||||
NORMAL_CULL =
|
||||
1, /// Cull model if player doesn't look at it. Ignored in GTA 3.
|
||||
DO_NOT_FADE = 1 << 1, /// Do not fade the object when it is being
|
||||
/// Cull model if player doesn't look at it. Ignored in GTA 3.
|
||||
NORMAL_CULL = 1,
|
||||
/// Do not fade the object when it is being
|
||||
/// loaded into or out of view.
|
||||
DRAW_LAST = 1 << 2, /// Model is transparent. Render this object after
|
||||
DO_NOT_FADE = 1 << 1,
|
||||
/// Model is transparent. Render this object after
|
||||
/// all opaque objects, allowing transparencies of
|
||||
/// other objects to be visible through this
|
||||
/// object.
|
||||
ADDITIVE = 1 << 3, /// Render with additive blending. Previous flag
|
||||
DRAW_LAST = 1 << 2,
|
||||
/// Render with additive blending. Previous flag
|
||||
/// must be enabled too.
|
||||
IS_SUBWAY = 1 << 4, /// Model is a tunnel, i.e. set the object as
|
||||
ADDITIVE = 1 << 3,
|
||||
/// Model is a tunnel, i.e. set the object as
|
||||
/// invisible unless the player enters cull zone
|
||||
/// flag 128. This flag works only with static
|
||||
/// models.
|
||||
IGNORE_LIGHTING = 1 << 5, /// Don't use static lighting, we want
|
||||
IS_SUBWAY = 1 << 4,
|
||||
/// Don't use static lighting, we want
|
||||
/// dynamic if it's possible.
|
||||
NO_ZBUFFER_WRITE =
|
||||
1 << 6, /// Model is a shadow. Disable writing to z-buffer when
|
||||
IGNORE_LIGHTING = 1 << 5,
|
||||
/// Model is a shadow. Disable writing to z-buffer when
|
||||
/// rendering it, allowing transparencies of other objects,
|
||||
/// shadows, and lights to be visible through this object.
|
||||
/// (Not implemented in the PS2 version)
|
||||
NO_ZBUFFER_WRITE = 1 << 6,
|
||||
};
|
||||
|
||||
// Information loaded from PATH sections
|
||||
std::vector<PathData> paths;
|
||||
private:
|
||||
Model* model_ = nullptr;
|
||||
ModelFrame* atomics_[3] = {};
|
||||
float loddistances_[3] = {};
|
||||
uint8_t numatomics_ = 0;
|
||||
uint8_t alpha_ = 0; /// @todo ask aap why
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<ObjectData> ObjectDataPtr;
|
||||
|
||||
/**
|
||||
* Data used by peds
|
||||
* @todo this
|
||||
*/
|
||||
struct CharacterData : public ObjectInformation {
|
||||
static const ObjectClass class_id;
|
||||
class TimeModelInfo : public SimpleModelInfo {
|
||||
TimeModelInfo() : SimpleModelInfo(ModelDataType::TimeModelInfo) {
|
||||
}
|
||||
};
|
||||
|
||||
CharacterData() : ObjectInformation(_class("PEDS")) {
|
||||
/**
|
||||
* @todo document me
|
||||
*/
|
||||
class ClumpModelInfo : public BaseModelInfo {
|
||||
public:
|
||||
static constexpr ModelDataType kType = ModelDataType::ClumpInfo;
|
||||
|
||||
ClumpModelInfo() : BaseModelInfo(kType) {
|
||||
}
|
||||
ClumpModelInfo(ModelDataType type) : BaseModelInfo(type) {
|
||||
}
|
||||
|
||||
std::string modelName;
|
||||
std::string textureName;
|
||||
std::string type;
|
||||
std::string behaviour;
|
||||
std::string animGroup;
|
||||
uint8_t driveMask;
|
||||
void setModel(Model* model) {
|
||||
model_ = model;
|
||||
}
|
||||
|
||||
Model* getModel() const {
|
||||
return model_;
|
||||
}
|
||||
|
||||
private:
|
||||
Model* model_ = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Stores vehicle data loaded from item definition files.
|
||||
* Data for a vehicle model type
|
||||
*/
|
||||
struct VehicleData : public ObjectInformation {
|
||||
static const ObjectClass class_id;
|
||||
class VehicleModelInfo : public ClumpModelInfo {
|
||||
public:
|
||||
static constexpr ModelDataType kType = ModelDataType::VehicleInfo;
|
||||
|
||||
VehicleData() : ObjectInformation(_class("CARS")) {
|
||||
VehicleModelInfo() : ClumpModelInfo(kType) {
|
||||
}
|
||||
|
||||
enum VehicleClass {
|
||||
@ -124,6 +242,8 @@ struct VehicleData : public ObjectInformation {
|
||||
WORKERBOAT = 1 << 10,
|
||||
BICYCLE = 1 << 11,
|
||||
ONFOOT = 1 << 12,
|
||||
/// @todo verify that this is the correct bit
|
||||
SPECIAL = 1 << 13,
|
||||
};
|
||||
|
||||
enum VehicleType {
|
||||
@ -134,32 +254,120 @@ struct VehicleData : public ObjectInformation {
|
||||
HELI,
|
||||
};
|
||||
|
||||
std::string modelName;
|
||||
std::string textureName;
|
||||
VehicleType type;
|
||||
std::string handlingID;
|
||||
std::string gameName;
|
||||
VehicleClass classType;
|
||||
uint8_t frequency; // big enough int type?
|
||||
uint8_t lvl; // big enough int type?
|
||||
uint16_t comprules;
|
||||
union { // big enough int types?
|
||||
uint16_t wheelModelID; // used only when type == CAR
|
||||
int16_t modelLOD; // used only when type == PLANE
|
||||
};
|
||||
float wheelScale; // used only when type == CAR
|
||||
};
|
||||
VehicleType vehicletype_;
|
||||
ModelID wheelmodel_;
|
||||
float wheelscale_;
|
||||
int numdoors_;
|
||||
std::string handling_;
|
||||
VehicleClass vehicleclass_;
|
||||
int frequency_;
|
||||
int level_;
|
||||
int componentrules_;
|
||||
std::string vehiclename_;
|
||||
|
||||
typedef std::shared_ptr<VehicleData> VehicleDataHandle;
|
||||
|
||||
struct CutsceneObjectData : public ObjectInformation {
|
||||
static const ObjectClass class_id;
|
||||
|
||||
CutsceneObjectData() : ObjectInformation(_class("HIER")) {
|
||||
static VehicleType findVehicleType(const std::string& name) {
|
||||
static const std::unordered_map<std::string, VehicleType> vehicleTypes{
|
||||
{"car", CAR},
|
||||
{"boat", BOAT},
|
||||
{"train", TRAIN},
|
||||
{"plane", PLANE},
|
||||
{"heli", HELI}};
|
||||
return vehicleTypes.at(name);
|
||||
}
|
||||
|
||||
std::string modelName;
|
||||
std::string textureName;
|
||||
static VehicleClass findVehicleClass(const std::string& name) {
|
||||
static const std::unordered_map<std::string, VehicleClass> classTypes{
|
||||
// III, VC, SA
|
||||
{"ignore", IGNORE},
|
||||
{"normal", NORMAL},
|
||||
{"poorfamily", POORFAMILY},
|
||||
{"richfamily", RICHFAMILY},
|
||||
{"executive", EXECUTIVE},
|
||||
{"worker", WORKER},
|
||||
{"big", BIG},
|
||||
{"taxi", TAXI},
|
||||
{"special", SPECIAL},
|
||||
// VC, SA
|
||||
{"moped", MOPED},
|
||||
{"motorbike", MOTORBIKE},
|
||||
{"leisureboat", LEISUREBOAT},
|
||||
{"workerboat", WORKERBOAT},
|
||||
{"bicycle", BICYCLE},
|
||||
{"onfoot", ONFOOT},
|
||||
};
|
||||
return classTypes.at(name);
|
||||
}
|
||||
};
|
||||
|
||||
class PedModelInfo : public ClumpModelInfo {
|
||||
public:
|
||||
static constexpr ModelDataType kType = ModelDataType::PedInfo;
|
||||
|
||||
PedModelInfo() : ClumpModelInfo(kType) {
|
||||
}
|
||||
|
||||
enum PedType {
|
||||
// III
|
||||
PLAYER1 = 0,
|
||||
PLAYER2,
|
||||
PLAYER3,
|
||||
PLAYER_4,
|
||||
CIVMALE,
|
||||
CIVFEMALE,
|
||||
COP,
|
||||
GANG1,
|
||||
GANG2,
|
||||
GANG3,
|
||||
GANG4,
|
||||
GANG5,
|
||||
GANG6,
|
||||
GANG7,
|
||||
GANG8,
|
||||
GANG9,
|
||||
EMERGENCY,
|
||||
FIREMAN,
|
||||
CRIMINAL,
|
||||
_UNNAMED,
|
||||
PROSTITUTE,
|
||||
SPECIAL,
|
||||
};
|
||||
|
||||
PedType pedtype_ = PLAYER1;
|
||||
/// @todo this should be an index
|
||||
std::string behaviour_;
|
||||
/// @todo this should be an index
|
||||
std::string animgroup_;
|
||||
/// The mask of vehicle classes this ped can drive
|
||||
int carsmask_ = 0;
|
||||
|
||||
static PedType findPedType(const std::string& name) {
|
||||
static const std::unordered_map<std::string, PedType> pedTypes{
|
||||
// III
|
||||
{"PLAYER1", PLAYER1},
|
||||
{"PLAYER2", PLAYER2},
|
||||
{"PLAYER3", PLAYER3},
|
||||
{"PLAYER_4", PLAYER_4},
|
||||
{"CIVMALE", CIVMALE},
|
||||
{"CIVFEMALE", CIVFEMALE},
|
||||
{"COP", COP},
|
||||
{"GANG1", GANG1},
|
||||
{"GANG2", GANG2},
|
||||
{"GANG3", GANG3},
|
||||
{"GANG4", GANG4},
|
||||
{"GANG5", GANG5},
|
||||
{"GANG6", GANG6},
|
||||
{"GANG7", GANG7},
|
||||
{"GANG8", GANG8},
|
||||
{"GANG9", GANG9},
|
||||
{"EMERGENCY", EMERGENCY},
|
||||
{"FIREMAN", FIREMAN},
|
||||
{"CRIMINAL", CRIMINAL},
|
||||
{"_UNNAMED", _UNNAMED},
|
||||
{"PROSTITUTE", PROSTITUTE},
|
||||
{"SPECIAL", SPECIAL},
|
||||
};
|
||||
return pedTypes.at(name);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -109,23 +109,19 @@ void GameData::loadIDE(const std::string& path) {
|
||||
LoaderIDE idel;
|
||||
|
||||
if (idel.load(systempath)) {
|
||||
objectTypes.insert(idel.objects.begin(), idel.objects.end());
|
||||
std::move(idel.objects.begin(), idel.objects.end(),
|
||||
std::inserter(modelinfo, modelinfo.end()));
|
||||
} else {
|
||||
logger->error("Data", "Failed to load IDE " + path);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t GameData::findModelObject(const std::string model) {
|
||||
auto defit = std::find_if(
|
||||
objectTypes.begin(), objectTypes.end(),
|
||||
[&](const decltype(objectTypes)::value_type& d) {
|
||||
if (d.second->class_type == ObjectInformation::_class("OBJS")) {
|
||||
auto dat = static_cast<ObjectData*>(d.second.get());
|
||||
return boost::iequals(dat->modelName, model);
|
||||
}
|
||||
return false;
|
||||
auto defit = std::find_if(modelinfo.begin(), modelinfo.end(),
|
||||
[&](const decltype(modelinfo)::value_type& d) {
|
||||
return boost::iequals(d.second->name, model);
|
||||
});
|
||||
if (defit != objectTypes.end()) return defit->first;
|
||||
if (defit != modelinfo.end()) return defit->first;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -170,20 +170,15 @@ public:
|
||||
*/
|
||||
std::map<std::string, ZoneData> zones;
|
||||
|
||||
/**
|
||||
* Object Definitions
|
||||
*/
|
||||
std::map<ObjectID, ObjectInformationPtr> objectTypes;
|
||||
std::unordered_map<ModelID, std::unique_ptr<BaseModelInfo>> modelinfo;
|
||||
|
||||
uint16_t findModelObject(const std::string model);
|
||||
|
||||
template <class T>
|
||||
std::shared_ptr<T> findObjectType(ObjectID id) {
|
||||
auto f = objectTypes.find(id);
|
||||
/// @TODO don't instanciate an object here just to read .type
|
||||
T tmp;
|
||||
if (f != objectTypes.end() && f->second->class_type == tmp.class_type) {
|
||||
return std::static_pointer_cast<T>(f->second);
|
||||
T* findModelInfo(ModelID id) {
|
||||
auto f = modelinfo.find(id);
|
||||
if (f != modelinfo.end() && f->second->type() == T::kType) {
|
||||
return static_cast<T*>(f->second.get());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -140,10 +140,10 @@ bool GameWorld::placeItems(const std::string& name) {
|
||||
for (auto& p : instancePool.objects) {
|
||||
auto object = p.second;
|
||||
InstanceObject* instance = static_cast<InstanceObject*>(object);
|
||||
if (!instance->object->LOD &&
|
||||
instance->object->modelName.length() > 3) {
|
||||
auto lodInstit = modelInstances.find(
|
||||
"LOD" + instance->object->modelName.substr(3));
|
||||
auto modelinfo = instance->getModelInfo<SimpleModelInfo>();
|
||||
if (!modelinfo->LOD && modelinfo->name.length() > 3) {
|
||||
auto lodInstit =
|
||||
modelInstances.find("LOD" + modelinfo->name.substr(3));
|
||||
if (lodInstit != modelInstances.end()) {
|
||||
instance->LODinstance = lodInstit->second;
|
||||
}
|
||||
@ -162,10 +162,10 @@ bool GameWorld::placeItems(const std::string& name) {
|
||||
InstanceObject* GameWorld::createInstance(const uint16_t id,
|
||||
const glm::vec3& pos,
|
||||
const glm::quat& rot) {
|
||||
auto oi = data->findObjectType<ObjectData>(id);
|
||||
auto oi = data->findModelInfo<SimpleModelInfo>(id);
|
||||
if (oi) {
|
||||
std::string modelname = oi->modelName;
|
||||
std::string texturename = oi->textureName;
|
||||
std::string modelname = oi->name;
|
||||
std::string texturename = oi->textureslot;
|
||||
|
||||
std::transform(std::begin(modelname), std::end(modelname),
|
||||
std::begin(modelname), tolower);
|
||||
@ -173,7 +173,7 @@ InstanceObject* GameWorld::createInstance(const uint16_t id,
|
||||
std::begin(texturename), tolower);
|
||||
|
||||
// Ensure the relevant data is loaded.
|
||||
if (!oi->modelName.empty()) {
|
||||
if (!modelname.empty()) {
|
||||
if (modelname != "null") {
|
||||
data->loadDFF(modelname + ".dff", false);
|
||||
}
|
||||
@ -185,7 +185,7 @@ InstanceObject* GameWorld::createInstance(const uint16_t id,
|
||||
ModelRef m = data->models[modelname];
|
||||
|
||||
// Check for dynamic data.
|
||||
auto dyit = data->dynamicObjectData.find(oi->modelName);
|
||||
auto dyit = data->dynamicObjectData.find(oi->name);
|
||||
std::shared_ptr<DynamicObjectData> dydata;
|
||||
if (dyit != data->dynamicObjectData.end()) {
|
||||
dydata = dyit->second;
|
||||
@ -202,7 +202,7 @@ InstanceObject* GameWorld::createInstance(const uint16_t id,
|
||||
instancePool.insert(instance);
|
||||
allObjects.push_back(instance);
|
||||
|
||||
modelInstances.insert({oi->modelName, instance});
|
||||
modelInstances.insert({oi->name, instance});
|
||||
|
||||
return instance;
|
||||
}
|
||||
@ -250,34 +250,33 @@ void GameWorld::cleanupTraffic(const ViewCamera& focus) {
|
||||
CutsceneObject* GameWorld::createCutsceneObject(const uint16_t id,
|
||||
const glm::vec3& pos,
|
||||
const glm::quat& rot) {
|
||||
auto modelinfo = data->modelinfo[id].get();
|
||||
std::string modelname;
|
||||
std::string texturename;
|
||||
|
||||
auto type = data->objectTypes.find(id);
|
||||
if (type != data->objectTypes.end()) {
|
||||
if (type->second->class_type == ObjectInformation::_class("HIER")) {
|
||||
if (modelinfo) {
|
||||
modelname = modelinfo->name;
|
||||
texturename = modelinfo->textureslot;
|
||||
|
||||
/// @todo Store loaded models directly
|
||||
switch (modelinfo->type()) {
|
||||
case ModelDataType::ClumpInfo:
|
||||
// Re-direct the hier objects to the special object ids
|
||||
modelname = state->specialModels[id];
|
||||
texturename = state->specialModels[id];
|
||||
} else {
|
||||
if (type->second->class_type == ObjectInformation::_class("OBJS")) {
|
||||
auto v = static_cast<ObjectData*>(type->second.get());
|
||||
modelname = v->modelName;
|
||||
texturename = v->textureName;
|
||||
} else if (type->second->class_type ==
|
||||
ObjectInformation::_class("PEDS")) {
|
||||
auto v = static_cast<CharacterData*>(type->second.get());
|
||||
modelname = v->modelName;
|
||||
texturename = v->textureName;
|
||||
|
||||
static std::string specialPrefix("special");
|
||||
break;
|
||||
case ModelDataType::PedInfo:
|
||||
static const std::string specialPrefix("special");
|
||||
if (!modelname.compare(0, specialPrefix.size(),
|
||||
specialPrefix)) {
|
||||
auto sid = modelname.substr(specialPrefix.size());
|
||||
unsigned short specialID = std::atoi(sid.c_str());
|
||||
modelname = state->specialCharacters[specialID];
|
||||
texturename = state->specialCharacters[specialID];
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,7 +304,7 @@ CutsceneObject* GameWorld::createCutsceneObject(const uint16_t id,
|
||||
|
||||
ModelRef m = data->models[modelname];
|
||||
|
||||
auto instance = new CutsceneObject(this, pos, rot, m);
|
||||
auto instance = new CutsceneObject(this, pos, rot, m, modelinfo);
|
||||
|
||||
cutscenePool.insert(instance);
|
||||
allObjects.push_back(instance);
|
||||
@ -316,21 +315,21 @@ CutsceneObject* GameWorld::createCutsceneObject(const uint16_t id,
|
||||
VehicleObject* GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos,
|
||||
const glm::quat& rot,
|
||||
GameObjectID gid) {
|
||||
auto vti = data->findObjectType<VehicleData>(id);
|
||||
auto vti = data->findModelInfo<VehicleModelInfo>(id);
|
||||
if (vti) {
|
||||
logger->info("World", "Creating Vehicle ID " + std::to_string(id) +
|
||||
" (" + vti->gameName + ")");
|
||||
" (" + vti->vehiclename_ + ")");
|
||||
|
||||
if (!vti->modelName.empty()) {
|
||||
data->loadDFF(vti->modelName + ".dff");
|
||||
if (!vti->name.empty()) {
|
||||
data->loadDFF(vti->name + ".dff");
|
||||
}
|
||||
if (!vti->textureName.empty()) {
|
||||
data->loadTXD(vti->textureName + ".txd");
|
||||
if (!vti->textureslot.empty()) {
|
||||
data->loadTXD(vti->textureslot + ".txd");
|
||||
}
|
||||
|
||||
glm::u8vec3 prim(255), sec(128);
|
||||
auto palit = data->vehiclePalettes.find(
|
||||
vti->modelName); // modelname is conveniently lowercase (usually)
|
||||
vti->name); // modelname is conveniently lowercase (usually)
|
||||
if (palit != data->vehiclePalettes.end() && palit->second.size() > 0) {
|
||||
std::uniform_int_distribution<int> uniform(
|
||||
0, palit->second.size() - 1);
|
||||
@ -339,19 +338,12 @@ VehicleObject* GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos,
|
||||
sec = data->vehicleColours[palit->second[set].second];
|
||||
} else {
|
||||
logger->warning("World",
|
||||
"No colour palette for vehicle " + vti->modelName);
|
||||
"No colour palette for vehicle " + vti->name);
|
||||
}
|
||||
|
||||
auto wi = data->findObjectType<ObjectData>(vti->wheelModelID);
|
||||
if (wi) {
|
||||
if (!wi->textureName.empty()) {
|
||||
data->loadTXD(wi->textureName + ".txd");
|
||||
}
|
||||
}
|
||||
|
||||
ModelRef& m = data->models[vti->modelName];
|
||||
ModelRef& m = data->models[vti->name];
|
||||
auto model = m->resource;
|
||||
auto info = data->vehicleInfo.find(vti->handlingID);
|
||||
auto info = data->vehicleInfo.find(vti->handling_);
|
||||
if (model && info != data->vehicleInfo.end()) {
|
||||
if (info->second->wheels.size() == 0 &&
|
||||
info->second->seats.size() == 0) {
|
||||
@ -403,13 +395,13 @@ CharacterObject* GameWorld::createPedestrian(const uint16_t id,
|
||||
const glm::vec3& pos,
|
||||
const glm::quat& rot,
|
||||
GameObjectID gid) {
|
||||
auto pt = data->findObjectType<CharacterData>(id);
|
||||
auto pt = data->findModelInfo<PedModelInfo>(id);
|
||||
if (pt) {
|
||||
std::string modelname = pt->modelName;
|
||||
std::string texturename = pt->textureName;
|
||||
std::string modelname = pt->name;
|
||||
std::string texturename = pt->textureslot;
|
||||
|
||||
// Ensure the relevant data is loaded.
|
||||
if (!pt->modelName.empty()) {
|
||||
if (!modelname.empty()) {
|
||||
// Some model names have special meanings.
|
||||
/// @todo Should CharacterObjects handle this?
|
||||
static std::string specialPrefix("special");
|
||||
@ -446,7 +438,7 @@ CharacterObject* GameWorld::createPlayer(const glm::vec3& pos,
|
||||
const glm::quat& rot,
|
||||
GameObjectID gid) {
|
||||
// Player object ID is hardcoded to 0.
|
||||
auto pt = data->findObjectType<CharacterData>(0);
|
||||
auto pt = data->findModelInfo<PedModelInfo>(0);
|
||||
if (pt) {
|
||||
// Model name is also hardcoded.
|
||||
std::string modelname = "player";
|
||||
@ -472,15 +464,15 @@ CharacterObject* GameWorld::createPlayer(const glm::vec3& pos,
|
||||
}
|
||||
|
||||
PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) {
|
||||
auto modelInfo = data->findObjectType<ObjectData>(id);
|
||||
auto modelInfo = data->modelinfo[id].get();
|
||||
|
||||
RW_CHECK(modelInfo != nullptr, "Pickup Object Data is not found");
|
||||
if (modelInfo == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
data->loadDFF(modelInfo->modelName + ".dff");
|
||||
data->loadTXD(modelInfo->textureName + ".txd");
|
||||
data->loadDFF(modelInfo->name + ".dff");
|
||||
data->loadTXD(modelInfo->textureslot + ".txd");
|
||||
|
||||
PickupObject* pickup = nullptr;
|
||||
auto pickuptype = (PickupObject::PickupType)type;
|
||||
@ -492,10 +484,10 @@ PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) {
|
||||
|
||||
// If nothing, create a generic pickup instead of an item pickup
|
||||
if (it != inventoryItems.end()) {
|
||||
pickup = new ItemPickup(this, pos, pickuptype, *it);
|
||||
pickup = new ItemPickup(this, pos, modelInfo, pickuptype, *it);
|
||||
} else {
|
||||
RW_UNIMPLEMENTED("Non-weapon pickups");
|
||||
pickup = new PickupObject(this, pos, id, pickuptype);
|
||||
pickup = new PickupObject(this, pos, modelInfo, pickuptype);
|
||||
}
|
||||
|
||||
pickupPool.insert(pickup);
|
||||
|
@ -48,34 +48,35 @@ bool LoaderIDE::load(const std::string &filename) {
|
||||
line.end());
|
||||
|
||||
std::stringstream strstream(line);
|
||||
std::string buff;
|
||||
|
||||
switch (section) {
|
||||
default:
|
||||
break;
|
||||
case OBJS:
|
||||
case TOBJ: { // Supports Type 1, 2 and 3
|
||||
std::shared_ptr<ObjectData> objs(new ObjectData);
|
||||
auto objs =
|
||||
std::unique_ptr<SimpleModelInfo>(new SimpleModelInfo);
|
||||
|
||||
std::string id, numClumps, flags, modelName, textureName;
|
||||
getline(strstream, buff, ',');
|
||||
objs->setModelID(atoi(buff.c_str()));
|
||||
|
||||
// Read the content of the line
|
||||
getline(strstream, id, ',');
|
||||
getline(strstream, modelName, ',');
|
||||
getline(strstream, textureName, ',');
|
||||
getline(strstream, numClumps, ',');
|
||||
getline(strstream, objs->name, ',');
|
||||
getline(strstream, objs->textureslot, ',');
|
||||
|
||||
objs->numClumps = atoi(numClumps.c_str());
|
||||
for (size_t i = 0; i < objs->numClumps; i++) {
|
||||
std::string drawDistance;
|
||||
getline(strstream, drawDistance, ',');
|
||||
objs->drawDistance[i] = atoi(drawDistance.c_str());
|
||||
getline(strstream, buff, ',');
|
||||
objs->setNumAtomics(atoi(buff.c_str()));
|
||||
|
||||
for (int i = 0; i < objs->getNumAtomics(); i++) {
|
||||
getline(strstream, buff, ',');
|
||||
objs->setLodDistance(i, atof(buff.c_str()));
|
||||
}
|
||||
|
||||
getline(strstream, flags, ',');
|
||||
getline(strstream, buff, ',');
|
||||
objs->flags = atoi(buff.c_str());
|
||||
|
||||
// Keep reading TOBJ data
|
||||
if (section == LoaderIDE::TOBJ) {
|
||||
std::string buff;
|
||||
getline(strstream, buff, ',');
|
||||
objs->timeOn = atoi(buff.c_str());
|
||||
getline(strstream, buff, ',');
|
||||
@ -85,104 +86,82 @@ bool LoaderIDE::load(const std::string &filename) {
|
||||
objs->timeOff = 24;
|
||||
}
|
||||
|
||||
// Put stuff in our struct
|
||||
objs->ID = atoi(id.c_str());
|
||||
objs->flags = atoi(flags.c_str());
|
||||
objs->modelName = modelName;
|
||||
objs->textureName = textureName;
|
||||
objs->LOD = false;
|
||||
|
||||
if (modelName.find("LOD", 0, 3) != modelName.npos &&
|
||||
modelName != "LODistancoast01") {
|
||||
/// @todo Figure out how LOD stuff is intended to work
|
||||
if (objs->name.find("LOD", 0, 3) != std::string::npos &&
|
||||
objs->name != "LODistancoast01") {
|
||||
objs->LOD = true;
|
||||
}
|
||||
|
||||
objects.insert({objs->ID, objs});
|
||||
objects.emplace(objs->id(), std::move(objs));
|
||||
break;
|
||||
}
|
||||
case CARS: {
|
||||
std::shared_ptr<VehicleData> cars(new VehicleData);
|
||||
auto cars =
|
||||
std::unique_ptr<VehicleModelInfo>(new VehicleModelInfo);
|
||||
|
||||
std::string id, type, classType, frequency, lvl, comprules,
|
||||
wheelModelID, wheelScale;
|
||||
getline(strstream, buff, ',');
|
||||
cars->setModelID(std::atoi(buff.c_str()));
|
||||
|
||||
getline(strstream, id, ',');
|
||||
getline(strstream, cars->modelName, ',');
|
||||
getline(strstream, cars->textureName, ',');
|
||||
getline(strstream, type, ',');
|
||||
getline(strstream, cars->handlingID, ',');
|
||||
getline(strstream, cars->gameName, ',');
|
||||
getline(strstream, classType, ',');
|
||||
getline(strstream, frequency, ',');
|
||||
getline(strstream, lvl, ',');
|
||||
getline(strstream, comprules, ',');
|
||||
getline(strstream, wheelModelID, ',');
|
||||
getline(strstream, wheelScale, ',');
|
||||
getline(strstream, cars->name, ',');
|
||||
getline(strstream, cars->textureslot, ',');
|
||||
|
||||
cars->ID = atoi(id.c_str());
|
||||
cars->frequency = atoi(frequency.c_str());
|
||||
cars->lvl = atoi(lvl.c_str());
|
||||
cars->comprules = atoi(comprules.c_str());
|
||||
getline(strstream, buff, ',');
|
||||
cars->vehicletype_ =
|
||||
VehicleModelInfo::findVehicleType(buff);
|
||||
|
||||
if (type == "car") {
|
||||
cars->type = VehicleData::CAR;
|
||||
cars->wheelModelID = atoi(wheelModelID.c_str());
|
||||
cars->wheelScale = atof(wheelScale.c_str());
|
||||
} else if (type == "boat") {
|
||||
cars->type = VehicleData::BOAT;
|
||||
} else if (type == "train") {
|
||||
cars->type = VehicleData::TRAIN;
|
||||
cars->modelLOD = atoi(wheelModelID.c_str());
|
||||
} else if (type == "plane") {
|
||||
cars->type = VehicleData::PLANE;
|
||||
} else if (type == "heli") {
|
||||
cars->type = VehicleData::HELI;
|
||||
}
|
||||
getline(strstream, cars->handling_, ',');
|
||||
getline(strstream, cars->vehiclename_, ',');
|
||||
getline(strstream, buff, ',');
|
||||
cars->vehicleclass_ =
|
||||
VehicleModelInfo::findVehicleClass(buff);
|
||||
|
||||
const std::map<VehicleData::VehicleClass, std::string>
|
||||
classTypes{
|
||||
{VehicleData::IGNORE, "ignore"},
|
||||
{VehicleData::NORMAL, "normal"},
|
||||
{VehicleData::POORFAMILY, "poorfamily"},
|
||||
{VehicleData::RICHFAMILY, "richfamily"},
|
||||
{VehicleData::EXECUTIVE, "executive"},
|
||||
{VehicleData::WORKER, "worker"},
|
||||
{VehicleData::BIG, "big"},
|
||||
{VehicleData::TAXI, "taxi"},
|
||||
{VehicleData::MOPED, "moped"},
|
||||
{VehicleData::MOTORBIKE, "motorbike"},
|
||||
{VehicleData::LEISUREBOAT, "leisureboat"},
|
||||
{VehicleData::WORKERBOAT, "workerboat"},
|
||||
{VehicleData::BICYCLE, "bicycle"},
|
||||
{VehicleData::ONFOOT, "onfoot"},
|
||||
};
|
||||
for (auto &a : classTypes) {
|
||||
if (classType == a.second) {
|
||||
cars->classType = a.first;
|
||||
getline(strstream, buff, ',');
|
||||
cars->frequency_ = std::atoi(buff.c_str());
|
||||
|
||||
getline(strstream, buff, ',');
|
||||
cars->level_ = std::atoi(buff.c_str());
|
||||
|
||||
getline(strstream, buff, ',');
|
||||
cars->componentrules_ = std::atoi(buff.c_str());
|
||||
|
||||
switch (cars->vehicletype_) {
|
||||
case VehicleModelInfo::CAR:
|
||||
getline(strstream, buff, ',');
|
||||
cars->wheelmodel_ = std::atoi(buff.c_str());
|
||||
getline(strstream, buff, ',');
|
||||
cars->wheelscale_ = std::atof(buff.c_str());
|
||||
break;
|
||||
case VehicleModelInfo::PLANE:
|
||||
/// @todo load LOD
|
||||
getline(strstream, buff, ',');
|
||||
// cars->planeLOD_ = std::atoi(buff.c_str());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
objects.insert({cars->ID, cars});
|
||||
objects.emplace(cars->id(), std::move(cars));
|
||||
break;
|
||||
}
|
||||
case PEDS: {
|
||||
std::shared_ptr<CharacterData> peds(new CharacterData);
|
||||
auto peds = std::unique_ptr<PedModelInfo>(new PedModelInfo);
|
||||
|
||||
std::string id, driveMask;
|
||||
getline(strstream, buff, ',');
|
||||
peds->setModelID(std::atoi(buff.c_str()));
|
||||
|
||||
getline(strstream, id, ',');
|
||||
getline(strstream, peds->modelName, ',');
|
||||
getline(strstream, peds->textureName, ',');
|
||||
getline(strstream, peds->type, ',');
|
||||
getline(strstream, peds->behaviour, ',');
|
||||
getline(strstream, peds->animGroup, ',');
|
||||
getline(strstream, driveMask, ',');
|
||||
getline(strstream, peds->name, ',');
|
||||
getline(strstream, peds->textureslot, ',');
|
||||
|
||||
peds->ID = atoi(id.c_str());
|
||||
peds->driveMask = atoi(driveMask.c_str());
|
||||
getline(strstream, buff, ',');
|
||||
peds->pedtype_ = PedModelInfo::findPedType(buff);
|
||||
|
||||
objects.insert({peds->ID, peds});
|
||||
getline(strstream, peds->behaviour_, ',');
|
||||
getline(strstream, peds->animgroup_, ',');
|
||||
|
||||
getline(strstream, buff, ',');
|
||||
peds->carsmask_ = std::atoi(buff.c_str());
|
||||
|
||||
objects.emplace(peds->id(), std::move(peds));
|
||||
break;
|
||||
}
|
||||
case PATH: {
|
||||
@ -253,25 +232,22 @@ bool LoaderIDE::load(const std::string &filename) {
|
||||
}
|
||||
|
||||
auto &object = objects[path.ID];
|
||||
auto instance =
|
||||
std::dynamic_pointer_cast<ObjectData>(object);
|
||||
instance->paths.push_back(path);
|
||||
auto simple = dynamic_cast<SimpleModelInfo*>(object.get());
|
||||
simple->paths.push_back(path);
|
||||
|
||||
break;
|
||||
}
|
||||
case HIER: {
|
||||
std::shared_ptr<CutsceneObjectData> cut(
|
||||
new CutsceneObjectData);
|
||||
auto hier =
|
||||
std::unique_ptr<ClumpModelInfo>(new ClumpModelInfo);
|
||||
|
||||
std::string id;
|
||||
getline(strstream, buff, ',');
|
||||
hier->setModelID(std::atoi(buff.c_str()));
|
||||
|
||||
getline(strstream, id, ',');
|
||||
getline(strstream, cut->modelName, ',');
|
||||
getline(strstream, cut->textureName, ',');
|
||||
getline(strstream, hier->name, ',');
|
||||
getline(strstream, hier->textureslot, ',');
|
||||
|
||||
cut->ID = atoi(id.c_str());
|
||||
|
||||
objects.insert({cut->ID, cut});
|
||||
objects.emplace(hier->id(), std::move(hier));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -27,13 +27,7 @@ public:
|
||||
/**
|
||||
* @brief objects loaded during the call to load()
|
||||
*/
|
||||
std::map<ObjectID, ObjectInformationPtr> objects;
|
||||
|
||||
/*std::vector<std::shared_ptr<ObjectData>> OBJSs;
|
||||
std::vector<std::shared_ptr<VehicleData>> CARSs;
|
||||
std::vector<std::shared_ptr<CharacterData>> PEDSs;
|
||||
std::vector<std::shared_ptr<CutsceneObjectData>> HIERs;
|
||||
std::vector<std::shared_ptr<PathData>> PATHs;*/
|
||||
std::map<ModelID, std::unique_ptr<BaseModelInfo>> objects;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -15,8 +15,8 @@ const float CharacterObject::DefaultJumpSpeed = 2.f;
|
||||
|
||||
CharacterObject::CharacterObject(GameWorld* engine, const glm::vec3& pos,
|
||||
const glm::quat& rot, const ModelRef& model,
|
||||
std::shared_ptr<CharacterData> data)
|
||||
: GameObject(engine, pos, rot, model)
|
||||
BaseModelInfo *modelinfo)
|
||||
: GameObject(engine, pos, rot, modelinfo, model)
|
||||
, currentState({})
|
||||
, currentVehicle(nullptr)
|
||||
, currentSeat(0)
|
||||
@ -24,7 +24,6 @@ CharacterObject::CharacterObject(GameWorld* engine, const glm::vec3& pos,
|
||||
, jumped(false)
|
||||
, jumpSpeed(DefaultJumpSpeed)
|
||||
, motionBlockedByActivity(false)
|
||||
, ped(data)
|
||||
, physCharacter(nullptr)
|
||||
, physObject(nullptr)
|
||||
, physShape(nullptr)
|
||||
|
@ -125,8 +125,6 @@ private:
|
||||
public:
|
||||
static const float DefaultJumpSpeed;
|
||||
|
||||
std::shared_ptr<CharacterData> ped;
|
||||
|
||||
btKinematicCharacterController* physCharacter;
|
||||
btPairCachingGhostObject* physObject;
|
||||
btCapsuleShapeZ* physShape;
|
||||
@ -143,7 +141,7 @@ public:
|
||||
*/
|
||||
CharacterObject(GameWorld* engine, const glm::vec3& pos,
|
||||
const glm::quat& rot, const ModelRef& model,
|
||||
std::shared_ptr<CharacterData> data);
|
||||
BaseModelInfo* modelinfo);
|
||||
|
||||
~CharacterObject();
|
||||
|
||||
@ -151,6 +149,7 @@ public:
|
||||
return Character;
|
||||
}
|
||||
|
||||
|
||||
void tick(float dt);
|
||||
|
||||
const CharacterState& getCurrentState() const {
|
||||
|
@ -3,8 +3,11 @@
|
||||
#include <objects/CutsceneObject.hpp>
|
||||
|
||||
CutsceneObject::CutsceneObject(GameWorld *engine, const glm::vec3 &pos,
|
||||
const glm::quat &rot, const ModelRef &model)
|
||||
: GameObject(engine, pos, rot, model), _parent(nullptr), _bone(nullptr) {
|
||||
const glm::quat &rot,
|
||||
const ModelRef &model, BaseModelInfo *modelinfo)
|
||||
: GameObject(engine, pos, rot, modelinfo, model)
|
||||
, _parent(nullptr)
|
||||
, _bone(nullptr) {
|
||||
skeleton = new Skeleton;
|
||||
animator = new Animator(model->resource, skeleton);
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ class CutsceneObject : public GameObject {
|
||||
|
||||
public:
|
||||
CutsceneObject(GameWorld* engine, const glm::vec3& pos,
|
||||
const glm::quat& rot, const ModelRef& model);
|
||||
const glm::quat& rot, const ModelRef& model, BaseModelInfo *modelinfo);
|
||||
~CutsceneObject();
|
||||
|
||||
Type type() {
|
||||
|
@ -12,6 +12,10 @@ GameObject::~GameObject() {
|
||||
if (skeleton) {
|
||||
delete skeleton;
|
||||
}
|
||||
|
||||
if (modelinfo_) {
|
||||
modelinfo_->removeReference();
|
||||
}
|
||||
}
|
||||
|
||||
void GameObject::setPosition(const glm::vec3& pos) {
|
||||
|
@ -28,6 +28,8 @@ class GameObject {
|
||||
glm::quat _lastRotation;
|
||||
GameObjectID objectID;
|
||||
|
||||
BaseModelInfo* modelinfo_;
|
||||
|
||||
public:
|
||||
glm::vec3 position;
|
||||
glm::quat rotation;
|
||||
@ -53,10 +55,11 @@ public:
|
||||
bool visible;
|
||||
|
||||
GameObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot,
|
||||
ModelRef model)
|
||||
BaseModelInfo* modelinfo, ModelRef model)
|
||||
: _lastPosition(pos)
|
||||
, _lastRotation(rot)
|
||||
, objectID(0)
|
||||
, modelinfo_(modelinfo)
|
||||
, position(pos)
|
||||
, rotation(rot)
|
||||
, model(model)
|
||||
@ -67,6 +70,9 @@ public:
|
||||
, _lastHeight(std::numeric_limits<float>::max())
|
||||
, visible(true)
|
||||
, lifetime(GameObject::UnknownLifetime) {
|
||||
if (modelinfo_) {
|
||||
modelinfo_->addReference();
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~GameObject();
|
||||
@ -85,6 +91,11 @@ public:
|
||||
return getGameObjectID();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T* getModelInfo() const {
|
||||
return static_cast<T*>(modelinfo_);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enumeration of possible object types.
|
||||
*/
|
||||
|
@ -8,25 +8,28 @@
|
||||
InstanceObject::InstanceObject(GameWorld* engine, const glm::vec3& pos,
|
||||
const glm::quat& rot, const ModelRef& model,
|
||||
const glm::vec3& scale,
|
||||
std::shared_ptr<ObjectData> obj,
|
||||
BaseModelInfo *modelinfo,
|
||||
InstanceObject* lod,
|
||||
std::shared_ptr<DynamicObjectData> dyn)
|
||||
: GameObject(engine, pos, rot, model)
|
||||
: GameObject(engine, pos, rot, modelinfo, model)
|
||||
, health(100.f)
|
||||
, scale(scale)
|
||||
, body(nullptr)
|
||||
, object(obj)
|
||||
, LODinstance(lod)
|
||||
, dynamics(dyn)
|
||||
, _enablePhysics(false) {
|
||||
if (obj) {
|
||||
changeModel(obj);
|
||||
if (modelinfo) {
|
||||
changeModel(modelinfo);
|
||||
|
||||
for (auto& path : obj->paths) {
|
||||
/// @todo store path information properly
|
||||
if (modelinfo->type() == ModelDataType::SimpleInfo) {
|
||||
auto simpledata = static_cast<SimpleModelInfo*>(modelinfo);
|
||||
for (auto& path : simpledata->paths) {
|
||||
engine->aigraph.createPathNodes(position, rot, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InstanceObject::~InstanceObject() {
|
||||
if (body) {
|
||||
@ -120,18 +123,18 @@ void InstanceObject::tick(float dt) {
|
||||
if (animator) animator->tick(dt);
|
||||
}
|
||||
|
||||
void InstanceObject::changeModel(std::shared_ptr<ObjectData> incoming) {
|
||||
void InstanceObject::changeModel(BaseModelInfo *incoming) {
|
||||
if (body) {
|
||||
delete body;
|
||||
body = nullptr;
|
||||
}
|
||||
|
||||
object = incoming;
|
||||
/// @todo store the new object
|
||||
|
||||
if (incoming) {
|
||||
auto bod = new CollisionInstance;
|
||||
|
||||
if (bod->createPhysicsBody(this, object->modelName, dynamics.get())) {
|
||||
if (bod->createPhysicsBody(this, incoming->name, dynamics.get())) {
|
||||
bod->getBulletBody()->setActivationState(ISLAND_SLEEPING);
|
||||
body = bod;
|
||||
}
|
||||
|
@ -17,14 +17,13 @@ class InstanceObject : public GameObject {
|
||||
public:
|
||||
glm::vec3 scale;
|
||||
CollisionInstance* body;
|
||||
std::shared_ptr<ObjectData> object;
|
||||
InstanceObject* LODinstance;
|
||||
std::shared_ptr<DynamicObjectData> dynamics;
|
||||
bool _enablePhysics;
|
||||
|
||||
InstanceObject(GameWorld* engine, const glm::vec3& pos,
|
||||
const glm::quat& rot, const ModelRef& model,
|
||||
const glm::vec3& scale, std::shared_ptr<ObjectData> obj,
|
||||
const glm::vec3& scale, BaseModelInfo* modelinfo,
|
||||
InstanceObject* lod, std::shared_ptr<DynamicObjectData> dyn);
|
||||
~InstanceObject();
|
||||
|
||||
@ -34,7 +33,7 @@ public:
|
||||
|
||||
void tick(float dt);
|
||||
|
||||
void changeModel(std::shared_ptr<ObjectData> incoming);
|
||||
void changeModel(BaseModelInfo* incoming);
|
||||
|
||||
virtual void setRotation(const glm::quat& r);
|
||||
|
||||
|
@ -5,8 +5,9 @@
|
||||
#include <rw/defines.hpp>
|
||||
|
||||
ItemPickup::ItemPickup(GameWorld *world, const glm::vec3 &position,
|
||||
PickupType type, InventoryItem *item)
|
||||
: PickupObject(world, position, item->getModelID(), type), item(item) {
|
||||
BaseModelInfo *modelinfo, PickupType type,
|
||||
InventoryItem *item)
|
||||
: PickupObject(world, position, modelinfo, type), item(item) {
|
||||
RW_CHECK(item != nullptr, "Pickup created with null item");
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ class ItemPickup : public PickupObject {
|
||||
InventoryItem* item;
|
||||
|
||||
public:
|
||||
ItemPickup(GameWorld* world, const glm::vec3& position, PickupType type,
|
||||
ItemPickup(GameWorld* world, const glm::vec3& position, BaseModelInfo *modelinfo, PickupType type,
|
||||
InventoryItem* item);
|
||||
|
||||
bool onCharacterTouch(CharacterObject* character);
|
||||
|
@ -59,13 +59,12 @@ uint32_t PickupObject::behaviourFlags(PickupType type) {
|
||||
}
|
||||
|
||||
PickupObject::PickupObject(GameWorld* world, const glm::vec3& position,
|
||||
int modelID, PickupType type)
|
||||
: GameObject(world, position, glm::quat(), nullptr)
|
||||
BaseModelInfo* modelinfo, PickupType type)
|
||||
: GameObject(world, position, glm::quat(), modelinfo, nullptr)
|
||||
, m_ghost(nullptr)
|
||||
, m_shape(nullptr)
|
||||
, m_enabled(false)
|
||||
, m_collected(false)
|
||||
, m_model(modelID)
|
||||
, m_type(type) {
|
||||
btTransform tf;
|
||||
tf.setIdentity();
|
||||
|
@ -37,15 +37,11 @@ public:
|
||||
static float respawnTime(PickupType type);
|
||||
static uint32_t behaviourFlags(PickupType type);
|
||||
|
||||
PickupObject(GameWorld* world, const glm::vec3& position, int modelID,
|
||||
PickupObject(GameWorld* world, const glm::vec3& position, BaseModelInfo *modelinfo,
|
||||
PickupType type);
|
||||
|
||||
~PickupObject();
|
||||
|
||||
int getModelID() const {
|
||||
return m_model;
|
||||
}
|
||||
|
||||
Type type() {
|
||||
return Pickup;
|
||||
}
|
||||
@ -76,7 +72,6 @@ private:
|
||||
bool m_enabled;
|
||||
float m_enableTimer;
|
||||
bool m_collected;
|
||||
int m_model;
|
||||
VisualFX* m_corona;
|
||||
|
||||
PickupType m_type;
|
||||
|
@ -107,7 +107,7 @@ void ProjectileObject::cleanup() {
|
||||
|
||||
ProjectileObject::ProjectileObject(GameWorld* world, const glm::vec3& position,
|
||||
const ProjectileObject::ProjectileInfo& info)
|
||||
: GameObject(world, position, glm::quat(), nullptr)
|
||||
: GameObject(world, position, glm::quat(), nullptr, nullptr)
|
||||
, _info(info)
|
||||
, _body(nullptr)
|
||||
, _ghostBody(nullptr)
|
||||
|
@ -6,8 +6,6 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct VehicleData;
|
||||
|
||||
/**
|
||||
* @brief Stores data loaded from handling.cfg
|
||||
*/
|
||||
|
@ -84,14 +84,13 @@ private:
|
||||
|
||||
VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos,
|
||||
const glm::quat& rot, const ModelRef& model,
|
||||
VehicleDataHandle data, VehicleInfoHandle info,
|
||||
BaseModelInfo *modelinfo, VehicleInfoHandle info,
|
||||
const glm::u8vec3& prim, const glm::u8vec3& sec)
|
||||
: GameObject(engine, pos, rot, model)
|
||||
: GameObject(engine, pos, rot, modelinfo, model)
|
||||
, steerAngle(0.f)
|
||||
, throttle(0.f)
|
||||
, brake(0.f)
|
||||
, handbrake(true)
|
||||
, vehicle(data)
|
||||
, info(info)
|
||||
, colourPrimary(prim)
|
||||
, colourSecondary(sec)
|
||||
@ -99,7 +98,7 @@ VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos,
|
||||
, physRaycaster(nullptr)
|
||||
, physVehicle(nullptr) {
|
||||
collision = new CollisionInstance;
|
||||
if (collision->createPhysicsBody(this, data->modelName, nullptr,
|
||||
if (collision->createPhysicsBody(this, modelinfo->name, nullptr,
|
||||
&info->handling)) {
|
||||
physRaycaster = new VehicleRaycaster(this, engine->dynamicsWorld);
|
||||
btRaycastVehicle::btVehicleTuning tuning;
|
||||
@ -127,7 +126,7 @@ VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos,
|
||||
bool front = connection.y() > 0;
|
||||
btWheelInfo& wi = physVehicle->addWheel(
|
||||
connection, btVector3(0.f, 0.f, -1.f), btVector3(1.f, 0.f, 0.f),
|
||||
restLength, data->wheelScale / 2.f, tuning, front);
|
||||
restLength, getVehicle()->wheelscale_ / 2.f, tuning, front);
|
||||
wi.m_suspensionRestLength1 = restLength;
|
||||
wi.m_raycastInfo.m_suspensionLength = 0.f;
|
||||
|
||||
@ -282,7 +281,7 @@ void VehicleObject::tickPhysics(float dt) {
|
||||
seat.second->updateTransform(passPosition, getRotation());
|
||||
}
|
||||
|
||||
if (vehicle->type == VehicleData::BOAT) {
|
||||
if (getVehicle()->vehicletype_ == VehicleModelInfo::BOAT) {
|
||||
if (isInWater()) {
|
||||
float sign = std::signbit(steerAngle) ? -1.f : 1.f;
|
||||
float steer =
|
||||
@ -356,6 +355,7 @@ void VehicleObject::tickPhysics(float dt) {
|
||||
}
|
||||
}
|
||||
|
||||
auto isBoat = getVehicle()->vehicletype_ == VehicleModelInfo::BOAT;
|
||||
if (inWater) {
|
||||
// Ensure that vehicles don't fall asleep at the top of a wave.
|
||||
if (!collision->getBulletBody()->isActive()) {
|
||||
@ -367,15 +367,13 @@ void VehicleObject::tickPhysics(float dt) {
|
||||
float oZ = 0.f;
|
||||
oZ = -bbZ / 2.f + (bbZ * (info->handling.percentSubmerged / 120.f));
|
||||
|
||||
if (vehicle->type != VehicleData::BOAT) {
|
||||
if (isBoat) {
|
||||
oZ = 0.f;
|
||||
} else {
|
||||
// Damper motion
|
||||
collision->getBulletBody()->setDamping(0.95f, 0.9f);
|
||||
}
|
||||
|
||||
if (vehicle->type == VehicleData::BOAT) {
|
||||
oZ = 0.f;
|
||||
}
|
||||
|
||||
// Boats, Buoyancy offset is affected by the orientation of the
|
||||
// chassis.
|
||||
// Vehicles, it isn't.
|
||||
@ -399,7 +397,7 @@ void VehicleObject::tickPhysics(float dt) {
|
||||
applyWaterFloat(vRt);
|
||||
applyWaterFloat(vLeft);
|
||||
} else {
|
||||
if (vehicle->type == VehicleData::BOAT) {
|
||||
if (isBoat) {
|
||||
collision->getBulletBody()->setDamping(0.1f, 0.8f);
|
||||
} else {
|
||||
collision->getBulletBody()->setDamping(0.05f, 0.0f);
|
||||
|
@ -24,7 +24,6 @@ private:
|
||||
bool handbrake;
|
||||
|
||||
public:
|
||||
VehicleDataHandle vehicle;
|
||||
VehicleInfoHandle info;
|
||||
glm::u8vec3 colourPrimary;
|
||||
glm::u8vec3 colourSecondary;
|
||||
@ -50,7 +49,7 @@ public:
|
||||
std::map<std::string, Part> dynamicParts;
|
||||
|
||||
VehicleObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot,
|
||||
const ModelRef& model, VehicleDataHandle data,
|
||||
const ModelRef& model, BaseModelInfo* modelinfo,
|
||||
VehicleInfoHandle info, const glm::u8vec3& prim,
|
||||
const glm::u8vec3& sec);
|
||||
|
||||
@ -60,6 +59,10 @@ public:
|
||||
|
||||
void setRotation(const glm::quat& orientation);
|
||||
|
||||
VehicleModelInfo* getVehicle() const {
|
||||
return getModelInfo<VehicleModelInfo>();
|
||||
}
|
||||
|
||||
Type type() {
|
||||
return Vehicle;
|
||||
}
|
||||
|
@ -51,9 +51,9 @@ void ObjectRenderer::renderGeometry(Model* model, size_t g,
|
||||
dp.visibility = 1.f;
|
||||
|
||||
if (object && object->type() == GameObject::Instance) {
|
||||
auto instance = static_cast<InstanceObject*>(object);
|
||||
auto modelinfo = object->getModelInfo<SimpleModelInfo>();
|
||||
dp.depthWrite =
|
||||
!(instance->object->flags & ObjectData::NO_ZBUFFER_WRITE);
|
||||
!(modelinfo->flags & SimpleModelInfo::NO_ZBUFFER_WRITE);
|
||||
}
|
||||
|
||||
if (model->geometries[g]->materials.size() > subgeom.material) {
|
||||
@ -163,11 +163,10 @@ void ObjectRenderer::renderItem(InventoryItem* item,
|
||||
return; // No model for this item
|
||||
}
|
||||
|
||||
std::shared_ptr<ObjectData> odata =
|
||||
m_world->data->findObjectType<ObjectData>(item->getModelID());
|
||||
auto odata = m_world->data->modelinfo[item->getModelID()].get();
|
||||
auto weapons = m_world->data->models["weapons"];
|
||||
if (weapons && weapons->resource) {
|
||||
auto itemModel = weapons->resource->findFrame(odata->modelName + "_l0");
|
||||
auto itemModel = weapons->resource->findFrame(odata->name + "_l0");
|
||||
auto matrix = glm::inverse(itemModel->getTransform());
|
||||
if (itemModel) {
|
||||
renderFrame(weapons->resource, itemModel, modelMatrix * matrix,
|
||||
@ -187,15 +186,17 @@ void ObjectRenderer::renderInstance(InstanceObject* instance,
|
||||
return;
|
||||
}
|
||||
|
||||
auto modelinfo = instance->getModelInfo<SimpleModelInfo>();
|
||||
|
||||
// Handles times provided by TOBJ data
|
||||
const auto currentHour = m_world->getHour();
|
||||
if (instance->object->timeOff < instance->object->timeOn) {
|
||||
if (currentHour >= instance->object->timeOff &&
|
||||
currentHour < instance->object->timeOn)
|
||||
if (modelinfo->timeOff < modelinfo->timeOn) {
|
||||
if (currentHour >= modelinfo->timeOff &&
|
||||
currentHour < modelinfo->timeOn)
|
||||
return;
|
||||
} else {
|
||||
if (currentHour >= instance->object->timeOff ||
|
||||
currentHour < instance->object->timeOn)
|
||||
if (currentHour >= modelinfo->timeOff ||
|
||||
currentHour < modelinfo->timeOn)
|
||||
return;
|
||||
}
|
||||
|
||||
@ -216,17 +217,20 @@ void ObjectRenderer::renderInstance(InstanceObject* instance,
|
||||
float opacity = 0.f;
|
||||
constexpr float fadeRange = 50.f;
|
||||
|
||||
if (instance->object->numClumps == 1) {
|
||||
/// @todo replace this block with the correct logic
|
||||
if (modelinfo->getNumAtomics() == 1) {
|
||||
// Is closest point greater than the *object* draw distance
|
||||
float objectRange = instance->object->drawDistance[0];
|
||||
float objectRange = modelinfo->getLodDistance(0);
|
||||
float overlap = (mindist - objectRange);
|
||||
if (mindist > objectRange) {
|
||||
// Check for LOD instances
|
||||
if (instance->LODinstance) {
|
||||
// Is the closest point greater than the *LOD* draw distance
|
||||
float LODrange = instance->LODinstance->object->drawDistance[0];
|
||||
if (mindist > LODrange) {
|
||||
} else if (instance->LODinstance->model->resource) {
|
||||
auto lodmodelinfo =
|
||||
instance->LODinstance->getModelInfo<SimpleModelInfo>();
|
||||
float LODrange = lodmodelinfo->getLodDistance(0);
|
||||
if (mindist <= LODrange &&
|
||||
instance->LODinstance->model->resource) {
|
||||
// The model matrix needs to be for the LOD instead
|
||||
matrixModel =
|
||||
instance->LODinstance->getTimeAdjustedTransform(
|
||||
@ -249,7 +253,7 @@ void ObjectRenderer::renderInstance(InstanceObject* instance,
|
||||
}
|
||||
}
|
||||
// Otherwise, if we aren't marked as a LOD model, we can render
|
||||
else if (!instance->object->LOD) {
|
||||
else if (!modelinfo->LOD) {
|
||||
model = instance->model->resource;
|
||||
}
|
||||
} else {
|
||||
@ -260,9 +264,9 @@ void ObjectRenderer::renderInstance(InstanceObject* instance,
|
||||
|
||||
matrixModel *= root->getTransform();
|
||||
|
||||
for (int i = 0; i < instance->object->numClumps - 1; ++i) {
|
||||
auto ind = (instance->object->numClumps - 1) - i;
|
||||
float lodDistance = instance->object->drawDistance[i];
|
||||
for (int i = 0; i < modelinfo->getNumAtomics() - 1; ++i) {
|
||||
auto ind = (modelinfo->getNumAtomics() - 1) - i;
|
||||
float lodDistance = modelinfo->getLodDistance(i);
|
||||
if (mindist > lodDistance) {
|
||||
fadingFrame = root->getChildren()[ind];
|
||||
fadingModel = objectModel;
|
||||
@ -372,10 +376,11 @@ void ObjectRenderer::renderVehicle(VehicleObject* vehicle,
|
||||
renderFrame(vehicle->model->resource, vehicle->model->resource->frames[0],
|
||||
matrixModel, vehicle, 1.f, outList);
|
||||
|
||||
auto modelinfo = vehicle->getVehicle();
|
||||
// Draw wheels n' stuff
|
||||
for (size_t w = 0; w < vehicle->info->wheels.size(); ++w) {
|
||||
auto woi = m_world->data->findObjectType<ObjectData>(
|
||||
vehicle->vehicle->wheelModelID);
|
||||
auto woi = m_world->data->findModelInfo<SimpleModelInfo>(
|
||||
modelinfo->wheelmodel_);
|
||||
if (woi) {
|
||||
Model* wheelModel = m_world->data->models["wheels"]->resource;
|
||||
auto& wi = vehicle->physVehicle->getWheelInfo(w);
|
||||
@ -406,12 +411,12 @@ void ObjectRenderer::renderVehicle(VehicleObject* vehicle,
|
||||
wheelM = matrixModel * wheelM;
|
||||
|
||||
wheelM =
|
||||
glm::scale(wheelM, glm::vec3(vehicle->vehicle->wheelScale));
|
||||
glm::scale(wheelM, glm::vec3(modelinfo->wheelscale_));
|
||||
if (wi.m_chassisConnectionPointCS.x() < 0.f) {
|
||||
wheelM = glm::scale(wheelM, glm::vec3(-1.f, 1.f, 1.f));
|
||||
}
|
||||
|
||||
renderWheel(vehicle, wheelModel, wheelM, woi->modelName,
|
||||
renderWheel(vehicle, wheelModel, wheelM, woi->name,
|
||||
outList);
|
||||
}
|
||||
}
|
||||
@ -425,25 +430,24 @@ void ObjectRenderer::renderPickup(PickupObject* pickup, RenderList& outList) {
|
||||
modelMatrix = glm::rotate(modelMatrix, m_world->getGameTime(),
|
||||
glm::vec3(0.f, 0.f, 1.f));
|
||||
|
||||
auto odata =
|
||||
m_world->data->findObjectType<ObjectData>(pickup->getModelID());
|
||||
auto odata = pickup->getModelInfo<SimpleModelInfo>();
|
||||
|
||||
Model* model = nullptr;
|
||||
ModelFrame* itemModel = nullptr;
|
||||
|
||||
/// @todo Better determination of is this object a weapon.
|
||||
if (odata->ID >= 170 && odata->ID <= 184) {
|
||||
if (odata->id() >= 170 && odata->id() <= 184) {
|
||||
auto weapons = m_world->data->models["weapons"];
|
||||
if (weapons && weapons->resource && odata) {
|
||||
model = weapons->resource;
|
||||
itemModel = weapons->resource->findFrame(odata->modelName + "_l0");
|
||||
itemModel = weapons->resource->findFrame(odata->name + "_l0");
|
||||
RW_CHECK(itemModel, "Weapon Frame not present int weapon model");
|
||||
if (!itemModel) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto handle = m_world->data->models[odata->modelName];
|
||||
auto handle = m_world->data->models[odata->name];
|
||||
RW_CHECK(handle && handle->resource, "Pickup has no model");
|
||||
if (handle && handle->resource) {
|
||||
model = handle->resource;
|
||||
@ -505,14 +509,14 @@ void ObjectRenderer::renderProjectile(ProjectileObject* projectile,
|
||||
RenderList& outList) {
|
||||
glm::mat4 modelMatrix = projectile->getTimeAdjustedTransform(m_renderAlpha);
|
||||
|
||||
auto odata = m_world->data->findObjectType<ObjectData>(
|
||||
auto odata = m_world->data->findModelInfo<SimpleModelInfo>(
|
||||
projectile->getProjectileInfo().weapon->modelID);
|
||||
auto weapons = m_world->data->models["weapons"];
|
||||
|
||||
RW_CHECK(weapons, "Weapons model not loaded");
|
||||
|
||||
if (weapons && weapons->resource) {
|
||||
auto itemModel = weapons->resource->findFrame(odata->modelName + "_l0");
|
||||
auto itemModel = weapons->resource->findFrame(odata->name + "_l0");
|
||||
auto matrix = glm::inverse(itemModel->getTransform());
|
||||
RW_CHECK(itemModel, "Weapon frame not in model");
|
||||
if (itemModel) {
|
||||
|
@ -31,11 +31,11 @@ inline VehicleObject* getCharacterVehicle(CharacterObject* character) {
|
||||
}
|
||||
inline bool isInModel(const ScriptArguments& args, CharacterObject* character,
|
||||
int model) {
|
||||
auto data = args.getWorld()->data->findObjectType<VehicleData>(model);
|
||||
auto data = args.getWorld()->data->findModelInfo<VehicleModelInfo>(model);
|
||||
if (data) {
|
||||
auto vehicle = getCharacterVehicle(character);
|
||||
if (vehicle) {
|
||||
return vehicle->model ? vehicle->model->name == data->modelName
|
||||
return vehicle->model ? vehicle->model->name == data->name
|
||||
: false;
|
||||
}
|
||||
}
|
||||
|
@ -3546,12 +3546,8 @@ void opcode_0136(const ScriptArguments& args, const ScriptInt arg1, const Script
|
||||
@arg model Model ID
|
||||
*/
|
||||
bool opcode_0137(const ScriptArguments& args, const ScriptVehicle vehicle, const ScriptModelID model) {
|
||||
auto data = args.getWorld()->data->findObjectType<VehicleData>(model);
|
||||
RW_CHECK(data, "non-vehicle model ID");
|
||||
if (data) {
|
||||
return vehicle->model->name == data->modelName;
|
||||
}
|
||||
return false;
|
||||
RW_UNUSED(args);
|
||||
return vehicle->getVehicle()->id() == model;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -8156,7 +8152,11 @@ void opcode_02dd(const ScriptArguments& args, const ScriptString areaName, Scrip
|
||||
bool opcode_02de(const ScriptArguments& args, const ScriptPlayer player) {
|
||||
RW_UNUSED(args);
|
||||
auto vehicle = player->getCharacter()->getCurrentVehicle();
|
||||
return (vehicle && (vehicle->vehicle->classType & VehicleData::TAXI) == VehicleData::TAXI);
|
||||
if (!vehicle) {
|
||||
return false;
|
||||
}
|
||||
auto type = vehicle->getVehicle()->vehicleclass_;
|
||||
return (type & VehicleModelInfo::TAXI) == VehicleModelInfo::TAXI;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -10063,7 +10063,8 @@ void opcode_0363(const ScriptArguments& args, ScriptVec3 coord, const ScriptFloa
|
||||
InstanceObject* object = static_cast<InstanceObject*>(i.second);
|
||||
|
||||
// Check if this instance has the correct model id, early out if it isn't
|
||||
if (!boost::iequals(object->object->modelName, modelName)) {
|
||||
auto modelinfo = object->getModelInfo<BaseModelInfo>();
|
||||
if (!boost::iequals(modelinfo->name, modelName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -11343,7 +11344,7 @@ void opcode_03b6(const ScriptArguments& args, ScriptVec3 coord, const ScriptFloa
|
||||
std::transform(oldmodel.begin(), oldmodel.end(), oldmodel.begin(), ::tolower);
|
||||
|
||||
auto newobjectid = args.getWorld()->data->findModelObject(newmodel);
|
||||
auto nobj = args.getWorld()->data->findObjectType<ObjectData>(newobjectid);
|
||||
auto nobj = args.getWorld()->data->findModelInfo<SimpleModelInfo>(newobjectid);
|
||||
|
||||
/// @todo Objects need to adopt the new object ID, not just the model.
|
||||
for(auto p : args.getWorld()->instancePool.objects) {
|
||||
|
@ -157,10 +157,10 @@ void drawPlayerInfo(PlayerController* player, GameWorld* world,
|
||||
if (current) {
|
||||
uint16_t model = current->getModelID();
|
||||
if (model > 0) {
|
||||
ObjectDataPtr weaponData =
|
||||
world->data->findObjectType<ObjectData>(model);
|
||||
auto weaponData =
|
||||
world->data->findModelInfo<SimpleModelInfo>(model);
|
||||
if (weaponData != nullptr) {
|
||||
itemTextureName = weaponData->modelName;
|
||||
itemTextureName = weaponData->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -116,16 +116,15 @@ void IngameState::startTest() {
|
||||
auto carRot = glm::angleAxis(glm::radians(90.f), glm::vec3(0.f, 0.f, 1.f));
|
||||
// auto boatPos = glm::vec3( -1000.f, -1040.f, 5.f );
|
||||
int i = 0;
|
||||
for (auto& vi : getWorld()->data->objectTypes) {
|
||||
for (auto& vi : getWorld()->data->modelinfo) {
|
||||
switch (vi.first) {
|
||||
case 140:
|
||||
continue;
|
||||
case 141:
|
||||
continue;
|
||||
}
|
||||
if (vi.second->class_type == ObjectInformation::_class("CARS")) {
|
||||
if (vi.second->type() == ModelDataType::VehicleInfo) {
|
||||
if (i++ > 20) break;
|
||||
auto vehicle = std::static_pointer_cast<VehicleData>(vi.second);
|
||||
|
||||
auto& sp = carPos;
|
||||
auto& sr = carRot;
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <engine/GameData.hpp>
|
||||
|
||||
qint16 ItemListModel::getIDOf(unsigned int row) const {
|
||||
if (row < world()->data->objectTypes.size()) {
|
||||
if (row < world()->data->modelinfo.size()) {
|
||||
return row;
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ ItemListModel::ItemListModel(GameWorld *world, QObject *parent)
|
||||
}
|
||||
|
||||
int ItemListModel::rowCount(const QModelIndex &parent) const {
|
||||
return _world->data->objectTypes.size();
|
||||
return _world->data->modelinfo.size();
|
||||
}
|
||||
|
||||
int ItemListModel::columnCount(const QModelIndex &parent) const {
|
||||
|
@ -177,16 +177,21 @@ void ViewerWidget::showObject(qint16 item) {
|
||||
|
||||
if (dummyObject) gworld->destroyObject(dummyObject);
|
||||
|
||||
auto def = world()->data->objectTypes[item];
|
||||
auto def = world()->data->modelinfo[item].get();
|
||||
|
||||
if (def) {
|
||||
if (def->class_type == ObjectData::class_id) {
|
||||
switch (def->type()) {
|
||||
default:
|
||||
dummyObject = gworld->createInstance(item, {});
|
||||
} else if (def->class_type == CharacterData::class_id) {
|
||||
break;
|
||||
case ModelDataType::PedInfo:
|
||||
dummyObject = gworld->createPedestrian(item, {});
|
||||
} else if (def->class_type == VehicleData::class_id) {
|
||||
break;
|
||||
case ModelDataType::VehicleInfo:
|
||||
dummyObject = gworld->createVehicle(item, {});
|
||||
break;
|
||||
}
|
||||
|
||||
RW_CHECK(dummyObject != nullptr, "Dummy Object is null");
|
||||
if (dummyObject != nullptr) {
|
||||
activeModel = dummyObject->model->resource;
|
||||
|
@ -5,19 +5,13 @@ ObjectListModel::ObjectListModel(GameData *dat, QObject *parent)
|
||||
}
|
||||
|
||||
int ObjectListModel::rowCount(const QModelIndex &parent) const {
|
||||
return _gameData->objectTypes.size();
|
||||
return _gameData->modelinfo.size();
|
||||
}
|
||||
|
||||
int ObjectListModel::columnCount(const QModelIndex &parent) const {
|
||||
return 3;
|
||||
}
|
||||
|
||||
static std::map<ObjectInformation::ObjectClass, QString> gDataType = {
|
||||
{ObjectInformation::_class("OBJS"), "Object"},
|
||||
{ObjectInformation::_class("CARS"), "Vehicle"},
|
||||
{ObjectInformation::_class("PEDS"), "Pedestrian"},
|
||||
{ObjectInformation::_class("HIER"), "Cutscene"}};
|
||||
|
||||
QVariant ObjectListModel::data(const QModelIndex &index, int role) const {
|
||||
if (role == Qt::DisplayRole) {
|
||||
auto id = index.internalId();
|
||||
@ -25,23 +19,12 @@ QVariant ObjectListModel::data(const QModelIndex &index, int role) const {
|
||||
if (index.column() == 0) {
|
||||
return id;
|
||||
} else if (index.column() == 1) {
|
||||
auto object = _gameData->objectTypes[id];
|
||||
if (gDataType[object->class_type].isEmpty()) {
|
||||
return QString("Unknown");
|
||||
}
|
||||
return gDataType[object->class_type];
|
||||
auto object = _gameData->modelinfo[id].get();
|
||||
return QString::fromStdString(
|
||||
BaseModelInfo::getTypeName(object->type()));
|
||||
} else if (index.column() == 2) {
|
||||
auto object = _gameData->objectTypes[id];
|
||||
if (object->class_type == ObjectData::class_id) {
|
||||
auto v = std::static_pointer_cast<ObjectData>(object);
|
||||
return QString::fromStdString(v->modelName);
|
||||
} else if (object->class_type == VehicleData::class_id) {
|
||||
auto v = std::static_pointer_cast<VehicleData>(object);
|
||||
return QString::fromStdString(v->modelName);
|
||||
} else if (object->class_type == CharacterData::class_id) {
|
||||
auto v = std::static_pointer_cast<CharacterData>(object);
|
||||
return QString::fromStdString(v->modelName);
|
||||
}
|
||||
auto object = _gameData->modelinfo[id].get();
|
||||
return QString::fromStdString(object->name);
|
||||
}
|
||||
}
|
||||
return QVariant::Invalid;
|
||||
@ -64,9 +47,9 @@ QVariant ObjectListModel::headerData(int section, Qt::Orientation orientation,
|
||||
|
||||
QModelIndex ObjectListModel::index(int row, int column,
|
||||
const QModelIndex &parent) const {
|
||||
auto it = _gameData->objectTypes.begin();
|
||||
auto it = _gameData->modelinfo.begin();
|
||||
for (int i = 0; i < row; i++) it++;
|
||||
auto id = it->second->ID;
|
||||
auto id = it->second->id();
|
||||
|
||||
return hasIndex(row, column, parent) ? createIndex(row, column, id)
|
||||
: QModelIndex();
|
||||
|
@ -60,30 +60,14 @@ void ObjectViewer::worldChanged() {
|
||||
SLOT(showItem(QModelIndex)));
|
||||
}
|
||||
|
||||
static std::map<ObjectInformation::ObjectClass, QString> gDataType = {
|
||||
{ObjectInformation::_class("OBJS"), "Object"},
|
||||
{ObjectInformation::_class("CARS"), "Vehicle"},
|
||||
{ObjectInformation::_class("PEDS"), "Pedestrian"},
|
||||
{ObjectInformation::_class("HIER"), "Cutscene"}};
|
||||
|
||||
void ObjectViewer::showItem(qint16 item) {
|
||||
auto def = world()->data->objectTypes[item];
|
||||
auto def = world()->data->modelinfo[item].get();
|
||||
|
||||
if (def) {
|
||||
previewID->setText(QString::number(def->ID));
|
||||
previewClass->setText(gDataType[def->class_type]);
|
||||
|
||||
if (def->class_type == ObjectData::class_id) {
|
||||
auto v = std::static_pointer_cast<ObjectData>(def);
|
||||
previewModel->setText(QString::fromStdString(v->modelName));
|
||||
} else if (def->class_type == VehicleData::class_id) {
|
||||
auto v = std::static_pointer_cast<VehicleData>(def);
|
||||
previewModel->setText(QString::fromStdString(v->modelName));
|
||||
} else if (def->class_type == CharacterData::class_id) {
|
||||
auto v = std::static_pointer_cast<CharacterData>(def);
|
||||
previewModel->setText(QString::fromStdString(v->modelName));
|
||||
}
|
||||
|
||||
previewID->setText(QString::number(def->id()));
|
||||
previewClass->setText(
|
||||
QString::fromStdString(BaseModelInfo::getTypeName(def->type())));
|
||||
previewModel->setText(QString::fromStdString(def->name));
|
||||
previewWidget->showObject(item);
|
||||
}
|
||||
}
|
||||
|
@ -12,16 +12,16 @@ BOOST_AUTO_TEST_CASE(test_object_data) {
|
||||
gd.load();
|
||||
|
||||
{
|
||||
auto def = gd.findObjectType<ObjectData>(1100);
|
||||
auto def = gd.findModelInfo<SimpleModelInfo>(1100);
|
||||
|
||||
BOOST_REQUIRE(def);
|
||||
|
||||
BOOST_ASSERT(def->class_type == ObjectInformation::_class("OBJS"));
|
||||
BOOST_ASSERT(def->type() == ModelDataType::SimpleInfo);
|
||||
|
||||
BOOST_CHECK_EQUAL(def->modelName, "rd_Corner1");
|
||||
BOOST_CHECK_EQUAL(def->textureName, "generic");
|
||||
BOOST_CHECK_EQUAL(def->numClumps, 1);
|
||||
BOOST_CHECK_EQUAL(def->drawDistance[0], 220);
|
||||
BOOST_CHECK_EQUAL(def->name, "rd_Corner1");
|
||||
BOOST_CHECK_EQUAL(def->textureslot, "generic");
|
||||
BOOST_CHECK_EQUAL(def->getNumAtomics(), 1);
|
||||
BOOST_CHECK_EQUAL(def->getLodDistance(0), 220);
|
||||
BOOST_CHECK_EQUAL(def->flags, 0);
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ BOOST_AUTO_TEST_CASE(test_vehicle_buoyancy) {
|
||||
BOOST_REQUIRE(vehicle != nullptr);
|
||||
|
||||
BOOST_REQUIRE(vehicle->info != nullptr);
|
||||
BOOST_REQUIRE(vehicle->vehicle != nullptr);
|
||||
BOOST_REQUIRE(vehicle->getVehicle() != nullptr);
|
||||
|
||||
// Relies on tile 0,0 being watered...
|
||||
|
||||
|
@ -13,16 +13,16 @@ BOOST_AUTO_TEST_CASE(test_object_data) {
|
||||
|
||||
BOOST_ASSERT(l.objects.find(1100) != l.objects.end());
|
||||
|
||||
auto obj = l.objects[1100];
|
||||
auto obj = l.objects[1100].get();
|
||||
|
||||
auto def = std::dynamic_pointer_cast<ObjectData>(obj);
|
||||
auto def = dynamic_cast<SimpleModelInfo*>(obj);
|
||||
|
||||
BOOST_ASSERT(def->class_type == ObjectInformation::_class("OBJS"));
|
||||
BOOST_ASSERT(def->type() == ModelDataType::SimpleInfo);
|
||||
|
||||
BOOST_CHECK_EQUAL(def->modelName, "rd_Corner1");
|
||||
BOOST_CHECK_EQUAL(def->textureName, "generic");
|
||||
BOOST_CHECK_EQUAL(def->numClumps, 1);
|
||||
BOOST_CHECK_EQUAL(def->drawDistance[0], 220);
|
||||
BOOST_CHECK_EQUAL(def->name, "rd_Corner1");
|
||||
BOOST_CHECK_EQUAL(def->textureslot, "generic");
|
||||
BOOST_CHECK_EQUAL(def->getNumAtomics(), 1);
|
||||
BOOST_CHECK_EQUAL(def->getLodDistance(0), 220);
|
||||
BOOST_CHECK_EQUAL(def->flags, 0);
|
||||
}
|
||||
{
|
||||
@ -32,21 +32,21 @@ BOOST_AUTO_TEST_CASE(test_object_data) {
|
||||
|
||||
BOOST_ASSERT(l.objects.find(90) != l.objects.end());
|
||||
|
||||
auto obj = l.objects[90];
|
||||
auto obj = l.objects[90].get();
|
||||
|
||||
auto def = std::dynamic_pointer_cast<VehicleData>(obj);
|
||||
auto def = dynamic_cast<VehicleModelInfo*>(obj);
|
||||
|
||||
BOOST_ASSERT(def->class_type == ObjectInformation::_class("CARS"));
|
||||
BOOST_ASSERT(def->type() == ModelDataType::VehicleInfo);
|
||||
|
||||
BOOST_CHECK_EQUAL(def->modelName, "landstal");
|
||||
BOOST_CHECK_EQUAL(def->textureName, "landstal");
|
||||
BOOST_CHECK_EQUAL(def->type, VehicleData::CAR);
|
||||
BOOST_CHECK_EQUAL(def->handlingID, "LANDSTAL");
|
||||
BOOST_CHECK_EQUAL(def->gameName, "LANDSTK");
|
||||
BOOST_CHECK_EQUAL(def->classType, VehicleData::RICHFAMILY);
|
||||
BOOST_CHECK_EQUAL(def->frequency, 10);
|
||||
BOOST_CHECK_EQUAL(def->wheelModelID, 164);
|
||||
BOOST_CHECK_CLOSE(def->wheelScale, 0.8f, 0.01f);
|
||||
BOOST_CHECK_EQUAL(def->name, "landstal");
|
||||
BOOST_CHECK_EQUAL(def->textureslot, "landstal");
|
||||
BOOST_CHECK_EQUAL(def->vehicletype_, VehicleModelInfo::CAR);
|
||||
BOOST_CHECK_EQUAL(def->handling_, "LANDSTAL");
|
||||
BOOST_CHECK_EQUAL(def->vehiclename_, "LANDSTK");
|
||||
BOOST_CHECK_EQUAL(def->vehicleclass_, VehicleModelInfo::RICHFAMILY);
|
||||
BOOST_CHECK_EQUAL(def->frequency_, 10);
|
||||
BOOST_CHECK_EQUAL(def->wheelmodel_, 164);
|
||||
BOOST_CHECK_CLOSE(def->wheelscale_, 0.8f, 0.01f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(test_item_pickup) {
|
||||
BOOST_REQUIRE(item != nullptr);
|
||||
|
||||
ItemPickup* p = new ItemPickup(Global::get().e, {30.f, 0.f, 0.f},
|
||||
PickupObject::OnStreet, item);
|
||||
nullptr, PickupObject::OnStreet, item);
|
||||
|
||||
Global::get().e->allObjects.push_back(p);
|
||||
|
||||
|
@ -14,10 +14,11 @@ BOOST_AUTO_TEST_CASE(test_create_vehicle) {
|
||||
BOOST_REQUIRE(vehicle != nullptr);
|
||||
|
||||
BOOST_REQUIRE(vehicle->info != nullptr);
|
||||
BOOST_REQUIRE(vehicle->vehicle != nullptr);
|
||||
BOOST_REQUIRE(vehicle->getVehicle() != nullptr);
|
||||
|
||||
// Hardcoded values for the moment
|
||||
BOOST_CHECK_EQUAL(vehicle->vehicle->type, VehicleData::CAR);
|
||||
BOOST_CHECK_EQUAL(vehicle->getVehicle()->vehicletype_,
|
||||
VehicleModelInfo::CAR);
|
||||
|
||||
BOOST_CHECK_EQUAL(vehicle->info->wheels.size(), 4);
|
||||
|
||||
@ -76,7 +77,7 @@ BOOST_AUTO_TEST_CASE(test_door_position) {
|
||||
BOOST_REQUIRE(vehicle != nullptr);
|
||||
|
||||
BOOST_REQUIRE(vehicle->info != nullptr);
|
||||
BOOST_REQUIRE(vehicle->vehicle != nullptr);
|
||||
BOOST_REQUIRE(vehicle->getVehicle() != nullptr);
|
||||
|
||||
BOOST_CHECK(vehicle->getSeatEntryPositionWorld(0).x > 5.f);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user