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。欢迎加入!
    转载请注明出处。
  • 相关阅读:
    如何在Unity中播放影片
    C# typeof()实例详解
    unity3d用鼠标拖动物体的一段代码
    unity3d中Find的用法
    geometry_msgs/PoseStamped 类型的变量的构造
    c++ ros 计算两点距离
    C++ 利用指针和数组以及指针和结构体实现一个函数返回多个值
    C++ 结构体指针的定义
    Cannot initialize a variable of type 'Stu *' with an rvalue of type 'void *'
    C++中的平方、开方、绝对值怎么计算
  • 原文地址:https://www.cnblogs.com/kanego/p/2234939.html
Copyright © 2011-2022 走看看