ScriptManager.java 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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. import me.hammerle.snuviscript.exceptions.StackTrace;
  10. public class ScriptManager {
  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. this.logger = logger;
  21. this.scheduler = scheduler;
  22. }
  23. public ISnuviLogger getLogger() {
  24. return logger;
  25. }
  26. public ISnuviScheduler getScheduler() {
  27. return scheduler;
  28. }
  29. // -------------------------------------------------------------------------
  30. // function registry
  31. // -------------------------------------------------------------------------
  32. public void registerFunction(String s, ExceptionBiFunction<Script, InputProvider[], Object> f) {
  33. FunctionRegistry.registerFunction(s, f);
  34. }
  35. public void registerConsumer(String s, ExceptionBiConsumer<Script, InputProvider[]> f) {
  36. FunctionRegistry.registerConsumer(s, f);
  37. }
  38. public void registerAlias(String original, String alias) {
  39. FunctionRegistry.registerAlias(original, alias);
  40. }
  41. // -------------------------------------------------------------------------
  42. // script controller
  43. // -------------------------------------------------------------------------
  44. public Script getScript(int id) {
  45. return scripts.get(id);
  46. }
  47. private void removeScriptUnsafe(Script sc) {
  48. sc.term();
  49. sc.onTerm();
  50. scripts.remove(sc.getId());
  51. loadedEvents.values().forEach(list -> list.remove(sc));
  52. }
  53. private void addScript(Script sc) {
  54. scripts.put(sc.getId(), sc);
  55. sc.onStart();
  56. sc.run();
  57. if(sc.shouldTerm()) {
  58. removeScriptUnsafe(sc);
  59. }
  60. }
  61. private void handleQueues() {
  62. if(!removeList.isEmpty()) {
  63. removeList.forEach(sc -> removeScriptUnsafe(sc));
  64. removeList.clear();
  65. }
  66. if(!addList.isEmpty()) {
  67. addList.forEach(sc -> addScript(sc));
  68. addList.clear();
  69. }
  70. if(!eventAddList.isEmpty()) {
  71. eventAddList.forEach(r -> r.run());
  72. eventAddList.clear();
  73. }
  74. }
  75. public void removeScriptSafe(Script sc) {
  76. if(isIterating) {
  77. removeList.add(sc);
  78. } else {
  79. removeScriptUnsafe(sc);
  80. }
  81. }
  82. public boolean removeScriptsSafe() {
  83. if(isIterating) {
  84. return false;
  85. }
  86. scripts.values().forEach(sc -> {
  87. sc.term();
  88. sc.onTerm();
  89. });
  90. scripts.clear();
  91. loadedEvents.values().forEach(list -> list.clear());
  92. return true;
  93. }
  94. public Collection<Script> getScripts() {
  95. return scripts.values();
  96. }
  97. public Script startScript(boolean rEventBroadcast, Consumer<Script> onStart, Consumer<Script> onTerm, String name, String... paths) {
  98. if(paths.length == 0) {
  99. return null;
  100. }
  101. try {
  102. Script sc = new Script(this, onStart, onTerm, name, paths);
  103. sc.setEventBroadcast(rEventBroadcast);
  104. if(isIterating) {
  105. addList.add(sc);
  106. } else {
  107. addScript(sc);
  108. }
  109. return sc;
  110. } catch(PreScriptException ex) {
  111. logger.print(null, ex, null, paths[0], null, new StackTrace(ex.getLine()));
  112. return null;
  113. }
  114. }
  115. public Script startScript(boolean rEventBroadcast, String name, String... paths) {
  116. return startScript(rEventBroadcast, null, null, name, paths);
  117. }
  118. // -------------------------------------------------------------------------
  119. // event
  120. // -------------------------------------------------------------------------
  121. private void loadEventUnsafe(String event, Script sc) {
  122. HashSet<Script> set = loadedEvents.get(event);
  123. if(set == null) {
  124. set = new HashSet<>();
  125. loadedEvents.put(event, set);
  126. }
  127. set.add(sc);
  128. }
  129. private void unloadEventUnsafe(String event, Script sc) {
  130. HashSet<Script> set = loadedEvents.get(event);
  131. if(set != null) {
  132. set.remove(sc);
  133. }
  134. }
  135. public void loadEventSafe(String event, Script sc) {
  136. if(isIterating) {
  137. eventAddList.add(() -> loadEventUnsafe(event, sc));
  138. } else {
  139. loadEventUnsafe(event, sc);
  140. }
  141. }
  142. public void unloadEventSafe(String event, Script sc) {
  143. if(isIterating) {
  144. eventAddList.add(() -> unloadEventUnsafe(event, sc));
  145. } else {
  146. unloadEventUnsafe(event, sc);
  147. }
  148. }
  149. public void callEvent(String name, Consumer<Script> before, Consumer<Script> after) {
  150. HashSet<Script> set = loadedEvents.get(name);
  151. if(set == null) {
  152. return;
  153. }
  154. isIterating = true;
  155. try {
  156. set.stream().filter(sc -> sc.shouldReceiveEventBroadcast() && !sc.isHolded() && sc.isWaiting())
  157. .forEach(sc -> {
  158. sc.setVar("event", name);
  159. if(before != null) {
  160. before.accept(sc);
  161. }
  162. sc.run();
  163. if(after != null) {
  164. after.accept(sc);
  165. }
  166. });
  167. } catch(Exception ex) {
  168. ex.printStackTrace();
  169. }
  170. isIterating = false;
  171. handleQueues();
  172. }
  173. public boolean callEvent(String name, Script sc, Consumer<Script> before, Consumer<Script> after) {
  174. if(sc.isEventLoaded(name) && !sc.isHolded() && sc.isWaiting()) {
  175. sc.setVar("event", name);
  176. if(before != null) {
  177. before.accept(sc);
  178. }
  179. sc.run();
  180. if(after != null) {
  181. after.accept(sc);
  182. }
  183. if(sc.shouldTerm()) {
  184. removeScriptUnsafe(sc);
  185. }
  186. return true;
  187. }
  188. return false;
  189. }
  190. }