@@ -366,3 +366,162 @@ def call_func(hook):
366
366
hook .chain (rv )
367
367
368
368
hook .hook_func = call_func
369
+
370
+
371
+ def hook_opcode (node , func ):
372
+ """Hook ``func`` to ``node``
373
+
374
+ Args:
375
+ node (Node): The node object for the function to hook
376
+ func (function): The function to be executed when the node is executed
377
+
378
+ Todo:
379
+ Check if a hook already exists and make the code more cohesive
380
+
381
+ Returns:
382
+ An :class:`ASTHook` object
383
+ """
384
+ # Keep a copy of the node's original next node
385
+ next_statement = node .next
386
+
387
+ # Make a new ASTHook and hook it to the node
388
+ # The tuple is in the format (filename, filenumber)
389
+ # This is used by the renpy stacktrace
390
+ hook = ASTHook (("AWSWMod" , 1 ), func , node )
391
+ node .next = hook
392
+
393
+ # Put the original next node to the hook node
394
+ # Also keep a copy of the original next node in the hook node, allowing us to unhook it
395
+ hook .chain (next_statement )
396
+ hook .old_next = next_statement
397
+
398
+ return hook
399
+
400
+
401
+ def call_hook (node , dest_node , func = None ):
402
+ """Hook ``func`` to ``node`` and once executed, redirect execution to
403
+ ``dest_node``
404
+
405
+ Args:
406
+ node (Node): The node to hook
407
+ dest_node (Node): the node to go after ``node`` is executed
408
+ func (function): The function to call
409
+
410
+ Returns:
411
+ An :class:`ASTHook` object
412
+ """
413
+ hook = hook_opcode (node , None )
414
+
415
+ def call_function (hook ):
416
+ if func :
417
+ func (hook )
418
+
419
+ #TODO: Better understand this line
420
+ label = renpy .game .context ().call (dest_node .name , return_site = hook .old_next .name )
421
+ hook .chain (label )
422
+
423
+ hook .hook_func = call_function
424
+ return hook
425
+
426
+
427
+ def unhook_label (label ):
428
+ """Unhook a hook from a lbel
429
+
430
+ Args:
431
+ label (str): The label's name
432
+ """
433
+ #TODO: Test this
434
+ found_node = find_label (label )
435
+ if isinstance (found_node , ASTHook ):
436
+ found_node .from_op .next = found_node .next
437
+
438
+
439
+ def disable_slast_cache ():
440
+ """Disable SLAst's load cache"""
441
+ renpy .sl2 .slast .load_cache = lambda * _ : None
442
+
443
+
444
+ def disable_bytecode_cache ():
445
+ """Disable bytecode cache"""
446
+ renpy .game .script .init_bytecode = lambda * _ : None
447
+
448
+
449
+ def get_node_after_nodes (node , location ):
450
+ """Get the ``location``th node after ``node``
451
+
452
+ Note:
453
+ This skips :class:`ASTHook` nodes
454
+
455
+ Args:
456
+ node (Node): The starting search node
457
+ location (int): The number of nodes to skip
458
+
459
+ Returns:
460
+ A :class:`renpy.ast.Node` object
461
+ """
462
+ for _ in range (0 , location ):
463
+ node = node .next
464
+
465
+ # Effectively skip the ASTHook nodes by continuing on
466
+ while node and isinstance (node , ASTHook ):
467
+ node = node .next
468
+ return node
469
+
470
+
471
+ def get_renpy_global (key ):
472
+ """Get a Ren'Py global
473
+
474
+ Args:
475
+ key (str): The dictionary key
476
+
477
+ Returns:
478
+ The value put into the key or None if it doesn't exist
479
+ """
480
+ store = renpy .python .store_dicts ["store" ]
481
+ if key in store :
482
+ return store [key ]
483
+
484
+
485
+ def set_renpy_global (key , val ):
486
+ """Set a Ren'Py glboal
487
+
488
+ Ren'Py globals can be used during execution of rpy.
489
+
490
+ Args:
491
+ key (str): The dictionary key
492
+ val (str): The value of the dictionary object
493
+ """
494
+ renpy .python .store_dicts ["store" ][key ] = val
495
+
496
+
497
+ def jump_ret (node , dest_node , return_node , func = None ):
498
+ """Hook ``func`` to ``node`` and once executed, redirect execution to
499
+ ``dest_node`` and allow ``return_node`` to be executed after
500
+ ``dest_node`` returns
501
+
502
+ Args:
503
+ node (Node): The node to hook
504
+ dest_node (Node): The node to go after ``node`` is executed
505
+ return_node (Node): The node that is executed after ``dest_node`` returns
506
+ func (function): The function hook
507
+
508
+ Returns:
509
+ An :class:`ASTHook` object
510
+ """
511
+ hook = call_hook (node , dest_node , func )
512
+ hook .next = return_node
513
+ return hook
514
+
515
+
516
+ def hook_label (label , func ):
517
+ """Hook a function to a label
518
+
519
+ Args:
520
+ label (renpy.ast.Label): The label
521
+ func (function): The function to be hooked
522
+
523
+ Returns:
524
+ An :class:`ASTHook` object
525
+ """
526
+ node_label = find_label (label )
527
+ return hook_opcode (node_label , func )
0 commit comments