Kaioru / Edelstein

A v.95.1 Mushroom game server emulator written in C# .NET

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Question] Lua scripting.

juliolitwin opened this issue · comments

Your project is incredible, it's rare to see emulation projects for C# lovingly developed! :)

There isn't a discord group or anything like that, so I would like to ask about an issue regarding lua.

It's not necessarily about MS, but rather your implementation of Lua, I saw that some of your scripts wait for a response from the user, such as ask_menu, could you explain to me how you manage this?

Sample:

if target.field == mapFields.getID("NLCSubwayStation") then
    selection = self.ask_menu("Hello. Would you like to buy a ticket for the subway?", {
        [0] = "Kerning City of Victoria Island"
    })

    if selection == 0 then
		ticket = charInventory.selectTicketToVictoriaFromNLC()
		cost = charInventory.getPriceOfTicket(ticket)

        if self.ask_yes_no("The ride to Kerning City of Victoria Island takes off every " .. target.as_continent().term .. " minutes, beginning on the hour, and it'll cost you #b" .. cost .. " mesos#k. Are you sure you want to purchase #b#t" .. ticket .. "##k?") then	         
			charInventory.buyTicket(ticket, cost)
        else
            self.say("You must have some business to take care of here, right?")
        end
    end

When ask_menu is called, you call AskMenu (in C#), but in the Lua background, it waits for the return at the exact point where it stopped executing? Do you make any kind of use of threads/coroutines?

commented

image

this is the important part were registering an entire conversation interface for 2 speakers

this exposes the accessibility to lua to call the func with params

so the interface is loaded in the script globals and then the entire source is evaluated if it finds reference to the global it can call the C# function.

the heavy lifting is done by moonsharp, thats where the magic of converting a DynValue result which is placeholder for lua types gets auto converted to CLR type.

commented

On top of what @Bia10 said,

The whole request/response system is called Conversations in the project. Do check out FieldUser::Converse and FieldUser::Prompt to see where the logic flow starts for script dialogs.

Essentially, there is a Channel<object> in each conversation context which is basically an async queue that handles request and responses from the client. This creates the stateless 'awaiting' mechanism that powers every dialog that requires user input.

Every time a method like Self.AskMenu(..) is called, the conversation context reads from the async queue and if its empty, it waits.. forever. And on the packet handling side, whenever a response is received by the server, the server pushes into the async queue which finally unblocks the read and continues on with the conversation.

See:

  1. https://github.com/Kaioru/Edelstein/blob/dev/src/common/Edelstein.Common.Gameplay.Game/Conversations/ConversationContext.cs#L26
  2. https://learn.microsoft.com/en-us/dotnet/core/extensions/channels
commented

Closing this issue, feel free to continue the discussion under the 'Discussions' tab.