📄 player.cc
字号:
Player::Player()
{
mTypeMask |= PlayerObjectType;
delta.pos = mAnchorPoint = Point3F(0,0,100);
delta.rot = delta.head = Point3F(0,0,0);
delta.rotOffset = delta.warpOffset = Point3F(0,0,0);
delta.posVec = delta.rotVec = delta.headVec = VectorF(0,0,0);
delta.warpTicks = 0;
delta.dt = 1;
delta.move = NullMove;
mPredictionCount = sMaxPredictionTicks;
mObjToWorld.setColumn(3,delta.pos);
mRot = delta.rot;
mHead = delta.head;
mVelocity.set(0,0,0);
mDataBlock = 0;
mHeadHThread = mHeadVThread = mRecoilThread = 0;
mArmAnimation.action = PlayerData::NullAnimation;
mArmAnimation.thread = 0;
mActionAnimation.action = PlayerData::NullAnimation;
mActionAnimation.thread = 0;
mActionAnimation.delayTicks = 0;
mActionAnimation.forward = true;
mActionAnimation.firstPerson = false;
mActionAnimation.waitForEnd = false;
mActionAnimation.holdAtEnd = false;
mActionAnimation.animateOnServer = false;
mActionAnimation.atEnd = false;
//mState = MoveState; /// TGE_PlayerAnim
mState = WalkState;
mFalling = false;
mContactTimer = 0;
mJumpDelay = 0;
mJumpSurfaceLastContact = 0;
mJumpSurfaceNormal.set(0,0,1);
mControlObject = 0;
mGenerateShadow = true;
dMemset( mSplashEmitter, 0, sizeof( mSplashEmitter ) );
mImpactSound = 0;
mRecoverTicks = 0;
mReversePending = 0;
mLastPos.set( 0.0, 0.0, 0.0 );
mMoveBubbleHandle = 0;
mWaterBreathHandle = 0;
inLiquid = false;
mConvex.init(this);
mWorkingQueryBox.min.set(-1e9, -1e9, -1e9);
mWorkingQueryBox.max.set(-1e9, -1e9, -1e9);
mWeaponBackFraction = 0.0;
mInMissionArea = true;
mBubbleEmitterTime = 10.0;
mLastWaterPos.set( 0.0, 0.0, 0.0 );
mMountPending = 0;
#ifdef TGE_RPG /// TGE_Move
m_ptOriginBak.set(-1.0,-1.0,-1.0);
m_fMoveRate = 1.0f;
m_fMoveSpeed = 0.f;
m_fRunRate = 0.f;
#endif
}
Player::~Player()
{
}
//----------------------------------------------------------------------------
bool Player::onAdd()
{
ActionAnimation serverAnim = mActionAnimation;
if(!Parent::onAdd() || !mDataBlock)
return false;
mWorkingQueryBox.min.set(-1e9, -1e9, -1e9);
mWorkingQueryBox.max.set(-1e9, -1e9, -1e9);
addToScene();
// Make sure any state and animation passed from the server
// in the initial update is set correctly.
ActionState state = mState;
mState = NullState;
setState(state);
if (serverAnim.action != PlayerData::NullAnimation)
{
setActionThread(serverAnim.action, true, serverAnim.holdAtEnd, true, false, true);
if (serverAnim.atEnd)
{
mShapeInstance->clearTransition(mActionAnimation.thread);
mShapeInstance->setPos(mActionAnimation.thread,
mActionAnimation.forward? 1: 0);
if (inDeathAnim())
mDeath.lastPos = 1.0;
}
// We have to leave them sitting for a while since mounts don't come through right
// away (and sometimes not for a while). Still going to let this time out because
// I'm not sure if we're guaranteed another anim will come through and cancel.
#ifdef TGE_RPGCLIENT2 /// TGE_RPGIsServerObject
mMountPending = (S32) sMountPendingTickWait;
#else
if (!isServerObject() && inSittingAnim())
mMountPending = (S32) sMountPendingTickWait;
else
mMountPending = 0;
#endif
}
if (mArmAnimation.action != PlayerData::NullAnimation)
setArmThread(mArmAnimation.action);
//
if (isServerObject())
{
scriptOnAdd();
#ifndef TGE_RPGCLIENT2 /// TGE_RPGIsServerObject
}
else
{
#endif
U32 i;
for( i=0; i<PlayerData::NUM_SPLASH_EMITTERS; i++ )
{
mSplashEmitter[i] = new ParticleEmitter;
mSplashEmitter[i]->onNewDataBlock( mDataBlock->splashEmitterList[i] );
if( !mSplashEmitter[i]->registerObject() )
{
Con::warnf( ConsoleLogEntry::General, "Could not register dust emitter for class: %s", mDataBlock->getName() );
delete mSplashEmitter[i];
mSplashEmitter[i] = NULL;
}
}
mLastWaterPos = getPosition();
// clear out all camera effects
gCamFXMgr.clear();
}
return true;
}
void Player::onRemove()
{
setControlObject(0);
scriptOnRemove();
removeFromScene();
U32 i;
for( i=0; i<PlayerData::NUM_SPLASH_EMITTERS; i++ )
{
if( mSplashEmitter[i] )
{
mSplashEmitter[i]->deleteWhenEmpty();
mSplashEmitter[i] = NULL;
}
}
mWorkingQueryBox.min.set(-1e9, -1e9, -1e9);
mWorkingQueryBox.max.set(-1e9, -1e9, -1e9);
Parent::onRemove();
}
void Player::onScaleChanged()
{
const Point3F& scale = getScale();
mScaledBox = mObjBox;
mScaledBox.min.convolve( scale );
mScaledBox.max.convolve( scale );
}
//----------------------------------------------------------------------------
bool Player::onNewDataBlock(GameBaseData* dptr)
{
PlayerData* prevData = mDataBlock;
mDataBlock = dynamic_cast<PlayerData*>(dptr);
if (!mDataBlock || !Parent::onNewDataBlock(dptr))
return false;
// Initialize arm thread, preserve arm sequence from last datablock.
// Arm animation can be from last datablock, or sent from the server.
U32 prevAction = mArmAnimation.action;
mArmAnimation.action = PlayerData::NullAnimation;
if (mDataBlock->lookAction) {
mArmAnimation.thread = mShapeInstance->addThread();
mShapeInstance->setTimeScale(mArmAnimation.thread,0);
if (prevData) {
if (prevAction != prevData->lookAction && prevAction != PlayerData::NullAnimation)
setArmThread(prevData->actionList[prevAction].name);
prevAction = PlayerData::NullAnimation;
}
if (mArmAnimation.action == PlayerData::NullAnimation) {
mArmAnimation.action = (prevAction != PlayerData::NullAnimation)?
prevAction: mDataBlock->lookAction;
mShapeInstance->setSequence(mArmAnimation.thread,
mDataBlock->actionList[mArmAnimation.action].sequence,0);
}
}
else
mArmAnimation.thread = 0;
// Initialize head look thread
TSShape const* shape = mShapeInstance->getShape();
S32 headSeq = shape->findSequence("head");
if (headSeq != -1) {
mHeadVThread = mShapeInstance->addThread();
mShapeInstance->setSequence(mHeadVThread,headSeq,0);
mShapeInstance->setTimeScale(mHeadVThread,0);
}
else
mHeadVThread = 0;
headSeq = shape->findSequence("headside");
if (headSeq != -1) {
mHeadHThread = mShapeInstance->addThread();
mShapeInstance->setSequence(mHeadHThread,headSeq,0);
mShapeInstance->setTimeScale(mHeadHThread,0);
}
else
mHeadHThread = 0;
// Recoil thread. The server player does not play this animation.
mRecoilThread = 0;
if (isGhost())
for (U32 s = 0; s < PlayerData::NumRecoilSequences; s++)
if (mDataBlock->recoilSequence[s] != -1) {
mRecoilThread = mShapeInstance->addThread();
mShapeInstance->setSequence(mRecoilThread,mDataBlock->recoilSequence[s],0);
mShapeInstance->setTimeScale(mRecoilThread,0);
}
// Initialize the primary thread, the actual sequence is
// set later depending on player actions.
mActionAnimation.action = PlayerData::NullAnimation;
mActionAnimation.thread = mShapeInstance->addThread();
updateAnimationTree(!isGhost());
mObjBox.max.x = mDataBlock->boxSize.x * 0.5;
mObjBox.max.y = mDataBlock->boxSize.y * 0.5;
mObjBox.max.z = mDataBlock->boxSize.z;
mObjBox.min.x = -mObjBox.max.x;
mObjBox.min.y = -mObjBox.max.y;
mObjBox.min.z = 0;
// Setup the box for our convex object...
mObjBox.getCenter(&mConvex.mCenter);
mConvex.mSize.x = mObjBox.len_x() / 2.0;
mConvex.mSize.y = mObjBox.len_y() / 2.0;
mConvex.mSize.z = mObjBox.len_z() / 2.0;
// Initialize our scaled attributes as well
onScaleChanged();
scriptOnNewDataBlock();
return true;
}
//----------------------------------------------------------------------------
void Player::setControllingClient(GameConnection* client)
{
Parent::setControllingClient(client);
if (mControlObject)
mControlObject->setControllingClient(client);
}
void Player::setControlObject(ShapeBase* obj)
{
if (mControlObject) {
mControlObject->setControllingObject(0);
mControlObject->setControllingClient(0);
}
if (obj == this || obj == 0)
mControlObject = 0;
else {
if (ShapeBase* coo = obj->getControllingObject())
coo->setControlObject(0);
if (GameConnection* con = obj->getControllingClient())
con->setControlObject(0);
mControlObject = obj;
mControlObject->setControllingObject(this);
mControlObject->setControllingClient(getControllingClient());
}
}
void Player::onCameraScopeQuery(NetConnection *connection, CameraScopeQuery *query)
{
// First, we are certainly in scope, and whatever we're riding is too...
if(mControlObject.isNull() || mControlObject == mMount.object)
Parent::onCameraScopeQuery(connection, query);
else
{
connection->objectInScope(this);
if (isMounted())
connection->objectInScope(mMount.object);
mControlObject->onCameraScopeQuery(connection, query);
}
}
ShapeBase* Player::getControlObject()
{
return mControlObject;
}
//-----------------------------------------------------------------------------
void Player::processTick(const Move* move)
{
PROFILE_START(Player_ProcessTick);
// If we're not being controlled by a client, let the
// AI sub-module get a chance at producing a move.
Move aiMove;
if (!move && isServerObject() && getAIMove(&aiMove))
move = &aiMove;
// Manage the control object and filter moves for the player
Move pMove,cMove;
if (mControlObject)
{
if (!move)
mControlObject->processTick(0);
else
{
pMove = NullMove;
cMove = *move;
if (isMounted())
{
// Filter Jump trigger if mounted
pMove.trigger[2] = move->trigger[2];
cMove.trigger[2] = false;
}
if (move->freeLook)
{
// Filter yaw/picth/roll when freelooking.
pMove.yaw = move->yaw;
pMove.pitch = move->pitch;
pMove.roll = move->roll;
pMove.freeLook = true;
cMove.freeLook = false;
cMove.yaw = cMove.pitch = cMove.roll = 0;
}
mControlObject->processTick((mDamageState == Enabled)? &cMove: &NullMove);
move = &pMove;
}
}
Parent::processTick(move);
/// 只处理非ControlObject对象
// Warp to catch up to server
if (delta.warpTicks > 0)
{
//Con::warnf(" warpTicks %d",delta.warpTicks);//Leo testing
delta.warpTicks--;
// Set new pos.
getTransform().getColumn(3,&delta.pos);
delta.pos += delta.warpOffset;
delta.rot += delta.rotOffset;
setPosition(delta.pos,delta.rot);
setRenderPosition(delta.pos,delta.rot);
updateDeathOffsets();
updateLookAnimation();
// Backstepping
delta.posVec.x = -delta.warpOffset.x;
delta.posVec.y = -delta.warpOffset.y;
delta.posVec.z = -delta.warpOffset.z;
delta.rotVec.x = -delta.rotOffset.x;
delta.rotVec.y = -delta.rotOffset.y;
delta.rotVec.z = -delta.rotOffset.z;
}
else
{
// If there is no move, the player is either an
// unattached player on the server, or a player's
// client ghost.
if (!move)
{
if (isGhost())
{
// If we haven't run out of prediction time,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -