Skip to content

Instantly share code, notes, and snippets.

@HurricanKai
Created September 28, 2018 10:07
Show Gist options
  • Save HurricanKai/e5f484233652e5728aa67b9cb5538cc7 to your computer and use it in GitHub Desktop.
Save HurricanKai/e5f484233652e5728aa67b9cb5538cc7 to your computer and use it in GitHub Desktop.
malformed byte around byte 1
using AutoSerialize;
using SM2.Core.BaseTypes;
using SM2.Core.Server;
using SM2.Dimensions;
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using System.Threading.Tasks;
using System.IO;
using SM2.Blocks;
namespace SM2.Packets
{
public class ChunkData : Packet
{
public override ConnectionState RequiredState { get; } = ConnectionState.Play;
public override ConnectionSide WritingSide { get; } = ConnectionSide.Server;
public override VarInt Id { get; } = 0x22;
[AutoSerialize(0)]
public int ChunkX;
[AutoSerialize(1)]
public int ChunkZ;
[AutoSerialize(2)]
public bool GroundUpContinous;
[AutoSerialize(4)]
[NoLength]
public byte[] Data;
//TODO: Implement NBT Entities
const int CHUNK_HEIGHT = Chunk.ChunkSizeY;
const int SECTION_HEIGHT = Chunk.SectionHeight;
const int SECTION_WIDTH = Chunk.ChunkSizeX; // or ChunkSizeZ it doesnt matter
public override async Task PreWrite()
{
if (!GroundUpContinous)
throw new NotImplementedException("Ouuh, pls no");
var chunkPos = new Vector2(ChunkX, ChunkZ);
Console.WriteLine($"Writing ChunkData {ChunkX}, {ChunkZ}");
var uByte = _ctx.Provider.GetService<ITypeAccessor<Byte>>();
var VarInt = _ctx.Provider.GetService<ITypeAccessor<VarInt>>();
var Int = _ctx.Provider.GetService<ITypeAccessor<int>>();
var chunk = _ctx.Player.Dimension.GetChunk(chunkPos);
using (var data = new MemoryStream())
{
int mask = 0;
using (var columnBuffer = new MemoryStream())
{
for (int sectionY = 0; sectionY < (CHUNK_HEIGHT / SECTION_HEIGHT); sectionY++)
{
if (chunk[sectionY].AnyOther<Air>())
{
mask |= (1 << sectionY); // Set that bit to true in the mask
WriteChunkSection(chunk[sectionY], columnBuffer);
}
}
if (GroundUpContinous)
{
var biomes = new int[256];
for (int z = 0; z < SECTION_WIDTH - 1; z++)
{
for (int x = 0; x < SECTION_WIDTH - 1; x++)
{
biomes[z * 16 | x] = 127;
}
}
Int.WriteArray(columnBuffer, biomes);
}
VarInt.Write(data, mask);
VarInt.Write(data, (int)columnBuffer.Position);
columnBuffer.Position = 0;
columnBuffer.CopyTo(data);
}
// If you don't support block entities yet, use 0
// If you need to implement it by sending block entities later with the update block entity packet,
// do it that way and send 0 as well. (Note that 1.10.1 (not 1.10 or 1.10.2) will not accept that)
VarInt.Write(data, 0);
Data = data.ToArray();
}
await base.PreWrite();
}
private void WriteChunkSection(ChunkSection section, MemoryStream buf)
{
var uByte = _ctx.Provider.GetService<ITypeAccessor<Byte>>();
var VarInt = _ctx.Provider.GetService<ITypeAccessor<VarInt>>();
var Int = _ctx.Provider.GetService<ITypeAccessor<int>>();
var ULong = _ctx.Provider.GetService<ITypeAccessor<ulong>>();
byte bitsPerBlock = 14;
uByte.Write(buf, bitsPerBlock);
uByte.Write(buf, 9);
int dataLength = (16 * 16 * 16) * bitsPerBlock / 64; // See tips section for an explanation of this calculation
UInt64[] data = new UInt64[dataLength];
// A bitmask that contains bitsPerBlock set bits
uint individualValueMask = (uint)((1 << bitsPerBlock) - 1);
for (int y = 0; y < SECTION_HEIGHT - 1; y++)
{
for (int z = 0; z < SECTION_WIDTH - 1; z++)
{
for (int x = 0; x < SECTION_WIDTH - 1; x++)
{
var relPos = new Position(x, y, z);
int blockNumber = (((relPos.Y * SECTION_HEIGHT) + relPos.Z) * SECTION_WIDTH) + relPos.X;
int startLong = (blockNumber * bitsPerBlock) / 64;
int startOffset = (blockNumber * bitsPerBlock) % 64;
int endLong = ((blockNumber + 1) * bitsPerBlock - 1) / 64;
UInt64 value = (ulong)section[relPos].GetState();
value &= individualValueMask;
data[startLong] |= (value << startOffset);
if (startLong != endLong)
{
data[endLong] = (value >> (64 - startOffset));
}
}
}
}
VarInt.Write(buf, dataLength);
ULong.WriteArray(buf, data);
for (int y = 0; y < SECTION_HEIGHT; y++)
{
for (int z = 0; z < SECTION_WIDTH; z++)
{
for (int x = 0; x < SECTION_WIDTH; x += 2)
{
// Note: x += 2 above; we read 2 values along x each time
//byte value = section.GetBlockLight(x, y, z) | (section.GetBlockLight(x + 1, y, z) << 4);
byte value = (12) | ((12) << 4);
uByte.Write(buf, value);
}
}
}
if (/*currentDimension.HasSkylight()*/true)
{ // IE, current dimension is overworld / 0
for (int y = 0; y < SECTION_HEIGHT; y++)
{
for (int z = 0; z < SECTION_WIDTH; z++)
{
for (int x = 0; x < SECTION_WIDTH; x += 2)
{
// Note: x += 2 above; we read 2 values along x each time
//byte value = section.GetSkyLight(x, y, z) | (section.GetSkyLight(x + 1, y, z) << 4);
byte value = (12) | ((12) << 4);
uByte.Write(buf, value);
}
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment