IModApi - get objects from id?

Discussion in 'Empyrion API' started by me777, Sep 25, 2022.

  1. me777

    me777 Commander

    Joined:
    Aug 18, 2020
    Messages:
    384
    Likes Received:
    131
    HI,
    I try to do a IModApi mod and could not figure out (yet?) how to get the player and entity/structure object from the (int) id ...
    (also is there a better manual than the html in the game folder anywhere?)

    thanks a lot!
     
    #1
  2. ASTIC

    ASTIC Captain

    Joined:
    Dec 11, 2016
    Messages:
    993
    Likes Received:
    707
    #2
  3. me777

    me777 Commander

    Joined:
    Aug 18, 2020
    Messages:
    384
    Likes Received:
    131
    Thank you ASTIC.
    Your code is almost to high for me to understand. (lots of googleing needed for me)
    I tryed to copy/adapt parts of it, and I can get the objects now; but I am in the wrong thread most of the time...
    So I tryed to use the modapi.network stuff - does it work? I could not get it to, even as I copyed the whole class.
     
    #3
  4. ASTIC

    ASTIC Captain

    Joined:
    Dec 11, 2016
    Messages:
    993
    Likes Received:
    707
    Ok, you can get this data from an IPlayfield
    Code:
    namespace Eleon.Modding
    {
        public interface IPlayfield
        {
    ...
            Dictionary<int, IPlayer> Players { get; }
    
            Dictionary<int, IEntity> Entities { get; }
    ...
    }
    and you can get the playfields from the event
    Code:
    namespace Eleon.Modding
    {
        public interface IApplication
        {
    ...
            event PlayfieldDelegate OnPlayfieldLoaded;
    
            event PlayfieldDelegate OnPlayfieldUnloading;
    you have to store the IPlayfield localy and remove it from your List wenn the unloading event ist raised
    Code:
    ModApi.Application.OnPlayfieldLoaded    += Application_OnPlayfieldLoaded;
    ModApi.Application.OnPlayfieldUnloading += Application_OnPlayfieldUnloading;
    
    
    ConcurrentDictionary<string, IPlayfield> YourLocalPlayfieldCache = new ...
    
    private void Application_OnPlayfieldLoaded(IPlayfield playfield)
    {
     YourLocalPlayfieldCache.TryAdd(playfield.Name, playfield)
    }
    This way you get access to the elements by ID which are on the playfield.
    For a "global" query for a specific ID, you unfortunately have to query the SQLite database, because only that contains all the elements.
     
    #4
  5. me777

    me777 Commander

    Joined:
    Aug 18, 2020
    Messages:
    384
    Likes Received:
    131
    Thanks again, but I kind of already was that far.

    I got the playfield and player object in the playfield server (at least I think so)
    In the dedicated server i get a callback for chat mesages, but there i got no objects (i get the info objects from the chat and application, but i need the real ones).

    Now the problem is now how to (best) tell the playfield server i got a chat callback.
    I noticed the modapi.network code in your mod, but could not get it to work; is this the right way?

    Code:
    ConcurrentDictionary<string, IPlayfield> YourLocalPlayfieldCache = new ConcurrentDictionary<string, IPlayfield>();
    public void Init(IModApi modAPI)
            {
                ModApi = modAPI;
                if (ModApi.Application.Mode == ApplicationMode.DedicatedServer)
                {
                    //set up a Listener for Chat Messages
                    ModApi.Application.ChatMessageSent += Application_ChatMessageSent;
                    return;
                }
                ModApi.Network.RegisterReceiverForDediPackets(callback_playfield);
                ModApi.Application.OnPlayfieldLoaded += Application_OnPlayfieldLoaded;
                ModApi.Application.OnPlayfieldUnloading += Application_OnPlayfieldUnloading;
            }
    private void Application_OnPlayfieldLoaded(IPlayfield playfield)
            {
                Log($"CALLBACK Application_OnPlayfieldLoaded {playfield.Name}");
                if( ! YourLocalPlayfieldCache.TryAdd(playfield.Name, playfield))
                    {
                        Log("FAILED: YourLocalPlayfieldCache.TryAdd(playfield.Name, playfield))");
                    };
                }
    private void Application_OnPlayfieldUnloading(IPlayfield playfield)
            {
                YourLocalPlayfieldCache.TryRemove(playfield.Name, out var outp);
            }
    private void callback_playfield(string sender, string playfieldName, byte[] data)
            {
                LogFile("CALLBACK.txt", "command callback callback_playfield");
                Log($"CALLBACK Sender {sender} playfield {playfieldName} {Encoding.ASCII.GetString(data)}");
            }
    private void Application_ChatMessageSent(MessageData chatMsgData)
            {           
                if (chatMsgData.Text.StartsWith("/warp ") )
                {
                    Log("warp");
                    int from = chatMsgData.SenderEntityId;
                    string[] SplitMsg = chatMsgData.Text.Split(' ');
                    string msg = "";
                    for (int i = 1; i < SplitMsg.Count(); i++)
                    {
                        msg += " " + SplitMsg[i];
                    }
                    if(int.TryParse(SplitMsg[1],out int dist))
                    {
                        msg = "int geht " + dist.ToString() + msg;
                    }else dist = 0;
                    try
                    {
                    PlayerData? playerData = ModApi.Application.GetPlayerDataFor(chatMsgData.SenderEntityId);
                    if (playerData != null)
                        {
                            var playerData2 = (PlayerData)playerData;
                            var pf = playerData2.PlayfieldName;
                            var playername = playerData2.PlayerName;
                            msg = $"player {playername} playfield {pf} mode {ModApi.Application.Mode.ToString()} {msg}";
                        byte[] Data = Encoding.ASCII.GetBytes($"Data {playername} {msg}");
                        ModApi.Network.SendToPlayfieldServer("me777", pf, Data);
                        }
                    }
                    catch
                    {
                        msg = "try catch " +msg;
                    }
                    Log("say " + msg);
                    //Complicated thing for assembling all the variables for Sending a Server message
                    MessageData SendableMsgData = new MessageData
                    {
                        //Channel = Eleon.MsgChannel.SinglePlayer,
                        //Channel = Eleon.MsgChannel.Global,
                        RecipientEntityId = chatMsgData.SenderEntityId,
                        Text = msg,
                        SenderNameOverride = ModApi.Application.GetPlayerDataFor(chatMsgData.SenderEntityId).Value.PlayerName,
                        SenderType = Eleon.SenderType.ServerPrio
                    };
    
                    //Send the request to the server
                    ModApi.Application.SendChatMessage(SendableMsgData);
                }
            }
     
    #5
  6. ASTIC

    ASTIC Captain

    Joined:
    Dec 11, 2016
    Messages:
    993
    Likes Received:
    707
    #6
  7. me777

    me777 Commander

    Joined:
    Aug 18, 2020
    Messages:
    384
    Likes Received:
    131
    Sorry ASTIC, ich glaube ich mache hier lost in translation...
    Ich habe sowohl die Objekte im Spielfeld als auch die Chat Messages im dediacated Prozess, ich kann praktisch alles logen.

    Wo das Problem ist ist dem Spielfeld zu sagen das ich eine Nachricht im dedicated bekommen habe.
    Code:
    im playfield:
        ModApi.Network.RegisterReceiverForDediPackets(callback_playfield);
    private void callback_playfield(string sender, string playfieldName, byte[] data)
        {
            LogFile("CALLBACK.txt", "command callback callback_playfield");
            Log($"CALLBACK Sender {sender} playfield {playfieldName} {Encoding.ASCII.GetString(data)}");
       }
    ==========================
    im dedicated:
        ModApi.Network.SendToPlayfieldServer("me777", pf, Data);
     
    #7
  8. ASTIC

    ASTIC Captain

    Joined:
    Dec 11, 2016
    Messages:
    993
    Likes Received:
    707
    lol - ok dann haben wir uns missverstanden
    ich bin mir nicht sicher ob man als "Kanal" für die Kommunikation nicht immer den Namen der MOD verwenden muss. Ich habe bisher nur Codebeispiele gesehen die das genau so gemacht haben, also müsste deine Mod demnach "me777" heißen.

    Hier für den umgekehrten Weg
    Code:
    ModApi.Network.SendToDedicatedServer("EmpyrionScripting", data, currentPlayfield.Name)
    Ob der Name nur der in der .._info.yaml ist oder auch die DLL so heißen muss weis ich nicht, ich habe sie einfachheitshalber gleich benannt
     
    #8
  9. me777

    me777 Commander

    Joined:
    Aug 18, 2020
    Messages:
    384
    Likes Received:
    131
    Danke, probiere ich wenn ich wieder zu hause bin.

    *edit*
    Ja, war der Name. Ich dachte der ist frei, aber wie so oft falsch gedacht :NewRollingEyes:...
    Vielen Dank.
     
    #9
    Last edited: Sep 28, 2022

Share This Page