日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python firefly 游戏引擎 教程(二) 程序入口

發布時間:2024/3/12 python 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python firefly 游戏引擎 教程(二) 程序入口 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

第一章我們講了程序的基本啟動流程,這里面涉及到了各種節點信息,master,net,gate,game…,當然,無論他叫什么名字,歸根結底他都是一個節點。就好比爺爺爸爸兒子,就像是父父節點,父節點,子節點,不管在家里地位如何,他終究是人。那么是如何實現這個分布式節點的呢,我們這章進入firefly源碼內一探究竟

節點相關的文件都存放在distributed,也就是分布式模塊當中
  • distributed模塊說明
    該模塊主要封裝了關于節點的所有方法以及類
  • distributed模塊結構解析

PBRoot,root節點對象(所有擁有child節點的都是root節點,root節點本身可以有root節點,好比爺爺是root節點,爸爸是root節點,因為他們都有兒子,但是兒子就只能是child節點)

ChildsManager,子節點管理基類
Child 對象對應的是連接到本服務進程的某個服務進程對象。稱為子節點對象

RemoteObject遠程調用對象,所有child對象都是一個遠程調用對象,遠程調用對象封裝了一個child對象和child對象的遠程代理通道(用于反向調用),以及service對象(用于提供遠程調用的方法,在下面你會看到很多他的身影,你可先不用管他是什么,只需要知道他能提供被調用的方法就可以了,因為在下一章,我們會詳細描述service)

  • 分布式模塊的文件結構如下
    模塊結構如下:
文件結構:-distributed-__init__.py-child.py-manager.py-node.py-reference.py-root.py
  • _ init _.py
#該文件本身并沒有什么意義,存在的作用是將distributed文件變成一個可以導入的包
  • child.py
# 沒有子節點的節點統稱為child節點,這類節點一般用于提供各類服務 ''' Created on 2013-8-14@author: lan (www.9miao.com) ''' class Child(object):'''子節點對象'''def __init__(self,cid,name):'''初始化子節點對象'''self._id = cidself._name = nameself._transport = Nonedef getName(self):'''獲取子節點的名稱'''return self._namedef setTransport(self,transport):'''設置子節點的通道'''self._transport = transportdef callbackChild(self,*args,**kw):'''回調子節點的接口return a Defered Object (recvdata)'''recvdata = self._transport.callRemote('callChild',*args,**kw)return recvdata
  • manager.py
# manager 顧名思義,是一個管理類 # 在分布式節點中,既然有子節點,那么就會有父節點。 # 而有了根節點,就需要賦予父節點管理子節點的功能 # manager 的出現就是為了這個功能 ''' Created on 2013-8-14@author: lan (www.9miao.com) ''' from twisted.python import log from zope.interface import Interface from zope.interface import implementsclass _ChildsManager(Interface): #接口類(這里用到接口這種開發模式,有興趣的可以看一下)'''節點管理器接口'''def __init__(self):'''初始化接口'''def getChildById(self,childId):'''根據節點id獲取節點實例'''def getChildByName(self,childname):'''根據節點的名稱獲取節點實例'''def addChild(self,child):'''添加一個child節點@param child: Child object'''def dropChild(self,*arg,**kw):'''刪除一個節點'''def callChild(self,*args,**kw):'''調用子節點的接口'''def callChildByName(self,*args,**kw):'''調用子節點的接口@param childname: str 子節點的名稱'''def dropChildByID(self,childId):'''刪除一個child 節點@param childId: Child ID '''def dropChildSessionId(self, session_id):"""根據session_id刪除child節點"""@implementer(_ChildsManager) class ChildsManager(object): ''' 子節點管理器 因為裝飾器implementer 用戶必須得完成_ChildsManager的所有方法 ''' def __init__(self):'''初始化子節點管理器'''self._childs = {} #第一步初始化子節點字典#所有子節點對象都將以鍵值對的形式存儲在這里#key -> child的ID#value -> child 對象,也就是子節點def getChildById(self,childId):'''根據節點的ID獲取節點實例'''return self._childs.get(childId)def getChildByName(self,childname):'''根據節點的名稱獲取節點實例遍歷子節點從中提取節點名稱為childname的節點'''for key,child in self._childs.items():if child.getName() == childname:return self._childs[key]return Nonedef addChild(self,child):'''添加一個child節點@param child: Child object'''key = child._idif self._childs.has_key(key):raise "child node %s exists"% keyself._childs[key] = childdef dropChild(self,child):'''刪除一個child 節點@param child: Child Object '''key = child._idtry:del self._childs[key]except Exception,e:log.msg(str(e))def dropChildByID(self,childId):'''通過ID刪除一個child 節點@param childId: Child ID '''try:del self._childs[childId]except Exception,e:log.msg(str(e))def callChild(self,childId,*args,**kw):'''調用子節點的接口@param childId: int 子節點的id'''child = self._childs.get(childId,None)if not child:log.err("child %s doesn't exists"%childId)returnreturn child.callbackChild(*args,**kw)def callChildByName(self,childname,*args,**kw):'''通過節點名稱調用子節點的接口@param childname: str 子節點的名稱'''child = self.getChildByName(childname)if not child:log.err("child %s doesn't exists"%childname)returnreturn child.callbackChild(*args,**kw)def getChildBYSessionId(self, session_id):"""根據sessionID獲取child節點信息"""for child in self._childs.values():if child._transport.broker.transport.sessionno == session_id:return childreturn None #從代碼中,我們基本上可以看出來這個類除了用于管理子節點的添加,移除,獲取這種最基本的以外, #還有callChild**,callChild函數首先取出子節點,然后再調用子節點的callbackChild函數。 #從字面意思上,我們基本就可以看出來,這是一個調用子節點函數的函數。 #至于怎么實現的,可以去看twisted的透明代理部分,官網都有詳細的說明以及demo。
  • node.py
    介紹了那么多關于子節點的內容,
    下面我們正式開始揭開子節點的面紗。
