Skip to content

Commit

Permalink
1.60 使用decorator的插件系统,用户数据文件改为.loc-id.playerdata #1
Browse files Browse the repository at this point in the history
  • Loading branch information
fffonion committed Oct 12, 2013
1 parent b61b421 commit 468a22a
Show file tree
Hide file tree
Showing 9 changed files with 288 additions and 109 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ maclient_cli.py [config file] [task]/[commands]

###account_?

?可选cn,cn2,tw分别对应国服1区,国服2区,台服
?可选cn,cn2,cn3,tw分别对应国服1区,国服2区,国服3区,台服

session不用管它

Expand Down
7 changes: 2 additions & 5 deletions config_sample.ini
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ device_token =
display_ani=1
save_traffic=0
auto_update=1
enable_plugin=1

[tactic]
auto_explore =1
Expand Down Expand Up @@ -84,9 +85,5 @@ factor_limit = BC>20
last_set_card =
last_set_bc =

[remote]
uname =
pwd =
maclient =
macserver = http://mac.yooooo.us
[plugin]

209 changes: 118 additions & 91 deletions maclient.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion maclient_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import maclient_logging
import maclient_remote
import getpass
__version__=1.50
__version__=1.60
#look out for ironpython
du8=sys.platform.startswith('cli') and \
(lambda str:str) or\
Expand Down
5 changes: 2 additions & 3 deletions maclient_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ def calc_ap_bc(self):
getattr(self,key)['current']=getattr(self,key)['max']

def _update_data(self,xmldata):
self.calc_ap_bc()
try:
xmlresp = XML2Dict().fromstring(xmldata).response
if 'login' in xmlresp.body:
Expand All @@ -64,8 +63,8 @@ def _update_data(self,xmldata):
self.lv=self.playerdata['town_level'].value
self.leader_sid=self.playerdata['leader_serial_id'].value
self.name=self.playerdata['name'].value
except KeyError:
pass
except KeyError:#没有就自己算
self.calc_ap_bc()
if not self.checked_update:
# try:
cardrev=int(xmlresp.header.revision.card_rev)
Expand Down
125 changes: 119 additions & 6 deletions maclient_plugin.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,132 @@
#!/usr/bin/env python
# coding:utf-8
# maclient plugin loader
# maclient plugin loader and hooker
# Contributor:
# fffonion <[email protected]>
import os,os.path as opath
import sys
import glob
getPATH0=(opath.split(sys.argv[0])[1].find('py') != -1 or sys.platform=='cli') \
and sys.path[0].decode(sys.getfilesystemencoding()) \
or sys.path[1].decode(sys.getfilesystemencoding())#pyinstaller build
sys.path.append(opath.join(getPATH0,'plugins'))
#os.chdir(opath.join(getPATH0(),'plugins'))
sys.path[0]=os.path.abspath(opath.join(getPATH0,'plugins'))
def load_plugins():
import hehe
hehe.a()
#sys.path[0]=os.path.abspath(opath.join(getPATH0,'plugins'))

PREF_ENTER='ENTER_'
PREF_EXIT='EXIT_'
class plugins():
def __init__(self,logger):
self.traced_func = set()
self.plugins=[]
self.load_plugins()
self.scan_hooks()
self.logger=logger
self.enable=True

def scan_hooks(self):
self.hook_reg={}
ALL_ACTIONS=['tasker','auto_check','check_strict_bc','set_card','red_tea','green_tea',
'explore','_explore_floor','gacha','select_card_sell','fairy_battle_loop','fairy_select','_fairy_battle',
'like','friends','reward_box','point_setting','factor_battle']
#scan plugin hooks
for act in ALL_ACTIONS:
for p in self.plugins:
for method in [PREF_ENTER,PREF_EXIT]:#enter, exit
key='%s%s'%(method,act)
if key not in self.hook_reg:
self.hook_reg[key]={}
if key in self._get_plugin_meta(p,'hooks'):#add to hook reg
self.hook_reg[key][p]=self._get_plugin_meta(p,'hooks')[key]

# def set_enable(self,lst):
# pass

def set_disable(self,lst):
for p in lst:
if p:
del(self.plugins[self.plugins.index(p)])
self.scan_hooks()

def _get_plugin_meta(self,mod,key):
try:
return getattr(globals()[mod],key)
except AttributeError:
self.logger.warning('No meta found for module "%s"'%mod)
return []

