Changes to MantellaSpell when switching to HTTP - Leidtier/Mantella-Spell GitHub Wiki

MantellaSpell using HTTP

This is a higher level overview of the changes to MantellaSpell for using HTTP transfer

Summary

  • Requires SKSE_HTTP plugin
  • No longer requires PapyrusUtil (if I havent overlooked a spot where it is used)
  • MantellaEffectScript has been significantly reduced and only serves to trigger the changes in the actual conversation
  • New quest MantellaConversation now handles the actual conversation
  • Conversation is now event driven, meaning it only goes forward on actions of the player or when receiving a reply from MantellaSoftware
  • There are no running while loops anymore and hopefull no scripts that can get stuck
  • If an inferred Action is received, a global event for this specific Action is triggered. Examples of the usage can be found in MantellaAction_OffendForgiveFollow.psc
  • The player character can now be part of the conversation in both MantellaSpell and MantellaSoftware. There is no separate tracking of radiant conversations anymore. It is simply a conversation without the player character in it

MantellaConversation

This is still a slightly larger script with ca. 400 lines split into smaller functions that should be good to digest. The central part for a conversation is now a Quest:

  • The Quest is started if a conversation is started
  • The Quest is being stopped if the conversation end
  • To check if a conversation is currently running, simply checking if it IsRunning() of the Quest should be enough:
MantellaConversation conversation = Quest.GetQuest("MantellaConversation") as MantellaConversation
if(conversation.IsRunning())
   ;Do something with the running conversation here 
endIf

Utilising SKSE_HTTP

SKSE_HTTP has 3 main features:

  • Creating strongly typed dictionaries in Papyrus. See here for an example
  • Sending a request over HTTP using one of the dictionaries created before. This dictionary will get turned into JSON by SKSE_HTTP before sending
  • Receiving replies from an HTTP server which will arrive in an event together with a strongly typed dictionary containing the JSON of the server reply

MantellaConversation.psc starts out with registering for SKSE_HTTPs two main events in its OnInit():

event OnInit()    
    RegisterForModEvent("SKSE_HTTP_OnHttpReplyReceived","OnHttpReplyReceived")
    RegisterForModEvent("SKSE_HTTP_OnHttpErrorReceived","OnHttpErrorReceived")
endEvent
  • The first RegisterForModEvent registers for the event that is called if a HTTP reply is received
  • The second registers for the event that is called if there was an error in the HTTP communication (we use this to stop the conversation ingame)

