Delta3d中,如何通过网络为 local actor创建在另一个客户端的 remote actor。

原博客地址:http://www.cnblogs.com/kanego/archive/2011/11/03/2234939.html

前言:纠结了很长时间,remote actor(模拟本地actor的行为) 到底如何创建的呢?是自己手动,抑或是系统自动创建?由于delta3d,本身的说明文档少之又少,而其自带的demo 也没有这方面的应用。Oman大哥和我通过跟踪基于delta3d的开源类库SimCore中的例子netdemo,了解到 这些是通过对本地的actor的稍加些属性,就可以由系统自动创建。

正文:用到的主要类库:dtGame、dtDAL,相关类:GameManager、GMComponent、GameActor、GameActorProxy。不懂的请仔细看下delta3d官网自带的说明文档(末尾的qq群共享里也有O(∩_∩)O~)。

首先,在本地创建actor ,如下:

 1     dtCore::RefPtr<dtGame::GameActorProxy>gap;
 2     GetGameManager()->CreateActor(*dtActors::EngineActorRegistry::GAME_MESH_ACTOR_TYPE,gap);
 3     dtActors::GameMeshActor *gma = static_cast<dtActors::GameMeshActor *>(gap->GetActor());
 4     gma->GetGameActorProxy().SetInitialOwnership(dtGame::GameActorProxy::Ownership::SERVER_PUBLISHED);
 5     gma->SetName("Tank1");
 6     gma->SetUniqueId(dtCore::UniqueId("guo"));
 7     gma->SetMesh("E:/project/Client06/brdm.ive");
 8     gma->SetModelTranslation(osg::Vec3(0.0,6.0,10.0));
 9     gma->SetPrototypeName(gma->GetPrototypeName());
10     //mServerGameManager->AddActor(*actorProxy.get());
11     GetGameManager()->AddActor(gma->GetGameActorProxy(),false,true);

这里的关键属性为

dtGame::GameActorProxy::Ownership::SERVER_PUBLISHED。GameActorProxy中的Owership属性掌管着当map加载完毕时,actor如何加载到各个客户端。
其各个属性的含义如下图所示。其中published代表对外发布,就是可以通过网络发布关于其自己的消息。以我的理解,不具备published性质的actor是不会通过系统
自动创建actor(手动,理论上就可以,感觉没有必要)。

除了这个属性,还要看关键函数,

GetGameManager()->AddActor(gma->GetGameActorProxy(),false,true);其原型为:
 void GameManager::AddActor(GameActorProxy& gameActorProxy, bool isRemote, bool publish),参一为要添加的代理,参二为是否为远程,
