refactor(entity): models get their physics in the client's model case

ObjectLoader2::LoadModelBehaviorsComponent: a model without physics gets simple
physics 4247 (with behaviors: controllable 4246 for modelType 0, else simple,
or the registry's id, which the simple physics case leaves to it), and
modelType 0 gets pathfinding control. This replaces the BBB model (LOT 14)
special case, which now loads through the registry like any object (same
bytes as live LOT 14 constructions); the 17 other model LOTs without
physics in the registry now get the simple physics the client makes for them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-10-01 11:49:38 -05:00
parent 91942b16a2
commit d786290803

View File

@@ -288,26 +288,6 @@ void Entity::Initialize() {
// Get the registry table
CDComponentsRegistryTable* const compRegistryTable = CDClientManager::GetTable<CDComponentsRegistryTable>();
/**
* Special case for BBB models. They have components not corresponding to the registry.
*/
if (m_TemplateID == 14) {
const auto simplePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SIMPLE_PHYSICS);
AddComponent<SimplePhysicsComponent>(simplePhysicsComponentID);
AddComponent<ItemComponent>(compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ITEM));
AddComponent<ModelComponent>(-1)->LoadBehaviors();
AddComponent<RenderComponent>(-1);
AddComponent<DestroyableComponent>(-1, true);
// We have all our components.
return;
}
/**
* Player components (the client makes them with the character, not from the registry)
*/
@@ -332,6 +312,10 @@ void Entity::Initialize() {
|| HasComponent(eReplicaComponentType::VEHICLE_PHYSICS) || HasComponent(eReplicaComponentType::HAVOK_VEHICLE_PHYSICS);
if (hasMovementPhysics && !HasComponent(eReplicaComponentType::PATHFINDING)) AddComponent<PathfindingComponent>(-1);
};
// A model with behaviors (DoObjectPreLoad 0x01055667: not inInventory, and modelType and modelBehaviors in its
// config) gets its physics from the model case, which takes the registry's simple physics id
const bool hasModelBehaviors = !GetVar<bool>(u"inInventory") && HasVar(u"modelType") && HasVar(u"modelBehaviors");
int32_t modelPhysicsComponentID = -1;
// If an entity is marked a phantom, simple physics is made into phantom phyics.
const bool markedAsPhantom = GetVar<bool>(u"markedAsPhantom");
@@ -409,7 +393,10 @@ void Entity::Initialize() {
}
case eReplicaComponentType::SIMPLE_PHYSICS: {
const auto simplePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SIMPLE_PHYSICS);
if (!markedAsPhantom && simplePhysicsComponentID > 0) {
if (hasModelBehaviors) {
// LWOSimplePhysicsComponent::Allocator (0x0104ded0): left to the model case
if (simplePhysicsComponentID > 0) modelPhysicsComponentID = simplePhysicsComponentID;
} else if (!markedAsPhantom && simplePhysicsComponentID > 0) {
AddComponent<SimplePhysicsComponent>(simplePhysicsComponentID);
}
break;
@@ -788,6 +775,21 @@ void Entity::Initialize() {
case eReplicaComponentType::MODEL: {
const auto modelID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MODEL, -1);
if (modelID > -1 && !GetComponent<PetComponent>()) {
// ObjectLoader2::LoadModelBehaviorsComponent (0x0104d1f0): a model without physics gets it here (BBB models,
// LOT 14, have none in the registry): simple physics 4247 without behaviors; with behaviors controllable
// (4246) for modelType 0, else simple (4247), unless the registry gave an id. modelType 0 also gets
// pathfinding control.
const bool hasPhysics = HasComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS) || HasComponent(eReplicaComponentType::SIMPLE_PHYSICS)
|| HasComponent(eReplicaComponentType::PROJECTILE_PHYSICS) || HasComponent(eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS)
|| HasComponent(eReplicaComponentType::HAVOK_VEHICLE_PHYSICS) || HasComponent(eReplicaComponentType::PHANTOM_PHYSICS)
|| HasComponent(eReplicaComponentType::VEHICLE_PHYSICS) || HasComponent(eReplicaComponentType::PHYSICS_SYSTEM);
const int32_t modelType = HasVar(u"modelType") ? GetVarAs<int32_t>(u"modelType") : -1;
if (!hasPhysics) {
if (!hasModelBehaviors) AddComponent<SimplePhysicsComponent>(4247);
else if (modelType == 0) AddComponent<ControllablePhysicsComponent>(modelPhysicsComponentID == -1 ? 4246 : modelPhysicsComponentID);
else AddComponent<SimplePhysicsComponent>(modelPhysicsComponentID == -1 ? 4247 : modelPhysicsComponentID);
}
if (modelType == 0 && !HasComponent(eReplicaComponentType::PATHFINDING)) AddComponent<PathfindingComponent>(-1);
AddComponent<ModelComponent>(modelID)->LoadBehaviors();
if (!HasComponent(eReplicaComponentType::DESTROYABLE)) {
AddComponent<DestroyableComponent>(-1, true);