Fix object movement between cells producing a stale Ptr within the script execution (Bug #1942)

moveref
scrawl 10 years ago
parent cda0363f29
commit 7e8ca3fff1

@ -281,7 +281,8 @@ namespace MWBase
virtual void deleteObject (const MWWorld::Ptr& ptr) = 0; virtual void deleteObject (const MWWorld::Ptr& ptr) = 0;
virtual void undeleteObject (const MWWorld::Ptr& ptr) = 0; virtual void undeleteObject (const MWWorld::Ptr& ptr) = 0;
virtual void moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0; virtual MWWorld::Ptr moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0;
///< @return an updated Ptr in case the Ptr's cell changes
virtual void virtual void
moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, float x, float y, float z) = 0; moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, float x, float y, float z) = 0;

@ -590,4 +590,10 @@ namespace MWScript
{ {
return mTargetId; return mTargetId;
} }
void InterpreterContext::updatePtr(const MWWorld::Ptr& updated)
{
if (!mReference.isEmpty())
mReference = updated;
}
} }

@ -169,6 +169,9 @@ namespace MWScript
MWWorld::Ptr getReference(bool required=true); MWWorld::Ptr getReference(bool required=true);
///< Reference, that the script is running from (can be empty) ///< Reference, that the script is running from (can be empty)
void updatePtr(const MWWorld::Ptr& updated);
///< Update the Ptr stored in mReference, if there is one stored there. Should be called after the reference has been moved to a new cell.
virtual std::string getTargetId() const; virtual std::string getTargetId() const;
}; };
} }

@ -224,20 +224,23 @@ namespace MWScript
float ay = ptr.getRefData().getPosition().pos[1]; float ay = ptr.getRefData().getPosition().pos[1];
float az = ptr.getRefData().getPosition().pos[2]; float az = ptr.getRefData().getPosition().pos[2];
MWWorld::Ptr updated = ptr;
if(axis == "x") if(axis == "x")
{ {
MWBase::Environment::get().getWorld()->moveObject(ptr,pos,ay,az); updated = MWBase::Environment::get().getWorld()->moveObject(ptr,pos,ay,az);
} }
else if(axis == "y") else if(axis == "y")
{ {
MWBase::Environment::get().getWorld()->moveObject(ptr,ax,pos,az); updated = MWBase::Environment::get().getWorld()->moveObject(ptr,ax,pos,az);
} }
else if(axis == "z") else if(axis == "z")
{ {
MWBase::Environment::get().getWorld()->moveObject(ptr,ax,ay,pos); updated = MWBase::Environment::get().getWorld()->moveObject(ptr,ax,ay,pos);
} }
else else
throw std::runtime_error ("invalid axis: " + axis); throw std::runtime_error ("invalid axis: " + axis);
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(updated);
} }
}; };
@ -317,6 +320,8 @@ namespace MWScript
{ {
MWBase::Environment::get().getWorld()->moveObject(ptr,store,x,y,z); MWBase::Environment::get().getWorld()->moveObject(ptr,store,x,y,z);
ptr = MWWorld::Ptr(ptr.getBase(), store); ptr = MWWorld::Ptr(ptr.getBase(), store);
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(ptr);
float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees();
float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees();
// Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south = 10800, west = 16200) // Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south = 10800, west = 16200)
@ -365,15 +370,18 @@ namespace MWScript
// another morrowind oddity: player will be moved to the exterior cell at this location, // another morrowind oddity: player will be moved to the exterior cell at this location,
// non-player actors will move within the cell they are in. // non-player actors will move within the cell they are in.
MWWorld::Ptr updated;
if (ptr.getRefData().getHandle() == "player") if (ptr.getRefData().getHandle() == "player")
{ {
MWBase::Environment::get().getWorld()->moveObject(ptr, MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy);
MWBase::Environment::get().getWorld()->getExterior(cx,cy),x,y,z); MWBase::Environment::get().getWorld()->moveObject(ptr,cell,x,y,z);
updated = MWWorld::Ptr(ptr.getBase(), cell);
} }
else else
{ {
MWBase::Environment::get().getWorld()->moveObject(ptr, x, y, z); updated = MWBase::Environment::get().getWorld()->moveObject(ptr, x, y, z);
} }
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(updated);
float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees();
float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees();
@ -638,8 +646,10 @@ namespace MWScript
ptr.getRefData().setLocalRotation(rot); ptr.getRefData().setLocalRotation(rot);
MWBase::Environment::get().getWorld()->rotateObject(ptr, 0,0,0,true); MWBase::Environment::get().getWorld()->rotateObject(ptr, 0,0,0,true);
MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().pos[0],
ptr.getCellRef().getPosition().pos[1], ptr.getCellRef().getPosition().pos[2]); dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(
MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().pos[0],
ptr.getCellRef().getPosition().pos[1], ptr.getCellRef().getPosition().pos[2]));
} }
}; };
@ -678,7 +688,8 @@ namespace MWScript
throw std::runtime_error ("invalid movement axis: " + axis); throw std::runtime_error ("invalid movement axis: " + axis);
Ogre::Vector3 worldPos = ptr.getRefData().getBaseNode()->convertLocalToWorldPosition(posChange); Ogre::Vector3 worldPos = ptr.getRefData().getBaseNode()->convertLocalToWorldPosition(posChange);
MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z); dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(
MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z));
} }
}; };
@ -701,17 +712,18 @@ namespace MWScript
const float *objPos = ptr.getRefData().getPosition().pos; const float *objPos = ptr.getRefData().getPosition().pos;
MWWorld::Ptr updated;
if (axis == "x") if (axis == "x")
{ {
MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0]+movement, objPos[1], objPos[2]); updated = MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0]+movement, objPos[1], objPos[2]);
} }
else if (axis == "y") else if (axis == "y")
{ {
MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0], objPos[1]+movement, objPos[2]); updated = MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0], objPos[1]+movement, objPos[2]);
} }
else if (axis == "z") else if (axis == "z")
{ {
MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0], objPos[1], objPos[2]+movement); updated = MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0], objPos[1], objPos[2]+movement);
} }
else else
throw std::runtime_error ("invalid movement axis: " + axis); throw std::runtime_error ("invalid movement axis: " + axis);

