public static partial void CustomBinaryEndExport(MutagenWriter writer, IWorldspaceGetter obj) { try { var topCell = obj.TopCell; var subCells = obj.SubCells; if (subCells?.Count == 0 && topCell == null) { return; } using (HeaderExport.Header(writer, RecordTypes.GRUP, ObjectType.Group)) { FormKeyBinaryTranslation.Instance.Write( writer, obj.FormKey); writer.Write((int)GroupTypeEnum.WorldChildren); writer.Write(obj.SubCellsTimestamp); writer.Write(obj.SubCellsUnknown); topCell?.WriteToBinary(writer); ListBinaryTranslation <IWorldspaceBlockGetter> .Instance.Write( writer : writer, items : subCells, transl : (MutagenWriter subWriter, IWorldspaceBlockGetter subItem) => { subItem.WriteToBinary(subWriter); }); } } catch (Exception ex) { throw RecordException.Enrich(ex, obj); } }
static partial void CustomBinaryEndExport(MutagenWriter writer, IWorldspaceGetter obj) { var road = obj.Road; var topCell = obj.TopCell; var subCells = obj.SubCells; if (subCells?.Count == 0 && road == null && topCell == null) { return; } using (HeaderExport.Header(writer, RecordTypes.GRUP, ObjectType.Group)) { FormKeyBinaryTranslation.Instance.Write( writer, obj.FormKey); writer.Write((int)GroupTypeEnum.WorldChildren); writer.Write(obj.SubCellsTimestamp); road?.WriteToBinary(writer); topCell?.WriteToBinary(writer); Mutagen.Bethesda.Binary.ListBinaryTranslation <IWorldspaceBlockGetter> .Instance.Write( writer : writer, items : subCells, transl : (MutagenWriter subWriter, IWorldspaceBlockGetter subItem) => { subItem.WriteToBinary(subWriter); }); } }
internal static IEnumerable <IModContext <IOblivionMod, IOblivionModGetter, IMajorRecordCommon, IMajorRecordCommonGetter> > EnumerateMajorRecordContexts( this IReadOnlyList <IWorldspaceBlockGetter> worldspaceBlocks, IWorldspaceGetter worldspace, ILinkCache linkCache, Type type, ModKey modKey, IModContext?parent, bool throwIfUnknown, Func <IOblivionMod, IWorldspaceGetter, IWorldspace> getOrAddAsOverride) { foreach (var readOnlyBlock in worldspaceBlocks) { var blockNumX = readOnlyBlock.BlockNumberX; var blockNumY = readOnlyBlock.BlockNumberY; var blockModified = readOnlyBlock.LastModified; var blockContext = new ModContext <IWorldspaceBlockGetter>( modKey: modKey, parent: parent, record: readOnlyBlock); foreach (var readOnlySubBlock in readOnlyBlock.Items) { var subBlockNumY = readOnlySubBlock.BlockNumberY; var subBlockNumX = readOnlySubBlock.BlockNumberX; var subBlockModified = readOnlySubBlock.LastModified; var subBlockContext = new ModContext <IWorldspaceSubBlockGetter>( modKey: modKey, parent: blockContext, record: readOnlySubBlock); foreach (var readOnlyCell in readOnlySubBlock.Items) { Func <IOblivionMod, ICellGetter, bool, string?, ICell> cellGetter = (mod, copyCell, dup, edid) => { var worldspaceCopy = getOrAddAsOverride(mod, worldspace); var formKey = copyCell.FormKey; var retrievedBlock = worldspaceCopy.SubCells.FirstOrDefault(x => x.BlockNumberX == blockNumX && x.BlockNumberY == blockNumY); if (retrievedBlock == null) { retrievedBlock = new WorldspaceBlock() { BlockNumberX = blockNumX, BlockNumberY = blockNumY, GroupType = GroupTypeEnum.ExteriorCellBlock, LastModified = blockModified, }; worldspaceCopy.SubCells.Add(retrievedBlock); } var subBlock = retrievedBlock.Items.FirstOrDefault(x => x.BlockNumberX == subBlockNumX && x.BlockNumberY == subBlockNumY); if (subBlock == null) { subBlock = new WorldspaceSubBlock() { BlockNumberX = subBlockNumX, BlockNumberY = subBlockNumY, GroupType = GroupTypeEnum.ExteriorCellSubBlock, LastModified = readOnlySubBlock.LastModified, }; retrievedBlock.Items.Add(subBlock); } var cell = subBlock.Items.FirstOrDefault(cell => cell.FormKey == formKey); if (cell == null) { if (dup) { cell = copyCell.Duplicate(mod.GetNextFormKey(edid), CellCopyMask); } else { cell = copyCell.DeepCopy(CellCopyMask); } subBlock.Items.Add(cell); } return(cell); }; if (LoquiRegistration.TryGetRegister(type, out var regis) && regis.ClassType == typeof(Cell)) { yield return(new ModContext <IOblivionMod, IOblivionModGetter, IMajorRecordCommon, IMajorRecordCommonGetter>( modKey: modKey, record: readOnlyCell, getOrAddAsOverride: (m, r) => cellGetter(m, (ICellGetter)r, false, default(string?)), duplicateInto: (m, r, e) => cellGetter(m, (ICellGetter)r, true, e), parent: subBlockContext)); } else { foreach (var con in CellCommon.Instance.EnumerateMajorRecordContexts( readOnlyCell, linkCache, type, modKey, subBlockContext, throwIfUnknown, (m, c) => cellGetter(m, c, false, default(string?)), (m, c, e) => cellGetter(m, c, true, e))) { yield return(con); } } } } } }
void CreateFromWorld(IWorldspaceGetter wrld) { const int cellsize = 33; // Each cell has 33 x 33 datapoints. Some of those are double, which we don't care about, it will just look more gridlike. const int maxheight = 9771; // -4842 is the lowest point of the map. 9771 is the total max const int minheight = 4842; // These are just used to calculate the color of each pixel later. const int worldwidthincells = 118; // How many cells the world is in X and Y const int worldheightincells = 95; Bitmap bitmap = new Bitmap(cellsize * worldwidthincells, cellsize * worldheightincells, System.Drawing.Imaging.PixelFormat.Format48bppRgb); const int pixelsize = 6; // Each pixel is 6 bytes long byte[] outBuffer = new byte[bitmap.Width * bitmap.Height * pixelsize]; foreach (var block in wrld.SubCells) { foreach (var subblock in block.Items) { bool black = false; foreach (var cell in subblock.Items) { //if (cell.Grid == null) continue; int cell_x_normalized = cell.Grid.Point.X + 57; // -57 and -43 are the lowest numbers respectively int cell_y_normalized = cell.Grid.Point.Y + 43; if (!cell.Landscape.TryGet(out var land) || land.VertexHeightMap == null) { continue; } float[,] heightmap = ParseHeights(land.VertexHeightMap.Value); for (int y = 0; y < cellsize; y++) { int rowoffsetbytes = ( (cell_y_normalized * bitmap.Width * cellsize) + (y * bitmap.Width) + (cell_y_normalized != 0 ? -bitmap.Width : 0) ) * pixelsize; // this is the offset, in bytes, to find the correct row in the buffer for (int x = 0; x < cellsize; x++) { // Decide the color of the pixel float percent = (heightmap[y, x] + minheight) / maxheight; ushort color = (ushort)(ushort.MaxValue * percent); //ushort color = ushort.MaxValue / 2; // byte[] snippet = BitConverter.GetBytes(color).Concat(BitConverter.GetBytes(color)).Concat(BitConverter.GetBytes(color)).ToArray(); // converted to byte array // Figure out what position to put it in int column = ( (cell_x_normalized * cellsize) + x + (cell_x_normalized != 0 ? -1 : 0) ) * pixelsize; // offset, in positions, in the row int position = rowoffsetbytes + column; // if(position < outBuffer.Length) // { snippet.CopyTo(outBuffer, position); // } } } black = !black; } } } // Lock the unmanaged bits for efficient writing. var data = bitmap.LockBits( new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat); // Bulk copy pixel data from a byte array: Marshal.Copy(outBuffer, 0, data.Scan0, outBuffer.Length); // When finished, unlock the unmanaged bits bitmap.UnlockBits(data); picture.Width = bitmap.Width; picture.Height = bitmap.Height; picture.Image = bitmap; bitmap.Save(@"C:\debug\tamriel.bmp"); }
public (float, float) FindMinMax(IWorldspaceGetter worldspace) { float minheight = float.MaxValue; float maxheight = float.MaxValue; int mincellx = int.MaxValue; int maxcellx = int.MaxValue; int mincelly = int.MaxValue; int maxcelly = int.MaxValue; /* * foreach (var block in worldspace.SubCells) * { * foreach (var subblock in block.Items) * { * foreach (var subcell in subblock.Items) * { * var land = subcell.Landscape; * float[,] heightmap = ParseHeights((Noggog.ReadOnlyMemorySlice<byte>)land.VertexHeightMap); * foreach (var pos in heightmap) * { * if (minheight == float.MaxValue || minheight > pos) * { * minheight = pos; * } * if (maxheight == float.MaxValue || maxheight < pos) * { * maxheight = pos; * } * * if (maxcellx == int.MaxValue || maxcellx < subcell.Grid.Point.X) * { * maxcellx = subcell.Grid.Point.X; * } * * if (mincellx == int.MaxValue || mincellx > subcell.Grid.Point.X) * { * mincellx = subcell.Grid.Point.X; * } * * if (maxcelly == int.MaxValue || maxcelly < subcell.Grid.Point.Y) * { * maxcelly = subcell.Grid.Point.Y; * } * * if (mincelly == int.MaxValue || mincelly > subcell.Grid.Point.Y) * { * mincelly = subcell.Grid.Point.Y; * } * } * * //txtDebug.Text += subcell.EditorID; * * if (subcell.EditorID == "Whiterun") * { * txtDebug.Text += "Woop, whiterun"; * CreateFromCell(heightmap); * } * } * } * //CreateFromBlock(block); * }*/ //txtDebug.Text += "Min cell X: " + mincellx + " Max cell X: " + maxcellx + " Min cell y: " + mincelly + " Max cell y: " + maxcelly; // txtDebug.Text += "Minheight: " + minheight + " Maxheight: " + maxheight + "\r\n"; CreateFromWorld(worldspace); return(minheight, maxheight); }
internal static IEnumerable <IModContext <ISkyrimMod, IMajorRecordCommon, IMajorRecordCommonGetter> > EnumerateMajorRecordContexts( this IReadOnlyList <IWorldspaceBlockGetter> worldspaceBlocks, IWorldspaceGetter worldspace, ILinkCache linkCache, Type type, ModKey modKey, IModContext?parent, bool throwIfUnknown, Func <ISkyrimMod, IWorldspaceGetter, IWorldspace> getter) { foreach (var readOnlyBlock in worldspaceBlocks) { var blockNumX = readOnlyBlock.BlockNumberX; var blockNumY = readOnlyBlock.BlockNumberY; var blockContext = new ModContext <IWorldspaceBlockGetter>( modKey: modKey, parent: parent, record: readOnlyBlock); foreach (var readOnlySubBlock in readOnlyBlock.Items) { var subBlockNumY = readOnlySubBlock.BlockNumberY; var subBlockNumX = readOnlySubBlock.BlockNumberX; var subBlockContext = new ModContext <IWorldspaceSubBlockGetter>( modKey: modKey, parent: blockContext, record: readOnlySubBlock); foreach (var readOnlyCell in readOnlySubBlock.Items) { Func <ISkyrimMod, ICellGetter, ICell> cellGetter = (mod, copyCell) => { var worldspaceCopy = getter(mod, worldspace); var formKey = copyCell.FormKey; var retrievedBlock = worldspaceCopy.SubCells.FirstOrDefault(x => x.BlockNumberX == blockNumX && x.BlockNumberY == blockNumY); if (retrievedBlock == null) { retrievedBlock = new WorldspaceBlock() { BlockNumberX = blockNumX, BlockNumberY = blockNumY, GroupType = GroupTypeEnum.ExteriorCellBlock, }; worldspaceCopy.SubCells.Add(retrievedBlock); } var subBlock = retrievedBlock.Items.FirstOrDefault(x => x.BlockNumberX == subBlockNumX && x.BlockNumberY == subBlockNumY); if (subBlock == null) { subBlock = new WorldspaceSubBlock() { BlockNumberX = subBlockNumX, BlockNumberY = subBlockNumY, GroupType = GroupTypeEnum.ExteriorCellSubBlock, }; retrievedBlock.Items.Add(subBlock); } var cell = subBlock.Items.FirstOrDefault(cell => cell.FormKey == formKey); if (cell == null) { cell = copyCell.DeepCopy(CellCopyMask); subBlock.Items.Add(cell); } return(cell); }; if (LoquiRegistration.TryGetRegister(type, out var regis) && regis.ClassType == typeof(Cell)) { yield return(new ModContext <ISkyrimMod, IMajorRecordCommon, IMajorRecordCommonGetter>( modKey: modKey, record: readOnlyCell, getter: (m, r) => cellGetter(m, (ICellGetter)r), parent: subBlockContext)); } else { foreach (var con in CellCommon.Instance.EnumerateMajorRecordContexts(readOnlyCell, linkCache, type, modKey, subBlockContext, throwIfUnknown, cellGetter)) { yield return(con); } } } } } }