33import time
44from enum import Enum
55from io import StringIO
6- from typing import List , Any
6+ from typing import List , Any , Union
77
88from mcdreforged .api .all import *
99from mcdreforged .api .utils import serializer
10+ from ruamel import yaml
1011
12+ scripts_folder : str = ''
13+
14+ scripts_list : dict [str , str ] = {}
1115
12- ##################################################################
13- ##################### Basic Function #############################
14- ##################################################################
1516
1617class Hooks (Enum ):
1718 undefined = 'undefined'
@@ -75,14 +76,12 @@ def execute_task(self, server: PluginServerInterface, hook: str, var_dict: dict
7576 command .write ('"' )
7677 command .write (str (var_dict .get (key )))
7778 command .write ('" && ' )
78-
7979 command .write (self .command )
8080
8181 os .system (command .getvalue ())
8282 elif self .task_type == TaskType .server_command :
8383 # 替换参数
8484 command = self .command
85-
8685 if var_dict is not None :
8786 for key in var_dict .keys ():
8887 command = command .replace ('{$' + key + '}' , str (var_dict .get (key )))
@@ -91,7 +90,6 @@ def execute_task(self, server: PluginServerInterface, hook: str, var_dict: dict
9190 elif self .task_type == TaskType .mcdr_command :
9291 # 替换参数
9392 command = self .command
94-
9593 if var_dict is not None :
9694 for key in var_dict .keys ():
9795 command = command .replace ('{$' + key + '}' , str (var_dict .get (key )))
@@ -103,11 +101,16 @@ def execute_task(self, server: PluginServerInterface, hook: str, var_dict: dict
103101
104102
105103class Configuration (Serializable ):
106-
107104 def __init__ (self , ** kwargs ):
108105 super ().__init__ (** kwargs )
109106
110107 automatically : bool = True
108+
109+
110+ class TempConfig (Serializable ):
111+
112+ def __init__ (self , ** kwargs ):
113+ super ().__init__ (** kwargs )
111114
112115 hooks : dict [str , List [str ]] = {
113116 'undefined' : [],
@@ -132,6 +135,8 @@ def __init__(self, **kwargs):
132135 task : dict [str , Task ] = {}
133136
134137
138+ temp_config : TempConfig = TempConfig ()
139+
135140config : Configuration
136141
137142
@@ -142,7 +147,7 @@ def trigger_hooks(hook: Hooks, server: PluginServerInterface, objects_dict: dict
142147 try :
143148 server .logger .debug (f'Triggered hooks { hook .value } ' )
144149 server .logger .debug (f'objects_dict: { str (objects_dict )} ' )
145- if len (config .hooks .get (hook .value )) != 0 :
150+ if len (temp_config .hooks .get (hook .value )) != 0 :
146151 _trigger_hooks (hook , server , objects_dict )
147152 except Exception as e :
148153 server .logger .exception (f'Unexpected exception when triggering hook { hook .value } ' , e )
@@ -173,30 +178,25 @@ def _trigger_hooks(hook: Hooks, server: PluginServerInterface, objects_dict: dic
173178 var_inner_attr_value : Any = var_inner_attr_dict .get (var_inner_attr_key )
174179
175180 finally_var_dict [an_object_key + '_' + var_inner_attr_key ] = var_inner_attr_value
176-
181+
177182 server .logger .debug (f'Executing hook { hook .value } ' )
178183 # 遍历被挂载到此hook的task的key
179- for task in config .hooks .get (hook .value ):
180- if config .task .get (task ) is None :
184+ for task in temp_config .hooks .get (hook .value ):
185+ if temp_config .task .get (task ) is None :
181186 server .logger .warning (f'Task { task } is not exist, unmount it from hook { hook .value } !' )
182- config .hooks .get (hook .value ).remove (task )
187+ temp_config .hooks .get (hook .value ).remove (task )
183188 return
184189 # 执行任务
185190 try :
186- config .task .get (task ).execute_task (server , hook .value , finally_var_dict )
191+ temp_config .task .get (task ).execute_task (server , hook .value , finally_var_dict )
187192 except Exception as e :
188193 server .logger .exception (
189- f'Unexpected exception when executing task { task } , hook { hook .value } , task_type { config .task .get (task ).task_type } , command { config .task .get (task ).command } ' ,
194+ f'Unexpected exception when executing task { task } , hook { hook .value } , task_type { temp_config .task .get (task ).task_type } , command { temp_config .task .get (task ).command } ' ,
190195 e )
191196
192197
193- ##################################################################
194- ######################### For Commands ###########################
195- ##################################################################
196-
197- @new_thread ('hooks - mount' )
198198def mount_task (hook : str , task : str , src : CommandSource , server : PluginServerInterface ):
199- h = config .hooks .get (hook )
199+ h = temp_config .hooks .get (hook )
200200
201201 if h is None :
202202 src .reply (RTextMCDRTranslation ('hooks.mount.hook_not_exist' , hook ))
@@ -211,9 +211,8 @@ def mount_task(hook: str, task: str, src: CommandSource, server: PluginServerInt
211211 server .logger .info (f'Successfully mounted task { task } ' )
212212
213213
214- @new_thread ('hooks - unmount' )
215214def unmount_task (hook : str , task : str , src : CommandSource , server : PluginServerInterface ):
216- h = config .hooks .get (hook )
215+ h = temp_config .hooks .get (hook )
217216
218217 if h is None :
219218 src .reply (RTextMCDRTranslation ('hooks.mount.hook_not_exist' , hook ))
@@ -228,9 +227,8 @@ def unmount_task(hook: str, task: str, src: CommandSource, server: PluginServerI
228227 server .logger .info (f'Successfully unmounted task { task } ' )
229228
230229
231- @new_thread ('hooks - create' )
232230def create_task (task_type : str , command : str , name : str , src : CommandSource , server : PluginServerInterface ):
233- if name in config .task :
231+ if name in temp_config .task :
234232 src .reply (RTextMCDRTranslation ('hooks.create.already_exist' ))
235233 return
236234
@@ -240,34 +238,33 @@ def create_task(task_type: str, command: str, name: str, src: CommandSource, ser
240238 src .reply (RTextMCDRTranslation ('hooks.create.task_type_wrong' , task_type ))
241239 return
242240
243- config .task [name ] = Task (name = name , task_type = tsk_type , command = command )
241+ temp_config .task [name ] = Task (name = name , task_type = tsk_type , command = command )
244242
245243 server .logger .info (f'Successfully created task { name } ' )
246244 src .reply (RTextMCDRTranslation ('hooks.create.success' , name ))
247245
248246
249- @new_thread ('hooks - delete' )
250247def delete_task (name : str , src : CommandSource , server : PluginServerInterface ):
251- if name not in config .task .keys ():
248+ if name not in temp_config .task .keys ():
252249 src .reply (RTextMCDRTranslation ('hooks.mount.task_not_exist' , name ))
253250 return
254251
255252 server .logger .info (f'Successfully deleted task { name } ' )
256253 src .reply (RTextMCDRTranslation ('hooks.delete.success' , name ))
257254
258- config .task .pop (name )
255+ temp_config .task .pop (name )
259256
260257
261258@new_thread ('hooks - list' )
262259def list_task (src : CommandSource ):
263260 rtext_list = RTextList ()
264261
265- if len (config .task .values ()) == 0 :
262+ if len (temp_config .task .values ()) == 0 :
266263 rtext_list .append (RText ('Nothing' , color = RColor .dark_gray , styles = RStyle .italic ))
267264 src .reply (RTextMCDRTranslation ('hooks.list.task' , rtext_list ))
268265 return
269266
270- for t in config .task .values ():
267+ for t in temp_config .task .values ():
271268 rtext_list .append (RText (t .name + ' ' , color = RColor .red ).h (t .task_type .name + ' -> ' + t .command ))
272269
273270 src .reply (RTextMCDRTranslation ('hooks.list.task' , rtext_list ))
@@ -277,31 +274,35 @@ def list_task(src: CommandSource):
277274def list_mount (src : CommandSource ):
278275 src .reply (
279276 RTextMCDRTranslation ('hooks.list.mount' ,
280- config .hooks .get (Hooks .on_plugin_loaded .value ),
281- config .hooks .get (Hooks .on_plugin_unloaded .value ),
282- config .hooks .get (Hooks .on_server_starting .value ),
283- config .hooks .get (Hooks .on_server_started .value ),
284- config .hooks .get (Hooks .on_server_stopped .value ),
285- config .hooks .get (Hooks .on_server_crashed .value ),
286- config .hooks .get (Hooks .on_mcdr_started .value ),
287- config .hooks .get (Hooks .on_mcdr_stopped .value ),
288- config .hooks .get (Hooks .on_player_joined .value ),
289- config .hooks .get (Hooks .on_player_left .value ),
290- config .hooks .get (Hooks .on_info .value ),
291- config .hooks .get (Hooks .on_user_info .value ),
292- config .hooks .get (Hooks .undefined .value ),
277+ temp_config .hooks .get (Hooks .on_plugin_loaded .value ),
278+ temp_config .hooks .get (Hooks .on_plugin_unloaded .value ),
279+ temp_config .hooks .get (Hooks .on_server_starting .value ),
280+ temp_config .hooks .get (Hooks .on_server_started .value ),
281+ temp_config .hooks .get (Hooks .on_server_stopped .value ),
282+ temp_config .hooks .get (Hooks .on_server_crashed .value ),
283+ temp_config .hooks .get (Hooks .on_mcdr_started .value ),
284+ temp_config .hooks .get (Hooks .on_mcdr_stopped .value ),
285+ temp_config .hooks .get (Hooks .on_player_joined .value ),
286+ temp_config .hooks .get (Hooks .on_player_left .value ),
287+ temp_config .hooks .get (Hooks .on_info .value ),
288+ temp_config .hooks .get (Hooks .on_user_info .value ),
289+ temp_config .hooks .get (Hooks .undefined .value ),
293290 )
294291 )
295292
296293
297294def reload_config (src : CommandSource , server : PluginServerInterface ):
298- server .load_config_simple (target_class = Configuration )
295+ global config , temp_config
296+
297+ temp_config = TempConfig ()
298+ config = server .load_config_simple (target_class = Configuration )
299+ load_scripts (server )
299300 server .logger .info ('Config reloaded.' )
300301 src .reply (RTextMCDRTranslation ('hooks.reload.success' ))
301-
302+
302303
303304def man_run_task (task : str , env_str : str , src : CommandSource , server : PluginServerInterface ):
304- if task not in config .task .keys ():
305+ if task not in temp_config .task .keys ():
305306 src .reply (RTextMCDRTranslation ('hooks.man_run.task_not_exist' ))
306307 return
307308
@@ -312,14 +313,66 @@ def man_run_task(task: str, env_str: str, src: CommandSource, server: PluginServ
312313 return
313314
314315 try :
315- config .task .get (task ).execute_task (server , Hooks .undefined .value , env_dict )
316+ temp_config .task .get (task ).execute_task (server , Hooks .undefined .value , env_dict )
316317 src .reply (RTextMCDRTranslation ('hooks.man_run.success' , task ))
317318 except Exception as e :
318319 server .logger .exception (
319- f'Unexpected exception when executing task { task } , hook { Hooks .undefined .value } , task_type { config .task .get (task ).task_type } , command { config .task .get (task ).command } ' ,
320+ f'Unexpected exception when executing task { task } , hook { Hooks .undefined .value } , task_type { temp_config .task .get (task ).task_type } , command { temp_config .task .get (task ).command } ' ,
320321 e )
321322
322323
324+ def register_scripts (script_path : str ):
325+ # 将绝对路径添加进入script_list
326+ scripts_list [os .path .basename (script_path )] = script_path
327+
328+
329+ def parse_and_load_scripts (script : str , server : PluginServerInterface ):
330+ # 读取
331+ with open (scripts_list .get (script ), 'r' ) as f :
332+ content : dict [str , Union [str , Union [list , dict ]]] = yaml .load (f .read (), Loader = yaml .Loader )
333+
334+ for task in content .get ('tasks' ).values ():
335+ # 创建task
336+ create_task (task .get ('task_type' ), task .get ('command' ), task .get ('name' ), server .get_plugin_command_source (),
337+ server )
338+ for hook in task .get ('hooks' ):
339+ # 挂载
340+ mount_task (hook , task .get ('name' ), server .get_plugin_command_source (), server )
341+
342+
343+ def load_scripts (server : PluginServerInterface ):
344+ global scripts_list
345+
346+ if not os .path .isdir (scripts_folder ):
347+ # 创建脚本目录
348+ os .makedirs (scripts_folder )
349+ return
350+
351+ def list_all_files (root_dir ) -> list [str ]:
352+ # 显示一个文件夹及子文件夹中的所有yaml文件
353+ _files_in_a_folder : list [str ] = []
354+
355+ for file in os .listdir (root_dir ):
356+ file_path = os .path .join (root_dir , file )
357+
358+ if os .path .isdir (file_path ):
359+ # 遍历子文件夹
360+ _files_in_a_folder .extend (list_all_files (file_path ))
361+ if os .path .isfile (file_path ) and (file_path .endswith ('.yaml' ) or file_path .endswith ('.yml' )):
362+ # 添加文件路径
363+ _files_in_a_folder .append (file_path )
364+
365+ return _files_in_a_folder
366+
367+ # 遍历所有文件
368+ for script_path in list_all_files (scripts_folder ):
369+ register_scripts (script_path )
370+
371+ # 遍历所有已成功注册的脚本
372+ for script in scripts_list .keys ():
373+ parse_and_load_scripts (script , server )
374+
375+
323376def process_arg_server (server : PluginServerInterface ) -> PluginServerInterface :
324377 server .func_is_server_running = server .is_server_running ()
325378 server .func_is_server_startup = server .is_server_startup ()
@@ -337,15 +390,16 @@ def process_arg_server(server: PluginServerInterface) -> PluginServerInterface:
337390 return server
338391
339392
340- ##################################################################
341- ############################ Triggers ############################
342- ##################################################################
343-
344393def on_load (server : PluginServerInterface , old_module ):
345- global config
394+ global config , scripts_folder , temp_config
395+
396+ temp_config = TempConfig ()
346397
347398 config = server .load_config_simple (target_class = Configuration )
348399
400+ scripts_folder = os .path .join (server .get_data_folder (), 'scripts' )
401+ load_scripts (server )
402+
349403 server .register_command (
350404 Literal ('!!hooks' )
351405 .then (
0 commit comments