armoha / euddraft

System for pluginizing eudplib codes.
Other
28 stars 4 forks source link

Questions about MSQC. (Condition problem, Passing big value, etc.) #17

Closed Chromowolf closed 9 months ago

Chromowolf commented 3 years ago

Q1. The VAL syntax of MSQC is:

[Condition(s)]; val, [Address]: [DeathUnit or PVariable or...]

It requires at least 1 condition. Why is the condition necessary? If I wanna pass the value of a non-shared address to a PVariable, I think I could just intuitively write something like:

val, 0x0057F1B0: Terran Marine

But this violates the syntax. So I must add some meaningless condition (which I don't think is necessary), like:

0x0057F1B0, AtLeast, 0; val, 0x0057F1B0: Terran Marine

This syntax is a little bit conter-intuitive for me. Could you explain why the syntax requires at least 1 condition?

Q2. What should I do if I want to pass a value which could possibly be very large? Say, my map is 128x128 so that the sendable value is 0 to 4194303. But the value I want to pass is far larger than 4194303.

armoha commented 3 years ago

A1.

Why is the condition necessary?

Without condition, sending occurs every frame and player's APM will spike, which is not desirable in most cases. (ex) MSQC built-in mouse location sends only when mouse positions are actually changed. You don't need to update value if it still remains same.

A2. Pass multiple times or split values into multiple entries :P There are max limit of command queue(=Max active MSQC units) so you gonna need both methods and your own additional way to verify it to send big values flawlessly. Check how SCArchive does.

Chromowolf commented 3 years ago

Thank you. Reading the code of SCA is really a challenge for me. But I'll try. I may need some hint later. :P

Chromowolf commented 3 years ago

I tried splitting the 4-byte value to two u16 variables, like this: main.edd:

[main]
input: in.scx
output: out.scx
[main.eps]
[MSQC]
0x6D0F38, AtLeast, 0; val, sendlb : receivelb
0x6D0F38, AtLeast, 0; val, sendhb : receivehb
[eudTurbo]

main.eps:

const receivelb = PVariable();
const receivehb = PVariable();
const receive = [0, 0, 0, 0, 0, 0, 0, 0];
var sendlb = 0; // low 2 byte
var sendhb = 0; // high 2 byte

function onPluginStart() {
    EUDRegisterObjectToNamespace("sendlb", sendlb);
    EUDRegisterObjectToNamespace("sendhb", sendhb);
    EUDRegisterObjectToNamespace("receivelb", receivelb);
    EUDRegisterObjectToNamespace("receivehb", receivehb);
}

function afterTriggerExec() {
    sendlb = dwread_epd(EPD(0x6D0F38)) % 0x10000; //low byte
    sendhb = dwread_epd(EPD(0x6D0F38)) / 0x10000; //high byte
    for (var i = 0; i < 8; i++) {
        receive[i] = receivelb[i] + receivehb[i] * 0x10000; //combine
    }
}

Seems OK? Is there a cleverer way?

armoha commented 3 years ago

q, m = div(a, b); calculates a ÷ b, returns quotient and remainder.

    sendlb = dwread_epd(EPD(0x6D0F38)) % 0x10000; //low byte
    sendhb = dwread_epd(EPD(0x6D0F38)) / 0x10000; //high byte
    // ▼ These can be written as,
    sendhb, sendlb = div(dwread(0x6D0F38), 0x10000);
Chromowolf commented 3 years ago

Thank you. Now I'm using this technique to run a test: main.edd:

[main]
input: in.scx
output: out.scx
[main.eps]
[MSQC]
0x51CE8C, AtLeast, 0; val, sendlb : receivelb
0x51CE8C, AtLeast, 0; val, sendhb : receivehb
[eudTurbo]

main.eps:

const receivelb = PVariable();
const receivehb = PVariable();
const receive = PVariable();
var sendlb = 0; // low 2 byte
var sendhb = 0; // high 2 byte

function onPluginStart() {
    EUDRegisterObjectToNamespace("sendlb", sendlb);
    EUDRegisterObjectToNamespace("sendhb", sendhb);
    EUDRegisterObjectToNamespace("receivelb", receivelb);
    EUDRegisterObjectToNamespace("receivehb", receivehb);
}

function afterTriggerExec() {
    const invSysTime = dwread_epd(EPD(0x51CE8C)); //Get inverse system time (local)
    sendhb, sendlb = div(invSysTime, 0x10000); //sendlb, sendhb = dwbreak(invSysTime); also ok?
    for (var i = 0; i < 8; i++) {
        receive[i] = receivelb[i] + receivehb[i] * 0x10000;
    }

    const cp = getcurpl();
    const localID = getuserplayerid();
    setcurpl(localID);
    const pp = StringBuffer(256);

    pp.printfAt(0, "Game tick = {}", getgametick());
    pp.printfAt(1, "invTime = {}, hex = 0x{}", invSysTime, hptr(invSysTime)); //invSysTime sent
    pp.printfAt(2, "sendhb = 0x{}, sendlb = 0x{}", hptr(sendhb), hptr(sendlb));
    pp.printfAt(3, "Receive = {}, hex = 0x{}", receive[localID], hptr(receive[localID]));//invSysTime received
    pp.printfAt(4, "recvhb = 0x{}, recvlb = 0x{}", hptr(receivehb[localID]), hptr(receivelb[localID]));
    pp.printfAt(5, "Time diff = {}", receive[localID] - invSysTime); // Time difference between send and receive
    pp.printfAt(6, "ms per frame: {}, {}, {}, {}, {}, {}, {}", dwread_epd(-122787), dwread_epd(-122786), dwread_epd(-122785), dwread_epd(-122784), dwread_epd(-122783), dwread_epd(-122782), dwread_epd(-122781));

    setcurpl(cp);
}

Then I tested the out.scx using single-player mode in the slowest game speed (167ms/frame). And got the following result:

Frame 2: image Frame 3: image Frame 4: image Frame 5: image Frame 6: image Frame 7: image Frame 8: (problematic) image Frame 9: image Frame 10: image ... Frame 20: image ... Frame 154: image

Frame 155: image Frame 156: image Frame 157: image Frame 158: (problematic) image Frame 159: image ... Frame 308: (problematic) image ... Frame 458: (problematic) image

(Q1) There are 500ms lag between "send" and "receive", indicating a lag of 3 frames. When I try the map in multiplayer mode, the lag becomes 4 frames. What makes this time lag? Is it because there is only 1 QCUnit and it has to send 2 times? Nonetheless I'm expecting a 2-frame lag only.

(Q2) There are strange values every 150 frames, (see frame 8, frame 158, frame 308). This is obviously because MSQC received/calculated a wrong value (0xFFFFFFFF, which is -1). For example, the received value in Frame158 should be the inverse system time of Frame155 (i.e. 0xF0913C5f). The actual received values (high byte and low byte) are both -1, which is weird. Why does MSQC fail to send correct value for every 150 frames?

armoha commented 3 years ago

(Q1) You don't need MSQC for singleplayer game so IMO this isn't proper test. Command queue has size limit so that's why I made additional condition mandatory to encourage to only send on demand. SC will silently fail to issue order when you issue too many command so queue is full. The delay is same amount of time between when you right click unit and when actual unit ordered to move.

(Q2) It is intended behavior that the value is set to -1 when no sending happens. Long time ago it was 0 but there was a problem, not able to distinguish between receiving 0 and no sending so it was changed to -1.

Chromowolf commented 3 years ago

You don't need MSQC for singleplayer game so IMO this isn't proper test.

I'll do another test with multiple players in one game.

SC will silently fail to issue order when you issue too many command so queue is full.

Could you please briefly explain the command queue mechanism in starcraft? I've read (a little bit) source code of MSQC and also the QueueCommand functions in the eudplib, but cannot fully understand. I've learned data structures in programming and know the queue structure. I just don't know how big the queue size is and how often starcraft does "dequeue/pop". Say If I select one unit and use right click to issue move order to this unit once for each frame, will the queue eventually be full? If I add frequency, say, 2 clicks for each frame, will the queue eventually be full? If I use trigger action Order(..., Move, ...), will it add to the command queue? My friend has made some maps in which he gave several "patrol" orders for many units using the action Order(..., Patrol, ...) constantly (nearly every frame). And he noticed that sometimes the units randomly failed to execute the order, and just stood still. May this be related to the command queue?

It is intended behavior that the value is set to -1 when no sending happens. Long time ago it was 0 but there was a problem, not able to distinguish between receiving 0 and no sending so it was changed to -1.

I know this feature: If no sending, then send -1. But in my case, I'm constantly sending values every frame, (see my codes). I cannot figure out why the "no sending" occurs every 150 frames. This means SC silently fail to issue order for every 150 frames in this case? If I add some additional condition, preventing MSQC from running every frame, this "no sending" problem would be fixed?

armoha commented 3 years ago

Order action is irrelevant. It doesn't share local command. Remaining queue space is at 0x57F0D8 but it's better to say sending is fallible, no sending can occur anytime so you would better handle it. I don't think the delay between sending and receiving is constant and your test does not check the number of receiving so I can't say whether it is really sending was lost or receiving didn't occur yet.

Chromowolf commented 3 years ago

your test does not check the number of receiving

How to check the number of receiving?

armoha commented 3 years ago

How to check the number of receiving?

Don't constantly send value during whole game. Set how many sending occurs by the number or time. Say sends 100 times and wait return values.

Chromowolf commented 3 years ago

I tested again. 2 players in battle.net (P1 and P2), fastest speed, send value 10 times: main.edd

[main]
input: in.scx
output: out.scx

[main.eps]

[MSQC]
sendlb.AtLeast(1); val, sendlb : receivelb
sendhb.AtLeast(1); val, sendhb : receivehb

[eudTurbo]

[freeze]
freeze: 0

main.eps:

const localID = getuserplayerid();

const receivelb = PVariable();
const receivehb = PVariable();
const receive = PVariable();
var sendlb = 0; // low 2 byte
var sendhb = 0; // high 2 byte

function onPluginStart() {
    EUDRegisterObjectToNamespace("sendlb", sendlb);
    EUDRegisterObjectToNamespace("sendhb", sendhb);
    EUDRegisterObjectToNamespace("receivelb", receivelb);
    EUDRegisterObjectToNamespace("receivehb", receivehb);
}

function afterTriggerExec() {
    const gametick = getgametick();
    const invSysTime = dwread_epd(EPD(0x51CE8C)); //Get inverse system time (local)

    sendlb = 0; //Set to 0
    sendhb = 0; //Set to 0
    if (gametick <= 11) { //send value when gametick is 2,3,4,5,6,7,8,9,10,11
        sendhb, sendlb = div(invSysTime, 0x10000); //break dw to w
    }

    for (var i = 0; i < 8; i++) {
        receive[i] = receivelb[i] + receivehb[i] * 0x10000;
    }

    const cp = getcurpl();
    setcurpl(localID);

    const pp = StringBuffer(256);
    pp.printfAt(0, "Game tick = {}", gametick);
    pp.printfAt(1, "invTime = {}, hex = 0x{}", invSysTime, hptr(invSysTime));
    pp.printfAt(2, "sendhb = 0x{}, sendlb = 0x{}", hptr(sendhb), hptr(sendlb));

    //receive P1:
    pp.printfAt(3, "Receive[0] = {}, hex = 0x{}", receive[0], hptr(receive[0]));
    pp.printfAt(4, "recvhb[0] = 0x{}, recvlb[0] = 0x{}", hptr(receivehb[0]), hptr(receivelb[0]));

    //receive P2:
    pp.printfAt(5, "Receive[1] = {}, hex = 0x{}", receive[1], hptr(receive[1]));
    pp.printfAt(6, "recvhb[1] = 0x{}, recvlb[1] = 0x{}", hptr(receivehb[1]), hptr(receivelb[1]));

    //receive P3:
    pp.printfAt(7, "Receive[2] = {}, hex = 0x{}", receive[2], hptr(receive[2]));
    pp.printfAt(8, "recvhb[2] = 0x{}, recvlb[2] = 0x{}", hptr(receivehb[2]), hptr(receivelb[2]));

    pp.printfAt(9, "Time diff = {}", receive[localID] - invSysTime); // Time difference between send and receive

    setcurpl(cp);
}

The result is the same. There is something wrong in Frame 8. The following is the screen shots for P1:

Frame 2: image Frame 3: image Frame 4: image Frame 5: image Frame 6: image Frame 7: image Frame 8: (problematic) image Frame 9: image Frame 10: image Frame 11: image Frame 12: image ... Frame 15: image Frame 16: (no more sendings since here) image

Is this test clear enough to illustrust the "frame 8" problem?

armoha commented 3 years ago

Is basemap size 256x256?

Chromowolf commented 3 years ago

It's 128x128. I'll attach you the files if needed

armoha commented 3 years ago

for (var i = 0; i < 8; i++) { receive[i] = receivelb[i] + receivehb[i] * 0x10000; }

  1. It is not guaranteed to send nor receive both receivelb and receivehb at the same time. You'd rather encode information about which parts of data it is.
  2. Also it is not guaranteed whether SC always process command queue at every gametick. If sending of frame 4 and 5 are happened to reside in queue and processed at the same time, later would overwrite. (You could insepct command queue to prove this.)
  3. Maybe QueueGameCommand was failed silently because queue was full. (dwread(0x57F0D8) - dwread(0x654AA0) = remaining queue space)
  4. nitpick
    for (var i = 0; i < 8; i++) {
    if(receivelb[i] != ~0 && receivehb[i] != ~0) {
        receive[i] = receivelb[i] + receivehb[i] * 0x10000;
    } else {
        receive[i] = ~0;
    }
    }
Chromowolf commented 3 years ago

It is not guaranteed to send nor receive both receivelb and receivehb at the same time. Also it is not guaranteed whether SC always process command queue at every gametick.

Thank you! These two points are crucial. I didn't even think of this possibility. I made it simple this time. I tried not combining the receivehb and receivelb. I also restrained the condition. main.eps:

const localID = getuserplayerid();

const receivelb = PVariable();
const receivehb = PVariable();
const receive = PVariable();
var sendlb = 0; // low 2 byte
var sendhb = 0; // high 2 byte

var gametick = getgametick();

function onPluginStart() {
    EUDRegisterObjectToNamespace("gametick", gametick);
    EUDRegisterObjectToNamespace("sendlb", sendlb);
    EUDRegisterObjectToNamespace("sendhb", sendhb);
    EUDRegisterObjectToNamespace("receivelb", receivelb);
    EUDRegisterObjectToNamespace("receivehb", receivehb);
}

function afterTriggerExec() {
    gametick = getgametick();
    const invSysTime = dwread_epd(EPD(0x51CE8C)); //Get inverse system time (local)

    sendhb, sendlb = div(invSysTime, 0x10000); //break dw to w

    const cp = getcurpl();
    setcurpl(localID);

    const pp = StringBuffer(256);
    pp.printfAt(0, "Game tick = {}", gametick);
    pp.printfAt(1, "invTime = {}, hex = 0x{}", invSysTime, hptr(invSysTime));
    pp.printfAt(2, "sendhb = 0x{}, sendlb = 0x{}", hptr(sendhb), hptr(sendlb));

    //receive P1:
    pp.printfAt(3, "recvhb[0] = 0x{}, recvlb[0] = 0x{}", hptr(receivehb[0]), hptr(receivelb[0]));

    //receive P2:
    pp.printfAt(4, "recvhb[1] = 0x{}, recvlb[1] = 0x{}", hptr(receivehb[1]), hptr(receivelb[1]));

    //receive P3:
    pp.printfAt(5, "recvhb[2] = 0x{}, recvlb[2] = 0x{}", hptr(receivehb[2]), hptr(receivelb[2]));

    const commandDataEPD = EPD(0x654880); //Copied from qgc.py, not sure it's the correct address
    const maxBufferSize = dwread_epd(EPD(0x57F0D8));
    const bufferUsed = dwread_epd(EPD(0x654AA0));
    pp.insert(0, "Command data =");
    for (var i = 0; i < 7; i++)
        pp.appendf(" {},", hptr(dwread_epd(commandDataEPD + i)));
    pp.DisplayAt(6);
    pp.printfAt(7, "Max buffer size = {}, buffer used = {}, remaining = {}", maxBufferSize, bufferUsed, maxBufferSize - bufferUsed);

    setcurpl(cp);
}

When [MSQC] is:

[MSQC]
gametick.AtLeast(3); gametick.AtMost(4); val, sendlb : receivelb
gametick.AtLeast(3); gametick.AtMost(4); val, sendhb : receivehb

I got: image

image

image

When [MSQC] is:

[MSQC]
gametick.Exactly(3); val, sendlb : receivelb
gametick.Exactly(3); val, sendhb : receivehb

I got: image

When [MSQC] is:

[MSQC]
gametick.Exactly(4); val, sendlb : receivelb
gametick.Exactly(4); val, sendhb : receivehb

I got: image

image

So the temporary conclusion is that: they are not received by the same time in this case. Seems that this weird situation happens with high probability in Frame8, Frame158, Frame308. Is there anything that MSQC can do to prevent/remedy this weird SC internal problem? Btw I don't know how to interpret the QueueGameCommand

Chromowolf commented 3 years ago

In short: It cannot be guaranteed that I receive the 2 value at the same time, even if I constrain the condition to make it send the 2 values only ONCE.

armoha commented 3 years ago

Is there anything that MSQC can do to prevent/remedy this weird SC internal problem?

Once sharing feature is integrated in upcoming new language, send function will be fallible operation and end user would choose what to do based on result of send.

Or another queue could be added and let send function to enqueue (again it is fallible when queue is full).

armoha commented 3 years ago

Fixed MSQC regression, please re-download euddraft: https://github.com/armoha/euddraft/releases/tag/v0.9.1.4

image

/* .edd
[main]
input: basemap.scx
output: msqc_dbg.scx
[EUDTurbo]
[main.eps]
[MSQC]
send_switch.Exactly(1) ; val, send : receive
QCDebug: False
[freeze]
freeze: 0
*/

// test code
var send, send_switch;
const receive = PVariable();
const dbg = StringBuffer();
const me = getuserplayerid();

function onPluginStart() {
    EUDRegisterObjectToNamespace("send", send);
    EUDRegisterObjectToNamespace("send_switch", send_switch);
    EUDRegisterObjectToNamespace("receive", receive);
}

function beforeTriggerExec() {
    // send value once user press Q
    static var is_q_pressed = false;

    if (list(
        is_q_pressed == false,
        MemoryX(0x596A18 + 0x51, Exactly, 256, 256)
    )) {
        is_q_pressed = true;
        // toggle send between 0 and 1
        send_switch = true;
        DoActions(send.AddNumberX(1, 1));

        setcurpl(me);
        dbg.printf("{0:c}{0:n} \x04sent \x07{1}", me, send);
    } else if (list(
        is_q_pressed == true,
        MemoryX(0x596A18 + 0x51, Exactly, 0, 256)
    )) {
        is_q_pressed = false;
    }
}

function afterTriggerExec() {
    if (send_switch == true)
        send_switch = false;

    setcurpl(me);

    foreach(human: EUDLoopPlayer("Human")) {
        const my_receive = receive[human];
        if (my_receive != -1) {
            dbg.printf("{0:c}{0:n} \x04got \x07{1}", human, my_receive);
        }
    }
}
Chromowolf commented 3 years ago

Thanks for the update! But are you sure you uploaded the correct MSQC.py? The newest MSQC.py is exactly the same file as that of euddraft0.8.9.9 Note: Line: 449

mrgn, strtb = chkt.getsection("MRGN"), TBL(chkt.getsection("STR"))

Newer version of MSQC:

        try:
            strtb = TBL(chkt.getsection("STR"))
        except KeyError:
            strtb = TBL(chkt.getsection("STRx"), load_entry=4, save_entry=4)
armoha commented 3 years ago

I copied wrong file soz! Editted release just now.

Chromowolf commented 3 years ago

Now it works! Thx a lot. More questions (and nitpicks) about MSQC:

(1) Why is Valkyrie the default QCUnit? All the QCUnits are invisible and cannot be built in the game. Why not choose some rarely-used air unit as QCUnit (like Gantrithor)? Any side effect of using Gantrithor? QCUnit cannot be built: image

(2) The 2nd syntax in the MSQC manual doesn't work image ( From https://cafe.naver.com/edac/78006 ) The received values are wrong

(3) Nitpick When the [MSQC] section is empty in the edd file, euddraft fails to compile.

[main]
in: ...
out: ...
[MSQC]
[eudTurbo]

(4) Nitpick MSQC keywords like QCDebug, QCUnit are case-sensitive. If user entered the wrong case or mis-spelled the keyword, the error log will be:

File "...\plugins\MSQC.py", line 422, in onInit
    increment = int(ret[1], 0)
IndexError: list index out of range

which makes it hard for user to detect the bug.

armoha commented 3 years ago

(1) Why is Valkyrie the default QCUnit? Why not use Gantrithor? Any side effect of using Gantrithor?

Old predecessor EasyNQC showcased valkyrie as QC unit. https://cafe.naver.com/edac/40357

(2) The 2nd syntax in the MSQC manual doesn't work

Sorry it's already pointed out in comment too but I forgot to fix.

(3) When the [MSQC] section is empty in the edd file, euddraft fails to compile.

[MSQC] adds non-trivial amount of triggers in your map, so it is intended to raise error when you add [MSQC] in plugins without any input. The error message (Forward declaration is not initialized) is not helpful though.

(4) MSQC keywords like QCDebug, QCUnit are case-sensitive. If user entered the wrong case or mis-spelled the keyword, the error log will be:

Yeah error message is misleading and ideally it should suggest correction.

Chromowolf commented 3 years ago

Thx. Btw, do u have the most comprehensive memory table? I'm curious about the memory address storing whether the local user is using Remastered UHQ graphics (not necessarily wide screen) or the original graphics. And so on... I only have this one: http://farty1billion.dyndns.org/EUDDB/ But it is incomplete and somehow outdated. Eg. It doesn't have the entries of 0x654880 and 0x654AA0, the QueueGameCommand ones.

armoha commented 3 years ago

For all I know EUD DB is still most exhaustive and complete one, not most informative for individual entries but best overview. For 0x654880 and 0x654AA0 they haven't documented well and people who researched those removed posts and left cafe so IMO eudplib internal is best to see what it does.

Let me bring a conversation about what they do at eud channel in SEN discord.

Armo — 03/11/2021 I know how to make human player ping at point. Added as euddraft function QueueGameCommand_MinimapPing(x + y * 65536) Armo — 03/11/2021 Looks yellow for oneself (not sure for allies) Zoan — 03/11/2021 Oh, that works ayylmao — 03/11/2021 What does the minimap ping command look like in raw writes? Armo — 03/11/2021 Kinda complex to explain... https://github.com/phu54321/eudplib/blob/066c0faa200dc19e70cdb6979daf8f008b8ae957/eudplib/eudlib/qgcf/qgc.py#L43 lol it's missing in eud db xd Game command queue is at 0x654880, its length is at 0x654AA0. https://github.com/phu54321/vgce/blob/0da9d14626c06351e66a3d9c18973f6d69b89a7a/docs/Blizzard/Starcraft/packets2.txt#L41 Packet Structure for minimap ping Probably @𝙃𝙚𝙞𝙣𝙚𝙧M𝙖𝙣𝙣 found these 𝙃𝙚𝙞𝙣𝙚𝙧M𝙖𝙣𝙣 — 03/11/2021 oh vgce is from my repo I need to reupload it to github FaRTy1billion — 03/11/2021 ya, lots of stuff is still missing from euddb and i've been too lazy to add it 𝙃𝙚𝙞𝙣𝙚𝙧M𝙖𝙣𝙣 — 03/11/2021 was surprised people were able to pull it to github I just forked that one back to mine Armo — 03/11/2021 So... for example, size for Minimap ping packet is 5 bytes. 1 bytes for packet kind (0x58) 2 bytes each for x and y (u16) -> Say queue length is currently 42. You need to write 5 bytes starting at 0x654880 + 42 (=0x6548AA~0x6548AE) and add queue length by 5. FaRTy1billion — 03/11/2021 :open_mouth: Armo — 03/11/2021 Sharing local data to sync depends on this too, make player to rclick unit at encoded coordinates and get shared data from its waypoint.

armoha commented 3 years ago

I'm curious about the memory address storing whether the local user is using Remastered UHQ graphics (not necessarily wide screen) or the original graphics.

A long time ago they can be differentiated with font width: https://cafe.naver.com/edac/66971 but not worked currently after strange patch. Now you know whether player run purchased version of SC:R or not, or user language setting with font width https://cafe.naver.com/edac/75968

armoha commented 3 years ago

I'm afraid this is not true.

KeyPress and MouseButton are not tied to trigger execution interval or gametick. MouseDown(R) on frame 2 only shows that you started pushing button between frame 1 and frame 2, and button is still down on frame 2. If you really want to measure it precisely, inspecting game memory is way to go. Btw delay is quite different between solo play and multiplayer.

Chromowolf commented 3 years ago

KeyPress and MouseButton are not tied to trigger execution interval or gametick.

Thx. I also noticed this after I post the comment. So I deleted it and did further tests yesterday. (So github still shows the deleted comment to the Owner???) So I'll just accept this fact.

Other stuffs: (1) I inspected 0x654880. The select and right click commands are different from what's written here: https://github.com/phu54321/vgce/blob/master/docs/Blizzard/Starcraft/packets2.txt The right click command has opcode 0x60 and something like:

def QueueGameCommand_RightClick_New(xy):
    RightClickCommand = c.Db(b"...\x60XXYY\0\0\0\0\xE4\0\x00")
    c.SetVariables(ut.EPD(RightClickCommand + 4), xy)
    QueueGameCommand(RightClickCommand + 3, 12)

Though 0x14 also works, I don't know the difference. The "select" command has opcode 0x63, and has a unitID that I cannot decode/parse.

(2) There's typo in qgc.py, https://github.com/armoha/euddraft/issues/27#issuecomment-812032598

(3) A minor request. What's the syntax of edd file? Can I comment out the unused lines using # like python? If so, it'll be better if # also works under [MSQC].

armoha commented 3 years ago

(1) Oh 0x60 or 0x63 are not found in https://github.com/bwapi/bwapi/blob/main/bwapi/BWAPI/Source/BW/OrderTypes.cpp too. Maybe they are added in SC:R, hmm.

alphaID (u16) = 2048 * targetOrderSpecial + index (not scmd one, 0x59CCA8 is 1) Hotkey, loaded unit, qgc use it for compactness and preventing using different unit of same index. 0xA5 uniquenessIdentifier or targetOrderSpecial increases by 1 when new unit take over that CUnit.

(2) Fixed. Thank you!

(3) There is no comment syntax for .eds/.edd now but it is nice feature request to add! We don't want to break any [chatEvent] maps with chat starting with # so I need to find a better option. 🤔

Chromowolf commented 3 years ago

(2) Fixed. Thank you!

The command opcode also needs to be fixed. It's 0x12, not 0x2A https://github.com/armoha/eudplib/blob/master/eudplib/eudlib/qgcf/qgc.py#L153

armoha commented 3 years ago
[header]
key : value pair
key-only
; comment
# comment

.eds/.edd config syntax (supposed) https://github.com/armoha/euddraft/blob/d252474f8553a902e0fe65d81a6d6c265c5b3b57/readconfig.py#L42-L46 This is bug that keyonly has higher priority than comment so has ignored...

armoha commented 3 years ago

So :: comment would work for all versions of euddraft.

[header]
key : value pair
key-only
:: comment
Chromowolf commented 3 years ago

Got it. kinda like windows batch :D

armoha commented 9 months ago

Closes as completed, please re-open or open new issue if you have any question.