Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 28 additions & 11 deletions PolarisServer/ConsoleSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ public class ConsoleSystem
ConsoleKey.RightArrow,
ConsoleKey.Home,
ConsoleKey.End,
ConsoleKey.Delete
ConsoleKey.Delete,
ConsoleKey.Escape
};

private const string Prompt = "Polaris> ";
Expand All @@ -112,7 +113,11 @@ public ConsoleSystem()
{
Console.Title = "Polaris";
Console.CursorVisible = true;
SetSize(80, 24);
Console.Clear();

Width = Console.WindowWidth;
Height = Console.WindowHeight;
_maxCommandLineSize = Width - Prompt.Length;

timer = new Timer(1000);
timer.Elapsed += TimerRefresh;
Expand All @@ -126,12 +131,18 @@ public ConsoleSystem()

public void SetSize(int width, int height)
{
Width = width;
Height = height;

_maxCommandLineSize = width - Prompt.Length;
try
{
Console.SetWindowSize(width, height);

Console.SetWindowSize(width, height);
Width = width;
Height = height;
_maxCommandLineSize = width - Prompt.Length;
}
catch (Exception)
{
Logger.WriteWarning("[WRN] Failed to set console size to ({0},{1}).", width, height);
}
}

public void AddLine(ConsoleColor color, string text)
Expand All @@ -143,16 +154,14 @@ public void AddLine(ConsoleColor color, string text)
var useColors = PolarisApp.Config.UseConsoleColors;
var saveColor = Console.ForegroundColor;

Console.SetCursorPosition(0, _commandRowInConsole);
if (useColors)
Console.ForegroundColor = color;
Console.WriteLine(text);

if (useColors)
Console.ForegroundColor = saveColor;

Console.WriteLine();
_commandRowInConsole = Console.CursorTop - 1;
_commandRowInConsole = Console.CursorTop;

RefreshCommandLine();
FixCursorPosition();
Expand All @@ -169,14 +178,15 @@ private void BlankDrawnCommandLine()
Console.Write(' ');

_lastDrawnCommandLineSize = 0;

Console.CursorLeft = 0;
}
}

private void RefreshCommandLine()
{
BlankDrawnCommandLine();

Console.SetCursorPosition(0, _commandRowInConsole);
Console.Write(Prompt);
Console.Write(_commandLine);

Expand Down Expand Up @@ -414,6 +424,13 @@ public void CheckInput()
_commandIndex--;
}

// Escape
if (_key.Key == ConsoleKey.Escape)
{
_commandLine = string.Empty;
_commandIndex = 0;
}

