Skip to content

Added support for input transfer during logging#92

Open
AlexanderK666 wants to merge 6 commits intonorthwood-studios:masterfrom
AlexanderK666:master
Open

Added support for input transfer during logging#92
AlexanderK666 wants to merge 6 commits intonorthwood-studios:masterfrom
AlexanderK666:master

Conversation

@AlexanderK666
Copy link
Copy Markdown

Now when logging commands in the console, input transfer works, which improves user interaction with the server console, where logs are written in a thread and begin to interfere with viewing the current input.

Tested on LocalAdmin v. 2.5.14 and Windows.

Now when logging commands in the console, input transfer works, which improves user interaction with the server console, where logs are written in a thread and begin to interfere with viewing the current input.
@AlexanderK666
Copy link
Copy Markdown
Author

Oh, I uploaded the changes from the wrong folder, I'll re-upload them now

@AlexanderK666
Copy link
Copy Markdown
Author

AlexanderK666 commented Jul 17, 2024

Oh, GitHub Desktop broke the commit.

Copy link
Copy Markdown

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, this feels a bit bulky, but, as long as it can be tested on both Windows & Linux (Which I'll do now), should be ok.

Comment thread Core/LocalAdmin.cs Outdated
Comment on lines +643 to +658
var headerLines = new string[] {
$"SCP: Secret Laboratory - LocalAdmin v. {VersionString}",
string.Empty,
"Licensed under The MIT License (use command \"license\" to get license text).",
"Copyright by Łukasz \"zabszk\" Jurczyk and KernelError, 2019 - 2024",
string.Empty,
"Type 'help' to get list of available commands.",
string.Empty,
};

ConsoleUtil.Clear();
ConsoleUtil.WriteLine($"SCP: Secret Laboratory - LocalAdmin v. {VersionString}", ConsoleColor.Cyan);
ConsoleUtil.WriteLine(string.Empty, ConsoleColor.Cyan);
ConsoleUtil.WriteLine("Licensed under The MIT License (use command \"license\" to get license text).", ConsoleColor.Cyan);
ConsoleUtil.WriteLine("Copyright by Łukasz \"zabszk\" Jurczyk and KernelError, 2019 - 2024", ConsoleColor.Cyan);
ConsoleUtil.WriteLine(string.Empty, ConsoleColor.Cyan);
ConsoleUtil.WriteLine("Type 'help' to get list of available commands.", ConsoleColor.Cyan);
ConsoleUtil.WriteLine(string.Empty, ConsoleColor.Cyan);

foreach (var line in headerLines)
{
ConsoleUtil.WriteLine(line, ConsoleColor.Cyan, inputIntro: false);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see why this needs to happen as you're doing what is effectively the same job, but I would've thought it'd be better to use a verbatim string instead which looks a bit cleaner imo.

But I'll let @zabszk decide.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion it's an unnecessary array allocation and foreach loop. You use more resources just to achieve the same effect.

Comment thread Core/LocalAdmin.cs Outdated
Comment on lines +734 to +741
if (_commandsHistory.Contains(command))
{
_commandsHistory.Remove(command);
}
else if (_commandsHistory.Count == CommandsHistorySize)
{
_commandsHistory.RemoveAt(_commandsHistory.Count - 1);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be crushed for better readability.

Suggested change
if (_commandsHistory.Contains(command))
{
_commandsHistory.Remove(command);
}
else if (_commandsHistory.Count == CommandsHistorySize)
{
_commandsHistory.RemoveAt(_commandsHistory.Count - 1);
}
if (_commandsHistory.Contains(command))
_commandsHistory.Remove(command);
else if (_commandsHistory.Count == CommandsHistorySize)
_commandsHistory.RemoveAt(_commandsHistory.Count - 1);

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it does look better that way

Copy link
Copy Markdown

@ghost ghost Jul 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then you can just hit commit to add this 👍 👍

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you use Contains check? It's completely redundant as Remove already checks that for you and returns a bool.

Just take a look at the docs: https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.remove?view=net-8.0

and how List.Remove() is implemented in .NET 8:

        // Removes the first occurrence of the given element, if found.
        // The size of the list is decreased by one if successful.
        public bool Remove(T item)
        {
            int index = IndexOf(item);
            if (index >= 0)
            {
                RemoveAt(index);
                return true;
            }

            return false;
        }

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you use Contains check?

I replaced this in the improved readability commit 4 days ago.

Comment thread Core/LocalAdmin.cs Outdated
if (_gameProcess.HasExited)
{
ConsoleUtil.WriteLine("Failed to send command - the game process was terminated...", ConsoleColor.Red);
ConsoleUtil.WriteLine("Failed to send command - the game process was terminated...", ConsoleColor.Red, inputIntro: false);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't really need the inputIntro as far as I remember. I'm not gonna make the exact same comment to every single instance of this specific comment.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, it just seems to me that without it, an unnecessary input line will appear

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. I've never seen that behaviour.

@zabszk
Copy link
Copy Markdown
Collaborator

zabszk commented Jul 19, 2024

Hi,

Unfortunately this PR makes LA unusable in environments that support only stdin, stdout and stderr, just like Pterodactyl (which is the most popular way of launching SCP:SL servers). It doesn't support ReadKey. I just tested your PR there and it was not possible to run any command in Pterodactyl. Furthermore the output is completely broken there. I attached a few screenshots below.

2024-07-19_17-57-57
2024-07-19_17-58-44
2024-07-19_18-01-04

Additionally I have noticed a significant negative performance impact.

I tested it on regular Ubuntu as well. It works, but it only prints output when you press enter key. I had to press enter key 9 times just to get this output.

2024-07-19_17-56-48

@ghost
Copy link
Copy Markdown

ghost commented Jul 20, 2024

Hi,

Unfortunately this PR makes LA unusable in environments that support only stdin, stdout and stderr, just like Pterodactyl (which is the most popular way of launching SCP:SL servers). It doesn't support ReadKey. I just tested your PR there and it was not possible to run any command in Pterodactyl. Furthermore the output is completely broken there. I attached a few screenshots below.

2024-07-19_17-57-57

2024-07-19_17-58-44

2024-07-19_18-01-04

Additionally I have noticed a significant negative performance impact.

I tested it on regular Ubuntu as well. It works, but it only prints output when you press enter key. I had to press enter key 9 times just to get this output.

2024-07-19_17-56-48

lmao.

This is pretty much why these things need to be tested on both Windows & Linux before they're marked as ready for review.

@zabszk
Copy link
Copy Markdown
Collaborator

zabszk commented Jul 20, 2024

The primary issue isn't lack of testing (bugs can be fixed, of course before merging the PR), but the fact that some environments don't support ReadKey() and other used features.

@ghost
Copy link
Copy Markdown

ghost commented Jul 20, 2024

The primary issue isn't lack of testing (bugs can be fixed, of course before merging the PR), but the fact that some environments don't support ReadKey() and other used features.

Is it possible to implement an os dependent ReadKey()?

@zabszk
Copy link
Copy Markdown
Collaborator

zabszk commented Jul 20, 2024

The primary issue isn't lack of testing (bugs can be fixed, of course before merging the PR), but the fact that some environments don't support ReadKey() and other used features.

Is it possible to implement an os dependent ReadKey()?

It's not an OS issue. For example pterodactyl doesn't support "all interactions". It only supports stdin and stdout (and likely stderr, I'm not sure). You can't press a key there. You can only type a line of text and send it as stdin. So it's not an OS limitation (linux supports it), but specific environment limitation.

Just like LA doesn't pass key presses to SCP:SL process itself. It only reads stdout and stderr. So if you for some reason call ReadKey() in SCP:SL itself (no LA), it will never be triggered, even if you press a key in LA.

@AlexanderK666
Copy link
Copy Markdown
Author

AlexanderK666 commented Jul 20, 2024

Hmm, I think we can add a check to see if the environment supports ReadKey. If not, we should use the regular ReadLine. Additionally, we should add an argument to the startup options to forcefully change the operating mode.

@ghost
Copy link
Copy Markdown

ghost commented Jul 21, 2024

Hmm, I think we can add a check to see if the environment supports ReadKey. If not, we should use the regular ReadLine. Additionally, we should add an argument to the startup options to forcefully change the operating mode.

While you can add an argument, the change would have to be communicated with people using pterodactyl who decide to get the latest localadmin, so I'd prefer the auto detection, but how?

@AlexanderK666
Copy link
Copy Markdown
Author

Hmm, I think we can add a check to see if the environment supports ReadKey. If not, we should use the regular ReadLine. Additionally, we should add an argument to the startup options to forcefully change the operating mode.

While you can add an argument, the change would have to be communicated with people using pterodactyl who decide to get the latest localadmin, so I'd prefer the auto detection, but how?

Yes, I meant to implement automatic detection and, in addition to that, a startup argument.

@AlexanderK666
Copy link
Copy Markdown
Author

implement automatic detection

So, I think I found a way to implement this automatic detection.
Screenshot of code

Console.IsInputRedirected is True when running through Docker Compose; I think it will be the same in Pterodactyl. I temporarily commented it out to see if there is another way to implement this. And yes, the catch works successfully. If there is no exception (for example, on Windows), we need to remove the key press wait; for this, I used .Wait(50).

Docker compose launch without Console.IsInputRedirected handling

What do you think?

@AlexanderK666
Copy link
Copy Markdown
Author

AlexanderK666 commented Jul 21, 2024

I read the Dotnet Runtime code, and it seems that performing additional checks besides Console.IsInputRedirected is unnecessary.

@zabszk
Copy link
Copy Markdown
Collaborator

zabszk commented Jul 21, 2024

I didn't see an exceptions when running in pterodactyl, but the entire output was broken, so I can't tell for sure (and there could be some try/catch somewhere in the code).

Of course this will not catch all the edge cases, but the most important is to make sure it works in docker in pterodactyl.

We should decide whether this feature should be opt-in (disabled by default) or opt-out (enabled by default).

@AlexanderK666
Copy link
Copy Markdown
Author

I didn't see an exceptions when running in pterodactyl, but the entire output was broken, so I can't tell for sure (and there could be some try/catch somewhere in the code).

Of course this will not catch all the edge cases, but the most important is to make sure it works in docker in pterodactyl.

We should decide whether this feature should be opt-in (disabled by default) or opt-out (enabled by default).

I'm thinking of making this feature enabled by default in environments that support the use of Console.ReadKey, while adding the option to disable this via the configuration file or the startup argument. In environments that do not support the use of Console.ReadKey turn it off.

@AlexanderK666
Copy link
Copy Markdown
Author

I didn't see an exceptions when running in pterodactyl

I think this is because the input is happening in a thread, and there's no try-catch block there.

@AlexanderK666
Copy link
Copy Markdown
Author

I didn't see an exceptions when running in pterodactyl

I think this is because the input is happening in a thread, and there's no try-catch block there.

In Visual Studio, with debugger:
In Visual Studio, with debugger screenshot

In runtime, without debugger:
In runtime, without debugger screenshot

@zabszk
Copy link
Copy Markdown
Collaborator

zabszk commented Jul 21, 2024

Is it possible for you to test it in linux and in pterodactyl? If not, I can test it after you commit fixes to this PR.

Don't forget about the issue that exists on linux (outside pterodactyl) that I mentioned (the one that requires to press enter key to get new output).

@AlexanderK666
Copy link
Copy Markdown
Author

Is it possible for you to test it in linux and in pterodactyl? If not, I can test it after you commit fixes to this PR.

Don't forget about the issue that exists on linux (outside pterodactyl) that I mentioned (the one that requires to press enter key to get new output).

Yes, I have the ability to test in Linux, but I haven't figured out how to work with Pterodactyl yet. I have Docker Compose and Portainer, which theoretically should work in a similar way. Additional testing would definitely be useful.

@AlexanderK666
Copy link
Copy Markdown
Author

Don't forget about the issue that exists on linux (outside pterodactyl) that I mentioned (the one that requires to press enter key to get new output).

It seems I managed to fix it. To solve this, I added a check for Console.KeyAvailable.

Screenshot

Currently partially tested on Windows, but some issues were found.
@AlexanderK666
Copy link
Copy Markdown
Author

So far, I found that the exit command on Windows does not close the window, but I haven't been able to figure out why yet.

@AlexanderK666
Copy link
Copy Markdown
Author

AlexanderK666 commented Jul 21, 2024

I did the build via GitHub Actions on my fork repository. P.S.: workflow dispatch is not necessary to contribute to the main repository, it was needed for the fork.

@ghost
Copy link
Copy Markdown

ghost commented Jul 25, 2024

So far, I found that the exit command on Windows does not close the window, but I haven't been able to figure out why yet.

If you CTRL + C, does it quit the application?

@AlexanderK666
Copy link
Copy Markdown
Author

If you CTRL + C, does it quit the application?

This closes SCPSL.exe, but the LocalAdmin window in Windows has to be closed manually. On Linux, everything closes correctly.

@ghost
Copy link
Copy Markdown

ghost commented Jul 25, 2024

If you CTRL + C, does it quit the application?

This closes SCPSL.exe, but the LocalAdmin window in Windows has to be closed manually. On Linux, everything closes correctly.

Console apps are designed by Microsoft to terminate if there is no valid code to process meaning somewhere in your changes, your preventing the console from reaching a termination state.

You’ll need to pause the application state after entering the state and discover what the JIT compiler is struggling to figure out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants