Skip to content

Instantly share code, notes, and snippets.

@copygirl
Created January 6, 2015 23:06
Show Gist options
  • Save copygirl/9e019a5651e7e6007443 to your computer and use it in GitHub Desktop.
Save copygirl/9e019a5651e7e6007443 to your computer and use it in GitHub Desktop.
using System;
using System.IO;
using System.Threading;
namespace obsidianUpdater.Utility
{
public class ServerSniffer
{
private StreamReader _reader;
private int _progress = 0;
public ServerStatus Status { get; private set; }
public ServerSniffer(StreamReader reader)
{
_reader = reader;
}
public void WaitUntilRunning()
{
Status = ServerStatus.Starting;
Console.WriteLine();
while (Status < ServerStatus.Running)
ParseLine(_reader.ReadLine());
if (Status > ServerStatus.Running)
throw new Exception("There was an error while starting up the server.");
}
public void WaitUntilStopped()
{
Status = ServerStatus.Running;
Console.WriteLine();
while (Status < ServerStatus.Stopped)
ParseLine(_reader.ReadLine());
}
public void ParseLine(string line)
{
if (line == null) {
Thread.Sleep(0);
return;
}
// TODO: Detect crashing.
switch (Status) {
case ServerStatus.Starting:
if (_startup[_progress](line, _progress, _startup.Length - 1) && (++_progress >= _startup.Length))
Status = ServerStatus.Running;
break;
case ServerStatus.Running:
if (UpdateStatus(LookForText(line, 44, "Sending event FMLServerStoppingEvent"), 0.5F, "Server stopping"))
Status = ServerStatus.Stopping;
break;
case ServerStatus.Stopping:
if (UpdateStatus(LookForText(line, 44, "Sending event FMLServerStoppedEvent"), 1.0F, "Server stopped!"))
Status = ServerStatus.Stopped;
break;
}
}
private static readonly Func<string, int, int, bool>[] _startup = new Func<string, int, int, bool>[]{
LookForText(31, "Forge Mod Loader version", "FML initializing"),
LookForText(51, "Attempting early MinecraftForge initialization", "Forge initializing"),
LookForEvent("FMLConstructionEvent", "Construction"),
LookForEvent("FMLConstructionEvent", "Construction", false) +
LookForEvent("FMLPreInitializationEvent", "Pre-initialization"),
LookForEvent("FMLPreInitializationEvent", "Pre-initialization", false) +
LookForEvent("FMLInitializationEvent", "Initialization"),
LookForEvent("FMLInitializationEvent", "Initialization", false) +
LookForEvent("FMLPostInitializationEvent", "Post-initialization"),
LookForEvent("FMLPostInitializationEvent", "Post-initialization", false) +
LookForText(40, "Injecting existing block and item data into this server instance", "Server about to start"),
LookForText(40, "Applying holder lookups", "Server starting"),
LookForText(44, "Sending event FMLServerStartedEvent", "Server started!")
};
private static bool UpdateStatus(bool update, float progress, string status)
{
if (!update)
return false;
string format;
if (!Console.IsOutputRedirected) {
Console.SetCursorPosition(Console.CursorLeft, Console.CursorTop - 1);
format = "[{0,3}%] {1,-" + (Console.WindowWidth - 7) + "}";
} else
format = "[{0,3}%] {1}";
Console.WriteLine(String.Format(format, (int)(progress * 100), status));
return true;
}
private static bool LookForText(string line, int start, string message)
{
return ((line.Length >= start + message.Length) && (line[0] == '[') &&
(line.IndexOf(message, start, message.Length) >= 0));
}
private static Func<string, int, int, bool> LookForText(int start, string message, string status)
{
return (line, progress, maxProgress) => UpdateStatus(
LookForText(line, start, message), (float)progress / maxProgress, status);
}
private static bool LookForEvent(string line, string eventName, out string modName)
{
int slashIndex;
modName = null;
return ((line.Length >= 63 + eventName.Length) && (line[33] == '[') &&
((slashIndex = line.IndexOf('/', 35, line.Length - 63)) >= 0) &&
(line.Length >= 60 + eventName.Length + (modName = line.Substring(34, slashIndex - 34)).Length * 3) &&
(line.IndexOf("Sending event", 38 + modName.Length * 2, 13) >= 0) &&
(line.IndexOf(eventName, 52 + modName.Length * 2, eventName.Length) >= 0));
}
private static Func<string, int, int, bool> LookForEvent(string eventName, string status, bool last = true)
{
string modName;
return (line, progress, maxProgress) => UpdateStatus(
LookForEvent(line, eventName, out modName),
(float)(progress - (last ? 0 : 1)) / maxProgress, status + ": " + modName);
}
}
public enum ServerStatus
{
Unknown,
Starting,
Running,
Stopping,
Stopped,
Crashed
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment