This week I got around to updating the guide on developing for EVE Online to include this.
This is now explained in the Entry Point - processEvent
section here: bots/developing-for-eve-online.md at 56333a44d00364cb9a45558faa6600a26b7212de · Viir/bots · GitHub
I copied this part of the guide below:
Entry Point - processEvent
Each time an event happens, the framework calls the function processEvent
. Because of this unique role, we also call it the ‘entry point’.
Let’s look at the structure of this function.
processEvent : InterfaceToHost.AppEvent -> State -> ( State, InterfaceToHost.AppResponse )
In the type annotation above, we can see a type State
used twice. This State
is specific to each app. Each app can use it’s own State
structure, it just have to be the same in all parts of processEvent
. The State
appears in one parameter for the first time, meaning the function receives a value of type State
when it is used. The second time State
appears in the part after the last arrow, meaning it is part of the return type. So the function also returns a value of type State
(as part of a tuple).
Each time the engine calls the processEvent
function, it gives the previous state as the second argument, and receives the new state with the return value. For the first event, the engine takes the State
from the initState
value. This passing on of the app state is what allows the engine to show you the current state of the app for inspection.
The other types used in the type annotation above are InterfaceToHost.AppEvent
and InterfaceToHost.AppResponse
. These are the same for each app.
The type of processEvent
is not specific to EVE Online. Apps for other games use the same structure. Apps for the EVE Online client use the EveOnline.AppFramework.processEvent
function to produce the more general processEvent
function. We can see this in the example projects, no matter if the app is a mining bot, ratting bot, or just a monitor that watches local chat and alerts the user when a hostile pilot enters.
Let’s have a closer look at EveOnline.AppFramework.processEvent
:
processEvent :
{ parseAppSettings : String -> Result String appSettings
, processEvent : EveOnline.AppFramework.AppEventContext appSettings -> EveOnline.AppFramework.AppEvent -> appState -> ( appState, EveOnline.AppFramework.AppEventResponse )
}
-> InterfaceToHost.AppEvent
-> EveOnline.AppFramework.StateIncludingFramework appSettings appState
-> ( EveOnline.AppFramework.StateIncludingFramework appSettings appState, InterfaceToHost.AppResponse )
(In the source code, you might see less of the EveOnline.AppFramework
prefixes because they are implicit for the current module. I added them here to clarify the difference between the ones in EveOnline.AppFramework
and in InterfaceToHost
).
This processEvent
function from the framework for EVE Online gives the event and the response a more specific shape, with a structure that is adapted for working with the game client. It works as a wrapper for the event and response types from the InterfaceToHost
module. It hides the generic language of the host, so we don’t need to learn about it but instead can focus on the language that is specific to EVE Online.
The function type shown above looks big and unwieldy, and the first thing we do is to divide it into two parts: The first parameter and the rest. The first parameter is what we supply when we build our app. This is a record with fields named parseAppSettings
and processEvent
.
All the rest describes what we get back after supplying the record for the first parameter. The type of this latter part matches the type constraint for the processEvent
function in the BotEngineApp.elm
file (Remember, the state can take any shape). So we don’t look closely at the part after the first parameter, we pass it on to the engine.
That leaves only the parseAppSettings
and processEvent
fields for us to look at.
Here is how the autopilot example bot code uses the framework function to connect the app code to the host:
processEvent : InterfaceToHost.AppEvent -> State -> ( State, InterfaceToHost.AppResponse )
processEvent =
EveOnline.AppFramework.processEvent
{ processEvent = processEveOnlineBotEvent
, parseAppSettings = AppSettings.parseAllowOnlyEmpty ()
}
Using the parseAppSettings
field, we describe how to translate from the app settings string given by the user to the settings. The framework invokes the parseAppSettings
function every time the user changes the app-settings. The return type is a kind of Result
which means we can decide that a given app-settings string is invalid and reject it. The Err
case uses the String
type, and we use this to explain to the user what exactly is wrong with the given app-settings string. You don’t need to worry about how to generate these error messages, because there is already a framework for this. In our app, we only need to define a list of valid settings, and the framework will generate a precise error message if the user misspells the name of a setting or tries to use a setting with an unsupported value.
Most of the development activity happens in the function that we give to the processEvent
field:
processEvent : EveOnline.AppFramework.AppEventContext appSettings -> EveOnline.AppFramework.AppEvent -> appState -> ( appState, EveOnline.AppFramework.AppEventResponse )
I will quickly break down the Elm syntax here: The part after the last arrow (->
) is the return type. It describes the shape of values returned by the app to the framework. The part between the colon (:
) and the return type is the list of parameters. So this function has three parameters.
Let’s have a closer look at the parameters:
-
EveOnline.AppFramework.AppEvent
: This describes an event that happens during the operation of the app.
-
BotState
: The BotState
type is specific to the app. With this type, we describe what the app remembers between events. When the framework informs the app about a new event, it also passes the BotState
value which the app returned after processing the previous event. But what if this is the first event? Then there is no previous event? In this case, the framework takes the value from the function initState
.
All information the app ever receives is coming through the values given with the first and second parameter (AppEventContext
and AppEvent
).
Just like the structure of the BotState
type, its name is also specific for the app. We could as well use another name, as long as we use it consistently in both the last parameter and the return type.