#顧名思義,node.py就是根節點下面的子節點''' Created on 2013-8-14@author: lan (www.9miao.com) ''' from twisted.spread import pb from twisted.internet import reactor reactor = reactor from reference import ProxyReferencedef callRemote(obj,funcName,*args,**kw):'''遠程調用(這里只是作為一個調用子節點的方法存在)@param obj 子節點對象,也就是RemoteObject@param funcName: str 遠程方法名稱'''return obj.callRemote(funcName, *args,**kw)class RemoteObject(object):'''遠程調用對象也就是真正的子節點'''def __init__(self,name):'''初始化遠程調用對象@param port: int 遠程分布服的端口號@param rootaddr: 根節點服務器地址'''self._name = name #本節點的節點名稱self._factory = pb.PBClientFactory() #twisted的透明代理客戶端工廠self._reference = ProxyReference() #twisted透明代理的代理通道self._addr = None #root節點的節點地址(host,port)def setName(self,name):'''設置節點的名稱'''self._name = namedef getName(self):'''獲取節點的名稱'''return self._namedef connect(self,addr):'''初始化遠程調用對象'''self._addr = addr # 保存遠程節點地址reactor.connectTCP(addr[0], addr[1], self._factory) # 連接遠程節點地址self.takeProxy() # 獲取遠程節點地址對象(這是一個異步操作,返回的是延時對象)def reconnect(self):'''重新連接'''self.connect(self._addr)def addServiceChannel(self,service):'''設置引用對象'''self._reference.addService(service)def takeProxy(self):'''向遠程服務端發送代理通道對象twisted的雙向透明代理規定的步驟1.向服務器請求root對象2.通過root對象向服務器發送自身的ProxyReference(代理通道)3.雙向連接完成'''deferedRemote = self._factory.getRootObject()deferedRemote.addCallback(callRemote,'takeProxy',self._name,self._reference)def callRemote(self,commandId,*args,**kw):'''這里就是正式的遠程調用函數了,子節點調用父節點的方法和建立雙向透明代理類似,調用的步驟為:1.獲取遠程root對象2.通過root對象調用服務器函數@param callRemote 這里調用的就是該文件頂部的那個同名函數由于 addCallback會將 異步獲取的 對象傳入Callback 中也就是傳入 callRemote 這個函數內,所以最終實現的效果是 :self._factory.getRootObject().callRemote('callTarget', ,commandId,*args,**kw)@param callTarget 這是firefly定義的遠程調用函數函數名稱@param commandId 遠程對象會根據 commandId 來最終絕對執行什么操作'''deferedRemote = self._factory.getRootObject()return deferedRemote.addCallback(callRemote,'callTarget',commandId,*args,**kw)
  • reference.py(代理通道)
