Survivalcraft API 1.8.2.3 v1.8.2.3
Survivalcraft 2.4
载入中...
搜索中...
未找到
JsInterface.cs
浏览该文件的文档.
1#if !IOS && !BROWSER
2using System.Diagnostics;
3using System.Net;
4using System.Text;
5using System.Text.Json;
6using Acornima.Ast;
7using Engine;
8using Engine.Input;
9using Jint;
10using Jint.Native;
11using Jint.Native.Function;
12using JsEngine = Jint.Engine;
13
14namespace Game {
15 public class JsInterface {
16 public static JsEngine engine;
17 public static JsModLoader loader;
18 public static Dictionary<string, List<Function>> handlersDictionary;
19
20 public static HttpListener httpListener;
21 public static int httpPort;
22 public static string httpPassword;
23 public static bool httpProcessing;
24 public static bool httpScriptPrepared;
25 public static Prepared<Script> httpScript;
26 public static TaskCompletionSource<HttpResponse> httpResponse = new();
27 public const string fName = "JsInterface";
28
29 public static void Initiate()
30 //修改前:先检查是否有外置 init.js 是安卓就直接加载内置,否则释放文件,释放成功就加载外置,否则报错
31 //修改后:先检查是安卓就加载内置,否则释放并检查外部有 init.js 文件则加载外置否则加载内置(如果外置出现问题可以直接加载内置)
32 {
33 engine = new JsEngine(
34 delegate(Options cfg) {
35 cfg.AllowClr(AppDomain.CurrentDomain.GetAssemblies());
36 cfg.DebugMode();
37 }
38 );
39 string codeString = null;
40 try {
41 if (Storage.FileExists("app:init.js")) {
42 codeString = Storage.ReadAllText("app:init.js");
43 }
44 }
45 catch {
47 }
48 Execute(codeString);
49 httpListener = new HttpListener();
50 if (ModsManager.Configs.TryGetValue("RemoteControlPort", out string portString)
51 && int.TryParse(portString, out int port)) {
52 SetHttpPort(port);
53 }
54 else {
55 SetHttpPort((DateTime.Now.Millisecond * 32749 + 8191) % 9000 + 1024, true);
56 }
57 if (ModsManager.Configs.TryGetValue("RemoteControlPassword", out string password)) {
58 httpPassword = password;
59 }
60 else {
61 httpPassword = ((DateTime.Now.Millisecond * 49999 + 3067) % 9000 + 999).ToString();
62 ModsManager.SetConfig("RemoteControlPassword", httpPassword);
63 }
64 if (ModsManager.Configs.TryGetValue("RemoteControlEnabled", out string enable)
65 && bool.Parse(enable)) {
66 Task.Run(StartHttpListener);
67 }
68 }
69
70 public static void RegisterEvent() {
71 List<Function> keyDownHandlers = GetHandlers("keyDownHandlers");
72 if (keyDownHandlers != null
73 && keyDownHandlers.Count > 0) {
74 Keyboard.KeyDown += delegate(Key key) {
75 string keyString = key.ToString();
76 keyDownHandlers.ForEach(function => { Invoke(function, keyString); });
77 };
78 }
79 List<Function> keyUpHandlers = GetHandlers("keyUpHandlers");
80 if (keyUpHandlers != null
81 && keyUpHandlers.Count > 0) {
82 Keyboard.KeyUp += delegate(Key key) {
83 string keyString = key.ToString();
84 keyUpHandlers.ForEach(function => { Invoke(function, keyString); });
85 };
86 }
87 List<Function> frameHandlers = GetHandlers("frameHandlers");
88 if (frameHandlers != null
89 && frameHandlers.Count > 0) {
90 Window.Frame += delegate { frameHandlers.ForEach(function => { Invoke(function); }); };
91 }
93 loader = (JsModLoader)ModsManager.ModLoaders.Find(item => item is JsModLoader);
94 GetAndRegisterHandlers("OnMinerDig");
95 GetAndRegisterHandlers("OnMinerPlace");
96 GetAndRegisterHandlers("OnPlayerSpawned");
97 GetAndRegisterHandlers("OnPlayerDead");
98 GetAndRegisterHandlers("ProcessAttackment");
99 GetAndRegisterHandlers("CalculateCreatureInjuryAmount");
100 GetAndRegisterHandlers("OnProjectLoaded");
101 GetAndRegisterHandlers("OnProjectDisposed");
102 }
103
104 public static void Execute(string str) {
105 try {
106 engine.Execute(str);
107 }
108 catch (Exception ex) {
109 Log.Error(ex);
110 }
111 }
112
113 public static void Execute(Prepared<Script> script) {
114 try {
115 engine.Execute(script);
116 }
117 catch (Exception ex) {
118 Log.Error(ex);
119 }
120 }
121
122 public static string Evaluate(string str) {
123 try {
124 return engine.Evaluate(str).ToString();
125 }
126 catch (Exception ex) {
127 string errors = ex.ToString();
128 Log.Error(errors);
129 return errors;
130 }
131 }
132
133 public static string Evaluate(Prepared<Script> script) {
134 try {
135 return engine.Evaluate(script).ToString();
136 }
137 catch (Exception ex) {
138 string errors = ex.ToString();
139 Log.Error(errors);
140 return errors;
141 }
142 }
143
144 public static JsValue Invoke(string str, params object[] arguments) {
145 try {
146 return engine.Invoke(str, arguments);
147 }
148 catch (Exception ex) {
149 Log.Error(ex);
150 }
151 return null;
152 }
153
154 public static JsValue Invoke(JsValue jsValue, params object[] arguments) {
155 try {
156 return engine.Invoke(jsValue, arguments);
157 }
158 catch (Exception ex) {
159 Log.Error(ex);
160 }
161 return null;
162 }
163
164 public static List<Function> GetHandlers(string str) {
165 JsArray array = engine.GetValue(str).AsArray();
166 if (array.IsNull()) {
167 return null;
168 }
169 List<Function> list = [];
170 foreach (JsValue item in array) {
171 try {
172 Function function = item.AsFunctionInstance();
173 if (!function.IsNull()) {
174 list.Add(function);
175 }
176 }
177 catch (Exception ex) {
178 Log.Error(ex);
179 }
180 }
181 return list;
182 }
183
184 public static void GetAndRegisterHandlers(string handlesName) {
185 try {
186 if (handlersDictionary.ContainsKey(handlesName)) {
187 return;
188 }
189 List<Function> handlers = GetHandlers($"{handlesName}Handlers");
190 if (handlers != null
191 && handlers.Count > 0) {
192 handlersDictionary.Add(handlesName, handlers);
193 ModsManager.RegisterHook(handlesName, loader);
194 }
195 }
196 catch (Exception ex) {
197 Log.Error(ex);
198 }
199 }
200
201 public static void SetHttpPort(int port, bool updateConfig = false) {
202 httpPort = port;
203#if DEBUG
204 httpListener.Prefixes.Add("http://+:28256/");
205#elif RELEASE
206 httpListener.Prefixes.Clear();
207 httpListener.Prefixes.Add($"http://{IPAddress.Loopback}:{port}/");
208 httpListener.Prefixes.Add($"http://localhost:{port}/");
209#endif
210 if (updateConfig) {
211 ModsManager.SetConfig("RemoteControlPort", port.ToString());
212 }
213 }
214
215 public static async Task StartHttpListener() {
216 try {
217 httpListener.Start();
218 }
219 catch (Exception e) {
220 Log.Error($"Remote control server starts failed: {e}");
221 }
222 while (httpListener.IsListening) {
223 HttpListenerContext context = await httpListener.GetContextAsync();
224 _ = Task.Run(() => HandleHttpRequest(context));
225 }
226 }
227
228 public static void StopHttpListener() {
229 //确实能关掉,但有报错,原因不明
230 try {
231 httpListener.Stop();
232 }
233 catch {
234 // ignored
235 }
236 }
237
238 public static void Update() {
240 Stopwatch stopwatch = Stopwatch.StartNew();
241 string result = Evaluate(httpScript);
242 stopwatch.Stop();
243 httpResponse.SetResult(
244 new HttpResponse {
245 success = !result.StartsWith("Jint.Runtime.JavaScriptException"), result = result, timeCosted = stopwatch.Elapsed
246 }
247 );
248 }
249 }
250
251 public static async void HandleHttpRequest(HttpListenerContext context) {
252 try {
253 string responseString;
254 if (httpProcessing) {
255 responseString = ErrorJsonResponse(LanguageControl.Get(fName, "1"));
256 }
257 else if (context.Request.HttpMethod == "POST") {
258 if (httpPassword.Length == 0
259 || (context.Request.Headers.Get("password")?.Equals(httpPassword) ?? false)) {
260 httpProcessing = true;
261 httpScriptPrepared = false;
262 httpResponse = new TaskCompletionSource<HttpResponse>();
263 try {
264 using (Stream bodyStream = context.Request.InputStream) {
265 using (StreamReader reader = new(bodyStream, context.Request.ContentEncoding)) {
266 string requestBody = reader.ReadToEnd();
267 if (requestBody.Length > 0) {
268 httpScript = JsEngine.PrepareScript(requestBody);
269 httpScriptPrepared = true;
270 responseString = JsonSerializer.Serialize(await httpResponse.Task);
271 }
272 else {
273 responseString = ErrorJsonResponse(LanguageControl.Get(fName, "2"));
274 }
275 }
276 }
277 }
278 catch (Exception e) {
279 responseString = ErrorJsonResponse(e.ToString());
280 }
281 httpProcessing = false;
282 }
283 else {
284 responseString = ErrorJsonResponse(LanguageControl.Get(fName, "3"));
285 }
286 }
287 else if (context.Request.HttpMethod == "ELEVATE") {
288#if !MOBILE && !BROWSER
289 Thread.CurrentThread.Priority = ThreadPriority.Highest;
290#endif
291 responseString = "Sucess";
292 }
293 else {
294 responseString = ErrorJsonResponse(LanguageControl.Get(fName, "4"));
295 }
296 HttpListenerResponse response = context.Response;
297 response.ContentType = "application/json";
298 byte[] buffer = Encoding.UTF8.GetBytes(responseString);
299 response.ContentLength64 = buffer.Length;
300 Stream output = response.OutputStream;
301 await output.WriteAsync(buffer);
302 output.Close();
303 }
304 catch (Exception e) {
305 context.Response.Close();
306 Log.Error(e);
307 }
308 }
309
310 public static string ErrorJsonResponse(string error) =>
311 JsonSerializer.Serialize(new HttpResponse { success = false, result = error, timeCosted = TimeSpan.Zero });
312
313 public class HttpResponse {
314 public bool success { get; set; }
315 public string result { get; set; }
316 public TimeSpan timeCosted { get; set; }
317 }
318 }
319}
320#elif __IOS
321using Engine;
322using Engine.Input;
323using JavaScriptCore;
324using System.Diagnostics;
325using System.Net;
326using System.Runtime.InteropServices.JavaScript;
327using System.Text;
328using System.Text.Json;
329using System.Xml.Linq;
330using static System.Runtime.InteropServices.JavaScript.JSType;
331
332namespace Game {
333 public class JsInterface {
334 private static JSContext jSContext;
335 public static Dictionary<string, List<JSValue>> handlersDictionary;
336 private static JsModLoader loader;
337 public static HttpListener httpListener;
338 public static int httpPort;
339 public static string httpPassword;
340 public static bool httpProcessing;
341 public static bool httpScriptPrepared;
342 public static TaskCompletionSource<HttpResponse> httpResponse = new();
343 private static string httpScript;
344 public const string fName = "JsInterface";
345
346
347 public static void Initiate() {
348 jSContext = new JSContext();
349 handlersDictionary = new();
350
351 string codeString = null;
352 try {
353 if (Storage.FileExists("app:init.js")) {
354 codeString = Storage.ReadAllText("app:init.js");
355 }
356 }
357 catch {
358 Log.Warning(LanguageControl.Get(fName, "5"));
359 }
360 Execute(codeString);
361 httpListener = new HttpListener();
362 if (ModsManager.Configs.TryGetValue("RemoteControlPort", out string portString)
363 && int.TryParse(portString, out int port)) {
364 SetHttpPort(port);
365 }
366 else {
367 SetHttpPort((DateTime.Now.Millisecond * 32749 + 8191) % 9000 + 1024, true);
368 }
369 if (ModsManager.Configs.TryGetValue("RemoteControlPassword", out string password)) {
370 httpPassword = password;
371 }
372 else {
373 httpPassword = ((DateTime.Now.Millisecond * 49999 + 3067) % 9000 + 999).ToString();
374 ModsManager.SetConfig("RemoteControlPassword", httpPassword);
375 }
376 if (ModsManager.Configs.TryGetValue("RemoteControlEnabled", out string enable)
377 && bool.Parse(enable)) {
378 Task.Run(StartHttpListener);
379 }
380
381 }
382
383 public static void SetHttpPort(int port, bool updateConfig = false) {
384 httpPort = port;
385#if DEBUG
386 httpListener.Prefixes.Add("http://+:28256/");
387#elif RELEASE
388 httpListener.Prefixes.Clear();
389 httpListener.Prefixes.Add($"http://{IPAddress.Loopback}:{port}/");
390 httpListener.Prefixes.Add($"http://localhost:{port}/");
391#endif
392 if (updateConfig) {
393 ModsManager.SetConfig("RemoteControlPort", port.ToString());
394 }
395 }
396
397 public static async Task StartHttpListener() {
398 try {
399 httpListener.Start();
400 }
401 catch (Exception e) {
402 Log.Error($"Remote control server starts failed: {e}");
403 }
404 while (httpListener.IsListening) {
405 HttpListenerContext context = await httpListener.GetContextAsync();
406 _ = Task.Run(() => HandleHttpRequest(context));
407 }
408 }
409
410
411 public static JSValue Invoke(string str, params object[] arguments) {
412 try {
413 var jv = JSValue.CreateArray(jSContext);
414 JSValue[] jSValues = new JSValue[arguments.Length];
415 for (int i = 0; i < arguments.Length; i++) jSValues[i] = JSValue.From((NSObject)arguments[i],jSContext);
416 return jSContext.GlobalObject.GetProperty(str).Call(jSValues);
417 }
418 catch (Exception ex) {
419 Log.Error(ex);
420 }
421 return null;
422 }
423
424 public static void RegisterEvent() {
425 var keyDownHandlers = GetHandlers("keyDownHandlers");
426 if (keyDownHandlers != null
427 && keyDownHandlers.Count > 0) {
428 Keyboard.KeyDown += delegate (Key key) {
429 string keyString = key.ToString();
430 keyDownHandlers.ForEach(keyDownEvt => { keyDownEvt.Call(new JSValue[] { JSValue.From(keyString,jSContext) }); });
431 };
432 }
433 var keyUpHandlers = GetHandlers("keyUpHandlers");
434 if (keyUpHandlers != null
435 && keyUpHandlers.Count > 0) {
436 Keyboard.KeyUp += delegate (Key key) {
437 string keyString = key.ToString();
438 keyUpHandlers.ForEach(keyDownEvt => { keyDownEvt.Call(new JSValue[] { JSValue.From(keyString, jSContext) }); });
439 };
440 }
441 var frameHandlers = GetHandlers("frameHandlers");
442 if (frameHandlers != null
443 && frameHandlers.Count > 0) {
444 Window.Frame += delegate { frameHandlers.ForEach(frameEvt => { frameEvt.Call(new JSValue[] { JSValue.From("", jSContext) }); }); };
445 }
447 loader = (JsModLoader)ModsManager.ModLoaders.Find(item => item is JsModLoader);
448 loader.JSContext = jSContext;
449 GetAndRegisterHandlers("OnMinerDig");
450 GetAndRegisterHandlers("OnMinerPlace");
451 GetAndRegisterHandlers("OnPlayerSpawned");
452 GetAndRegisterHandlers("OnPlayerDead");
453 GetAndRegisterHandlers("ProcessAttackment");
454 GetAndRegisterHandlers("CalculateCreatureInjuryAmount");
455 GetAndRegisterHandlers("OnProjectLoaded");
456 GetAndRegisterHandlers("OnProjectDisposed");
457 }
458
459 public static JSValue Execute(string str) {
460 try {
461 return jSContext.EvaluateScript(str);
462 }
463 catch (Exception ex) {
464 Log.Error(ex);
465 }
466 return null;
467 }
468
469 public static List<JSValue> GetHandlers(string str) {
470 JSValue arrayValue = jSContext.GlobalObject.GetProperty(str);
471 if (!arrayValue.IsArray) {
472 return null;
473 }
474 List<JSValue> list = new();
475 int length = arrayValue.GetProperty("length").ToInt32();
476 for (int i=0;i<length;i++) {
477 list.Add(arrayValue.GetProperty(i.ToString()));
478 }
479 return list;
480 }
481
482 public static void GetAndRegisterHandlers(string handlesName) {
483 try {
484 if (handlersDictionary.ContainsKey(handlesName)) {
485 return;
486 }
487 List<JSValue> handlers = GetHandlers($"{handlesName}Handlers");
488 if (handlers != null
489 && handlers.Count > 0) {
490 handlersDictionary.Add(handlesName, handlers);
491 ModsManager.RegisterHook(handlesName, loader);
492 }
493 }
494 catch (Exception ex) {
495 Log.Error(ex);
496 }
497 }
498
499 public static void Update() {
501 Stopwatch stopwatch = Stopwatch.StartNew();
502 var result = Execute(httpScript);
503 stopwatch.Stop();
504 httpResponse.SetResult(
505 new HttpResponse {
506 success = true,
507 result = result.ToString(),
508 timeCosted = stopwatch.Elapsed
509 }
510 );
511 }
512 }
513
514 public static async void HandleHttpRequest(HttpListenerContext context) {
515 try {
516 string responseString;
517 if (httpProcessing) {
518 responseString = ErrorJsonResponse(LanguageControl.Get(fName, "1"));
519 }
520 else if (context.Request.HttpMethod == "POST") {
521 if (httpPassword.Length == 0
522 || (context.Request.Headers.Get("password")?.Equals(httpPassword) ?? false)) {
523 httpProcessing = true;
524 httpScriptPrepared = false;
525 httpResponse = new TaskCompletionSource<HttpResponse>();
526 try {
527 using (Stream bodyStream = context.Request.InputStream) {
528 using (StreamReader reader = new(bodyStream, context.Request.ContentEncoding)) {
529 string requestBody = reader.ReadToEnd();
530 if (requestBody.Length > 0) {
531 httpScript = requestBody;
532 httpScriptPrepared = true;
533 responseString = JsonSerializer.Serialize(await httpResponse.Task);
534 }
535 else {
536 responseString = ErrorJsonResponse(LanguageControl.Get(fName, "2"));
537 }
538 }
539 }
540 }
541 catch (Exception e) {
542 responseString = ErrorJsonResponse(e.ToString());
543 }
544 httpProcessing = false;
545 }
546 else {
547 responseString = ErrorJsonResponse(LanguageControl.Get(fName, "3"));
548 }
549 }
550 else if (context.Request.HttpMethod == "ELEVATE") {
551 responseString = "Sucess";
552 }
553 else {
554 responseString = ErrorJsonResponse(LanguageControl.Get(fName, "4"));
555 }
556 HttpListenerResponse response = context.Response;
557 response.ContentType = "application/json";
558 byte[] buffer = Encoding.UTF8.GetBytes(responseString);
559 response.ContentLength64 = buffer.Length;
560 Stream output = response.OutputStream;
561 await output.WriteAsync(buffer);
562 output.Close();
563 }
564 catch (Exception e) {
565 context.Response.Close();
566 Log.Error(e);
567 }
568 }
569 public static void StopHttpListener() {
570 //确实能关掉,但有报错,原因不明
571 try {
572 httpListener.Stop();
573 }
574 catch {
575 // ignored
576 }
577 }
578 public static string ErrorJsonResponse(string error) =>
579 JsonSerializer.Serialize(new HttpResponse { success = false, result = error, timeCosted = TimeSpan.Zero });
580
581 public class HttpResponse {
582 public bool success { get; set; }
583 public string result { get; set; }
584 public TimeSpan timeCosted { get; set; }
585 }
586
587 }
588}
589
590#endif
Jint.Engine JsEngine
static Action< Key > KeyDown
static Action< Key > KeyUp
static void Error(object message)
定义 Log.cs:80
static void Warning(object message)
定义 Log.cs:68
static bool FileExists(string path)
static string ReadAllText(string path)
static Action Frame
static void StopHttpListener()
static void RegisterEvent()
static TaskCompletionSource< HttpResponse > httpResponse
static Dictionary< string, List< Function > > handlersDictionary
static string ErrorJsonResponse(string error)
static void Initiate()
static JsValue Invoke(string str, params object[] arguments)
static string Evaluate(Prepared< Script > script)
static List< Function > GetHandlers(string str)
static bool httpProcessing
static void SetHttpPort(int port, bool updateConfig=false)
static bool httpScriptPrepared
static async void HandleHttpRequest(HttpListenerContext context)
static string Evaluate(string str)
static string httpPassword
static JsEngine engine
static Prepared< Script > httpScript
static void Execute(string str)
static JsModLoader loader
static HttpListener httpListener
static void GetAndRegisterHandlers(string handlesName)
static void Execute(Prepared< Script > script)
static JsValue Invoke(JsValue jsValue, params object[] arguments)
static async Task StartHttpListener()
static string Get(string className, int key)
获取在当前语言类名键对应的字符串
static List< ModLoader > ModLoaders
static void SetConfig(string key, string value)
static Dictionary< string, string > Configs
static void RegisterHook(string HookName, ModLoader modLoader)
注册Hook