I originally tried to overcome 1700 units limit, and came out with some useful ideas. (Eventually failed.)
Trigger self-modifying itself (which I'll call payload) is placed in MRGN section. (You may just initalize them with SetDeaths. I just put them directly in MRGN section.)
Triggers in TRIG (which I'll call vector)
- 1. Fill in offsets for payload. These offsets were needed for payload. (not important)
- (a): Pointer to STR section + real STR section size, rounded up to 86 modulo 336. This is where the newly created CUnit* memory layout will reside in.
- (b): Pointer to the first empty unit node.
- (c): Pointer to the first trigger. (return address)
- 2. Modifies 0051a280 + 12 + 8 (where the first executing trigger for player 2 is) so that trigger in MRGN is executed at next trigger cycle.
- 3. Forces fast recycle with Wait(0). (Other triggers are crafted to not be executed before payload executes)
and the payload is executed at next trigger cycle.
Payload consists of setter, advancer, and finalizer.
- Setter sets up CUnit memory layout
- Advancer ends infinite loop at certain condition, and proceeds to finalizer
- Finalizer cleans up stuff, and return to original trigger list.
- Payload knows it's address. (Fixed at where MRGN is loaded) So they can use SetDeaths to modify their internal contents.
Payload is initally constructed to have infinite loop. (Trigger engine traverses through doubly linked list, so play with it->next)
like this.
p2 trigger start ---> setter <--- loop ---> advancer ; finalizer ---> NULL
- 5. Payload creates CUnit memory layout at (a), (prev, next)
- Increases (a) by 336. (Increasing 84 in player section of SetDeaths action, in fact) See trggen.py for more details.
- 6. After 3300 layouts has been created, advancer changes it's next to finalizer trigger node.
p2 trigger start ---> setter ---> advancer ---> finalizer ---> NULL
- 7. finalizer uses (b) and (c) to link empty unitnode list and player 2 trigger list, and sets it's own next to (c).
setter ---> advancer ---> finalizer ---> (c)
(not referencable)
p2 trigger start -> (c)
Trigger list returns to normal
This example fails because SC uses binary search to locate units in certain rectangle (FindAllUnits in BW, .text:004308A0)
and they uses 1700-sized array in their internal implementation. (.data:006BD3D0)
But payload seems to be working properly as expected.
Some proposal :
1. Vanilla location table + Switches + BW Location table < 7200byte = Size of 3 trigger values, so you actually can't do much with MRGN sections only.
The one and only continuous memory region with adjustable size is STR section.
We can upload our own trigger at STR section and init their needed offsets with trigger at MRGN sections.
(TRIG -> MRGN -> TRIG -> MRGN -> ... -> TRIG -> MRGN -> (after complete load) TRIG -> MRGN (This time to traverse through TRIG and make goto statement)
-> TRIG -> STR )
(or One can upload memcpy(eud version) & custom trigger at STR section and let MRGN use memcpy to copy some needed addresses to STR)
2. Goto is possible, as shown in stage 6, 7. (Modifying ->next) Since trigger in STR should know their offsets after having been initalized by MRGN,
sections in STR should be able to jump around over themselves, leading us to write EUD 'program' at least as powerful as brainfuck. (Maybe much more powerful)
3. These tasks are very tedious to do by hand. Some automated tool (brainfuck->eud compiler?) should be made before this trick would have any
usability.
Check out testmap.scx and two python source files used for trigger generation. (Python 3)
Attachments:
Post has been edited 2 time(s), last time on May 18 2014, 10:37 pm by trgk.
EUD