// Cursor movement
if (_key.Key == ConsoleKey.LeftArrow && _commandLine.Length > 0 && _commandIndex > 0)
_commandIndex--;
Expand Down
2 changes: 1 addition & 1 deletion PolarisServer/Models/PSOObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public override byte[] GenerateSpawnBlob()
{
PacketWriter writer = new PacketWriter();
writer.WriteStruct(Header);
writer.WritePosition(Position);
writer.Write(Position);
writer.Write((UInt16)0);
writer.WriteFixedLengthASCII(Name, 0x20);

Expand Down
145 changes: 81 additions & 64 deletions PolarisServer/Object/ObjectManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ class ObjectManager
{
private static readonly ObjectManager instance = new ObjectManager();

private Dictionary<String, Dictionary<ulong, PSOObject>> zoneObjects = new Dictionary<string, Dictionary<ulong, PSOObject>>();

private Dictionary<ulong, PSOObject> allTheObjects = new Dictionary<ulong, PSOObject>();
private List<Tuple<string, PSOObject>> object_list = new List<Tuple<string, PSOObject>>();

private ObjectManager() { }

Expand All @@ -34,88 +32,88 @@ public PSOObject[] GetObjectsForZone(string zone)
{
return new PSOObject[0];
}
if (!zoneObjects.ContainsKey(zone))
{
Dictionary<ulong, PSOObject> objects = new Dictionary<ulong, PSOObject>();

if (!object_list.Exists(o => o.Item1 == zone)) // Make sure objects for a zone are only loaded once
{
// Collect from db
using (var db = new PolarisEf())
{
var dbObjects = from dbo in db.GameObjects
where dbo.ZoneName == zone
select dbo;

foreach(var dbObject in dbObjects)
if (dbObjects.Count() > 0)
{
var newObject = PSOObject.FromDBObject(dbObject);
objects.Add(newObject.Header.ID, newObject);
allTheObjects.Add(newObject.Header.ID, newObject);
Logger.WriteInternal("[OBJ] Loaded object {0} for zone {1} from the DB.", newObject.Name, zone);
}
}

// Fallback
if (objects.Count < 1 && Directory.Exists("Resources/objects/" + zone))
{
Logger.WriteWarning("[OBJ] No objects defined for zone {0} in the database, falling back to filesystem!", zone);
var objectPaths = Directory.GetFiles("Resources/objects/" + zone);
Array.Sort(objectPaths);
foreach (var path in objectPaths)
{
if (Path.GetExtension(path) == ".bin")
foreach (var dbObject in dbObjects)
{
var newObject = PSOObject.FromPacketBin(File.ReadAllBytes(path));
objects.Add(newObject.Header.ID, newObject);
allTheObjects.Add(newObject.Header.ID, newObject);
Logger.WriteInternal("[OBJ] Loaded object ID {0} with name {1} pos: ({2}, {3}, {4})", newObject.Header.ID, newObject.Name, newObject.Position.PosX,
newObject.Position.PosY, newObject.Position.PosZ);
var newObject = PSOObject.FromDBObject(dbObject);
object_list.Add(new Tuple<string, PSOObject>(zone, newObject));
Logger.WriteInternal("[OBJ] Loaded object {0} for zone {1} from the DB.", newObject.Name, zone);
}
else if (Path.GetExtension(path) == ".json")
}
// Fallback
else if (Directory.Exists("Resources/objects/" + zone))
{
Logger.WriteWarning("[OBJ] No objects defined for zone {0} in the database, falling back to filesystem!", zone);
var objectPaths = Directory.GetFiles("Resources/objects/" + zone);
Array.Sort(objectPaths);
foreach (var path in objectPaths)
{
var newObject = JsonConvert.DeserializeObject<PSOObject>(File.ReadAllText(path));
objects.Add(newObject.Header.ID, newObject);
allTheObjects.Add(newObject.Header.ID, newObject);
Logger.WriteInternal("[OBJ] Loaded object ID {0} with name {1} pos: ({2}, {3}, {4})", newObject.Header.ID, newObject.Name, newObject.Position.PosX,
newObject.Position.PosY, newObject.Position.PosZ);
if (Path.GetExtension(path) == ".bin")
{
var newObject = PSOObject.FromPacketBin(File.ReadAllBytes(path));
object_list.Add(new Tuple<string, PSOObject>(zone, newObject));
Logger.WriteInternal("[OBJ] Loaded object ID {0} with name {1} pos: ({2}, {3}, {4})", newObject.Header.ID, newObject.Name, newObject.Position.PosX,
newObject.Position.PosY, newObject.Position.PosZ);
}
else if (Path.GetExtension(path) == ".json")
{
var newObject = JsonConvert.DeserializeObject<PSOObject>(File.ReadAllText(path));
object_list.Add(new Tuple<string, PSOObject>(zone, newObject));
Logger.WriteInternal("[OBJ] Loaded object ID {0} with name {1} pos: ({2}, {3}, {4})", newObject.Header.ID, newObject.Name, newObject.Position.PosX,
newObject.Position.PosY, newObject.Position.PosZ);
}
}
}
}
else
{
Logger.WriteWarning("[OBJ] Filesystem directory for zone {0} does not exist!", zone);
}
}

zoneObjects.Add(zone, objects);

}

return zoneObjects[zone].Values.ToArray();

// TODO: returning an IEnumerable<PSOObject> looks more favorable than converting to an array
return (from o in object_list
where o.Item1 == zone
select o.Item2).ToArray();
}

internal PSONPC[] getNPCSForZone(string zone)
{
List<PSONPC> npcs = new List<PSONPC>();
using (var db = new PolarisEf())
if (!object_list.Exists(o => o.Item1 == zone && o.Item2 as PSONPC != null)) // Make sure NPCs for a zone are only loaded once
{
var dbNpcs = from n in db.NPCs
where n.ZoneName == zone
select n;

foreach (NPC npc in dbNpcs)
using (var db = new PolarisEf())
{
PSONPC dNpc = new PSONPC();
dNpc.Header = new ObjectHeader((uint)npc.EntityID, EntityType.Object);
dNpc.Position = new PSOLocation(npc.RotX, npc.RotY, npc.RotZ, npc.RotW, npc.PosX, npc.PosY, npc.PosZ);
dNpc.Name = npc.NPCName;
var dbNpcs = from n in db.NPCs
where n.ZoneName == zone
select n;

npcs.Add(dNpc);
if (!zoneObjects[zone].ContainsKey(dNpc.Header.ID))
foreach (NPC npc in dbNpcs)
{
zoneObjects[zone].Add(dNpc.Header.ID, dNpc);
PSONPC dNpc = new PSONPC();
dNpc.Header = new ObjectHeader((uint)npc.EntityID, EntityType.Object);
dNpc.Position = new PSOLocation(npc.RotX, npc.RotY, npc.RotZ, npc.RotW, npc.PosX, npc.PosY, npc.PosZ);
dNpc.Name = npc.NPCName;

object_list.Add(new Tuple<string, PSOObject>(zone, dNpc));
}
if (!allTheObjects.ContainsKey(dNpc.Header.ID))
allTheObjects.Add(dNpc.Header.ID, dNpc);
}
}

return npcs.ToArray();
// TODO: returning an IEnumerable<PSONPC> looks more favorable than converting to an array
return (from o in object_list
where o.Item1 == zone
select o.Item2 as PSONPC).ToArray();
}

internal PSOObject getObjectByID(string zone, uint ID)
Expand All @@ -127,18 +125,37 @@ internal PSOObject getObjectByID(string zone, uint ID)
//}

//return zoneObjects[zone][ID];
return getObjectByID(ID);
}