#coding:utf8 ''' Created on 2013-8-14@author: lan (www.9miao.com) ''' from twisted.spread import pb from firefly.utils.services import Serviceclass ProxyReference(pb.Referenceable):'''代理通道'''def __init__(self):'''初始化'''self._service = Service('proxy')def addService(self,service):'''添加一條服務通道'''self._service = servicedef remote_callChild(self, command,*arg,**kw):'''代理發送數據'''return self._service.callTarget(command,*arg,**kw) #這一部分是代理通道相關的代碼 #主要實現功能就是在子節點實例化的時候產生一個代理通道 #然后在子節點連接上父節點之后通過調用takeProxy函數將自己的代理通道對象發送給父節點 #代理成功后,父節點就可以調用子節點中約定的函數(這也被稱為pb的反向調用)
  • 父節點對象 -root.py
    最后我們來看看分布式節點的中心root節點,當然這里的所謂中心并不代表只有一個root節點,比如暗黑世界里,直觀的你就能發現master和gate都是root節點,對于master而言,gate又是他的子節點。同理,game同樣可以作為一個root節點(當然在暗黑世界里,game是一個child節點),然后分裂出game1,game2,game3…,但同時,又是gate的子節點,這其中并不矛盾。
# root.py文件,顧名思義,是個根節點''' Created on 2013-8-14 分布式根節點 @author: lan (www.9miao.com) ''' from twisted.python import log from twisted.spread import pb from manager import ChildsManager from child import Childclass BilateralBroker(pb.Broker):''''''def connectionLost(self, reason):'''這里重寫了pb.broker的連接丟失方法,用于子連接丟失后將子節點從根節點中移除'''clientID = self.transport.sessionno #獲取斷開的節點idlog.msg("node [%d] lose"%clientID)self.factory.root.dropChildSessionId(clientID)# 移除斷開的節點對象pb.Broker.connectionLost(self, reason) #斷開節點class BilateralFactory(pb.PBServerFactory):'''重寫 PBServerFactory 類,目的只是為了重寫pb.Broker的connectionLost方法,而重寫connectionLost方法只是為了將子節點斷開后,從根節點中將對象刪除,保持根節點對于子節點信息存儲的準確性''' protocol = BilateralBrokerclass PBRoot(pb.Root):'''繼承PB 協議的root節點'''def __init__(self,dnsmanager = ChildsManager()):'''初始化根節點'''self.service = None self.childsmanager = dnsmanager # 創建子節點管理器def addServiceChannel(self,service):'''添加服務通道@param service: Service Object(In bilateral.services)'''self.service = service # def doChildConnect(self,name,transport):"""當node節點連接時的處理"""passdef dropChild(self,*args,**kw):'''刪除子節點記錄'''self.childsmanager.dropChild(*args,**kw)def dropChildByID(self,childId):'''刪除子節點記錄'''self.doChildLostConnect(childId)self.childsmanager.dropChildByID(childId)def dropChildSessionId(self, session_id):'''刪除子節點記錄'''child = self.childsmanager.getChildBYSessionId(session_id)if not child:returnchild_id = child._idself.doChildLostConnect(child_id)self.childsmanager.dropChildByID(child_id)def doChildLostConnect(self,childId):"""當node節點連接時的處理"""passdef callChild(self,key,*args,**kw):'''調用子節點的接口@param childId: int 子節點的idreturn Defered Object'''return self.childsmanager.callChild(key,*args,**kw)def callChildByName(self,childname,*args,**kw):'''調用子節點的接口@param childId: int 子節點的idreturn Defered Object'''return self.childsmanager.callChildByName(childname,*args,**kw)# 這里remote_**格式的方法,是twisted透明代理方法的格式,以此命名的方法都可被遠程調用def remote_takeProxy(self,name,transport):'''設置代理通道@param addr: (hostname,port)hostname 根節點的主機名,根節點的端口'''log.msg('node [%s] takeProxy ready'%name)child = Child(name,name) # 創建子節點self.childsmanager.addChild(child) # 添加子節點child.setTransport(transport) # 設置子節點連接對象self.doChildConnect(name, transport) #連接子節點 def remote_callTarget(self,command,*args,**kw):'''遠程調用方法@param commandId: int 指令號@param data: str 調用參數'''data = self.service.callTarget(command,*args,**kw)return data

總結

以上是生活随笔為你收集整理的python firefly 游戏引擎 教程(二) 程序入口的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。