Problems with .Net vrapper

chanlting

Member
Problems with .Net wrapper

I've been beating my head against the wall for hours trying to figure out how to use the wrapper. Some things work fine, and others inexplicably crash. I used the examples in the svn to figure out how to use Me(), and can read my name, get basic info, etc using Me. But I crash every time when trying to change anything with it. Me.StackAllHangarItems(), for example, or Me.OpenCorpHangar(), or ClearMarketOrderCache(); all of these I've been using as basic tests, and they crash every time, no matter how I declare Me, where I declare it, whatever. Even the sample from the SVN repository crashes upon trying to undock.

Here's a sample of a test script I've been trying:
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.IO;
using System.Threading;
using DirectEve;
using EVE.ISXEVE;
using LavishVMAPI;
using InnerSpaceAPI;
using LavishScriptAPI;

namespace MarketWrapper
{


    public class MarketInfo
    {
        public Extension Extension { get; private set; }
        public Character Me { get; private set; }
        public EVE.ISXEVE.EVE Eve { get; private set; }



        public List<MyOrder> GetMyMarketOrders()
        {
            //LavishScript.Events.AttachEventTarget((LavishScript.Events.RegisterEvent("ISXEVE_onFrame")), OnFrame);
            LavishScript.Events.AttachEventTarget("ISXEVE_onFrame", OnFrame);
            using (new FrameLock(true))
            {
                //Extension = new Extension();
                //Me = Extension.Me;
                //Eve = Extension.EVE();

                Me = new Character();
  
                Me.UpdateMyOrders();
                
                Thread.Sleep(100);
                
                List<MyOrder> myOrders = Me.GetMyOrders();
                Globals.Instance.Me.StackAllHangarItems();
                return myOrders;
                
            }
        }

        void OnFrame(object sender, LSEventArgs e)
         {
            // update the reference each frame
            Me = new Me();
         }

    }

    public sealed class Globals
    {
        public static readonly Globals Instance = new Globals();
        public EVE.ISXEVE.Extension Ext = new EVE.ISXEVE.Extension();
        public EVE.ISXEVE.Me Me = new EVE.ISXEVE.Me();
        public EVE.ISXEVE.EVE Eve = new EVE.ISXEVE.EVE();
        private Globals() { }
    } 
}
I know it's a mess, I'm assigning values to Me in like six different spots. I've tried so many different things trying to get it to work that it's all over the place, and I'm losing track of what goes where. But most of the various ways I've tried to define Me should work the same, I've tried each of them individually, and they all have the same result:

Software: Inner Space Kernel 1.11 Build 5395 (Sun Mar 06 13:35:49 2011)
Crash: 0x1E0B1CE7: Exception 0xc00000fd in module python27.dll
Additional information: .NET PersistentExecuteMethod StackAllHangarItems
What am I doing wrong?
 
Last edited:

stealthy

ISX Specialist
Everything.

Code:
        public List<MyOrder> GetMyMarketOrders()
        {
            //LavishScript.Events.AttachEventTarget((LavishScript.Events.RegisterEvent("ISXEVE_onFrame")), OnFrame);
            LavishScript.Events.AttachEventTarget("ISXEVE_onFrame", OnFrame);
            using (new FrameLock(true))
It doesn't appear you understand the Frame concept.
ALL ISXEVE access must be done from within the registered eventhandler for the ISXEVE_onFrame even. In this case, your OnFrame method.
You can't just framelock and hope it works. It -has- to be done from that event handler.
 

chanlting

Member
Awesome!! I just moved everything into my onframe event and it all works now. Thanks so much!:inlove: Yes I definitely didn't (don't) understand the onframe event. I've read over the information in both isxgames and lavishsoft's wiki, but it's a little obtuse for me; I need concrete examples to understand stuff, and unfortunately every .net scrap I could find doesn't work in one way or another.

To clarify, I was thinking the framelock was basically calling your code within the onframe event, but from my experimenting this morning, I guess it's the opposite? While in framelock, the onframe event will not occur?

So I've come up with the following conclusions/questions about onframe:

Code:
LavishScript.Events.AttachEventTarget("ISXEVE_onFrame", OnFrame);
1) This registers the "ISXEVE_onFrame" event to the function OnFrame(), which I declare in my code? I could theoretically replace "OnFrame" with whatever I want, or is it hardcoded to use that function?

2) The "ISXEVE_onFrame" event runs automatically, and thus once attached to my function, that function will be called every frame without me explicitly calling it? (This was my major stumbling block; I was under the impression OnFrame had to be called somehow, and that framelock was the way to do it)

3) AttachEventTarget() and DetachEventTarget() don't seem to be terribly quick to work, and in debugging I've noticed sometimes one or two onframe events from the return of the last onframe event to the point where onframe gets detached. So you really can't use those back to back to create a pseudo direct onframe function call, right? I.e., I can't update some variables, attach the onframe function to the event to act on those variables, then immediately detach it to prevent it from being called multiple times. I'm guessing that's what the framelock is for; work on your stuff without the onframe event occurring. But it still won't prevent the onframe event from happening multiple times before you can stop it, unless there's another function that can prevent this. Which leads to:

4) It sounds to me like you're pretty much going to have to use a state-based system for any code that needs to access the game at all. Am I off base here? You'd just about have to set up states and process them within the onframe function to get anything to work. Kind of sucks for me, because I was hoping to make a wrapper to even further encapsulate the isxEve interface from my projects (I have a bad habit of writing spaghetti code when I run into a wall. Obviously). I'm not very good at handling states.

In case it helps anybody else, this is the code that works:
Code:
    public class MarketInfo
    {
        public Extension Extension { get; private set; }
        public Character Me { get; private set; }
        public EVE.ISXEVE.EVE Eve { get; private set; }
        public List<MyOrder> myOrders { get; private set; }
        private int getOrders = 0;

        public MarketInfo()
        {
            LavishScript.Events.AttachEventTarget("ISXEVE_onFrame", OnFrame);
        }

        public List<MyOrder> GetMyMarketOrders()
        {
                getOrders = 1;
                InnerSpaceAPI.InnerSpace.Echo(string.Format("{0:HH:mm:ss} {1}", DateTime.Now, "AttachEvent 1"));
                Thread.Sleep(10);
                getOrders = 2;
                InnerSpaceAPI.InnerSpace.Echo(string.Format("{0:HH:mm:ss} {1}", DateTime.Now, "AttachEvent 2"));
                InnerSpaceAPI.InnerSpace.Echo(string.Format("{0:HH:mm:ss} {1}", DateTime.Now, "Back"));
                return myOrders;
        }

        void OnFrame(object sender, LSEventArgs e)
         {
             using (new FrameLock(true))
             {
                 // update the reference each frame
                 Me = new Me();
                 if (getOrders == 1)
                 {
                     Me.UpdateMyOrders();
                     InnerSpaceAPI.InnerSpace.Echo(string.Format("{0:HH:mm:ss} {1}", DateTime.Now, "UpdateMyOrders"));
                     getOrders = 0;
                     return;
                 }
                 else if (getOrders == 2)
                 {
                     myOrders = Me.GetMyOrders();
                     InnerSpaceAPI.InnerSpace.Echo(string.Format("{0:HH:mm:ss} {1}", DateTime.Now, "GetMyMorders"));
                     getOrders = 0;
                     return;
                 }
                 return;
                 //InnerSpaceAPI.InnerSpace.Echo(string.Format("{0:HH:mm:ss} {1}", DateTime.Now, "In OnFrame event"));
             }
         }
 

stealthy

ISX Specialist
To clarify, I was thinking the framelock was basically calling your code within the onframe event, but from my experimenting this morning, I guess it's the opposite? While in framelock, the onframe event will not occur?
The OnFrame events (including ISXEVE_onFrame) are fired when the game gets ready to start drawing the frame (updating what you see rendered). A framelock does nothing more than obtain a "lock" preventing the frame from rendering or starting on the next frame while you run your code.

In non-event frameworks, something like:
Code:
using (new FrameLock(true))
would block until a frame is locked, execute your call in the using block, and dispose the frame lock (unlock) when done.

Since all events are by default synchronous, and the frame is locked before calling the OnFrame events, you don't really need to worry about framelocking within the event handler - it's already locked before firing the event and unlocked when the event is complete. Never hurts to have to be safe but technically not necessary.

While you're in a framelock, the game stops drawing. It can't - the frame is locked so you can do your code. Any thread sleeping, etc. will fail miserably because they'll just make the game thread (which is running your event code!) sleep.

This registers the "ISXEVE_onFrame" event to the function OnFrame(), which I declare in my code? I could theoretically replace "OnFrame" with whatever I want, or is it hardcoded to use that function?
No. It registers the delegate specified (.NET does some casting for you here from method -> delegate, your method matches the EventHandler<LSEventArgs> signature) to be called when the LavishScript ISXEVE_onFrame event is raised.
More information on delegates: http://msdn.microsoft.com/en-us/library/ms173171(v=vs.80).aspx
More information on EventHandlers: http://msdn.microsoft.com/en-us/library/system.eventhandler(v=vs.71).aspx

2) The "ISXEVE_onFrame" event runs automatically, and thus once attached to my function, that function will be called every frame without me explicitly calling it? (This was my major stumbling block; I was under the impression OnFrame had to be called somehow, and that framelock was the way to do it)
Yes. The delegate registered will be called by InnerSpace when something raises the ISXEVE_onFrame LavishScript event, which will happen at the start of every frame.