def _get_plugin_attr(self,mod,attr):
try:
return getattr(globals()[mod].plugin(),attr)
except AttributeError:
self.logger.warning('Get "%s" failed from "%s" '%(attr,mod))
return []

def _do_hook(self,action,*args,**kwargs):
if action in self.hook_reg:
for plugin in sorted(self.hook_reg[action].iteritems(), key=lambda d:d[1], reverse = True):#high priority first
f=self._get_plugin_attr(plugin[0],action)
if f!=[]:
args,kwargs=f(*args, **kwargs)
return args,kwargs

def load_plugins(self):
import glob
plugin_dir=opath.abspath(opath.join(getPATH0,'plugins'))
mods=glob.glob(opath.join(plugin_dir,'*.py'))+\
glob.glob(opath.join(plugin_dir,'*.pyc'))+\
glob.glob(opath.join(plugin_dir,'*.pyo'))+\
glob.glob(opath.join(plugin_dir,'*.pyd'))
for m in mods:
m=opath.splitext(opath.split(m)[1])[0]
if m=='_prototype':
continue
if m not in self.plugins:
globals()[m]=__import__(m)
self.plugins.append(m)

def _line_tracer(self):
#originally from http://stackoverflow.com/questions/19227636/decorator-to-log-function-execution-line-by-line
#it works almostly the same as module 'memory_profiler'
#not working yet
traced_func.add(func.func_code)
def _wrapper(*args, **kwargs):#need a wrap
old_trace_function = sys.gettrace()
sys.settrace(logging_tracer)
try:
result = func(*args, **kwargs)
except:
raise
else:
return result
finally:
sys.settrace(old_trace_function)
return _wrapper

def func_hook(self,func):
def do(*args, **kwargs):
if self.enable:
args,kwargs=self._do_hook('%s%s'%(PREF_ENTER,func.__name__),*args, **kwargs)
ret=func(*args, **kwargs)
self._do_hook('%s%s'%(PREF_EXIT,func.__name__))
return ret
else:
return func(*args, **kwargs)#passby
return do

def line_hook(self):
pass

# def __call__(self,func):
# return self.func_hook(func)

if __name__=='__main__':
load_plugins
import maclient_logging
p=plugins(maclient_logging.Logging('logging'))
p.set_disable(['hehe'])
#print p.plugins,p.hook_reg
@p
def explore(a,b,c,d=1):
print 1
explore(1,2,3,d=3)

1 change: 1 addition & 0 deletions maclient_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
or sys.path[1].decode(sys.getfilesystemencoding())#pyinstaller build

def get_revision(loc):
loc=loc[:2]
local_revs=open(opath.join(getPATH0,'db/revision.txt')).read().split('\n')
rev=None
for r in local_revs:
Expand Down
16 changes: 16 additions & 0 deletions plugins/_prototype.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class plugin_prototype():
def __init__(self):
self.hooks={}

@classmethod
def register_action(self,action,priority=0):
self.hooks[action]=priority

def tuple_assign(self,ori_tuple,index,val):
new=list(ori_tuple)
new[int(index)]=val
return tuple(new)

# @classmethod
# def __call__(self,func):
# raise NotImplementedError("%s is called, but not implemented."%func)
30 changes: 28 additions & 2 deletions plugins/hehe.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,28 @@
def a():
print 123
from _prototype import plugin_prototype
#start meta
__name__='sample plugin'
__author='fffonion'
#hooks={'ENTER/EXIT_ACTION':PRIORITY}
#eg:
#hook on explore start with priority 1 (the bigger the higher):
#'ENTER_explore':1
hooks={'ENTER__fairy_battle':1,'EXIT__fairy_battle':1,'ENTER_explore':1}
#end meta
class plugin(plugin_prototype):

#must add classmethod decorator
@classmethod
def ENTER_explore(self,*args, **kwargs):
print 'explore!'
#must return input vals. no matter you've changed it or not
return args,kwargs

@classmethod
def EXIT__fairy_battle(self,*args, **kwargs):
print 'fairy_battle done!'
return args,kwargs

@classmethod
def ENTER__fairy_battle(self,*args, **kwargs):
print 'fairy_battle!'
return args,kwargs

0 comments on commit 468a22a

Please sign in to comment.