Skip to content
This repository was archived by the owner on Sep 3, 2022. It is now read-only.
Open

Zip #745

Show file tree
Hide file tree
Changes from 1 commit
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
7 changes: 6 additions & 1 deletion GameServerLib/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,12 @@ private void LoadConfig(Game game, string json)
// Read spawns info
ContentManager = ContentManager.LoadGameMode(game, GameConfig.GameMode, ContentPath);
var mapPath = ContentManager.GetMapConfigPath(GameConfig.Map);
var mapData = JObject.Parse(Encoding.UTF8.GetString(ContentManager.Content[mapPath]));
JObject mapData;
using (var stream = new BinaryReader(ContentManager.Content[mapPath].ReadFile()))
{
mapData = JObject.Parse(Encoding.UTF8.GetString(stream.ReadBytes((int)stream.BaseStream.Length)));
}

var spawns = mapData.SelectToken("spawns");

// Load items
Expand Down
2 changes: 1 addition & 1 deletion GameServerLib/Content/CharData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public void Load(string name)
var path = _game.Config.ContentManager.GetUnitStatPath(name);
var iniParser = new FileIniDataParser();
_logger.Debug($"Loading {name}'s Stats from path: {path}!");
using (var stream = new StreamReader(new MemoryStream(_game.Config.ContentManager.Content[path])))
using (var stream = new StreamReader(_game.Config.ContentManager.Content[path].ReadFile()))
{
var iniData = iniParser.ReadData(stream);
file = new ContentFile(ContentManager.ParseIniFile(iniData));
Expand Down
93 changes: 41 additions & 52 deletions GameServerLib/Content/ContentManager.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
Expand All @@ -18,7 +19,9 @@ public class ContentManager
private Dictionary<string, CharData> _charData = new Dictionary<string, CharData>();
private Dictionary<string, NavGrid> _navGrids = new Dictionary<string, NavGrid>();

public Dictionary<string, byte[]> Content { get; set; } = new Dictionary<string, byte[]>();
public Dictionary<string, FileEntry> Content { get; set; }
= new Dictionary<string, FileEntry>(StringComparer.InvariantCultureIgnoreCase);

public string GameModeName { get; }

private ContentManager(Game game, string gameModeName)
Expand All @@ -31,16 +34,13 @@ private ContentManager(Game game, string gameModeName)

public string GetMapConfigPath(int mapId)
{
var possibilities = new[]
var path = $"LEVELS/Map{mapId}/Map{mapId}.json";
if (!Content.ContainsKey(path))
{
$"LEVELS/Map{mapId}/Map{mapId}.json",
$"LEVELS/map{mapId}/Map{mapId}.json"
};
throw new ContentNotFoundException($"Map configuration for Map {mapId} was not found in the content.");
}

return possibilities.FirstOrDefault(path => Content.ContainsKey(path))
?? throw new ContentNotFoundException(
$"Map configuration for Map {mapId} was not found in the content."
);
return path;
}

public string GetUnitStatPath(string model)
Expand Down Expand Up @@ -93,21 +93,14 @@ public CharData GetCharData(string charName)

public NavGrid GetNavGrid(int mapId)
{
var possibilities = new[]
{
$"LEVELS/Map{mapId}/AIPath.aimesh_ngrid",
$"LEVELS/map{mapId}/AIPath.aimesh_ngrid"
};
var path = $"LEVELS/Map{mapId}/AIPath.aimesh_ngrid";

foreach (var path in possibilities)
if (!_navGrids.ContainsKey(path))
{
if (_navGrids.ContainsKey(path))
{
return _navGrids[path];
}
throw new ContentNotFoundException($"NavGrid for map {mapId} was not loaded.");
}

throw new ContentNotFoundException($"NavGrid for map {mapId} was not loaded.");
return _navGrids[path];
}

