feat: Adds housing.bin support (#2329)
### Summary Changes component verification so the order is now housing.bin, then txt files in client, then txt files in Data/Components folder on the server.
This commit is contained in:
parent
b191498569
commit
a9d2b0c01f
4 changed files with 340 additions and 267 deletions
|
|
@ -1,6 +1,6 @@
|
|||
/*************************************************************************
|
||||
* ModernUO *
|
||||
* Copyright 2019-2023 - ModernUO Development Team *
|
||||
* Copyright 2019-2026 - ModernUO Development Team *
|
||||
* Email: hi@modernuo.com *
|
||||
* File: MultiData.cs *
|
||||
* *
|
||||
|
|
@ -25,6 +25,9 @@ namespace Server;
|
|||
|
||||
public static class MultiData
|
||||
{
|
||||
public static string HousingUOPPath { get; private set; }
|
||||
public static UOPEntry HousingEntry { get; private set; }
|
||||
|
||||
public static void Configure()
|
||||
{
|
||||
var multiUOPPath = Core.FindDataFile("MultiCollection.uop", false);
|
||||
|
|
@ -53,8 +56,10 @@ public static class MultiData
|
|||
{
|
||||
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
|
||||
// TODO: Find out if housing.bin is needed and read that.
|
||||
var uopEntries = UOPFiles.ReadUOPIndexes(stream, ".bin", 0x10000, 4, 6);
|
||||
var housingHash = UOPFiles.HashLittle2("build/multicollection/housing.bin");
|
||||
var additionalHashes = new Dictionary<ulong, UOPEntry> { [housingHash] = default };
|
||||
|
||||
var uopEntries = UOPFiles.ReadUOPIndexes(stream, ".bin", 0x10000, 4, 6, additionalHashes);
|
||||
|
||||
var compressionBuffer = STArrayPool<byte>.Shared.Rent(0x10000);
|
||||
var buffer = STArrayPool<byte>.Shared.Rent(0x10000);
|
||||
|
|
@ -120,6 +125,12 @@ public static class MultiData
|
|||
|
||||
STArrayPool<byte>.Shared.Return(buffer);
|
||||
STArrayPool<byte>.Shared.Return(compressionBuffer);
|
||||
|
||||
if (additionalHashes.TryGetValue(housingHash, out var housingEntry) && housingEntry.Size > 0)
|
||||
{
|
||||
HousingUOPPath = path;
|
||||
HousingEntry = housingEntry;
|
||||
}
|
||||
}
|
||||
|
||||
private static void LoadMul(bool postHSMulFormat)
|
||||
|
|
@ -22,7 +22,8 @@ namespace Server;
|
|||
public static class UOPFiles
|
||||
{
|
||||
public static Dictionary<int, UOPEntry> ReadUOPIndexes(
|
||||
FileStream stream, string fileExt, int entryCount = 0x14000, int expectedVersion = -1, int precision = 8
|
||||
FileStream stream, string fileExt, int entryCount = 0x14000, int expectedVersion = -1, int precision = 8,
|
||||
Dictionary<ulong, UOPEntry> additionalHashes = null
|
||||
)
|
||||
{
|
||||
var reader = new BinaryReader(stream);
|
||||
|
|
@ -70,8 +71,12 @@ public static class UOPFiles
|
|||
|
||||
var compressed = reader.ReadInt16() == 1;
|
||||
|
||||
if (offset != 0 && hashes.TryGetValue(fileNameHash, out var fileIndex) && compressedLength > 0 &&
|
||||
decompressedLength > 0)
|
||||
if (offset == 0 || compressedLength <= 0 || decompressedLength <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hashes.TryGetValue(fileNameHash, out var fileIndex))
|
||||
{
|
||||
entries[fileIndex] = new UOPEntry(offset + headerLength, decompressedLength)
|
||||
{
|
||||
|
|
@ -79,6 +84,14 @@ public static class UOPFiles
|
|||
CompressedSize = compressedLength
|
||||
};
|
||||
}
|
||||
else if (additionalHashes != null && additionalHashes.ContainsKey(fileNameHash))
|
||||
{
|
||||
additionalHashes[fileNameHash] = new UOPEntry(offset + headerLength, decompressedLength)
|
||||
{
|
||||
Compressed = compressed,
|
||||
CompressedSize = compressedLength
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
while (nextBlock != 0 && nextBlock < length);
|
||||
|
|
|
|||
|
|
@ -1,315 +1,368 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using Server.Compression;
|
||||
|
||||
namespace Server.Multis
|
||||
namespace Server.Multis;
|
||||
|
||||
public static class ComponentVerification
|
||||
{
|
||||
public class ComponentVerification
|
||||
private static int[] _itemTable;
|
||||
private static int[] _multiTable;
|
||||
private static bool _loaded;
|
||||
|
||||
public static bool IsItemValid(int itemID)
|
||||
{
|
||||
private readonly int[] m_ItemTable;
|
||||
private readonly int[] m_MultiTable;
|
||||
EnsureLoaded();
|
||||
return itemID > 0 && itemID < _itemTable.Length && CheckValidity(_itemTable[itemID]);
|
||||
}
|
||||
|
||||
public ComponentVerification()
|
||||
public static bool IsMultiValid(int multiID)
|
||||
{
|
||||
EnsureLoaded();
|
||||
return multiID > 0 && multiID < _multiTable.Length && CheckValidity(_multiTable[multiID]);
|
||||
}
|
||||
|
||||
private static bool CheckValidity(int val) =>
|
||||
val != -1 && (val == 0 || ((int)ExpansionInfo.CoreExpansion.HousingFlags & val) != 0);
|
||||
|
||||
private static void EnsureLoaded()
|
||||
{
|
||||
if (_loaded)
|
||||
{
|
||||
m_ItemTable = CreateTable(TileData.MaxItemValue);
|
||||
m_MultiTable = CreateTable(0x4000);
|
||||
|
||||
LoadItems(
|
||||
"Data/Components/walls.txt",
|
||||
"South1",
|
||||
"South2",
|
||||
"South3",
|
||||
"Corner",
|
||||
"East1",
|
||||
"East2",
|
||||
"East3",
|
||||
"Post",
|
||||
"WindowS",
|
||||
"AltWindowS",
|
||||
"WindowE",
|
||||
"AltWindowE",
|
||||
"SecondAltWindowS",
|
||||
"SecondAltWindowE"
|
||||
);
|
||||
LoadItems(
|
||||
"Data/Components/teleprts.txt",
|
||||
"F1",
|
||||
"F2",
|
||||
"F3",
|
||||
"F4",
|
||||
"F5",
|
||||
"F6",
|
||||
"F7",
|
||||
"F8",
|
||||
"F9",
|
||||
"F10",
|
||||
"F11",
|
||||
"F12",
|
||||
"F13",
|
||||
"F14",
|
||||
"F15",
|
||||
"F16"
|
||||
);
|
||||
LoadItems(
|
||||
"Data/Components/stairs.txt",
|
||||
"Block",
|
||||
"North",
|
||||
"East",
|
||||
"South",
|
||||
"West",
|
||||
"Squared1",
|
||||
"Squared2",
|
||||
"Rounded1",
|
||||
"Rounded2"
|
||||
);
|
||||
LoadItems(
|
||||
"Data/Components/roof.txt",
|
||||
"North",
|
||||
"East",
|
||||
"South",
|
||||
"West",
|
||||
"NSCrosspiece",
|
||||
"EWCrosspiece",
|
||||
"NDent",
|
||||
"EDent",
|
||||
"SDent",
|
||||
"WDent",
|
||||
"NTPiece",
|
||||
"ETPiece",
|
||||
"STPiece",
|
||||
"WTPiece",
|
||||
"XPiece",
|
||||
"Extra Piece"
|
||||
);
|
||||
LoadItems(
|
||||
"Data/Components/floors.txt",
|
||||
"F1",
|
||||
"F2",
|
||||
"F3",
|
||||
"F4",
|
||||
"F5",
|
||||
"F6",
|
||||
"F7",
|
||||
"F8",
|
||||
"F9",
|
||||
"F10",
|
||||
"F11",
|
||||
"F12",
|
||||
"F13",
|
||||
"F14",
|
||||
"F15",
|
||||
"F16"
|
||||
);
|
||||
LoadItems(
|
||||
"Data/Components/misc.txt",
|
||||
"Piece1",
|
||||
"Piece2",
|
||||
"Piece3",
|
||||
"Piece4",
|
||||
"Piece5",
|
||||
"Piece6",
|
||||
"Piece7",
|
||||
"Piece8"
|
||||
);
|
||||
LoadItems(
|
||||
"Data/Components/doors.txt",
|
||||
"Piece1",
|
||||
"Piece2",
|
||||
"Piece3",
|
||||
"Piece4",
|
||||
"Piece5",
|
||||
"Piece6",
|
||||
"Piece7",
|
||||
"Piece8"
|
||||
);
|
||||
|
||||
LoadMultis("Data/Components/stairs.txt", "MultiNorth", "MultiEast", "MultiSouth", "MultiWest");
|
||||
return;
|
||||
}
|
||||
|
||||
public bool IsItemValid(int itemID) =>
|
||||
itemID > 0 && itemID < m_ItemTable.Length && CheckValidity(m_ItemTable[itemID]);
|
||||
_loaded = true;
|
||||
|
||||
public bool IsMultiValid(int multiID) =>
|
||||
multiID > 0 && multiID < m_MultiTable.Length && CheckValidity(m_MultiTable[multiID]);
|
||||
_itemTable = CreateTable(TileData.MaxItemValue);
|
||||
_multiTable = CreateTable(0x4000);
|
||||
|
||||
public bool CheckValidity(int val) =>
|
||||
val != -1 && (val == 0 || ((int)ExpansionInfo.CoreExpansion.HousingFlags & val) != 0);
|
||||
|
||||
private int[] CreateTable(int length)
|
||||
var housingPath = MultiData.HousingUOPPath;
|
||||
if (housingPath != null)
|
||||
{
|
||||
var table = new int[length];
|
||||
var entry = MultiData.HousingEntry;
|
||||
LoadFromHousingBin(ReadUOPEntry(housingPath, entry));
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < table.Length; ++i)
|
||||
LoadFromTxtFiles();
|
||||
}
|
||||
|
||||
private static byte[] ReadUOPEntry(string path, UOPEntry entry)
|
||||
{
|
||||
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
stream.Seek(entry.Offset, SeekOrigin.Begin);
|
||||
|
||||
if (entry.Compressed)
|
||||
{
|
||||
var compressedData = new byte[entry.CompressedSize];
|
||||
stream.ReadExactly(compressedData);
|
||||
var decompressedData = new byte[entry.Size];
|
||||
|
||||
if (Deflate.Standard.Unpack(decompressedData, compressedData, out var bytesDecompressed) != LibDeflateResult.Success
|
||||
|| entry.Size != bytesDecompressed)
|
||||
{
|
||||
table[i] = -1;
|
||||
return null;
|
||||
}
|
||||
|
||||
return table;
|
||||
return decompressedData;
|
||||
}
|
||||
|
||||
private void LoadItems(string path, params ReadOnlySpan<string> itemColumns)
|
||||
var data = new byte[entry.Size];
|
||||
stream.ReadExactly(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
private static void LoadFromHousingBin(byte[] data)
|
||||
{
|
||||
var reader = new SpanReader(data);
|
||||
|
||||
var fileTypesCount = (int)reader.ReadUInt32LE();
|
||||
|
||||
for (var f = 0; f < fileTypesCount; f++)
|
||||
{
|
||||
LoadSpreadsheet(m_ItemTable, path, itemColumns);
|
||||
}
|
||||
var fileType = (int)reader.ReadUInt32LE();
|
||||
var entriesCount = (int)reader.ReadUInt32LE();
|
||||
var isWalls = fileType == 5;
|
||||
var isStairs = fileType == 1;
|
||||
|
||||
private void LoadMultis(string path, params ReadOnlySpan<string> multiColumns)
|
||||
{
|
||||
LoadSpreadsheet(m_MultiTable, path, multiColumns);
|
||||
}
|
||||
|
||||
private void LoadSpreadsheet(int[] table, string path, params ReadOnlySpan<string> tileColumns)
|
||||
{
|
||||
var ss = new Spreadsheet(path);
|
||||
|
||||
var tileCIDs = new int[tileColumns.Length];
|
||||
|
||||
for (var i = 0; i < tileColumns.Length; ++i)
|
||||
for (var e = 0; e < entriesCount; e++)
|
||||
{
|
||||
tileCIDs[i] = ss.GetColumnID(tileColumns[i]);
|
||||
}
|
||||
reader.ReadUInt32LE(); // category_id
|
||||
reader.ReadUInt32LE(); // subcategory_id
|
||||
var featureMask = (int)reader.ReadUInt32LE();
|
||||
reader.ReadUInt32LE(); // cliloc_id
|
||||
|
||||
var featureCID = ss.GetColumnID("FeatureMask");
|
||||
|
||||
for (var i = 0; i < ss.Records.Length; ++i)
|
||||
{
|
||||
var record = ss.Records[i];
|
||||
|
||||
var fid = record.GetInt32(featureCID);
|
||||
|
||||
for (var j = 0; j < tileCIDs.Length; ++j)
|
||||
// fields_1
|
||||
var fieldsCount1 = (int)reader.ReadUInt32LE();
|
||||
for (var i = 0; i < fieldsCount1; i++)
|
||||
{
|
||||
var itemID = record.GetInt32(tileCIDs[j]);
|
||||
reader.ReadUInt32LE(); // direction
|
||||
var staticId = (int)reader.ReadUInt32LE();
|
||||
|
||||
if (itemID <= 0 || itemID >= table.Length)
|
||||
if (staticId > 0 && staticId < _itemTable.Length)
|
||||
{
|
||||
continue;
|
||||
_itemTable[staticId] = featureMask;
|
||||
}
|
||||
}
|
||||
|
||||
table[itemID] = fid;
|
||||
// unknown1 (only for walls, between fields_1 and fields_count_2)
|
||||
if (isWalls)
|
||||
{
|
||||
reader.ReadUInt32LE();
|
||||
}
|
||||
|
||||
// fields_2
|
||||
var fieldsCount2 = (int)reader.ReadUInt32LE();
|
||||
for (var i = 0; i < fieldsCount2; i++)
|
||||
{
|
||||
reader.ReadUInt32LE(); // direction
|
||||
var staticId = (int)reader.ReadUInt32LE();
|
||||
|
||||
if (isStairs)
|
||||
{
|
||||
if (staticId > 0 && staticId < _multiTable.Length)
|
||||
{
|
||||
_multiTable[staticId] = featureMask;
|
||||
}
|
||||
}
|
||||
else if (staticId > 0 && staticId < _itemTable.Length)
|
||||
{
|
||||
_itemTable[staticId] = featureMask;
|
||||
}
|
||||
}
|
||||
|
||||
// unknown2 (only for non-walls, after fields_2)
|
||||
if (!isWalls)
|
||||
{
|
||||
reader.ReadUInt32LE();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Spreadsheet
|
||||
private static void LoadFromTxtFiles()
|
||||
{
|
||||
private readonly ColumnInfo[] m_Columns;
|
||||
LoadItems(
|
||||
"walls.txt",
|
||||
"South1", "South2", "South3", "Corner",
|
||||
"East1", "East2", "East3", "Post",
|
||||
"WindowS", "AltWindowS", "WindowE", "AltWindowE",
|
||||
"SecondAltWindowS", "SecondAltWindowE"
|
||||
);
|
||||
LoadItems(
|
||||
"teleprts.txt",
|
||||
"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8",
|
||||
"F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16"
|
||||
);
|
||||
LoadItems(
|
||||
"stairs.txt",
|
||||
"Block", "North", "East", "South", "West",
|
||||
"Squared1", "Squared2", "Rounded1", "Rounded2"
|
||||
);
|
||||
LoadItems(
|
||||
"roof.txt",
|
||||
"North", "East", "South", "West",
|
||||
"NSCrosspiece", "EWCrosspiece",
|
||||
"NDent", "EDent", "SDent", "WDent",
|
||||
"NTPiece", "ETPiece", "STPiece", "WTPiece",
|
||||
"XPiece", "Extra Piece"
|
||||
);
|
||||
LoadItems(
|
||||
"floors.txt",
|
||||
"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8",
|
||||
"F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16"
|
||||
);
|
||||
LoadItems(
|
||||
"misc.txt",
|
||||
"Piece1", "Piece2", "Piece3", "Piece4",
|
||||
"Piece5", "Piece6", "Piece7", "Piece8"
|
||||
);
|
||||
LoadItems(
|
||||
"doors.txt",
|
||||
"Piece1", "Piece2", "Piece3", "Piece4",
|
||||
"Piece5", "Piece6", "Piece7", "Piece8"
|
||||
);
|
||||
|
||||
public Spreadsheet(string path)
|
||||
LoadMultis("stairs.txt", "MultiNorth", "MultiEast", "MultiSouth", "MultiWest");
|
||||
}
|
||||
|
||||
private static string ResolveTxtPath(string filename)
|
||||
{
|
||||
var clientPath = Core.FindDataFile(filename, false);
|
||||
if (clientPath != null)
|
||||
{
|
||||
using var ip = new StreamReader(path);
|
||||
var types = ReadLine(ip);
|
||||
var names = ReadLine(ip);
|
||||
|
||||
m_Columns = new ColumnInfo[types.Length];
|
||||
|
||||
for (var i = 0; i < m_Columns.Length; ++i)
|
||||
{
|
||||
m_Columns[i] = new ColumnInfo(i, types[i], names[i]);
|
||||
}
|
||||
|
||||
var records = new List<DataRecord>();
|
||||
|
||||
string[] values;
|
||||
|
||||
while ((values = ReadLine(ip)) != null)
|
||||
{
|
||||
var data = new object[m_Columns.Length];
|
||||
|
||||
for (var i = 0; i < m_Columns.Length; ++i)
|
||||
{
|
||||
var ci = m_Columns[i];
|
||||
|
||||
switch (ci.m_Type)
|
||||
{
|
||||
case "int":
|
||||
{
|
||||
data[i] = Utility.ToInt32(values[ci.m_DataIndex]);
|
||||
break;
|
||||
}
|
||||
case "string":
|
||||
{
|
||||
data[i] = values[ci.m_DataIndex];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
records.Add(new DataRecord(this, data));
|
||||
}
|
||||
|
||||
Records = records.ToArray();
|
||||
return clientPath;
|
||||
}
|
||||
|
||||
public DataRecord[] Records { get; }
|
||||
var bundledPath = Path.Combine("Data", "Components", filename);
|
||||
return File.Exists(bundledPath) ? bundledPath : null;
|
||||
}
|
||||
|
||||
public int GetColumnID(string name)
|
||||
private static void LoadItems(string filename, params ReadOnlySpan<string> itemColumns) =>
|
||||
LoadSpreadsheet(_itemTable, filename, itemColumns);
|
||||
|
||||
private static void LoadMultis(string filename, params ReadOnlySpan<string> multiColumns) =>
|
||||
LoadSpreadsheet(_multiTable, filename, multiColumns);
|
||||
|
||||
private static void LoadSpreadsheet(int[] table, string filename, params ReadOnlySpan<string> tileColumns)
|
||||
{
|
||||
var path = ResolveTxtPath(filename);
|
||||
if (path == null)
|
||||
{
|
||||
for (var i = 0; i < m_Columns.Length; ++i)
|
||||
{
|
||||
if (m_Columns[i].m_Name == name)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
private string[] ReadLine(StreamReader ip)
|
||||
var ss = new Spreadsheet(path);
|
||||
|
||||
var tileCIDs = new int[tileColumns.Length];
|
||||
|
||||
for (var i = 0; i < tileColumns.Length; ++i)
|
||||
{
|
||||
string line;
|
||||
|
||||
while ((line = ip.ReadLine()) != null)
|
||||
{
|
||||
if (line.Length > 0)
|
||||
{
|
||||
return line.Split('\t');
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
tileCIDs[i] = ss.GetColumnID(tileColumns[i]);
|
||||
}
|
||||
|
||||
private class ColumnInfo
|
||||
var featureCID = ss.GetColumnID("FeatureMask");
|
||||
|
||||
for (var i = 0; i < ss.Records.Length; ++i)
|
||||
{
|
||||
public readonly int m_DataIndex;
|
||||
public readonly string m_Name;
|
||||
var record = ss.Records[i];
|
||||
|
||||
public readonly string m_Type;
|
||||
var fid = record.GetInt32(featureCID);
|
||||
|
||||
public ColumnInfo(int dataIndex, string type, string name)
|
||||
for (var j = 0; j < tileCIDs.Length; ++j)
|
||||
{
|
||||
m_DataIndex = dataIndex;
|
||||
var itemID = record.GetInt32(tileCIDs[j]);
|
||||
|
||||
m_Type = type;
|
||||
m_Name = name;
|
||||
if (itemID <= 0 || itemID >= table.Length)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
table[itemID] = fid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class DataRecord
|
||||
private static int[] CreateTable(int length)
|
||||
{
|
||||
public DataRecord(Spreadsheet ss, object[] data)
|
||||
var table = new int[length];
|
||||
|
||||
for (var i = 0; i < table.Length; ++i)
|
||||
{
|
||||
Spreadsheet = ss;
|
||||
Data = data;
|
||||
table[i] = -1;
|
||||
}
|
||||
|
||||
public Spreadsheet Spreadsheet { get; }
|
||||
|
||||
public object[] Data { get; }
|
||||
|
||||
public object this[string name] => this[Spreadsheet.GetColumnID(name)];
|
||||
|
||||
public object this[int id] => id < 0 ? null : Data[id];
|
||||
|
||||
public int GetInt32(string name) => GetInt32(this[name]);
|
||||
|
||||
public int GetInt32(int id) => GetInt32(this[id]);
|
||||
|
||||
public int GetInt32(object obj) => Convert.ToInt32(obj);
|
||||
|
||||
public string GetString(string name) => this[name] as string;
|
||||
return table;
|
||||
}
|
||||
}
|
||||
|
||||
public class Spreadsheet
|
||||
{
|
||||
private readonly ColumnInfo[] m_Columns;
|
||||
|
||||
public Spreadsheet(string path)
|
||||
{
|
||||
using var ip = new StreamReader(path);
|
||||
var types = ReadLine(ip);
|
||||
var names = ReadLine(ip);
|
||||
|
||||
m_Columns = new ColumnInfo[types.Length];
|
||||
|
||||
for (var i = 0; i < m_Columns.Length; ++i)
|
||||
{
|
||||
m_Columns[i] = new ColumnInfo(i, types[i], names[i]);
|
||||
}
|
||||
|
||||
var records = new List<DataRecord>();
|
||||
|
||||
while (ReadLine(ip) is { } values)
|
||||
{
|
||||
var data = new object[m_Columns.Length];
|
||||
|
||||
for (var i = 0; i < m_Columns.Length; ++i)
|
||||
{
|
||||
var ci = m_Columns[i];
|
||||
|
||||
data[i] = ci.m_Type switch
|
||||
{
|
||||
"int" => Utility.ToInt32(values[ci.m_DataIndex]),
|
||||
"string" => values[ci.m_DataIndex],
|
||||
_ => data[i]
|
||||
};
|
||||
}
|
||||
|
||||
records.Add(new DataRecord(this, data));
|
||||
}
|
||||
|
||||
Records = records.ToArray();
|
||||
}
|
||||
|
||||
public DataRecord[] Records { get; }
|
||||
|
||||
public int GetColumnID(string name)
|
||||
{
|
||||
for (var i = 0; i < m_Columns.Length; ++i)
|
||||
{
|
||||
if (m_Columns[i].m_Name == name)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static string[] ReadLine(StreamReader ip)
|
||||
{
|
||||
while (ip.ReadLine() is { } line)
|
||||
{
|
||||
if (line.Length > 0)
|
||||
{
|
||||
return line.Split('\t');
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private class ColumnInfo
|
||||
{
|
||||
public readonly int m_DataIndex;
|
||||
public readonly string m_Name;
|
||||
|
||||
public readonly string m_Type;
|
||||
|
||||
public ColumnInfo(int dataIndex, string type, string name)
|
||||
{
|
||||
m_DataIndex = dataIndex;
|
||||
|
||||
m_Type = type;
|
||||
m_Name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class DataRecord
|
||||
{
|
||||
public DataRecord(Spreadsheet ss, object[] data)
|
||||
{
|
||||
Spreadsheet = ss;
|
||||
Data = data;
|
||||
}
|
||||
|
||||
public Spreadsheet Spreadsheet { get; }
|
||||
|
||||
public object[] Data { get; }
|
||||
|
||||
public object this[string name] => this[Spreadsheet.GetColumnID(name)];
|
||||
|
||||
public object this[int id] => id < 0 ? null : Data[id];
|
||||
|
||||
public int GetInt32(int id) => GetInt32(this[id]);
|
||||
|
||||
public int GetInt32(object obj) => Convert.ToInt32(obj);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@ namespace Server.Multis
|
|||
|
||||
public class HouseFoundation : BaseHouse
|
||||
{
|
||||
private static ComponentVerification m_Verification;
|
||||
|
||||
public static readonly bool AllowStairSectioning = true;
|
||||
|
||||
/* Stair block IDs
|
||||
|
|
@ -201,8 +199,6 @@ namespace Server.Multis
|
|||
}
|
||||
}
|
||||
|
||||
public static ComponentVerification Verification => m_Verification ??= new ComponentVerification();
|
||||
|
||||
public bool IsFixture(Item item) => Fixtures.Contains(item);
|
||||
|
||||
public override int GetMaxUpdateRange() => 24;
|
||||
|
|
@ -1358,7 +1354,7 @@ namespace Server.Multis
|
|||
public static bool ValidPiece(int itemID, bool roof = false)
|
||||
{
|
||||
itemID &= TileData.MaxItemValue;
|
||||
return roof == TileData.ItemTable[itemID].Roof && Verification.IsItemValid(itemID);
|
||||
return roof == TileData.ItemTable[itemID].Roof && ComponentVerification.IsItemValid(itemID);
|
||||
}
|
||||
|
||||
public static bool IsStairBlock(int id)
|
||||
|
|
@ -1638,7 +1634,7 @@ namespace Server.Multis
|
|||
// Validate stair multi ID
|
||||
var design = context.Foundation.DesignState;
|
||||
|
||||
if (!Verification.IsMultiValid(itemID))
|
||||
if (!ComponentVerification.IsMultiValid(itemID))
|
||||
{
|
||||
/* Specified multi ID is not a stair
|
||||
* - Resend design state
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue