目录

EntityCall

在之前的章节中一直提到EntityCall,那什么是EntityCall?我们可以简单的理解为:封装远程交互、通讯等方法的一种对象,是脚本层与实体远程交互的常规手段。

下面我们会围绕这几个问题来进行解释:

1

EntityCall的底层实现原理:

EntityCall对象在C++底层实现非常简单,它只包含了实体的ID、目的地的地址、实体类型、EntityCall类型。

当用户请求一次远程交互时,底层首先能够通过实体类型找到实体定义的描述(def配置文件),通过该描述对用户输入的数据进行检查,如果检查合法那么底层将数据打包并发往目的地,接着目的地进程根据协议进行解包,根据实体ID找到实体,最终调用到脚本层。

EntityCall的限制或要求:

刚才在底层实现原理中提到,必须先通过实体类型找到实体定义的描述,而这个描述即是def配置文件!相当于互相之间的远程通讯都通过def“协议”规定好的。所以EntityCall只能:

1:调用其对应def配置文件中声明过的方法;
2:def配置中的属性不可被访问;
3:在def定义之外的任何信息都不可被访问。

一个实体包含哪些EntityCall?

一个实体最多可以包含三个部分:

1.client:

当实体包含客户端部分时(通常为玩家),在服务器端可以访问实体的client属性,该属性是一个EntityCall。

如,Avatar.def中定义了client远程方法如下
<ClientMethods>
	<hello>
	</hello>
</ClientMethods>
在服务端可以通过如下方式向client进行远程方法调用:
class Avatar(KBEngine.Entity):
    def test():
        self.client.hello()

2.base:

当实体的一部分创建在Baseapp(如Baseapp A)时,在非当前Baseapp(如Baseapp B、Cellapp C等)中可以访问实体的base属性,该属性是一个EntityCall。

如,Avatar.def中定义了base远程方法如下
<BaseMethods>
	<hello>
	</hello>
</BaseMethods>
在服务端可以通过如下方式向base进行远程方法调用:
def test(entity):
    """
    entity是一个不在当前app上的实体
    """
    entity.base.hello()

2.cell:

当实体的一部分创建在Cellapp(如Cellapp A)时,在非当前Cellapp(如Cellapp B、Baseapp C等)中可以访问实体的cell属性,该属性是一个EntityCall。

如,Avatar.def中定义了cell远程方法如下
<CellMethods>
	<hello>
	</hello>
</CellMethods>
在服务端可以通过如下方式向cell进行远程方法调用:
def test(entity):
    """
    entity是一个不在当前app上的实体
    """
    entity.cell.hello()

利用EntityCall调用实体组件上的方法:

在新版本的引擎中,组件已被支持,并且EntityCall可以调用到实体组件上的方法了。因为组件及其方法也是声明在def配置文件中的,所以自然也是可以被远程调用到的(见上文的底层实现)。我们来看看如何进行调用:

如,Avatar.def中定义了其包含了Combat战斗组件,部分配置如下:
<Components>
    <!--战斗组件-->
    <combat>
        <Type>  		Combat          </Type>
        <Persistent>	true            </Persistent>
    </combat>
    ...
    ...
</Components>
Combat组件的部分def如下:
<CellMethods>
    <!--受到伤害-->
    <recvDamage>
        <!--伤害来源方-->
        <Arg>	        ENTITY_ID		</Arg>
        <!--伤害来源于的技能-->
        <Arg>	        SKILLID			</Arg>
        <!--伤害类型-->
        <Arg>	        DAMAGE_TYPE		</Arg>
        <!--伤害值-->
        <Arg>	        HP              </Arg>
    </recvDamage>
</CellMethods>
<ClientMethods>
    <!--给客户端通知,收到伤害反馈-->
    <onRecvDamage>
        <!--伤害来源方-->
        <Arg>	        ENTITY_ID		</Arg>
        <!--来源技能-->
        <Arg>	        SKILLID			</Arg>
        <!--伤害类型-->
        <Arg>	        DAMAGE_TYPE		</Arg>
        <!--造成伤害的值-->
        <Arg>	        HP              </Arg>
    </onRecvDamage>
</ClientMethods>
在服务端可以通过如下方式向AvatarCombat组件进行远程方法调用:

假设,以下方法是在cell上的实现。

逻辑脚本:
def doDamage(avatarCellEntityCall, attacker, skillID, damageType, damage):
    """
    avatarCellEntityCall是一个不在当前app上的Avatar实体的cellEntityCall
    """
    avatarCellEntityCall.combat.recvDamage(attacker.id, skillID, damageType, damage)
...
...
Combat组件上的实现代码Combat.py上:
def recvDamage(attackerID, skillID, damageType, damage):
    """
    Combat组件上recvDamage的实现
    """
    # 发送给组件对应的客户端
    self.client.onRecvDamage(attackerID, skillID, damageType, damage)

我们可以看到,通过avatarCellEntityCall.combat可以访问到实体在cell上声明的组件,并调用def中配置的方法recvDamage。同样的,在组件上调用self.client.onRecvDamage,向其客户端发出远程方法调用。

相关参考:

关于EntityCall,还必须提一下API中Cellapp下的Entity.allClientsEntity.otherClientsEntity.clientEntity(self, destID),具体请查看API手册。

Entity.allClients

通过这个属性调用实体的客户端远程方法,引擎会将这个消息广播给实体View范围内所有的其他绑定了客户端的实体(包括自己的客户端,绑定了客户端的实体通常为玩家)。

Entity.otherClients

通过这个属性调用实体的客户端远程方法,引擎会将这个消息广播给实体View范围内所有的其他绑定了客户端的实体(不包括自己的客户端,绑定了客户端的实体通常为玩家)。

Entity.clientEntity(self, destID)

通过这个方法可以访问自己客户端(当前实体必须绑定了客户端)中某个实体的方法,只有在View范围内的实体才会同步到客户端。它只能在一个real实体上被调用。


Copyright © 2018 Yolo Technologies. Publication: 2.0-025. Built: 2018-12-07.