ScriptManager.java 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. package me.hammerle.snuviscript.code;
  2. import java.util.ArrayList;
  3. import me.hammerle.snuviscript.inputprovider.InputProvider;
  4. import java.util.Collection;
  5. import java.util.HashMap;
  6. import java.util.HashSet;
  7. import java.util.function.Consumer;
  8. import me.hammerle.snuviscript.exceptions.PreScriptException;
  9. public class ScriptManager
  10. {
  11. private final ISnuviLogger logger;
  12. private final ISnuviScheduler scheduler;
  13. private final HashMap<Integer, Script> scripts = new HashMap<>();
  14. private final HashMap<String, HashSet<Script>> loadedEvents = new HashMap<>();
  15. private boolean isIterating = false;
  16. private final ArrayList<Script> addList = new ArrayList<>();
  17. private final ArrayList<Script> removeList = new ArrayList<>();
  18. private final ArrayList<Runnable> eventAddList = new ArrayList<>();
  19. public ScriptManager(ISnuviLogger logger, ISnuviScheduler scheduler)
  20. {
  21. this.logger = logger;
  22. this.scheduler = scheduler;
  23. }
  24. public ISnuviLogger getLogger()
  25. {
  26. return logger;
  27. }
  28. public ISnuviScheduler getScheduler()
  29. {
  30. return scheduler;
  31. }
  32. // -------------------------------------------------------------------------
  33. // function registry
  34. // -------------------------------------------------------------------------
  35. public void registerFunction(String s, ExceptionBiFunction<Script, InputProvider[], Object> f)
  36. {
  37. FunctionRegistry.registerFunction(s, f);
  38. }
  39. public void registerAlias(String original, String alias)
  40. {
  41. FunctionRegistry.registerAlias(original, alias);
  42. }
  43. // -------------------------------------------------------------------------
  44. // script controller
  45. // -------------------------------------------------------------------------
  46. public Script getScript(int id)
  47. {
  48. return scripts.get(id);
  49. }
  50. private void removeScriptUnsafe(Script sc)
  51. {
  52. sc.term();
  53. sc.onTerm();
  54. scripts.remove(sc.getId());
  55. loadedEvents.values().forEach(list -> list.remove(sc));
  56. }
  57. private void addScript(Script sc)
  58. {
  59. scripts.put(sc.getId(), sc);
  60. sc.onStart();
  61. sc.run();
  62. if(sc.shouldTerm())
  63. {
  64. removeScriptUnsafe(sc);
  65. }
  66. }
  67. private void handleQueues()
  68. {
  69. if(!removeList.isEmpty())
  70. {
  71. removeList.forEach(sc -> removeScriptUnsafe(sc));
  72. removeList.clear();
  73. }
  74. if(!addList.isEmpty())
  75. {
  76. addList.forEach(sc -> addScript(sc));
  77. addList.clear();
  78. }
  79. if(!eventAddList.isEmpty())
  80. {
  81. eventAddList.forEach(r -> r.run());
  82. eventAddList.clear();
  83. }
  84. }
  85. public void removeScriptSafe(Script sc)
  86. {
  87. if(isIterating)
  88. {
  89. removeList.add(sc);
  90. }
  91. else
  92. {
  93. removeScriptUnsafe(sc);
  94. }
  95. }
  96. public boolean removeScriptsSafe()
  97. {
  98. if(isIterating)
  99. {
  100. return false;
  101. }
  102. scripts.values().forEach(sc ->
  103. {
  104. sc.term();
  105. sc.onTerm();
  106. });
  107. scripts.clear();
  108. loadedEvents.values().forEach(list -> list.clear());
  109. return true;
  110. }
  111. public Collection<Script> getScripts()
  112. {
  113. return scripts.values();
  114. }
  115. public Script startScript(boolean rEventBroadcast, Consumer<Script> onStart, Consumer<Script> onTerm, String name, String... paths)
  116. {
  117. if(paths.length == 0)
  118. {
  119. return null;
  120. }
  121. try
  122. {
  123. Script sc = new Script(this, onStart, onTerm, name, paths);
  124. sc.setEventBroadcast(rEventBroadcast);
  125. if(isIterating)
  126. {
  127. addList.add(sc);
  128. }
  129. else
  130. {
  131. addScript(sc);
  132. }
  133. return sc;
  134. }
  135. catch(PreScriptException ex)
  136. {
  137. logger.print(null, ex, null, paths[0], null, ex.getLine());
  138. return null;
  139. }
  140. }
  141. public Script startScript(boolean rEventBroadcast, String name, String... paths)
  142. {
  143. return startScript(rEventBroadcast, null, null, name, paths);
  144. }
  145. // -------------------------------------------------------------------------
  146. // event
  147. // -------------------------------------------------------------------------
  148. private void loadEventUnsafe(String event, Script sc)
  149. {
  150. HashSet<Script> set = loadedEvents.get(event);
  151. if(set == null)
  152. {
  153. set = new HashSet<>();
  154. loadedEvents.put(event, set);
  155. }
  156. set.add(sc);
  157. }
  158. private void unloadEventUnsafe(String event, Script sc)
  159. {
  160. HashSet<Script> set = loadedEvents.get(event);
  161. if(set != null)
  162. {
  163. set.remove(sc);
  164. }
  165. }
  166. public void loadEventSafe(String event, Script sc)
  167. {
  168. if(isIterating)
  169. {
  170. eventAddList.add(() -> loadEventUnsafe(event, sc));
  171. }
  172. else
  173. {
  174. loadEventUnsafe(event, sc);
  175. }
  176. }
  177. public void unloadEventSafe(String event, Script sc)
  178. {
  179. if(isIterating)
  180. {
  181. eventAddList.add(() -> unloadEventUnsafe(event, sc));
  182. }
  183. else
  184. {
  185. unloadEventUnsafe(event, sc);
  186. }
  187. }
  188. public void callEvent(String name, Consumer<Script> before, Consumer<Script> after)
  189. {
  190. /*if(isIterating)
  191. {
  192. logger.print(String.format("'%s' called while executing another event", name), null, null, null, null, -1);
  193. return;
  194. }*/
  195. HashSet<Script> set = loadedEvents.get(name);
  196. if(set == null)
  197. {
  198. return;
  199. }
  200. isIterating = true;
  201. set.stream().filter(sc -> sc.shouldReceiveEventBroadcast() && !sc.isHolded() && sc.isWaiting())
  202. .forEach(sc ->
  203. {
  204. sc.setVar("event", name);
  205. if(before != null)
  206. {
  207. before.accept(sc);
  208. }
  209. sc.run();
  210. if(after != null)
  211. {
  212. after.accept(sc);
  213. }
  214. });
  215. isIterating = false;
  216. handleQueues();
  217. }
  218. public boolean callEvent(String name, Script sc, Consumer<Script> before, Consumer<Script> after)
  219. {
  220. if(sc.isEventLoaded(name) && !sc.isHolded() && sc.isWaiting())
  221. {
  222. sc.setVar("event", name);
  223. if(before != null)
  224. {
  225. before.accept(sc);
  226. }
  227. sc.run();
  228. if(after != null)
  229. {
  230. after.accept(sc);
  231. }
  232. if(sc.shouldTerm())
  233. {
  234. removeScriptUnsafe(sc);
  235. }
  236. return true;
  237. }
  238. return false;
  239. }
  240. }