Simple script to approach location

Hi everyone,

I’m trying to use the Sanderling bot to create some simple application but i’m having issue on the most easiest thing. I have created a bookmark names “NEAR BASE” and i just want to Approach it, here is the sample of my code :

while(true)

{

var Measurement = Sanderling?.MemoryMeasurementParsed?.Value;

Host.Log(Measurement.IsDocked);

var listSurroundingsButton = Measurement?.InfoPanelCurrentSystem?.ListSurroundingsButton;

Host.Delay(1000);

Sanderling.MouseClickRight(listSurroundingsButton);

Host.Delay(1000);

for(int i = 0; i < Measurement?.Menu?.Count(); i++) {

    for(int j = 0; j < Measurement.Menu.ElementAt(i).Entry.Count(); j++) {

        Sanderling.Parse.IMenuEntry entry = Measurement.Menu.ElementAt(i).Entry.ElementAt(j); 

        Host.Log(entry.Text);

        if(entry.Text == "NEAR BASE") {

            Sanderling.MouseClickLeft(entry);

            Measurement.Menu.ElementAt(1).EntryFirstMatchingRegexPattern("^Approcher de l'emplacement$", RegexOptions.IgnoreCase);
            // click the button
        }

    }

}

return true;
}

But the thing is that it never work, sometimes the first right click is done, sometimes it’s not. Sometimes when it’s done, it doesn’t find the bookmark and also it never approach the target.

Do you have any clue ? Thanks !

I see some problems with the code:

  • usage of outdated measurement: if the left click is performed in the inner loop it seems to continue using the measurement which was taken before the click and searches this for other menus? Is this intended? If not, I suggest you make Measurement a function to avoid updating it manually.
    Here is an example of how this could be implemented, take from the sample mining script:
Sanderling.Parse.IMemoryMeasurement	Measurement	=> Sanderling?.MemoryMeasurementParsed?.Value;

I do not see any statement in that code which I would expect to trigger an approach. Did you miss a call to click?

Hi,

Thanks for the answer, i understand what my mistake was, indeed the fact that i use the same object and i do action after, the Measurement is not updated (i tought it was). Right now i’m doing something like that :

while(true)
{
Sanderling.Parse.IMemoryMeasurement Measurement = Sanderling?.MemoryMeasurementParsed?.Value;
var listSurroundingsButton = Measurement?.InfoPanelCurrentSystem?.ListSurroundingsButton;
Sanderling.MouseClickRight(listSurroundingsButton);
Measurement = Sanderling?.MemoryMeasurementParsed?.Value;
if(Measurement.Menu.Count() > 0) {
	var menuEntry = Measurement.Menu.First().Entry.Where(e => e.Text == "something").First();
	if(menuEntry != null) {
		Sanderling.MouseClickLeft(menuEntry);
	}
}
return true;
}

And even if i’m not warping, i’m correctly opening the menu entry associated to my bookmark. For that i thank you, because i did not understand how it was working :slight_smile:
But the last part of your message is pretty obscur to me. I don’t understand how i can use that and the “=>” symbole in C# is not use for assignation. Can you give me an example on how i can avoid refreshing each time the measurement using my small code just on the top and your recommendation ? (or even send me a link to script that could give a hint)

Thanks anyway !

To do this, insert the following definition at the top of your script:

Sanderling.Parse.IMemoryMeasurement	Measurement	=> Sanderling?.MemoryMeasurementParsed?.Value;

This is a definition of a property with a get method. You can then use it like you would use a variable in the rest of your script. The difference is that each time you evaluate the expression Measurement, the expression on the right side of the arrow is evaluated.
You can think of it as a simple replacement of Measurement by Sanderling?.MemoryMeasurementParsed?.Value.

And a sample script which does this is the one at Sanderling/Mine.ore.cs at 5dc223deb738f9b835d2d09d78196bd0702dbaae · Arcitectus/Sanderling · GitHub

The same script also shows at Sanderling/Mine.ore.cs at 5dc223deb738f9b835d2d09d78196bd0702dbaae · Arcitectus/Sanderling · GitHub how to click a menu entry within the submenu of a bookmark in the function InitiateDockToOrWarpToBookmark. (It is somewhat more complex because it also works if you pass a bookmark folder instead of a bookmark)