如果是远程的话,就没有发布的必要了,参三即是否要发布。主要看参三,publish为true的话,就要通过网络将要添加actor的属性传输到另一个网络端。
详细看代码:
AddActor()
 1 void GameManager::AddActor(GameActorProxy& gameActorProxy, bool isRemote, bool publish)
 2    {
 3       if (gameActorProxy.GetId().ToString().empty())
 4       {
 5          throw dtGame::InvalidActorStateException(
 6             "Actors may not be added the GM with an empty unique id", __FILE__, __LINE__);
 7       }
 8 
 9       // Fail early here so that it doesn't fail is PublishActor and need to wait a tick to
10 // clean up the actor.
11       if (publish && isRemote)
12       {
13          throw dtGame::ActorIsRemoteException( "A remote game actor may not be published", __FILE__, __LINE__);
14       }
15 
16       gameActorProxy.SetGameManager(this);
17       gameActorProxy.SetRemote(isRemote);
18 
19       if (mGMImpl->mEnvironment.valid())
20       {
21          if (mGMImpl->mEnvironment.get() != &gameActorProxy)
22          {
23             IEnvGameActor* ea = static_cast<IEnvGameActor*>(mGMImpl->mEnvironment->GetActor());
24             ea->AddActor(*gameActorProxy.GetActor());
25             mGMImpl->mGameActorProxyMap.insert(std::make_pair(gameActorProxy.GetId(), &gameActorProxy));
26          }
27          else
28          {
29             mGMImpl->mGameActorProxyMap.insert(std::make_pair(mGMImpl->mEnvironment->GetId(), mGMImpl->mEnvironment.get()));
30             mGMImpl->mScene->AddDrawable(mGMImpl->mEnvironment->GetActor());
31             mGMImpl->SendEnvironmentChangedMessage(*this, mGMImpl->mEnvironment.get());
32          }
33       }
34       else
35       {
36          mGMImpl->mGameActorProxyMap.insert(std::make_pair(gameActorProxy.GetId(), &gameActorProxy));
37          mGMImpl->mScene->AddDrawable(gameActorProxy.GetActor());
38       }
39 
40       // Remote actors are normally created in response to a create message, so sending another is silly.
41 // Also, this doen't currently send messages when loading a map, so check here for that state.
42       if (!isRemote && mGMImpl->mMapChangeStateData->GetCurrentState() == MapChangeStateData::MapChangeState::IDLE)
43       {
44          dtCore::RefPtr<Message> msg = mGMImpl->mFactory.CreateMessage(MessageType::INFO_ACTOR_CREATED);
45          gameActorProxy.PopulateActorUpdate(static_cast<ActorUpdateMessage&>(*msg));
46          SendMessage(*msg);
47       }
48 
49       gameActorProxy.SetIsInGM(true);
50 
51       try
52       {
53          // If publishing fails. we need to delete the actor as well.
54          if (publish)
55          {
56             PublishActor(gameActorProxy);
57          }
58 
59          gameActorProxy.InvokeEnteredWorld();
60       }
61       catch (const dtUtil::Exception& ex)
62       {
63          ex.LogException(dtUtil::Log::LOG_ERROR, *mGMImpl->mLogger);
64          DeleteActor(gameActorProxy);
65          throw ex;
66       }
67    }
主要意思,把actor加入到GM里面,并把添加actor的消息通知到各组件,并没有通过网络把MessageType::INFO_ACTOR_CREATED的消息传输出去
。如果isRemote 为false,publish为true的话,通过函数
PublishActor(gameActorProxy)进行处理。继续跟踪,上其代码:
View Code
 1   void GameManager::PublishActor(GameActorProxy& gameActorProxy)
 2    {
 3       GMImpl::GameActorMap::iterator itor = mGMImpl->mGameActorProxyMap.find(gameActorProxy.GetId());
 4 
 5       if (itor == mGMImpl->mGameActorProxyMap.end())
 6       {
 7          throw dtGame::InvalidActorStateException(
 8             "A GameActor may only be published if it's added to the GameManager as a game actor.", __FILE__, __LINE__);
 9       }
10 
11       if (gameActorProxy.IsRemote())
12       {
13          throw dtGame::ActorIsRemoteException( "A remote game actor may not be published", __FILE__, __LINE__);
14       }
15 
16       gameActorProxy.SetPublished(true);
17       dtCore::RefPtr<Message> msg = mGMImpl->mFactory.CreateMessage(MessageType::INFO_ACTOR_PUBLISHED);
18       msg->SetDestination(&GetMachineInfo());
19       msg->SetAboutActorId(gameActorProxy.GetId());
20       msg->SetSendingActorId(gameActorProxy.GetId());
21       SendMessage(*msg);
22    }
主要作用,就是设置,gameActorProxy的属性为Published,创建一条MessageType::INFO_ACTOR_PUBLISHED的消息,发布本GM的各个组件。到此为止,
代码没有了,并没有通过网络传输一条MessageType::INFO_ACTOR_CREATED的消息。到这里,阻塞了。
。。。。。。。
。。。。。。。
通过Oman大哥提醒,消息是传输各个组件里面,肯定有组件进行了相应的处理。看DefaultNetworkPublishingComponent组件。其ProcessMessage()
函数中:if (msg.GetMessageType() == MessageType::INFO_ACTOR_PUBLISHED)
         {
            GameActorProxy* ga = GetGameManager()->FindGameActorById(msg.GetAboutActorId());
            if (ga != NULL && ga->IsPublished())
               ProcessPublishActor(msg, *ga);
         }
