Problem z pingowaniem

Problem z pingowaniem
Daniel Urbaniec
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 5 lat
  • Lokalizacja:Kraków
  • Postów:40
0
Dyzma napisał(a):

Swoja drogą po "uproszczeniu" nie powinien rzucać takim błędów.
Zastosuj uproszczenie i wrzuć ponownie cały kod.

Zastosowałem się do Twoich porad i:

  • przy załączaniu nie ma błędów
  • uproszczenie Ktos dalej nie działa, jest ten sam błąd
  • przy przejściu z okna logowania do okna strony głównej wyrzuca błąd przy public HomePage() "System.InvalidOperationException: „Wątkiem wywołującym musi być STA, ponieważ wiele składników interfejsów użytkownika go wymaga.”

Spotkałem się z nim i jako pierwsze to pamiętam, że trzeba było gdzieś dodać [STAThread] lub trzeba było edytować w jakiś sposób kod, ale dokładnie nie wiem.

Cały kod:

Kopiuj
namespace launchek
{
    /// <summary>
    /// Logika interakcji dla klasy HomePage.xaml
    /// </summary>
    /// 
    public partial class HomePage : Page
    {
        public HomePage() 
        {
            InitializeComponent();
        }

        MProfileInfo[] versions;
        MSession session;
        GamePatch Patcher;

