zoukankan      html  css  js  c++  java
  • Delta3d中,如何通过网络为 local actor创建在另一个客户端的 remote actor。

    前言:纠结了很长时间,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);
             }
    看来,
    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 }
    终于找到,原来是通过这里把创建actor的消息发送出去了。发送过程到此结束。
    下面来看delta3d中GM的默认处理过程。其处理过程是在组件DefaultMessageProcessor中进行处理的。其ProcessMessage()函数:
     if (msg.GetMessageType() == MessageType::INFO_ACTOR_CREATED)
          {
             ProcessCreateActor(static_cast<const ActorUpdateMessage&>(msg));
          },直接交给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,没有的话,此消息
    携带的actor不是本地的,即为其他客户端的远程actor,完全是模拟(mimc)别的客户端的行为。跳转到:
    dtCore::RefPtr<GameActorProxy> gap = ProcessRemoteCreateActor(msg);,通过此函数就成功创建remote actor。当然创建的是没有
    纹理的,必须自己手工添加,并添加到GM里,在客户端就显示出来了。
    流程就是这样。不足之后。以后补充。感谢Oman大哥的无私帮助。
    做个广告:Delta3d技术交流群:12483772。欢迎加入!
    转载请注明出处。
  • 相关阅读:
    1058 A+B in Hogwarts (20)
    1036. Boys vs Girls (25)
    1035 Password (20)
    1027 Colors in Mars (20)
    1009. Product of Polynomials (25)
    1006. Sign In and Sign Out
    1005 Spell It Right (20)
    1046 Shortest Distance (20)
    ViewPager页面滑动,滑动到最后一页,再往后滑动则执行一个事件
    IIS7.0上传文件限制的解决方法
  • 原文地址:https://www.cnblogs.com/kanego/p/2234939.html
Copyright © 2011-2022 走看看