看来,
1 PublishActor()函数把相关属性的消息发到了这里,进行了处理。看函数ProcessPublishActor(msg, *ga);代码如下
 1  void DefaultNetworkPublishingComponent::ProcessPublishActor(const Message& msg, GameActorProxy& gap)
 2    {
 3       if (mLogger->IsLevelEnabled(dtUtil::Log::LOG_INFO))
 4       {
 5          mLogger->LogMessage(dtUtil::Log::LOG_INFO, __FUNCTION__, __LINE__,
 6                   "Publishing Actor \"" + gap.GetName() + "\" With type \"" + gap.GetActorType().GetFullName() + "\"");
 7       }
 8 
 9       dtCore::RefPtr<Message> newMsg = GetGameManager()->GetMessageFactory().CreateMessage(MessageType::INFO_ACTOR_CREATED);
10       gap.PopulateActorUpdate(static_cast<ActorUpdateMessage&>(*newMsg));
11       GetGameManager()->SendNetworkMessage(*newMsg);
12    }
1 终于找到,原来是通过这里把创建actor的消息发送出去了。发送过程到此结束。<br>下面来看delta3d中GM的默认处理过程。其处理过程是在组件DefaultMessageProcessor中进行处理的。其ProcessMessage()函数:<br> if (msg.GetMessageType() == MessageType::INFO_ACTOR_CREATED)<br>      {<br>         ProcessCreateActor(static_cast<const ActorUpdateMessage&>(msg));<br>      },直接交给ProcessCreateActor()进行处理。
View Code
 1 void DefaultMessageProcessor::ProcessCreateActor(const ActorUpdateMessage& msg)
 2    {
 3       GameActorProxy* proxy = GetGameManager()->FindGameActorById(msg.GetAboutActorId());
 4       if (proxy == NULL)
 5       {
 6          // just to make sure the message is actually remote
 7          if (msg.GetSource() != GetGameManager()->GetMachineInfo())
 8          {
 9             try
10             {
11                dtCore::RefPtr<GameActorProxy> gap = ProcessRemoteCreateActor(msg);
12                if (gap.valid())
13                {
14                   ProcessRemoteUpdateActor(msg, gap.get());
15                   GetGameManager()->AddActor(*gap, true, false);
16                }
17             }
18             catch (const dtUtil::Exception& ex)
19             {
20                LOG_ERROR("Exception encountered trying to create a remote actor named \"" + msg.GetName()
21                         + "\".  The actor will be ignored. Message: " + ex.What()
22                         + " | Actor ID: " + dtUtil::ToString(msg.GetAboutActorId()));
23             }
24          }
25       }
26       else if (!proxy->IsRemote())
27       {
28          ProcessLocalCreateActor(msg);
29       }
30       else
31       {
32          ProcessRemoteUpdateActor(msg, proxy);
33       }
34    }
  GameActorProxy* proxy = GetGameManager()->FindGameActorById(msg.GetAboutActorId());查看本地是否有此actor,没有的话,此消息<br>携带的actor不是本地的,即为其他客户端的远程actor,完全是模拟(mimc)别的客户端的行为。跳转到:<br>dtCore::RefPtr<GameActorProxy> gap = ProcessRemoteCreateActor(msg);,通过此函数就成功创建remote actor。当然创建的是没有<br>纹理的,必须自己手工添加,并添加到GM里,在客户端就显示出来了。<br><br><br>流程就是这样。不足之后。以后补充。感谢Oman大哥的无私帮助。<br><br><span style="color: #ff0000; font-size: 14pt;"><strong>做个广告:Delta3d技术交流群:12483772。欢迎加入!</strong></span>

<br><br>转载请注明出处。<br><br><br> 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值