internal PSOObject getObjectByID(uint ID)
{
if (!allTheObjects.ContainsKey(ID))

// TODO: Per above old comments, do shared object errors still occur? Is an object 1 edge case still an issue?
PSOObject obj = null;
try
{
if (string.IsNullOrEmpty(zone)) // Lookup by ID alone when no zone is specified
{
obj = object_list.SingleOrDefault(o => o.Item2.Header.ID == ID).Item2;
}
else
{
obj = object_list.SingleOrDefault(o => o.Item1 == zone && o.Item2.Header.ID == ID).Item2;
}
}
catch (InvalidOperationException)
{
Logger.WriteWarning("[OBJ] Multiple objects with ID {0} exist, unknown which is intended.", ID);
}
catch (NullReferenceException)
{
// SingleOrDefault returns null when no object is found, access .Item2 anyway and catch null to simplify things
Logger.WriteWarning("[OBJ] Client requested object {0} which we don't know about. Investigate.", ID);
return new PSOObject() { Header = new ObjectHeader(ID, EntityType.Object), Name = "Unknown" };
}

return allTheObjects[ID];
return obj != null ? obj : new PSOObject() { Header = new ObjectHeader(ID, EntityType.Object), Name = "Unknown" };
}

internal PSOObject getObjectByID(uint ID)
{
return getObjectByID(null, ID);
}
}
}
2 changes: 1 addition & 1 deletion PolarisServer/Packets/PSOPackets/TeleportTransferPacket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public override byte[] Build()
PacketWriter writer = new PacketWriter();
writer.Write(new byte[12]);
writer.WriteStruct(src.Header);
writer.WritePosition(dst);
writer.Write(dst);
writer.Write(new byte[2]);
return writer.ToArray();
}
Expand Down
11 changes: 0 additions & 11 deletions PolarisServer/Packets/PacketWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,6 @@ public void WriteAscii(string str, uint xor, uint sub)
}
}

internal void WritePosition(PSOLocation location)
{
Write(Helper.FloatToHalfPrecision(location.RotX));
Write(Helper.FloatToHalfPrecision(location.RotY));
Write(Helper.FloatToHalfPrecision(location.RotZ));
Write(Helper.FloatToHalfPrecision(location.RotW));
Write(Helper.FloatToHalfPrecision(location.PosX));
Write(Helper.FloatToHalfPrecision(location.PosY));
Write(Helper.FloatToHalfPrecision(location.PosZ));
}

public void WriteUtf16(string str, uint xor, uint sub)
{
if (str.Length == 0)
Expand Down
19 changes: 10 additions & 9 deletions PolarisServer/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,20 @@ public static void Main(string[] args)
case "-s":
case "--size":
var splitArgs = args[++i].Split(',');
var width = int.Parse(splitArgs[0]);
var height = int.Parse(splitArgs[1]);
if (width < ConsoleSystem.Width)
int width;
int height;
try
{
Logger.WriteWarning("[ARG] Capping console width to {0} columns", ConsoleSystem.Width);
width = ConsoleSystem.Width;
width = int.Parse(splitArgs[0]);
height = int.Parse(splitArgs[1]);
Logger.WriteWarning("[ARG] Setting console width to {0} columns", width);
Logger.WriteWarning("[ARG] Setting console height to {0} rows", height);
ConsoleSystem.SetSize(width, height);
}
if (height < ConsoleSystem.Height)
catch (Exception)
{
Logger.WriteWarning("[ARG] Capping console height to {0} rows", ConsoleSystem.Height);
height = ConsoleSystem.Height;
Logger.WriteWarning("[WRN] Failed to set console size to ({0}).", args[i]);
}
ConsoleSystem.SetSize(width, height);
break;
}
}
Expand Down