Arcitectus / Sanderling

APIs and libraries to read information directly from the EVE Online game client.
https://forum.botlab.org
Apache License 2.0
259 stars 117 forks source link

WindowInventory->LeftTreeListEntry[ ]->Child does not populate unless I delay for 4.5 seconds #25

Closed ghost closed 7 years ago

ghost commented 7 years ago

I'm working on a simple script to do all the click work of reprocessing items and comparing values. At the moment I have things working but with work arounds on certain issues.

As the title says, the Child objects in a List Entry does not populate until I have waited ~5 seconds after the LeftTreeListEntry has been clicked on (selected), in the Inventory Window.

Also the WindowInventory.SelectedRightInventory.ListView.Entry.Length is sometimes 0 or 3 when there is 9 to 10 items visible in the list, unless I delay long enough for the script engine to catch up.

I have included my script:

#r "System.Windows.Forms"
using System;
using System.Runtime.InteropServices;

[DllImport("user32.dll")]
    private static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
[DllImport("user32.dll")]
    private static extern bool SetCursorPos(int x, int y);

Sanderling.WindowToForeground();    
Host.Delay(500);

Sanderling.Parse.IMemoryMeasurement Measurement => Sanderling?.MemoryMeasurementParsed?.Value;
Sanderling.Parse.IWindowInventory WindowInventory => Measurement?.WindowInventory?.FirstOrDefault();
IWindow WindowReprocessing => Measurement?.WindowOther?.FirstOrDefault(w => w.Caption == "Reprocessing Plant");

Main();

void Main() {
    EnsureReprocessingWindowOpen();
    EnsureWindowInventoryOpen();

    int leftListLength = (WindowInventory?.LeftTreeListEntry?.Length ?? 0);
    if (leftListLength == 0)
        return;
    int clen = 0;
    long mx = 0, my = 0;

    Sanderling.Interface.MemoryStruct.ITreeViewEntry leftListEntry = null;
    //Sanderling.Interface.MemoryStruct.ITreeViewEntry child = null;
    Sanderling.Interface.MemoryStruct.IListEntry[] rightListEntry = null;
    leftListEntry = WindowInventory.LeftTreeListEntry.FirstOrDefault(t => t.Text == "Item hangar");
    if (leftListEntry.IsSelected == false) {
        mx = leftListEntry.Region.Min0 + 65;
        my = leftListEntry.Region.Min1 + 11;
        clen = leftListEntry.Child.Length;
        if (clen == 0) {
            LeftMouseClick((int)mx, (int)my, true);
        } else {
            LeftMouseClick((int)mx, (int)my);
        }
    } else {
        clen = leftListEntry.Child.Length;
        if (clen == 0) {
            mx = leftListEntry.Region.Min0 + 65;
            my = leftListEntry.Region.Min1 + 11;
            LeftMouseClick((int)mx, (int)my, true);
        }
    }
    Host.Delay(1000);
    leftListEntry = WindowInventory.LeftTreeListEntry.FirstOrDefault(t => t.Text == "Item hangar");
    Host.Log("Log: leftListEntry.Child.Length = " + leftListEntry.Child.Length);
    mx = leftListEntry.Region.Min0 + 67; // 43, 560, 110, 614
    my = leftListEntry.Region.Min1 + 54;
    LeftMouseClick((int)mx, (int)my);

    /*clen = leftListEntry.Child.Length;
    Host.Log(clen);
    for (i = 0; i < clen; i++) {
        child = leftListEntry.Child[i];
        lable = child.Text;
        if (lable == "02 Junk Box") {
            if (child.IsSelected == false) {
                Sanderling.MouseClickLeft(child);
                break;
            }
        }
    }*/
    Host.Delay(1500);
    rightListEntry = WindowInventory.SelectedRightInventory.ListView.Entry;
    Host.Log("Log: rightListEntry.Length = " + rightListEntry.Length);
    if (rightListEntry.Length == 0)
        return;
    var inputMaterials = WindowReprocessing.LabelText.FirstOrDefault(t => t.Text == "Drop items here to reprocess");
    Sanderling.MouseDragAndDrop(rightListEntry[0], inputMaterials);
    Host.Delay(500);
    Host.Log(WindowReprocessing.ButtonText.ToArray()[1].Text);
    //Sanderling.MouseClickLeft();
}

void EnsureWindowInventoryOpen()
{
    if (null != WindowInventory)
        return;

    Sanderling.MouseClickLeft(Measurement?.Neocom?.InventoryButton);
    Host.Delay(100);
}

void EnsureReprocessingWindowOpen() {
    if (WindowReprocessing != null)
        return;
    string tPath = ""; 
    var winStation = Measurement?.WindowStation?.FirstOrDefault();
    for (var i = 0; i < winStation.ServiceButton.Length; i++) {
        tPath = winStation.ServiceButton[i].TexturePath;
        if (tPath.Contains("Reprocess")) {
            Sanderling.MouseClickLeft(winStation.ServiceButton[i]);
            break;
        }
    }
}

void LeftMouseClick(int mx, int my, bool DoubleClick = false) {
    const int MOUSEEVENTF_LEFTDOWN = 0x02;
    const int MOUSEEVENTF_LEFTUP = 0x04;
    //const int MOUSEEVENTF_RIGHTDOWN = 0x08;
    //const int MOUSEEVENTF_RIGHTUP = 0x10;
    SetCursorPos(mx, my);
    Host.Delay(100);
    mouse_event(MOUSEEVENTF_LEFTDOWN, mx, my, 0, 0);
    mouse_event(MOUSEEVENTF_LEFTUP, mx, my, 0, 0);
    if (DoubleClick) {
        Host.Delay(50);
        mouse_event(MOUSEEVENTF_LEFTDOWN, mx, my, 0, 0);
        mouse_event(MOUSEEVENTF_LEFTUP, mx, my, 0, 0);
    }
}
Viir commented 7 years ago

As the title says, the Child objects in a List Entry does not populate until I have waited ~5 seconds after the LeftTreeListEntry has been clicked on (selected), in the Inventory Window.

This delay is because Sanderling does not know that you clicked. It then continues to forward you the existing measurement as default until the timeout whose duration you measured happens.

To tell Sanderling that the existing measurement is not valid anymore, you can use the following code:

Sanderling.InvalidateMeasurement();

Add this to the end of your custom click method.

Viir commented 7 years ago

Closing this since it appears the problem was not observed anymore after applying the fix described above.