using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using Vintagestory.API.Client; using Vintagestory.API.Common; using Vintagestory.API.MathTools; namespace Automap { public static class Helpers { /// /// Hue, Saturation Value colorspace /// /// The color equiv. /// 0 - 360 for hue. /// 0 - 1 for saturation or value.. /// 0 - 1 for saturation or value.. public static Color FromHSV(double hue, double saturation, double value) { int hi = Convert.ToInt32(Math.Floor(hue / 60)) % 6; double f = hue / 60 - Math.Floor(hue / 60); value = value * 255; int v = Convert.ToInt32(value); int p = Convert.ToInt32(value * (1 - saturation)); int q = Convert.ToInt32(value * (1 - f * saturation)); int t = Convert.ToInt32(value * (1 - (1 - f) * saturation)); if (hi == 0) return Color.FromArgb(255, v, t, p); else if (hi == 1) return Color.FromArgb(255, q, v, p); else if (hi == 2) return Color.FromArgb(255, p, v, t); else if (hi == 3) return Color.FromArgb(255, p, q, v); else if (hi == 4) return Color.FromArgb(255, t, p, v); else return Color.FromArgb(255, v, p, q); } public static string PrettyCoords(this BlockPos location, ICoreClientAPI ClientApi) { var start = ClientApi.World.DefaultSpawnPosition.AsBlockPos; return string.Format("X{0}, Y{1}, Z{2}", location.X - start.X, location.Y, location.Z - start.Z ); } public static BlockPos AverageHighestPos(List positions) { int x = 0, y = 0, z = 0, length = positions.Count; foreach (BlockPos pos in positions) { x += pos.X; y = Math.Max(y, pos.Y);//Mutant Y-axis, take "HIGHEST" z += pos.Z; } return new BlockPos(x/ length, y, z / length); } public static BlockPos PickRepresentativePosition(List positions) { var averagePos = AverageHighestPos( positions ); if ( positions.Any( pos => pos.X == averagePos.X && pos.Y == averagePos.Y && pos.Z == averagePos.Z ) ) { return averagePos;//lucky ~ center was it! } //Otherwise...pick one var whichever = positions.Last(poz => poz.Y == averagePos.Y); return whichever; } /// /// Find a BLOCK partial path match: BlockID /// /// Matching finds /// Asset name. public static Dictionary ArbitrarytBlockIdHunter(this ICoreAPI CoreApi ,AssetLocation assetName, EnumBlockMaterial? material = null) { Dictionary arbBlockIDTable = new Dictionary( ); uint emptyCount = 0; if (CoreApi.World.Blocks != null) { #if DEBUG CoreApi.World.Logger.VerboseDebug(" World Blocks [Count: {0}]", CoreApi.World.Blocks.Count); #endif //If Brute force won't work; use GROOT FORCE! //var theBlock = ClientApi.World.BlockAccessor.GetBlock(0); if (!material.HasValue) { foreach (Block blk in CoreApi.World.Blocks) { if (blk.IsMissing || blk.Id == 0 || blk.BlockId == 0) { emptyCount++; } else if (blk.Code != null && blk.Code.BeginsWith(assetName.Domain, assetName.Path)) { #if DEBUG //CoreApi.World.Logger.VerboseDebug("Block: [{0} ({1})] = #{2}", blk.Code.Path, blk.BlockMaterial, blk.BlockId); #endif arbBlockIDTable.Add(blk.BlockId, blk.Code.Path); } } } else { foreach (Block blk in CoreApi.World.Blocks) { if (blk.IsMissing || blk.Id == 0 || blk.BlockId == 0) { emptyCount++; } else if (blk.Code != null && material.Value == blk.BlockMaterial && blk.Code.BeginsWith(assetName.Domain, assetName.Path)) { #if DEBUG //CoreApi.World.Logger.VerboseDebug("Block: [{0} ({1})] = #{2}", blk.Code.Path, blk.BlockMaterial, blk.BlockId); #endif arbBlockIDTable.Add(blk.BlockId, blk.Code.Path); } } } #if DEBUG CoreApi.World.Logger.VerboseDebug("Block gaps: {0}", emptyCount); #endif } return arbBlockIDTable; } /// /// Chunk local index. Not block position! /// /// Clamps to 5 bit ranges automagically public static int ChunkBlockIndicie16(int X_index, int Y_index, int Z_index) { return ((Y_index & 31) * 32 + (Z_index & 31)) * 32 + (X_index & 31); } /// /// Chunk index converted from block position (in world) /// /// The block indicie. /// Block position. /// Clamps to 5 bit ranges automagically public static int ChunkBlockIndicie16(BlockPos blockPos) { //Chunk masked return ((blockPos.Y & 31) * 32 + (blockPos.Z & 31)) * 32 + (blockPos.X & 31); } } }