@ -1187,7 +1187,7 @@ namespace MWWorld
} }
} }
bool World::moveObjectImp(const Ptr& ptr, float x, float y, float z) MWWorld::Ptr World::moveObjectImp(const Ptr& ptr, float x, float y, float z)
{ {
CellStore *cell = ptr.getCell(); CellStore *cell = ptr.getCell();
@ -1200,12 +1200,14 @@ namespace MWWorld
moveObject(ptr, cell, x, y, z); moveObject(ptr, cell, x, y, z);
return cell != ptr.getCell(); MWWorld::Ptr updated = ptr;
updated.mCell = cell;
return updated;
} }
void World::moveObject (const Ptr& ptr, float x, float y, float z) MWWorld::Ptr World::moveObject (const Ptr& ptr, float x, float y, float z)
{ {
moveObjectImp(ptr, x, y, z); return moveObjectImp(ptr, x, y, z);
} }
void World::scaleObject (const Ptr& ptr, float scale) void World::scaleObject (const Ptr& ptr, float scale)

@ -104,8 +104,8 @@ namespace MWWorld
void rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust); void rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust);
bool moveObjectImp (const Ptr& ptr, float x, float y, float z); Ptr moveObjectImp (const Ptr& ptr, float x, float y, float z);
///< @return true if the active cell (cell player is in) changed ///< @return an updated Ptr in case the Ptr's cell changes
Ptr copyObjectToCell(const Ptr &ptr, CellStore* cell, ESM::Position pos, bool adjustPos=true); Ptr copyObjectToCell(const Ptr &ptr, CellStore* cell, ESM::Position pos, bool adjustPos=true);
@ -341,7 +341,8 @@ namespace MWWorld
virtual void deleteObject (const Ptr& ptr); virtual void deleteObject (const Ptr& ptr);
virtual void undeleteObject (const Ptr& ptr); virtual void undeleteObject (const Ptr& ptr);
virtual void moveObject (const Ptr& ptr, float x, float y, float z); virtual MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z);
///< @return an updated Ptr in case the Ptr's cell changes
virtual void moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z); virtual void moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z);
virtual void scaleObject (const Ptr& ptr, float scale); virtual void scaleObject (const Ptr& ptr, float scale);

Loading…
Cancel
Save