using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using NBTExplorer.Model; namespace NBTExplorer.Windows { public partial class FindBlock : Form { private class CoordinateGroup { public int? Region; public int? Chunk; public int? Block; public int? LocalChunk; public int? LocalBlock; public WatermarkTextBox RegionBox; public WatermarkTextBox ChunkBox; public WatermarkTextBox BlockBox; public WatermarkTextBox LocalChunkBox; public WatermarkTextBox LocalBlockBox; } private bool _inUpdate; private CoordinateGroup _groupX; private CoordinateGroup _groupZ; private DataNode _searchRoot; private DataNode _searchResult; public FindBlock (DataNode searchRoot) { InitializeComponent(); _searchRoot = searchRoot; _groupX = new CoordinateGroup() { RegionBox = _regionXTextBox, ChunkBox = _chunkXTextBox, BlockBox = _blockXTextBox, LocalChunkBox = _localChunkXTextBox, LocalBlockBox = _localBlockXTextBox, }; _groupZ = new CoordinateGroup() { RegionBox = _regionZTextBox, ChunkBox = _chunkZTextBox, BlockBox = _blockZTextBox, LocalChunkBox = _localChunkZTextBox, LocalBlockBox = _localBlockZTextBox, }; ApplyRegion(_groupX, "0", true); ApplyRegion(_groupZ, "0", true); Validate(); } public DataNode Result { get { return _searchResult; } } private DataNode Search (DataNode node) { if (node is DirectoryDataNode) { DirectoryDataNode dirNode = node as DirectoryDataNode; if (!dirNode.IsExpanded) dirNode.Expand(); foreach (var subNode in dirNode.Nodes) { DataNode resultNode = Search(subNode); if (resultNode != null) return resultNode; } return null; } else if (node is RegionFileDataNode) { RegionFileDataNode regionNode = node as RegionFileDataNode; int rx, rz; if (!RegionFileDataNode.RegionCoordinates(regionNode.NodePathName, out rx, out rz)) return null; if (rx != _groupX.Region.Value || rz != _groupZ.Region.Value) return null; if (!regionNode.IsExpanded) regionNode.Expand(); foreach (var subNode in regionNode.Nodes) { DataNode resultNode = Search(subNode); if (resultNode != null) return resultNode; } return null; } else if (node is RegionChunkDataNode) { RegionChunkDataNode chunkNode = node as RegionChunkDataNode; if (chunkNode.X != _groupX.LocalChunk.Value || chunkNode.Z != _groupZ.LocalChunk.Value) return null; return chunkNode; } return null; } private int Mod (int a, int b) { return ((a % b) + b) % b; } // Block Set private string RegionFromBlock (int block) { return ((block >> 4) >> 5).ToString(); } private string ChunkFromBlock (int block) { return (block >> 4).ToString(); } private string LocalChunkFromBlock (int block) { return Mod(block >> 4, 32).ToString(); } private string LocalBlockFromBlock (int block) { return Mod(block, 16).ToString(); } // Chunk Set private string RegionFromChunk (int chunk) { return (chunk >> 5).ToString(); } private string BlockFromChunk (int chunk) { int start = chunk * 16; int end = (chunk + 1) * 16 - 1; return string.Format("({0} to {1})", start, end); } private string BlockFromChunk (int chunk, int localBlock) { return (chunk * 16 + localBlock).ToString(); } private string LocalChunkFromChunk (int chunk) { return Mod(chunk, 32).ToString(); } private string LocalBlockFromChunk (int chunk) { return "(0 to 15)"; } // Region Set private string ChunkFromRegion (int region) { int start = region * 32; int end = (region + 1) * 32 - 1; return string.Format("({0} to {1})", start, end); } private string BlockFromRegion (int region) { int start = region * 32 * 16; int end = (region + 1) * 32 * 16 - 1; return string.Format("({0} to {1})", start, end); } private string LocalChunkFromRegion (int region) { return "(0 to 31)"; } private string LocalBlockFromRegion (int region) { return "(0 to 15)"; } // Local Chunk Set private string RegionFromLocalChunk (int localChunk) { return "(ANY)"; } private string ChunkFromLocalChunk (int localChunk) { return "(ANY)"; } private string ChunkFromLocalChunk (int region, int localChunk) { return (region * 32 + localChunk).ToString(); } private string BlockFromLocalChunk (int localChunk) { return "(ANY)"; } private string BlockFromLocalChunk (int region, int localChunk) { return BlockFromChunk(region * 32 + localChunk); } private string LocalBlockFromLocalChunk (int localChunk) { return "(0 to 15)"; } private string LocalBlockFromLocalChunk (int region, int localChunk) { return "(0 to 15)"; } // Local Block Set private string RegionFromLocalBlock (int localBlock) { return "(ANY)"; } private string ChunkFromLocalBlock (int localBlock) { return "(ANY)"; } private string ChunkFromLocalBlock (int region, int localChunk, int localBlock) { return (region * 32 + localChunk).ToString(); } private string BlockFromLocalBlock (int localBlock) { return "(ANY)"; } private string BlockFromLocalBlock (int region, int localChunk, int localBlock) { return (region * 32 * 16 + localChunk * 16 + localBlock).ToString(); } private int? ParseInt (string value) { int parsedValue; if (int.TryParse(value, out parsedValue)) return parsedValue; else return null; } private void ApplyValueToTextBox (WatermarkTextBox textBox, string value, bool primary) { if (primary) textBox.ApplyText(value); else textBox.ApplyWatermark(value); } private void ApplyRegion (CoordinateGroup group, string value, bool primary) { group.Region = ParseInt(value); ApplyValueToTextBox(group.RegionBox, value, primary); if (primary && group.Region.HasValue) { if (group.LocalChunk.HasValue && !group.LocalChunkBox.WatermarkActive) { ApplyChunk(group, ChunkFromLocalChunk(group.Region.Value, group.LocalChunk.Value), false); if (group.LocalBlock.HasValue && !group.LocalBlockBox.WatermarkActive) ApplyBlock(group, BlockFromLocalBlock(group.Region.Value, group.LocalChunk.Value, group.LocalBlock.Value), false); else { ApplyBlock(group, BlockFromLocalChunk(group.Region.Value, group.LocalChunk.Value), false); ApplyLocalBlock(group, LocalBlockFromLocalChunk(group.Region.Value, group.LocalChunk.Value), false); } } else { ApplyChunk(group, ChunkFromRegion(group.Region.Value), false); ApplyBlock(group, BlockFromRegion(group.Region.Value), false); ApplyLocalChunk(group, LocalChunkFromRegion(group.Region.Value), false); ApplyLocalBlock(group, LocalBlockFromRegion(group.Region.Value), false); } } } private void ApplyChunk (CoordinateGroup group, string value, bool primary) { group.Chunk = ParseInt(value); ApplyValueToTextBox(group.ChunkBox, value, primary); if (primary && group.Chunk.HasValue) { ApplyRegion(group, RegionFromChunk(group.Chunk.Value), false); ApplyLocalChunk(group, LocalChunkFromChunk(group.Chunk.Value), false); if (group.LocalBlock.HasValue && !group.LocalBlockBox.WatermarkActive) ApplyBlock(group, BlockFromChunk(group.Chunk.Value, group.LocalBlock.Value), false); else { ApplyBlock(group, BlockFromChunk(group.Chunk.Value), false); ApplyLocalBlock(group, LocalBlockFromChunk(group.Chunk.Value), false); } } } private void ApplyBlock (CoordinateGroup group, string value, bool primary) { group.Block = ParseInt(value); ApplyValueToTextBox(group.BlockBox, value, primary); if (primary && group.Block.HasValue) { ApplyRegion(group, RegionFromBlock(group.Block.Value), false); ApplyChunk(group, ChunkFromBlock(group.Block.Value), false); ApplyLocalChunk(group, LocalChunkFromBlock(group.Block.Value), false); ApplyLocalBlock(group, LocalBlockFromBlock(group.Block.Value), false); } } private void ApplyLocalChunk (CoordinateGroup group, string value, bool primary) { group.LocalChunk = ParseInt(value); ApplyValueToTextBox(group.LocalChunkBox, value, primary); if (primary && group.LocalChunk.HasValue) { if (group.Region.HasValue) { ApplyChunk(group, ChunkFromLocalChunk(group.Region.Value, group.LocalChunk.Value), false); if (group.LocalBlock.HasValue && !group.LocalBlockBox.WatermarkActive) ApplyBlock(group, BlockFromLocalBlock(group.Region.Value, group.LocalChunk.Value, group.LocalBlock.Value), false); else { ApplyBlock(group, BlockFromLocalChunk(group.Region.Value, group.LocalChunk.Value), false); ApplyLocalBlock(group, LocalBlockFromLocalChunk(group.Region.Value, group.LocalChunk.Value), false); } } else { ApplyRegion(group, RegionFromLocalChunk(group.LocalChunk.Value), false); ApplyChunk(group, ChunkFromLocalChunk(group.LocalChunk.Value), false); ApplyBlock(group, BlockFromLocalChunk(group.LocalChunk.Value), false); ApplyLocalBlock(group, LocalBlockFromLocalChunk(group.LocalChunk.Value), false); } } } private void ApplyLocalBlock (CoordinateGroup group, string value, bool primary) { group.LocalBlock = ParseInt(value); ApplyValueToTextBox(group.LocalBlockBox, value, primary); if (primary && group.LocalBlock.HasValue) { if (group.Region.HasValue && group.LocalChunk.HasValue && !group.LocalChunkBox.WatermarkActive) { ApplyChunk(group, ChunkFromLocalBlock(group.Region.Value, group.LocalChunk.Value, group.LocalBlock.Value), false); ApplyBlock(group, BlockFromLocalBlock(group.Region.Value, group.LocalChunk.Value, group.LocalBlock.Value), false); } else { ApplyRegion(group, RegionFromLocalBlock(group.LocalBlock.Value), false); ApplyChunk(group, ChunkFromLocalBlock(group.LocalBlock.Value), false); ApplyBlock(group, BlockFromLocalBlock(group.LocalBlock.Value), false); } } } private void Validate () { if (_groupX.LocalChunk.HasValue && _groupZ.LocalChunk.HasValue) _findButton.Enabled = true; else _findButton.Enabled = false; } private void _regionXTextBox_TextChanged (object sender, EventArgs e) { int region = 0; if (_inUpdate || !int.TryParse(_regionXTextBox.Text, out region)) return; _inUpdate = true; ApplyRegion(_groupX, _regionXTextBox.Text, true); _inUpdate = false; Validate(); } private void _regionZTextBox_TextChanged (object sender, EventArgs e) { int region = 0; if (_inUpdate || !int.TryParse(_regionZTextBox.Text, out region)) return; _inUpdate = true; ApplyRegion(_groupZ, _regionZTextBox.Text, true); _inUpdate = false; Validate(); } private void _chunkXTextBox_TextChanged (object sender, EventArgs e) { int chunk = 0; if (_inUpdate || !int.TryParse(_chunkXTextBox.Text, out chunk)) return; _inUpdate = true; ApplyChunk(_groupX, _chunkXTextBox.Text, true); _inUpdate = false; Validate(); } private void _chunkZTextBox_TextChanged (object sender, EventArgs e) { int chunk = 0; if (_inUpdate || !int.TryParse(_chunkZTextBox.Text, out chunk)) return; _inUpdate = true; ApplyChunk(_groupZ, _chunkZTextBox.Text, true); _inUpdate = false; Validate(); } private void _blockXTextBox_TextChanged (object sender, EventArgs e) { int block = 0; if (_inUpdate || !int.TryParse(_blockXTextBox.Text, out block)) return; _inUpdate = true; ApplyBlock(_groupX, _blockXTextBox.Text, true); _inUpdate = false; Validate(); } private void _blockZTextBox_TextChanged (object sender, EventArgs e) { int block = 0; if (_inUpdate || !int.TryParse(_blockZTextBox.Text, out block)) return; _inUpdate = true; ApplyBlock(_groupZ, _blockZTextBox.Text, true); _inUpdate = false; Validate(); } private void _localChunkXTextBox_TextChanged (object sender, EventArgs e) { int localChunk = 0; if (_inUpdate || !int.TryParse(_localChunkXTextBox.Text, out localChunk)) return; _inUpdate = true; ApplyLocalChunk(_groupX, _localChunkXTextBox.Text, true); _inUpdate = false; Validate(); } private void _localChunkZTextBox_TextChanged (object sender, EventArgs e) { int localChunk = 0; if (_inUpdate || !int.TryParse(_localChunkZTextBox.Text, out localChunk)) return; _inUpdate = true; ApplyLocalChunk(_groupZ, _localChunkZTextBox.Text, true); _inUpdate = false; Validate(); } private void _localBlockXTextBox_TextChanged (object sender, EventArgs e) { int localBlock = 0; if (_inUpdate || !int.TryParse(_localBlockXTextBox.Text, out localBlock)) return; _inUpdate = true; ApplyLocalBlock(_groupX, _localBlockXTextBox.Text, true); _inUpdate = false; Validate(); } private void _localBlockZTextBox_TextChanged (object sender, EventArgs e) { int localBlock = 0; if (_inUpdate || !int.TryParse(_localBlockZTextBox.Text, out localBlock)) return; _inUpdate = true; ApplyLocalBlock(_groupZ, _localBlockZTextBox.Text, true); _inUpdate = false; Validate(); } private void _findButton_Click (object sender, EventArgs e) { _searchResult = Search(_searchRoot); DialogResult = DialogResult.OK; Close(); } private void _cancelButton_Click (object sender, EventArgs e) { DialogResult = DialogResult.Cancel; Close(); } } }