public static ContentManager LoadGameMode(Game game, string gameModeName, string contentPath)
Expand All @@ -128,36 +121,34 @@ public static ContentManager LoadGameMode(Game game, string gameModeName, string
// For every entry in the zip
foreach (var entry in zip.Entries)
{
// Uncompress the entry and read it
using (var entryData = new BinaryReader(entry.Open()))
// If file is aimesh_ngrid, load it up
if (entry.FullName.EndsWith(".aimesh_ngrid"))
{
if (entry.FullName.EndsWith(".ini") || entry.FullName.EndsWith(".json"))
{
contentManager.Content[entry.FullName] = entryData.ReadBytes((int)entry.Length);
}
else if (entry.FullName.EndsWith(".aimesh_ngrid"))
using (var reader = new BinaryReader(entry.Open()))
{
contentManager._navGrids[entry.FullName] =
NavGridReader.ReadBinary(entryData.ReadBytes((int)entry.Length));

contentManager.Content[entry.FullName] = entryData.ReadBytes((int)entry.Length);
NavGridReader.ReadBinary(reader.ReadBytes((int)entry.Length));
}
else if (entry.FullName.EndsWith(".cs"))
{
if (entry.FullName.StartsWith("bin") || entry.FullName.StartsWith("obj"))
{
continue;
}

contentManager.Content[entry.FullName] = entryData.ReadBytes((int)entry.Length);
}
else
}
// if file is cs and is not in either "bin" or "obj" folder, load it
else if (entry.FullName.EndsWith(".cs"))
{
if (entry.FullName.StartsWith("bin") || entry.FullName.StartsWith("obj"))
{
continue;
}

contentManager._logger.Debug($"Mapped content from zip [{entry.FullName}]");
}
// if file is ini or json, load them too, otherwise skip it
else if (!entry.FullName.EndsWith(".ini") && !entry.FullName.EndsWith(".json"))
{
continue;
}

// loading is put here to have less duplicate code
contentManager.Content[entry.FullName] =
new FileEntry(entry.Name, entry.FullName, entry.Open());

contentManager._logger.Debug($"Mapped content from zip [{entry.FullName}]");
}
}
}
Expand All @@ -168,29 +159,27 @@ public static ContentManager LoadGameMode(Game game, string gameModeName, string
{
var relativePath = file.Replace(contentPath, "").Replace(gameModeName, "").Substring(2)
.Replace('\\', '/');
if (file.EndsWith(".ini") || file.EndsWith(".json"))
{
contentManager.Content[relativePath] = File.ReadAllBytes(file);
}
else if (file.EndsWith(".cs"))

if (file.EndsWith(".cs"))
{
if (relativePath.StartsWith("bin") || relativePath.StartsWith("obj"))
{
continue;
}

contentManager.Content[relativePath] = File.ReadAllBytes(file);
}
else if (file.EndsWith(".aimesh_ngrid"))
{
contentManager.Content[relativePath] = File.ReadAllBytes(file);
contentManager._navGrids[relativePath] = NavGridReader.ReadBinary(file);
}
else
else if (!file.EndsWith(".ini") && !file.EndsWith(".json"))
{
continue;
}

var fileName = relativePath.Split('/').Last();
contentManager.Content[relativePath] =
new FileEntry(fileName, file, File.Open(file, FileMode.Open));

contentManager._logger.Debug($"Mapped Content [{relativePath}]");
}

Expand Down
38 changes: 38 additions & 0 deletions GameServerLib/Content/FileEntry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System.IO;

namespace LeagueSandbox.GameServer.Content
{
public class FileEntry
{
public string Name { get; }
public string FullPath { get; }

private byte[] _data;

public FileEntry(string name, string fullPath, Stream stream)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is still storing full content of the file into memory.
However this time you did define a class that describes an interface for a FileEntry.

You should extract this interface so that you can have multiple implementations for FileEntry(example .zip or file system).
And yes this would mean that your ContentManager would have to implement IDisposable to get rid of open .zip handles which should be trivial to implement(store them in list).

So what you should implement is FilesystemFileEntry which should be wraper for IFilerEntry around this class:
https://docs.microsoft.com/en-us/dotnet/api/system.io.fileinfo?view=netframework-4.7.2

For ZipFileEntry you can wrap this class(ZipArchiveEntry):
https://docs.microsoft.com/en-us/dotnet/standard/io/how-to-compress-and-extract-files

Both of those provide you a way to:

  1. File name
  2. File name relative to root path of package
  3. Open or OpenRead which returns a stream

{
Name = name;
FullPath = fullPath;
using (stream)
{
_data = new byte[stream.Length];
stream.Read(_data, 0, (int)stream.Length);
}
}

public MemoryStream ReadFile()
{
return new MemoryStream(_data);
}

public override string ToString()
{
return FullPath;
}

public override int GetHashCode()
{
return FullPath.GetHashCode();
}
}
}
13 changes: 6 additions & 7 deletions GameServerLib/Content/NavGrid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -619,18 +619,17 @@ public class NavGridReader
{
public static NavGrid ReadBinary(string filePath)
{
NavBinaryReader b = null;

FileStream stream = null;
try
{
b = new NavBinaryReader(File.Open(filePath, FileMode.Open, FileAccess.Read));
stream = File.Open(filePath, FileMode.Open, FileAccess.Read);
var b = new NavBinaryReader(stream);
return ReadData(b);
}
catch
finally
{
// Ignored
stream?.Dispose();
}

return ReadData(b);
}

public static NavGrid ReadBinary(byte[] fileBytes)
Expand Down
2 changes: 1 addition & 1 deletion GameServerLib/Content/SpellData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ public void Load(string champion, string spell)
{
var path = _game.Config.ContentManager.GetSpellDataPath(champion, spell);
_logger.Debug($"Loading spell {spell} data from path: {path}!");
using (var stream = new StreamReader(new MemoryStream(_game.Config.ContentManager.Content[path])))
using (var stream = new StreamReader(_game.Config.ContentManager.Content[path].ReadFile()))
{
var iniParser = new FileIniDataParser();
var iniData = iniParser.ReadData(stream);
Expand Down
9 changes: 8 additions & 1 deletion GameServerLib/Game.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,14 @@ public bool LoadScripts(bool doReloadContent = false)
continue;
}

scripts.Add(contentData.Key, contentData.Value);
byte[] data;
using (var stream = contentData.Value.ReadFile())
{
data = new byte[stream.Length];
stream.Read(data, 0, (int)stream.Length);
}

scripts.Add(contentData.Key, data);
}

return ScriptEngine.LoadFromData(scripts);
Expand Down
1 change: 1 addition & 0 deletions GameServerLib/GameServerLib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Chatbox\DebugMsgType.cs" />
<Compile Include="Content\FileEntry.cs" />
<Compile Include="Content\NavGrid.cs" />
<Compile Include="API\ApiFunctionManager.cs" />
<Compile Include="API\ApiEventManager.cs" />
Expand Down
2 changes: 1 addition & 1 deletion GameServerLib/Items/ItemManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public void LoadItems(ContentManager contentManager)
var itemIdStr = split.Last().Replace(".ini", "");

ContentFile contentFile;
using (var stream = new StreamReader(new MemoryStream(content.Value)))
using (var stream = new StreamReader(content.Value.ReadFile()))
{
var iniData = iniParser.ReadData(stream);
contentFile = new ContentFile(ContentManager.ParseIniFile(iniData));
Expand Down