Hello,

Thanks a lot for your answer, it was clear enough to make me understand.
One last question, is it possible to do the same output but without using the code editor inside the software ? I downloaded the source code, and tried to implement a small class that will do the same process but i can’t find where the Sanderling?.MemoryMeasurementParsed?.Value can be find. I’ll keep digging in the code but if you have the answer, i’ll be glad to here it.

Thanks !

[EDIT] I think i found my way inside the code, if i want to add a new tab it’s pretty easy, it’s just that the code that i create need to receive the Measurement of the client.
I found that in the App.UI there is a call to a “Present” method that basicly update the Measurement in the needed tab. I just have to add my tab there, call a custom function and pass the Measurement. The function that will pass the Measurement value is based on a timer tick meaning that it will automaticly refresh the correct datas.

To get the same memory measurement as you would from the Sanderling IDE, you can call the method Sanderling.Exe.App.FromScriptRequestMemoryMeasurementEvaluation.

As the name hints, this method is called when you call Sanderling.MemoryMeasurement or Sanderling.MemoryMeasurementParsed from the script executed in the Sanderling IDE.

Thing is, if you want to add a new tab to the application, you have to add the xaml file inside the Sanderling.UI project. But the Sanderling.UI project have no reference to the Sanderling.Exe project so you can’t to the Sanderling.Exe.App.FromScriptRequestMemoryMeasurementEvaluation call…

A simple way to implement the reference is to use a static field to store the reference to the method in a class which is available in all the projects where you want to call the method:

public class ContainerClassAvailableInEveryProject
{
  static public Func<FromProcessMeasurement<MemoryMeasurementEvaluation>> FromScriptRequestMemoryMeasurementEvaluation;
}

And then assign the reference to the method once at construction of the Sanderling.Exe.App:

ContainerClassAvailableInEveryProject.FromScriptRequestMemoryMeasurementEvaluation = this.FromScriptRequestMemoryMeasurementEvaluation;

Now you have the reference at your code in any project you want and you can call it like this:

ContainerClassAvailableInEveryProject.FromScriptRequestMemoryMeasurementEvaluation?.Invoke();

Hi,

Thanks for the answer and sorry for the late response. I understood your point of view and implementing it will be easy. But isn’t that “bad” ? I mean if the connexion are meant to be done following the fact that the UI classes can’t use the Exe components, i should not try to bypass it by using a bridge projet between those two right ?
I just tought about something and i’d like to know you opinion on it. The UI project create the basics of the interface and only that, what i’d like to do is that :

  • Create a WPF class inside the UI project containing the design of the window (button, label, etc…)
  • Inside the Exe project, i create a name partial class that will implements the “brain” part of the window. Meaning that having acces to the Measurement will be easly done and more importantly, properly done (since it won’t be available for everyone). Inside the class i’ll implement events, etc…

Do you think it is the way i should follow ?
Plus, i’ve been wondering how (i can’t test right now but will do when i’ll be home) can i simulate a click ? Using the Editor it’s fairly simple but after doing my researches, i found out that if you use the Sanderling.MouseClickLeft, you call a static function that if you look in depth call a ActMotionAsync with some paramters, is that correct ?

Thanks again.

[EDIT] I’m trying it right now but… it seems impossible :smiley: You can’t have partial class in two differents project and reference a method from one project to another (or even create a partial method and implement it in another project). I’m gonna try your method

Why would it be bad? It is just meant as an improvement for the use case you described, not necessarily a perfect solution.

I don’t know what those components would be and how those could be used.

I assume that the classification of “impossible” in your edit applies here and you are therefore not interested in this anymore.

For simulation of input, you can use the Motor property of the App and call the ActSequenceMotion method on this object.
For example, if you have an IUIElement , you can click on it with the following code:

var motionParam = uiElement.MouseClick(MouseButtonIdEnum.Left);

Motor.ActSequenceMotion(motionParam.AsSequenceMotion(memoryMeasurement));