        private void Window_Loaded(object sender, EventArgs e)
        {
            Task.Run(() =>
            {
                HomePage hmp = new HomePage();
                MineStat ms = new MineStat("mc.skkf.net", 25565);
                if (hmp.serverstatus2.Dispatcher.CheckAccess())
                    hmp.serverstatus2.Dispatcher.Invoke(new Action(() => hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline"));
                else
                    hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline";
            });

            string RootPath = Environment.GetEnvironmentVariable("appdata") + "\\SkyCraft";

            Minecraft.init(RootPath);
            versions = MProfileInfo.GetProfiles();
            Versions.Items.Clear();
            foreach (var item in versions)
            {
                Versions.Items.Add(item.Name);
            }
            Patcher = new GamePatch(session);

        }

        private void Play_Click_Btn(object sender, RoutedEventArgs e)
        {

        }

        private void GameFolder_Click_Btn(object sender, RoutedEventArgs e)
        {
            Patcher.OpenFolder();
        }
    }
}
DY
  • Rejestracja:około 6 lat
  • Ostatnio:około miesiąc
  • Postów:75
0

Pozmieniałeś kod względem tego co wrzuciłem.
Znowu wrzuciłeś:

Kopiuj
HomePage hmp = new HomePage();

Do task'a
I tutaj:

Kopiuj
                if (hmp.serverstatus2.Dispatcher.CheckAccess())
                    hmp.serverstatus2.Dispatcher.Invoke(new Action(() => hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline"));
                else
                    hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline";

Pozmieniałeś kolejność.

Daniel Urbaniec
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 5 lat
  • Lokalizacja:Kraków
  • Postów:40
0
Dyzma napisał(a):

Pozmieniałeś kolejność.

Okej, teraz wszystko powinno być jak należy, ale jak zwykle "jest jakieś ale".
Wszystko ładnie się ładuje, ale gdy dochodzi do momentu pokazania danych to:

  • wyrzuca dalej ten sam błąd przy hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline"; "System.InvalidOperationException: „Wątek wywołujący nie może uzyskać dostępu do tego obiektu, ponieważ należy on do innego wątku.”"
  • mimo wszystko dalej kod nie działa, gdyż serwer jest online, a całość próbuje załadować informację o tym, że jest offline.
Kopiuj
        private void Window_Loaded(object sender, EventArgs e)
        {
            HomePage hmp = new HomePage();
            Task.Run(() =>
            {
                MineStat ms = new MineStat("mc.skkf.net", 25565);
                if (hmp.serverstatus2.Dispatcher.CheckAccess())
                    hmp.serverstatus2.Dispatcher.Invoke(new Action(() => hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline"));
                else
                    hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline";
            });
DY
  • Rejestracja:około 6 lat
  • Ostatnio:około miesiąc
  • Postów:75
1

Bo pozmieniałeś kolejność.
Ma być:

Kopiuj
if (hmp.serverstatus2.Dispatcher.CheckAccess())
     hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline";
else
     hmp.serverstatus2.Dispatcher.Invoke((Action) (() => { hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline" } ));

A zrobiłeś odwrotnie.

Daniel Urbaniec
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 5 lat
  • Lokalizacja:Kraków
  • Postów:40
0
Dyzma napisał(a):

Bo pozmieniałeś kolejność.
Ma być:

Kopiuj
if (hmp.serverstatus2.Dispatcher.CheckAccess())
     hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline";
else
     hmp.serverstatus2.Dispatcher.Invoke((Action) (() => { hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline" } ));

A zrobiłeś odwrotnie.

Przepraszam, cały czas się patrzyłem na ten kod, ale jakoś mój mózg nie zarejestrował tego, że jest źle, mimo porad.

Teraz całość jest wstawiona poprawnie, nie ma żadnych błędów.
Jednak kod mimo wszystko nie działa, TextBox jak ma wpisany "Status" tak on pozostaje, nie wyświetla się już nic.

Kod:

Kopiuj
        private void Window_Loaded(object sender, EventArgs e)
        {
            HomePage hmp = new HomePage();
            Task.Run(() =>
            {
                MineStat ms = new MineStat ("mc.skkf.net", 25565);
                if (hmp.serverstatus2.Dispatcher.CheckAccess())
                    hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline";
                else
                    hmp.serverstatus2.Dispatcher.Invoke(new Action(() => hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline"));
            });

Dane wyjściowe:
"Wątek 0x2dec zakończył działanie z kodem 0 (0x0).
Zgłoszony wyjątek: „System.Exception” w launchek.exe
Wątek 0x6090 zakończył działanie z kodem 0 (0x0).
Wątek 0x4664 zakończył działanie z kodem 0 (0x0).
Wątek 0x5424 zakończył działanie z kodem 0 (0x0).
Wątek 0x5b0c zakończył działanie z kodem 0 (0x0).
Wątek 0x4888 zakończył działanie z kodem 0 (0x0)."

DY
  • Rejestracja:około 6 lat
  • Ostatnio:około miesiąc
  • Postów:75
3

I teraz zaczyna się proces debugowania. ;)
Sprawdź czy ten kawałek kodu od ldilley od pobierania tych danych coś sensownego zwraca.
Żeby mieć pewność, że to nie z jego powodu są problemy. Albo z powodu serwera.
Kod 0 (0x0) to dobry znak, oznacza brak błędu.
I pamiętaj, że te dane będą uzupełniać się jak zostaną pobrane, nie wiem ile to trwało, ale będzie trwać tyle samo,
tylko, że nie będzie blokować wątku interfejsu aplikacji.

Sunnyline2
  • Rejestracja:około 8 lat
  • Ostatnio:około 3 lata
  • Postów:58
2

W twoim przypadku nie musisz używać dispatchera.
Sprawdź czy biblioteka działa poprawnie na jakimś działającym serwerze.

Ja zrobiłbym coś takiego.

Kopiuj
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
    await UpdateMineStatsAsync();
}

// tutaj działasz w wątku UI
private async Task UpdateMineStatsAsync()
{
    var mineStats = await GetMineStatsAsync();
    if (mineStats == null || !mineStats.ServerUp)
    {
        // labelek to akurat moja kontrolka :)
        labelek.Content = "Offline";
    }
    else
    {
        labelek.Content = mineStats.CurrentPlayers.ToString();
    }
}

// tutaj tworzysz nowy wątek (za pomocą task run) więc w nim nie możesz aktualizować wątku UI
private Task<MineStat> GetMineStatsTaskAsync()
{
    return Task.Run(() =>
    {
        try
        {
            return new MineStat("mc.skkf.net", 25565);
        }
        catch (Exception)
        {
            // coś nie działa (możesz zapisać log, ew. zwrócić coś innego)
            return null;
        }
    });
}

@Dyzma
Gdy użyjesz taska w ten sposób (nie używając await) zostanie on uruchomiony jako 'ffire and forget' tzn. nie dostaniesz żadnego exception z wewnątrz.

edytowany 4x, ostatnio: Sunnyline2
Daniel Urbaniec
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 5 lat
  • Lokalizacja:Kraków
  • Postów:40
0

@Dyzma: Patrzyłem, ale nic się nie dzieje. Zostawiłem aplikację otwartą na dobrą chwilę i nic.
Teoretycznie wszystko działa.

@Sunnyline2 chcę sprawdzić kod, ale występuje błąd przy Window_Loaded:
await UpdateMineStatsAsync(); "Błąd CS4033 Operatora „await” można używać tylko wewnątrz metody asynchronicznej. Rozważ możliwość oznaczenia tej metody za pomocą modyfikatora „async” i zmiany zwracanego przez nią typu na „Task”."

Kod:

Kopiuj
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            await UpdateMineStatsAsync();

            string RootPath = Environment.GetEnvironmentVariable("appdata") + "\\SkyCraft";

            Minecraft.init(RootPath);
            versions = MProfileInfo.GetProfiles();
            Versions.Items.Clear();
            foreach (var item in versions)
            {
                Versions.Items.Add(item.Name);
            }
            Patcher = new GamePatch(session);

        }
        // tutaj działasz w wątku UI
        private async Task UpdateMineStatsAsync()
        {
            var mineStats = await GetMineStatsTaskAsync();
            if (mineStats == null || !mineStats.ServerUp)
            {
                // labelek to akurat moja kontrolka :)
                serverstatus2.Text = "Offline";
            }
            else
            {
                serverstatus2.Text = mineStats.CurrentPlayers.ToString();
            }
        }

        // tutaj tworzysz nowy wątek (za pomocą task run) więc w nim nie możesz aktualizować wątku UI
        private Task<MineStat> GetMineStatsTaskAsync()
        {
            return Task.Run(() =>
            {
                try
                {
                    return new MineStat("mc.skkf.net", 25565);
                }
                catch (Exception)
                {
                    // coś nie działa (możesz zapisać log, ew. zwrócić coś innego)
                    return null;
                }
            });
        }
Sunnyline2
Sunnyline2
async w window loaded (dodatkowo środowisko Ci przypomniało, że brakuje async - taka czerwona lampka - możesz na nią kliknąć i czasem może rozwiązać problem (wstawić coś gdzie czegoś brakuje)); zmień język w vs na angielski; używaj google do rozwiązywania problemów;
DY
  • Rejestracja:około 6 lat
  • Ostatnio:około miesiąc
  • Postów:75
0

A jak debugujesz i wchodzisz do klasy MineStat to co tam się dzieje? ;)
Wszystko działa i zwraca wszystkie dane?

Daniel Urbaniec
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 5 lat
  • Lokalizacja:Kraków
  • Postów:40
0
Dyzma napisał(a):

A jak debugujesz i wchodzisz do klasy MineStat to co tam się dzieje? ;)
Wszystko działa i zwraca wszystkie dane?

Wszystko działa, ale nic nie pokazuje.

DY
  • Rejestracja:około 6 lat
  • Ostatnio:około miesiąc
  • Postów:75
0

Zatrzymaj się w debug'u po linijce:

Kopiuj
MineStat ms = new MineStat("mc.skkf.net", 25565);

Najedź myszką na "ms", żeby pokazało pola, zrób screena i wrzuć.

Daniel Urbaniec
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 5 lat
  • Lokalizacja:Kraków
  • Postów:40
0
Dyzma napisał(a):

Zatrzymaj się w debug'u po linijce:

Kopiuj
MineStat ms = new MineStat("mc.skkf.net", 25565);

Najedź myszką na "ms", żeby pokazało pola, zrób screena i wrzuć.

Szczerze mówiąc nie za bardzo rozumiem o co chodzi.
Poniżej screen jaki udało mi się zrobić.
Nie wiem jak sprawdzić kiedy debugowanie dochodzi do momentu tej linijki.

title

DY
  • Rejestracja:około 6 lat
  • Ostatnio:około miesiąc
  • Postów:75
1

Właśnie dlatego poprosiłem o screen, żeby mieć pewność, że wiesz jak to sprawdzić. ;)
Nie możesz zakładać, że "wszystko działa", jak nie jesteś w stanie sprawdzić wewnętrznej funkcjonalności.
To, że nie rzuciło błędem, nie znaczy, że działa.
Generalnie wciśnięcie klawisza F9 ustawia tzw. breakpoint, czyli punkt, w którym program się zatrzyma podczas debugowania.
Ustaw na tej linijce:

Kopiuj
MineStat ms = new MineStat("mc.skkf.net", 25565);

I naciśnij F10, czyli przejście do kolejnej linii (w skrócie, po więcej zwróć się do google), żeby kod się wykonał.
A następnie jak najedziesz w Visual Studio na zmienną "ms" będziesz mógł podejrzeć, co jest w środku.
Generalnie bez umiejętności debugowania daleko nie zajdziesz, jest masa materiałów w internecie.
Proponuję zacząć od youtube i wpisania "Visual Studio C# debugging". ;)

Ktos
Moderator
  • Rejestracja:prawie 23 lata
  • Ostatnio:około 3 godziny
1

To System.Exception to pewnie jest tak naprawdę SocketException: "A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 104.18.54.100:25565", przynajmniej ja taki błąd dostaję próbując ten serwer, który tutaj masz podany. (po ludzku mówiąc: serwer nie działa) Biblioteka to przechwytuje i oznacza, że nie działa, ale w logach będziesz miał.

Tylko zanim to wyskoczy musi minąć timeout - u mnie jest to w okolicach 40 sekund (co jest swoją drogą ciekawe, bo chyba ta biblioteka ma ustalone standardowo na 5 sekund).

Daniel Urbaniec
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 5 lat
  • Lokalizacja:Kraków
  • Postów:40
0

@Dyzma:
Screeny wrzucam na dole, ale nie mam pojęcia o co chodzi. Sprawdziłem to na 3 serwerach, na każdym pokazuje, że jest nieaktywny.
Sprawdziłem na debugowaniu oraz dodałem log i faktycznie przerzuca mnie cały czas na offline.
Dodatkowo napis się nie zmienia, całość przechodzi normalnie, ale nie wiem w którym momencie dzieje się to, że tekst nie zostaje zamieniony na chociażby "Offline".
title
title

@Ktos
Ogółem to sprawdzałem 3 serwery i każdy według kodu jest offline co jest nieprawdą. Sam na nie wszedłem, żeby się upewnić i nie ma takiej możliwości.

DY
  • Rejestracja:około 6 lat
  • Ostatnio:około miesiąc
  • Postów:75
0

Czytaj proszę w całości to co piszę:

A następnie jak najedziesz w Visual Studio na zmienną "ms" będziesz mógł podejrzeć, co jest w środku.

title
Jak dla mnie kod z MineStat nie działa.
Zrób debug klasy MineStat. Ewentualnie poczytaj o TcpClient w C#, żeby wiedzieć co debugujesz.
I będziesz wiedział co i dlaczego nie działa. ;)

edytowany 1x, ostatnio: Dyzma
Ktos
Moderator
  • Rejestracja:prawie 23 lata
  • Ostatnio:około 3 godziny
1

Problem polega na tym, że ten kod jest stary, a Minecraft się rozwija (cudem). https://github.com/ldilley/minestat/issues/19#issuecomment-449702779

Daniel Urbaniec
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 5 lat
  • Lokalizacja:Kraków
  • Postów:40
0

@Dyzma:
To samo pokazało się na dole screena, więc uznałem, że nie mam po co najeżdżać skoro ta sama treść jest pokazana w oknie na dole.
Będę musiał spróbować to zrobić, jeszcze nie wiem jak, ale będę musiał.
Jedyną rzeczą, która mnie nurtuje to czemu napis się nie zmienia mimo, że wykrywa serwer offline.

@Ktos
To tego akurat nie widziałem, w każdym razie też ważna informacja.
Może po prostu poszukam jakiegoś innego kodu.

Sunnyline2
  • Rejestracja:około 8 lat
  • Ostatnio:około 3 lata
  • Postów:58
1
Daniel Urbaniec napisał(a):

@Dyzma:
To samo pokazało się na dole screena, więc uznałem, że nie mam po co najeżdżać skoro ta sama treść jest pokazana w oknie na dole.
Będę musiał spróbować to zrobić, jeszcze nie wiem jak, ale będę musiał.
Jedyną rzeczą, która mnie nurtuje to czemu napis się nie zmienia mimo, że wykrywa serwer offline.

@Ktos
To tego akurat nie widziałem, w każdym razie też ważna informacja.
Może po prostu poszukam jakiegoś innego kodu.

Jak ma coś wyświetlać skoro się wysypuje podczas tworzenia instancji mc stats?

Daniel Urbaniec
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 5 lat
  • Lokalizacja:Kraków
  • Postów:40
0

@Sunnyline2:
No w sumie tak.
Chociaż dziwi mnie to, bo gdy na początku testowałem kod to działał tylko były ścinki o których mówiłem.
Znalazłem inny kod odnośnie konsoli, lecz jest problem z elementem var ping = JsonConvert.DeserializeObject<PingPayload>(json);
"Newtonsoft.Json.JsonReaderException: „Unexpected character encountered while parsing value: {. Path 'description', line 1, position 100.”"

Kopiuj
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Newtonsoft.Json;

#if DEBUG
using System.Diagnostics;
#endif

namespace MCServerPing
{
    class ServerPing
    {
        private static readonly Dictionary<char, ConsoleColor> Colours = new Dictionary<char, ConsoleColor>
        {
             { '0', ConsoleColor.Black       },
             { '1', ConsoleColor.DarkBlue    },
             { '2', ConsoleColor.DarkGreen   },
             { '3', ConsoleColor.DarkCyan    },
             { '4', ConsoleColor.DarkRed     },
             { '5', ConsoleColor.DarkMagenta },
             { '6', ConsoleColor.Yellow      },
             { '7', ConsoleColor.Gray        },
             { '8', ConsoleColor.DarkGray    },
             { '9', ConsoleColor.Blue        },
             { 'a', ConsoleColor.Green       },
             { 'b', ConsoleColor.Cyan        },
             { 'c', ConsoleColor.Red         },
             { 'd', ConsoleColor.Magenta     },
             { 'e', ConsoleColor.Yellow      },
             { 'f', ConsoleColor.White       },
             { 'k', Console.ForegroundColor  },
             { 'l', Console.ForegroundColor  },
             { 'm', Console.ForegroundColor  },
             { 'n', Console.ForegroundColor  },
             { 'o', Console.ForegroundColor  },
             { 'r', ConsoleColor.White       }
        };

        private static NetworkStream _stream;
        private static List<byte> _buffer;
        private static int _offset;

        private static void Main(string[] args)
        {
            Console.Title = "Minecraft Server Ping";

            var client = new TcpClient();
            var task = client.ConnectAsync("mojemc.pl", 25565);
            Console.WriteLine("Connecting to Minecraft server..");

            while (!task.IsCompleted)
            {
#if DEBUG
                Debug.WriteLine("Connecting..");
#endif
                Thread.Sleep(250);
            }

            if (!client.Connected)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Unable to connect to the server");
                Console.ResetColor();
                Console.ReadKey(true);
                Environment.Exit(1);
            }

            _buffer = new List<byte>();
            _stream = client.GetStream();
            Console.WriteLine("Sending status request");


            /*
             * Send a "Handshake" packet
             * http://wiki.vg/Server_List_Ping#Ping_Process
             */
            WriteVarInt(47);
            WriteString("localhost");
            WriteShort(25565);
            WriteVarInt(1);
            Flush(0);

            /*
             * Send a "Status Request" packet
             * http://wiki.vg/Server_List_Ping#Ping_Process
             */
            Flush(0);

            /*
             * If you are using a modded server then use a larger buffer to account, 
             * see link for explanation and a motd to HTML snippet
             * https://gist.github.com/csh/2480d14fbbb33b4bbae3#gistcomment-2672658
             */
            var buffer = new byte[Int16.MaxValue];
            // var buffer = new byte[4096];
            _stream.Read(buffer, 0, buffer.Length);

            try
            {
                var length = ReadVarInt(buffer);
                var packet = ReadVarInt(buffer);
                var jsonLength = ReadVarInt(buffer);
#if DEBUG
                Console.WriteLine("Received packet 0x{0} with a length of {1}", packet.ToString("X2"), length);
#endif
                var json = ReadString(buffer, jsonLength);
                var ping = JsonConvert.DeserializeObject<PingPayload>(json);

                Console.WriteLine("Software: {0}", ping.Version.Name);
                Console.WriteLine("Protocol: {0}", ping.Version.Protocol);
                Console.WriteLine("Players Online: {0}/{1}", ping.Players.Online, ping.Players.Max);
                WriteMotd(ping);

                Console.ReadKey(true);
            }
            catch (IOException ex)
            {
                /*
                 * If an IOException is thrown then the server didn't 
                 * send us a VarInt or sent us an invalid one.
                 */
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Unable to read packet length from server,");
                Console.WriteLine("are you sure it's a Minecraft server?");
#if DEBUG
                Console.WriteLine("Here are the details:");
                Console.WriteLine(ex.ToString());
#endif
                Console.ResetColor();
            }
        }

        private static void WriteMotd(PingPayload ping)
        {
            Console.Write("Motd: ");
            var chars = ping.Motd.ToCharArray();
            for (var i = 0; i < ping.Motd.Length; i++)
            {
                try
                {
                    if (chars[i] == '\u00A7' && Colours.ContainsKey(chars[i + 1]))
                    {
                        Console.ForegroundColor = Colours[chars[i + 1]];
                        continue;
                    }
                    if (chars[i - 1] == '\u00A7' && Colours.ContainsKey(chars[i]))
                    {
                        continue;
                    }
                }
                catch (IndexOutOfRangeException)
                {
                    // End of string
                }
                Console.Write(chars[i]);
            }
            Console.WriteLine();
            Console.ResetColor();
        }

        #region Read/Write methods
        internal static byte ReadByte(byte[] buffer)
        {
            var b = buffer[_offset];
            _offset += 1;
            return b;
        }

        internal static byte[] Read(byte[] buffer, int length)
        {
            var data = new byte[length];
            Array.Copy(buffer, _offset, data, 0, length);
            _offset += length;
            return data;
        }

        internal static int ReadVarInt(byte[] buffer)
        {
            var value = 0;
            var size = 0;
            int b;
            while (((b = ReadByte(buffer)) & 0x80) == 0x80)
            {
                value |= (b & 0x7F) << (size++ * 7);
                if (size > 5)
                {
                    throw new IOException("This VarInt is an imposter!");
                }
            }
            return value | ((b & 0x7F) << (size * 7));
        }

        internal static string ReadString(byte[] buffer, int length)
        {
            var data = Read(buffer, length);
            return Encoding.UTF8.GetString(data);
        }

        internal static void WriteVarInt(int value)
        {
            while ((value & 128) != 0)
            {
                _buffer.Add((byte)(value & 127 | 128));
                value = (int)((uint)value) >> 7;
            }
            _buffer.Add((byte)value);
        }

        internal static void WriteShort(short value)
        {
            _buffer.AddRange(BitConverter.GetBytes(value));
        }

        internal static void WriteString(string data)
        {
            var buffer = Encoding.UTF8.GetBytes(data);
            WriteVarInt(buffer.Length);
            _buffer.AddRange(buffer);
        }

        internal static void Write(byte b)
        {
            _stream.WriteByte(b);
        }

        internal static void Flush(int id = -1)
        {
            var buffer = _buffer.ToArray();
            _buffer.Clear();

            var add = 0;
            var packetData = new[] { (byte)0x00 };
            if (id >= 0)
            {
                WriteVarInt(id);
                packetData = _buffer.ToArray();
                add = packetData.Length;
                _buffer.Clear();
            }

            WriteVarInt(buffer.Length + add);
            var bufferLength = _buffer.ToArray();
            _buffer.Clear();

            _stream.Write(bufferLength, 0, bufferLength.Length);
            _stream.Write(packetData, 0, packetData.Length);
            _stream.Write(buffer, 0, buffer.Length);
        }
        #endregion
    }

    #region Server ping 
    /// <summary>
    /// C# represenation of the following JSON file
    /// https://gist.github.com/thinkofdeath/6927216
    /// </summary>
    class PingPayload
    {
        /// <summary>
        /// Protocol that the server is using and the given name
        /// </summary>
        [JsonProperty(PropertyName = "version")]
        public VersionPayload Version { get; set; }

        [JsonProperty(PropertyName = "players")]
        public PlayersPayload Players { get; set; }

        [JsonProperty(PropertyName = "description")]
        public string Motd { get; set; }

        /// <summary>
        /// Server icon, important to note that it's encoded in base 64
        /// </summary>
        [JsonProperty(PropertyName = "favicon")]
        public string Icon { get; set; }
    }

    class VersionPayload
    {
        [JsonProperty(PropertyName = "protocol")]
        public int Protocol { get; set; }

        [JsonProperty(PropertyName = "name")]
        public string Name { get; set; }
    }

    class PlayersPayload
    {
        [JsonProperty(PropertyName = "max")]
        public int Max { get; set; }

        [JsonProperty(PropertyName = "online")]
        public int Online { get; set; }

        [JsonProperty(PropertyName = "sample")]
        public List<Player> Sample { get; set; }
    }

    class Player
    {
        [JsonProperty(PropertyName = "name")]
        public string Name { get; set; }

        [JsonProperty(PropertyName = "id")]
        public string Id { get; set; }
    }
    #endregion
}
obscurity
postaw breakpoint w linii 110 i zobacz co masz w zmiennej "json" i czy wygląda to jak JSON (możesz wkleić)
Daniel Urbaniec
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 5 lat
  • Lokalizacja:Kraków
  • Postów:40
0
DY
  • Rejestracja:około 6 lat
  • Ostatnio:około miesiąc
  • Postów:75
0

W komentarzach na GitHub pod tym projektem już dawno ktoś narzekał, że nie działa na niektórych serwerach.
A nie działa, bo struktura json'a się zmieniła.
Poprawiłem:

Kopiuj
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Newtonsoft.Json;
using System.Text.RegularExpressions;

#if DEBUG
using System.Diagnostics;
#endif

namespace MCServerPing
{
    class ServerPing
    {
        private static readonly Dictionary<char, ConsoleColor> Colours = new Dictionary<char, ConsoleColor>
        {
             { '0', ConsoleColor.Black       },
             { '1', ConsoleColor.DarkBlue    },
             { '2', ConsoleColor.DarkGreen   },
             { '3', ConsoleColor.DarkCyan    },
             { '4', ConsoleColor.DarkRed     },
             { '5', ConsoleColor.DarkMagenta },
             { '6', ConsoleColor.Yellow      },
             { '7', ConsoleColor.Gray        },
             { '8', ConsoleColor.DarkGray    },
             { '9', ConsoleColor.Blue        },
             { 'a', ConsoleColor.Green       },
             { 'b', ConsoleColor.Cyan        },
             { 'c', ConsoleColor.Red         },
             { 'd', ConsoleColor.Magenta     },
             { 'e', ConsoleColor.Yellow      },
             { 'f', ConsoleColor.White       },
             { 'k', Console.ForegroundColor  },
             { 'l', Console.ForegroundColor  },
             { 'm', Console.ForegroundColor  },
             { 'n', Console.ForegroundColor  },
             { 'o', Console.ForegroundColor  },
             { 'r', ConsoleColor.White       }
        };

        private static NetworkStream _stream;
        private static List<byte> _buffer;
        private static int _offset;

        private static void Main(string[] args)
        {
            Console.Title = "Minecraft Server Ping";

            var client = new TcpClient();
            var task = client.ConnectAsync("mojemc.pl", 25565);
            Console.WriteLine("Connecting to Minecraft server..");

            while (!task.IsCompleted)
            {
#if DEBUG
                Debug.WriteLine("Connecting..");
#endif
                Thread.Sleep(250);
            }

            if (!client.Connected)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Unable to connect to the server");
                Console.ResetColor();
                Console.ReadKey(true);
                Environment.Exit(1);
            }

            _buffer = new List<byte>();
            _stream = client.GetStream();
            Console.WriteLine("Sending status request");

            /*
             * Send a "Handshake" packet
             * http://wiki.vg/Server_List_Ping#Ping_Process
             */
            WriteVarInt(47);
            WriteString("localhost");
            WriteShort(25565);
            WriteVarInt(1);
            Flush(0);

            /*
             * Send a "Status Request" packet
             * http://wiki.vg/Server_List_Ping#Ping_Process
             */
            Flush(0);

            /*
             * If you are using a modded server then use a larger buffer to account, 
             * see link for explanation and a motd to HTML snippet
             * https://gist.github.com/csh/2480d14fbbb33b4bbae3#gistcomment-2672658
             */
            var buffer = new byte[Int16.MaxValue];
            // var buffer = new byte[4096];
            _stream.Read(buffer, 0, buffer.Length);

            try
            {
                var length = ReadVarInt(buffer);
                var packet = ReadVarInt(buffer);
                var jsonLength = ReadVarInt(buffer);
#if DEBUG
                Console.WriteLine("Received packet 0x{0} with a length of {1}", packet.ToString("X2"), length);
#endif
                var json = ReadString(buffer, jsonLength);
                var ping = JsonConvert.DeserializeObject<PingPayload>(json);

                Console.WriteLine("Software: {0}", ping.Version.Name);
                Console.WriteLine("Protocol: {0}", ping.Version.Protocol);
                Console.WriteLine("Players Online: {0}/{1}", ping.Players.Online, ping.Players.Max);
                WriteMotd(ping);

                Console.ReadKey(true);
            }
            catch (IOException ex)
            {
                /*
                 * If an IOException is thrown then the server didn't 
                 * send us a VarInt or sent us an invalid one.
                 */
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Unable to read packet length from server,");
                Console.WriteLine("are you sure it's a Minecraft server?");
#if DEBUG
                Console.WriteLine("Here are the details:");
                Console.WriteLine(ex.ToString());
#endif
                Console.ResetColor();
            }
        }

        private static void WriteMotd(PingPayload ping)
        {
            Console.Write("Motd: ");
            var chars = ping.Motd.Text.ToCharArray();
            for (var i = 0; i < ping.Motd.Text.Length; i++)
            {
                try
                {
                    if (chars[i] == '\u00A7' && Colours.ContainsKey(chars[i + 1]))
                    {
                        Console.ForegroundColor = Colours[chars[i + 1]];
                        continue;
                    }
                    if (chars[i - 1] == '\u00A7' && Colours.ContainsKey(chars[i]))
                    {
                        continue;
                    }
                }
                catch (IndexOutOfRangeException)
                {
                    // End of string
                }
                Console.Write(chars[i]);
            }
            Console.WriteLine();
            Console.ResetColor();
        }

        #region Read/Write methods
        internal static byte ReadByte(byte[] buffer)
        {
            var b = buffer[_offset];
            _offset += 1;
            return b;
        }

        internal static byte[] Read(byte[] buffer, int length)
        {
            var data = new byte[length];
            Array.Copy(buffer, _offset, data, 0, length);
            _offset += length;
            return data;
        }

        internal static int ReadVarInt(byte[] buffer)
        {
            var value = 0;
            var size = 0;
            int b;
            while (((b = ReadByte(buffer)) & 0x80) == 0x80)
            {
                value |= (b & 0x7F) << (size++ * 7);
                if (size > 5)
                {
                    throw new IOException("This VarInt is an imposter!");
                }
            }
            return value | ((b & 0x7F) << (size * 7));
        }

        internal static string ReadString(byte[] buffer, int length)
        {
            var data = Read(buffer, length);
            return Encoding.UTF8.GetString(data);
        }

        internal static void WriteVarInt(int value)
        {
            while ((value & 128) != 0)
            {
                _buffer.Add((byte)(value & 127 | 128));
                value = (int)((uint)value) >> 7;
            }
            _buffer.Add((byte)value);
        }

        internal static void WriteShort(short value)
        {
            var bytes = BitConverter.GetBytes(value);
            if (BitConverter.IsLittleEndian)
                Array.Reverse(bytes);
            _buffer.AddRange(BitConverter.GetBytes(value));
        }

        internal static void WriteString(string data)
        {
            var buffer = Encoding.UTF8.GetBytes(data);
            WriteVarInt(buffer.Length);
            _buffer.AddRange(buffer);
        }

        internal static void Write(byte b)
        {
            _stream.WriteByte(b);
        }

        internal static void Flush(int id = -1)
        {
            var buffer = _buffer.ToArray();
            _buffer.Clear();

            var add = 0;
            var packetData = new[] { (byte)0x00 };
            if (id >= 0)
            {
                WriteVarInt(id);
                packetData = _buffer.ToArray();
                add = packetData.Length;
                _buffer.Clear();
            }

            WriteVarInt(buffer.Length + add);
            var bufferLength = _buffer.ToArray();
            _buffer.Clear();

            _stream.Write(bufferLength, 0, bufferLength.Length);
            _stream.Write(packetData, 0, packetData.Length);
            _stream.Write(buffer, 0, buffer.Length);
        }
        #endregion
    }

    #region Server ping 
    /// <summary>
    /// C# represenation of the following JSON file
    /// https://gist.github.com/thinkofdeath/6927216
    /// </summary>
    class PingPayload
    {
        /// <summary>
        /// Protocol that the server is using and the given name
        /// </summary>
        [JsonProperty(PropertyName = "version")]
        public VersionPayload Version { get; set; }

        [JsonProperty(PropertyName = "players")]
        public PlayersPayload Players { get; set; }

        [JsonProperty(PropertyName = "description")]
        public DescriptionPayload Motd { get; set; }

        /// <summary>
        /// Server icon, important to note that it's encoded in base 64
        /// </summary>
        [JsonProperty(PropertyName = "favicon")]
        public string Icon { get; set; }
    }

    class DescriptionPayload
    {
        [JsonProperty(PropertyName = "text")]
        public string Text { get; set; }
    }

    class VersionPayload
    {
        [JsonProperty(PropertyName = "protocol")]
        public int Protocol { get; set; }

        [JsonProperty(PropertyName = "name")]
        public string Name { get; set; }
    }

    class PlayersPayload
    {
        [JsonProperty(PropertyName = "max")]
        public int Max { get; set; }

        [JsonProperty(PropertyName = "online")]
        public int Online { get; set; }

        [JsonProperty(PropertyName = "sample")]
        public List<Player> Sample { get; set; }
    }

    class Player
    {
        [JsonProperty(PropertyName = "name")]
        public string Name { get; set; }

        [JsonProperty(PropertyName = "id")]
        public string Id { get; set; }
    }
    #endregion
}

Czyli różne serwery mogą mieć różne struktury.
Zatem może na niektórych dalej się wysypywać na deserializacji json'a.

edytowany 4x, ostatnio: Dyzma
Daniel Urbaniec
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 5 lat
  • Lokalizacja:Kraków
  • Postów:40
0

@Dyzma:
@Sunnyline2
@Ktos
@obscurity

Powiem tak - kod przekształciłem na swoje potrzeby, wrzuciłem go do ```HomePage : Page``.
Całość działa, lecz zauważyłem mały problem:

  • serwery typu mc.skkf.net , hypixel.net , pvpstar.pl nie funkcjonują, po prostu następuje loop w kodzie pomiędzy while (!task.IsCompleted) a Thread.Sleep(250);.
    Debugowałem całość, pokazuje jakby brak połączenia z serwerem, ale powstaje loop (?). Dodatkowo, gdy nie wpiszę IP tylko np. "xd" to całość ładnie zakończy działanie, pokaże informację o serwerze "Offline" i wszystko zapisze w logach.

Tutaj daje mój edytowany kod:

Kopiuj
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using launchek.Core;
using log4net;
using System.Threading;
using Newtonsoft.Json;
using System.Net.Sockets;
using System.Diagnostics;
using System.IO;

namespace launchek
{
    /// <summary>
    /// Logika interakcji dla klasy HomePage.xaml
    /// </summary>
    /// 
    public partial class HomePage : Page
    {
        public static NetworkStream _stream;
        public static List<byte> _buffer;
        public static int _offset;
        private static ILog log = LogManager.GetLogger("HomePage");

        public HomePage() 
        {
            InitializeComponent();
        }

        MProfileInfo[] versions;
        MSession session;
        GamePatch Patcher;

        private void Window_Loaded(object sender, EventArgs e)
        {

            var client = new TcpClient();
            var task = client.ConnectAsync("hypixel.net", 25565);
            log.Info("Connecting to Minecraft server..");
            Task.Run(() =>
            {
                while (!task.IsCompleted)
                {
                    log.Info("Connecting..");
                    Thread.Sleep(250);
                }
                if (!client.Connected)
                {
                    serverstatus2.Dispatcher.Invoke(new Action(() => serverstatus2.Text = "Offline"));
                    log.Info("Offline");
                    return;
                }

                _buffer = new List<byte>();
                _stream = client.GetStream();
                log.Info("Sending status request");

                WriteVarInt(47);
                WriteString("localhost");
                WriteShort(25565);
                WriteVarInt(1);
                Flush(0);
                Flush(0);

                var buffer = new byte[Int16.MaxValue];
                _stream.Read(buffer, 0, buffer.Length);

                try
                {
                    var length = ReadVarInt(buffer);
                    var packet = ReadVarInt(buffer);
                    var jsonLength = ReadVarInt(buffer);
                    var json = ReadString(buffer, jsonLength);
                    var ping = JsonConvert.DeserializeObject<PingPayload>(json);

                    serverstatus2.Dispatcher.Invoke(new Action(() => serverstatus2.Text = ping.Players.Online + "/" + ping.Players.Max ));
                }
                catch (IOException ex)
                {
                    log.Info("Unable to read packet length from server,");
                    log.Info("are you sure it's a Minecraft server?");
#if DEBUG
                    log.Info("Here are the details:");
                    log.Info(ex.ToString());
#endif
                }
            });




            string RootPath = Environment.GetEnvironmentVariable("appdata") + "\\SkyCraft";

            Minecraft.init(RootPath);
            versions = MProfileInfo.GetProfiles();
            Versions.Items.Clear();
            foreach (var item in versions)
            {
                Versions.Items.Add(item.Name);
            }
            Patcher = new GamePatch(session);

        }

        private void Play_Click_Btn(object sender, RoutedEventArgs e)
        {

        }

        private void GameFolder_Click_Btn(object sender, RoutedEventArgs e)
        {
            Patcher.OpenFolder();
        }







    #region Read/Write methods
    internal static byte ReadByte(byte[] buffer)
    {
        var b = buffer[_offset];
        _offset += 1;
        return b;
    }

    internal static byte[] Read(byte[] buffer, int length)
    {
        var data = new byte[length];
        Array.Copy(buffer, _offset, data, 0, length);
        _offset += length;
        return data;
    }

    internal static int ReadVarInt(byte[] buffer)
    {
        var value = 0;
        var size = 0;
        int b;
        while (((b = ReadByte(buffer)) & 0x80) == 0x80)
        {
            value |= (b & 0x7F) << (size++ * 7);
            if (size > 5)
            {
                throw new IOException("This VarInt is an imposter!");
            }
        }
        return value | ((b & 0x7F) << (size * 7));
    }

    internal static string ReadString(byte[] buffer, int length)
    {
        var data = Read(buffer, length);
        return Encoding.UTF8.GetString(data);
    }

    internal static void WriteVarInt(int value)
    {
        while ((value & 128) != 0)
        {
            _buffer.Add((byte)(value & 127 | 128));
            value = (int)((uint)value) >> 7;
        }
        _buffer.Add((byte)value);
    }

    internal static void WriteShort(short value)
    {
        var bytes = BitConverter.GetBytes(value);
        if (BitConverter.IsLittleEndian)
            Array.Reverse(bytes);
        _buffer.AddRange(BitConverter.GetBytes(value));
    }

    internal static void WriteString(string data)
    {
        var buffer = Encoding.UTF8.GetBytes(data);
        WriteVarInt(buffer.Length);
        _buffer.AddRange(buffer);
    }

    internal static void Write(byte b)
    {
        _stream.WriteByte(b);
    }

    internal static void Flush(int id = -1)
    {
        var buffer = _buffer.ToArray();
        _buffer.Clear();

        var add = 0;
        var packetData = new[] { (byte)0x00 };
        if (id >= 0)
        {
            WriteVarInt(id);
            packetData = _buffer.ToArray();
            add = packetData.Length;
            _buffer.Clear();
        }

        WriteVarInt(buffer.Length + add);
        var bufferLength = _buffer.ToArray();
        _buffer.Clear();

        _stream.Write(bufferLength, 0, bufferLength.Length);
        _stream.Write(packetData, 0, packetData.Length);
        _stream.Write(buffer, 0, buffer.Length);
    }
    #endregion
}

#region Server ping 
class PingPayload
    {
        /// <summary>
        /// Protocol that the server is using and the given name
        /// </summary>
        [JsonProperty(PropertyName = "version")]
        public VersionPayload Version { get; set; }

        [JsonProperty(PropertyName = "players")]
        public PlayersPayload Players { get; set; }

        [JsonProperty(PropertyName = "description")]
        public DescriptionPayload Motd { get; set; }

        /// <summary>
        /// Server icon, important to note that it's encoded in base 64
        /// </summary>
        [JsonProperty(PropertyName = "favicon")]
        public string Icon { get; set; }
    }

    class DescriptionPayload
    {
        [JsonProperty(PropertyName = "text")]
        public string Text { get; set; }
    }

    class VersionPayload
    {
        [JsonProperty(PropertyName = "protocol")]
        public int Protocol { get; set; }

        [JsonProperty(PropertyName = "name")]
        public string Name { get; set; }
    }

    class PlayersPayload
    {
        [JsonProperty(PropertyName = "max")]
        public int Max { get; set; }

        [JsonProperty(PropertyName = "online")]
        public int Online { get; set; }

        [JsonProperty(PropertyName = "sample")]
        public List<Player> Sample { get; set; }
    }

    class Player
    {
        [JsonProperty(PropertyName = "name")]
        public string Name { get; set; }

        [JsonProperty(PropertyName = "id")]
        public string Id { get; set; }
    }
    #endregion
}
DY
  • Rejestracja:około 6 lat
  • Ostatnio:około miesiąc
  • Postów:75
1

Bo tam jest po prostu pętla.
Na pierwszej stronie tego wątku zwróciłem uwagę, że nie ma timeout'u dla TcpClient w przypadku "Connect".
Jeśli zrobisz po prostu Connect, to będzie czekał na odpowiedź jakąkolwiek, czasem bardzo długo.
I taka sytuacja ma miejsce właśnie w tym przypadku.
Jak wpiszesz cokolwiek zamiast adresu to przechodzi dalej, bo od razu ma odpowiedź, że nie da się ustanowić połączenia.
Również na pierwszej stronie napisałem kawałek kodu, który pozwala "dodać" timeout dla połączenia.
A dlaczego niektóre serwery odpowiadają, a niektóre nie - nie wiem.
Pewnie trzeba by przysiąść i się dowiedzieć jak to działa. ;)

edytowany 1x, ostatnio: Dyzma
Daniel Urbaniec
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 5 lat
  • Lokalizacja:Kraków
  • Postów:40
0
Dyzma napisał(a):

Bo tam jest po prostu pętla.
Na pierwszej stronie tego wątku zwróciłem uwagę, że nie ma timeout'u dla TcpClient w przypadku "Connect".
Jeśli zrobisz po prostu Connect, to będzie czekał na odpowiedź jakąkolwiek, czasem bardzo długo.
I taka sytuacja ma miejsce właśnie w tym przypadku.
Jak wpiszesz cokolwiek zamiast adresu to przechodzi dalej, bo od razu ma odpowiedź, że nie da się ustanowić połączenia.
Również na pierwszej stronie napisałem kawałek kodu, który pozwala "dodać" timeout dla połączenia.
A dlaczego niektóre serwery odpowiadają, a niektóre nie - nie wiem.
Pewnie trzeba by przysiąść i się dowiedzieć jak to działa. ;)

Okej, w każdym razie dziękuję każdemu za pomoc i myślę, że temat jest do zamknięcia.
Z resztą spróbuję uporać się sam. Jeszcze raz - dzięki wielkie :)

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)