/************************************************************************* * ModernUO * * Copyright 2019-2023 - ModernUO Development Team * * Email: hi@modernuo.com * * File: TileMatrixPatch.cs * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * *************************************************************************/ using System; using System.IO; namespace Server; public class TileMatrixPatch { private StaticTile[] _tileBuffer = new StaticTile[128]; public static bool PatchLandEnabled { get; private set; } public static bool PatchStaticsEnabled { get; private set; } public int LandBlocks { get; } public int StaticBlocks { get; } public TileMatrixPatch(TileMatrix matrix, int index) { if (PatchLandEnabled) { var mapDataPath = Core.FindDataFile($"mapdif{index}.mul", false); var mapIndexPath = Core.FindDataFile($"mapdifl{index}.mul", false); if (mapDataPath != null && mapIndexPath != null) { LandBlocks = PatchLand(matrix, mapDataPath, mapIndexPath); } } if (PatchStaticsEnabled) { var staDataPath = Core.FindDataFile($"stadif{index}.mul", false); var staIndexPath = Core.FindDataFile($"stadifl{index}.mul", false); var staLookupPath = Core.FindDataFile($"stadifi{index}.mul", false); if (staDataPath != null && staIndexPath != null && staLookupPath != null) { StaticBlocks = PatchStatics(matrix, staDataPath, staIndexPath, staLookupPath); } } } public static void Configure() { if (UOClient.ServerClientVersion != null) { PatchLandEnabled = ServerConfiguration.GetSetting( "maps.enableMapDiffPatches", UOClient.ServerClientVersion < ClientVersion.Version6000 ); // TODO: Should this be enabled for 6.0 through <7.0.9? PatchStaticsEnabled = ServerConfiguration.GetSetting( "maps.enableStaticsDiffPatches", UOClient.ServerClientVersion < ClientVersion.Version7090 ); } } private unsafe int PatchLand(TileMatrix matrix, string dataPath, string indexPath) { using var fsData = new FileStream(dataPath, FileMode.Open, FileAccess.Read, FileShare.Read); using var fsIndex = new FileStream(indexPath, FileMode.Open, FileAccess.Read, FileShare.Read); using var indexReader = new BinaryReader(fsIndex); var count = (int)(indexReader.BaseStream.Length / 4); for (var i = 0; i < count; i++) { var blockID = indexReader.ReadInt32(); var x = Math.DivRem(blockID, matrix.BlockHeight, out var y); fsData.Seek(4, SeekOrigin.Current); var tiles = new LandTile[64]; fixed (LandTile* pTiles = tiles) { _ = fsData.Read(new Span(pTiles, 192)); } matrix.SetLandBlock(x, y, tiles); } return count; } private unsafe int PatchStatics(TileMatrix matrix, string dataPath, string indexPath, string lookupPath) { using var fsData = new FileStream(dataPath, FileMode.Open, FileAccess.Read, FileShare.Read); using var fsIndex = new FileStream(indexPath, FileMode.Open, FileAccess.Read, FileShare.Read); using var fsLookup = new FileStream(lookupPath, FileMode.Open, FileAccess.Read, FileShare.Read); using var indexReader = new BinaryReader(fsIndex); using var lookupReader = new BinaryReader(fsLookup); var count = (int)(indexReader.BaseStream.Length / 4); var lists = new TileList[8][]; for (var x = 0; x < 8; ++x) { lists[x] = new TileList[8]; for (var y = 0; y < 8; ++y) { lists[x][y] = new TileList(); } } for (var i = 0; i < count; ++i) { var blockID = indexReader.ReadInt32(); var blockX = blockID / matrix.BlockHeight; var blockY = blockID % matrix.BlockHeight; var offset = lookupReader.ReadInt32(); var length = lookupReader.ReadInt32(); lookupReader.ReadInt32(); // Extra if (offset < 0 || length <= 0) { matrix.SetStaticBlock(blockX, blockY, matrix.EmptyStaticBlock); continue; } fsData.Seek(offset, SeekOrigin.Begin); var tileCount = length / 7; if (_tileBuffer.Length < tileCount) { _tileBuffer = new StaticTile[tileCount]; } var staTiles = _tileBuffer; fixed (StaticTile* pTiles = staTiles) { _ = fsData.Read(new Span(pTiles, length)); StaticTile* pCur = pTiles, pEnd = pTiles + tileCount; while (pCur < pEnd) { lists[pCur->m_X & 0x7][pCur->m_Y & 0x7].Add(pCur); pCur += 1; } var tiles = new StaticTile[8][][]; for (var x = 0; x < 8; ++x) { tiles[x] = new StaticTile[8][]; for (var y = 0; y < 8; ++y) { tiles[x][y] = lists[x][y].ToArray(); } } matrix.SetStaticBlock(blockX, blockY, tiles); } } return count; } }