SCI/FreeSCI/Kernel hacking/Selectors

From ScummVM :: Wiki
Jump to navigation Jump to search

Selectors

Selectors are very important for some of the kernel functions. BaseSetter(), Animate(), Display(), GetEvent() and others take data from or write directly to selectors of a specified object (passed as a parameter or retreived from a node list), or even call object methods from kernel space.[1]

To prepare the usage of selectors, a variable has do be declared (in src/include/vm.h, selector_map_t). This variable will carry the numeric selector ID during run time. Now, the selector has to be mapped- this is happens once during initialization, to save time. It is performed by script_map_selectors(), which is located at the end of src/core/script.c (just use the "FIND_SELECTOR" macro).

If everything went right, accessing selectors should be really easy now. Just use the GET_SELECTOR(obj, selector) and PUT_SELECTOR(obj, selector, value) macros, where obj is a heap_ptr pointing to the object you want to read from or write to, and selector is the name of the selector to use.

An example for PUT_SELECTOR and GET_SELECTOR:

<syntax type="C">

             void
             kSwapXY(state_t *s, int funct_nr, int argc, heap_ptr argp)
             {
               int posx, posy;
               heap_ptr obj = PARAM(0);
               posx = GET_SELECTOR(obj, x);
               posy = GET_SELECTOR(obj, y); /* x and y are defined in selector_map_t */
               PUT_SELECTOR(obj, y, posx);
               PUT_SELECTOR(obj, x, posy);
             }</syntax>

Also, it may be neccessary to invoke an actual method. To do this, a varargs macro has been provided: INVOKE_SELECTOR(obj, selector, argc...). In theory, this macro can be used to set and read selectors as well (it would even handle multiple sends correctly), but this is discouraged for the sake of clarity.

INVOKE_SELECTOR works very much like the other macros; it must be called directly from a kernel function (or from any function supplying valid argc, argp and s).

An example for INVOKE_SELECTOR:

<syntax type="C">

       INVOKE_SELECTOR(obj, doit, 0); /* Call doit() without any parameters */
       INVOKE_SELECTOR(s->game_obj, setCursor, 2, 999, 1);
                               /* Call game_obj::setCursor(999, 1) */</syntax>

Notes

  1. Yes, this is evil. Don't do this at home, kids!