Conversation Flow

  1. A conversation gets initiated by the player
  2. MantellaEffectScript starts the quest MantellaConversation
  3. MantellaEffectScript calls MantellaConversation.StartConversation(Actor[] actorsToStartConversationWith) using the caster and the target (so player character and NPC) as the two entries for the actorsToStartConversationWith parameter. (MantellaEffectScript already ends here)
  4. MantellaConversation updates its internal list of participants in the conversation with the two Actors it just received for starting the conversation
  5. A strongly typed dictionary is created containing the request type, the actors and the context:
{
   mantella_request_type: "mantella_start_conversation",
   mantella_actors: [
       {
           mantella_actor_id: 7,
           mantella_actor_name: "Gurden",
           mantella_actor_gender: 0,
           mantella_actor_race: "Nord", // <- Or however that actually comes out of the game
           mantella_actor_is_player: true,
           mantella_actor_relationshiprank: 5, // <- Or however the relationship rank with yourself is
           mantella_actor_voicetype: "MaleNord",
           mantella_actor_is_in_combat: false,
           mantella_actor_is_enemy: false,
           mantella_custom_values:{
               // other mods or games can put additional values here Skyrim does not use it
               // Fallout4 should put the position of characters here
           }
       },
       {
           mantella_actor_id: 666772,
           mantella_actor_name: "Lydia",
           mantella_actor_gender: 1,
           mantella_actor_race: "Nord", // <- Or however that actually comes out of the game
           mantella_actor_is_player: false,
           mantella_actor_relationshiprank: 4,
           mantella_actor_voicetype: "FemaleEvenToned",
           mantella_actor_is_in_combat: false,
           mantella_actor_is_enemy: false,
           mantella_custom_values:{
               // other mods or games can put additional values here Skyrim does not use it
               // Fallout4 should put the position of characters here
           }
       }
   ],
   mantella_context:{
       mantella_location: "Skyrim" // <- Not sending empty strings anymore. I felt it should be the duty of the client to provide correct values to the server
       mantella_time: 1234 // <- Or however that actually comes out of the game
       mantella_ingame_events: [
           "Lydia sat down on a bench",
           "The player picked up a purple mountain flower",
           "The player gifted Lydia a purple mountain flower"
       ],
       custom_context_values: [
           // other mods or games can put additional values here Skyrim does not use it
           // Fallout4 should put the position of the player character here, because that would be needed even if the character is not participating in the conversation
       ]
   }
}
  1. This dictionary is sent to MantellaSoftware
  2. At some point a reply is received which triggers the OnHttpReplyReceived(int typedDictionaryHandle) event we subscribed to in OnInit(). ALL succesful replies arrive at this event
    The dictionary received must always contain a string value called mantella_reply_type which indicates to MantellaSpell what to do with the reply
    The possible reply types and what they indicate are:
  • mantella_start_conversation_completed -> conversation has started on side of MantellaSoftware
  • mantella_npc_talk -> reply contains a sentence for an NPC to speak
  • mantella_player_talk -> player should now provide input. It is now the sole duty of MantellaSpell to determine if via text or mic
  • mantella_tts -> reply contains transcribe of a STT
  • mantella_end_conversation -> conversation has ended on side of MantellaSoftware
  1. Receiving mantella_start_conversation_completed triggers an immediate ContinueConversation http request from MantellaSpell to MantellaSoftware This will request the next thing that happens in the conversation from MantellaSoftware
    The request is nearly identical to the mantella_start_conversation request earlier, but the request type is now mantella_continue_conversation This will again send along all actors in the conversation with their current stats and the context in its current state. MantellaSoftware will update its own context at once using these information (for example if a new chaarcter has joined the conversation)
  2. If receiving a mantella_npc_talk reply, the reply will also contain the information needed to play it. The dictionary received looks like this:
{
   mantella_request_type: "mantella_npc_talk",
   mantella_npc_talk: {
       mantella_actor_speaker: "Lydia",
       mantella_actor_line_to_speak: "A flower? Really?",
       mantella_actor_voice_file: "Mantellaxxxx.wav",
       mantella_actor_line_duration: 1.7,
       mantella_actor_actions: [
           "Offend", "Follow"
       ]
   }
}

MantellaConversation will then trigger all Actions in the received list, make the NPC speak their line, wait for the duration of the audio and then issue a new ContinueConversation request to the server.

  1. If receiving a mantella_player_talk, MantellaSpell will decide on the spot if it should use text or voice input.
    If text input, it will unlock the text input box for the player. Once a text input is entered, a new request is sent to the server that contains:
  • mantella_request_type: "mantella_player_input"
  • mantella_player_input: "Oh Lydia, I didn't mean to offend you, I'm sorry."
  • All current actors in the conversation with their current stats
  • Current context

If voice input, it will send a request to the server to start a STT and display the "Listening..." message

  1. If receiving a mantella_tts this will also contain the transcribe of the voice input. This transcrivbe is then used like text input in step
  2. If receiving mantella_end_conversation the MantellaConversation quest will be stopped.

MantellaEffectScript

This has been massively cut down cause most of its functionality is now in MantellaConversation

This now only reacts if it is invoked by Spell, Shout or Hotkey and either starts a conversation or add the actors to it.

Actions

For every Action that is received with a mantella_npc_talk reply a unique global event is called.
It is possible to subscribe to this event from everywhere.

For example the Offend, Forgive and Follow Actions have been moved to a new separate Quest called MantellaAction_OffendForgiveFollow

This Quest now implements the existing Actions in a nice simple way and serves as a blueprint for additional actions in the future. https://github.com/Leidtier/Mantella-Spell/blob/http-integration/Scripts/Source/MantellaAction_OffendForgiveFollow.psc