3) AttachEventTarget() and DetachEventTarget() don't seem to be terribly quick to work, and in debugging I've noticed sometimes one or two onframe events from the return of the last onframe event to the point where onframe gets detached. So you really can't use those back to back to create a pseudo direct onframe function call, right? I.e., I can't update some variables, attach the onframe function to the event to act on those variables, then immediately detach it to prevent it from being called multiple times. I'm guessing that's what the framelock is for; work on your stuff without the onframe event occurring. But it still won't prevent the onframe event from happening multiple times before you can stop it, unless there's another function that can prevent this. Which leads to:
Not necessarily. Execution should block until the code in your EventHandler (OnPulse in your case) is finished executing. Stepping through does slow things down, so by the time you're finished stepping through the fraction of a second it takes to draw a frame will go by and you'll be stepping through again. The best bet here is to use some sort of timer to limit the number of pulses you handle. For instance...
Code:
DateTime _nextPulseDateTime = DateTime.Now;

(in event handler)
    if (!DateTime.Now.CompareTo(_nextPulseDateTime) >= 0)
        return;

... do my work ...

    _nextPulseDateTime = DateTime.Now.AddSeconds(1);
This way it wont pulse unless enough time has passed to pulse again, and it doesn't update the timer until the end of the method call so you don't have to worry about how long it takes your code to execute.

It sounds to me like you're pretty much going to have to use a state-based system for any code that needs to access the game at all. Am I off base here? You'd just about have to set up states and process them within the onframe function to get anything to work. Kind of sucks for me, because I was hoping to make a wrapper to even further encapsulate the isxEve interface from my projects (I have a bad habit of writing spaghetti code when I run into a wall. Obviously). I'm not very good at handling states.
Pretty much. Finite State Machines handle EVE really well. Definitely pulsed architecture, which leads into a finite state machine naturally anyway.
 

chanlting

Member
Thanks for the clarification. I'll read up on delegates and eventhandlers - I've never even heard of delegates.

I hadn't realized that stepping through took time (or at least enough time for a new onframe event to come up before I was back). I'd figured the few lines of code I had would execute far faster than a new frame could be drawn. That explains the weirdness I was getting when trying to attach and detach the event to pulse the onframe function. I got around that by using getOrders to keep track of the state in my second posting. In my actual code, I've set up a state-based system that, for the moment, appears to be working well. Once I start adding functions, though, it's going to be a nightmare to remember what the states and substates are. I'll have to look at it and see if using something like your pulse example with timers makes more sense for what I'm doing.
 
Top Bottom