server -> client tile sync

This commit is contained in:
jacob 2026-01-16 20:54:12 -06:00
parent 27c337202d
commit f88c33e332
20 changed files with 945 additions and 2204 deletions

View File

@ -482,9 +482,9 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
ASE_DecodedImage result = Zi;
BB_Buff bb = BB_BuffFromString(encoded);
BB_Reader br = BB_ReaderFromBuffNoDebug(&bb);
BB_Reader bbr = BB_ReaderFromBuffNoDebug(&bb);
ASE_Header ase_header;
BB_ReadBytes(&br, StringFromStruct(&ase_header));
BB_ReadBytes(&bbr, StringFromStruct(&ase_header));
if (ase_header.magic != 0xA5E0)
{
@ -530,7 +530,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
for (u16 i = 0; i < ase_header.frames; ++i)
{
ASE_FrameHeader frame_header;
BB_ReadBytes(&br, StringFromStruct(&frame_header));
BB_ReadBytes(&bbr, StringFromStruct(&frame_header));
u32 num_chunks = frame_header.chunks_new;
if (num_chunks == 0)
@ -544,20 +544,20 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
for (u32 j = 0; j < num_chunks; ++j)
{
u32 chunk_size = BB_ReadUBits(&br, 32);
ASE_ChunkKind chunk_type = BB_ReadUBits(&br, 16);
u32 chunk_size = BB_ReadUBits(&bbr, 32);
ASE_ChunkKind chunk_type = BB_ReadUBits(&bbr, 16);
// Chunk size includes size & type
Assert(chunk_size >= 6);
chunk_size -= 6;
u64 chunk_end_pos = BB_GetCurrentReaderByte(&br) + chunk_size;
u64 chunk_end_pos = BB_GetCurrentReaderByte(&bbr) + chunk_size;
switch (chunk_type)
{
default:
{
BB_ReadSeekToByte(&br, chunk_end_pos);
BB_ReadSeekToByte(&bbr, chunk_end_pos);
} break;
//////////////////////////////
@ -569,14 +569,14 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
layer->next = layer_head;
layer_head = layer;
layer->flags = BB_ReadUBits(&br, 16);
layer->type = BB_ReadUBits(&br, 16);
layer->child_level = BB_ReadUBits(&br, 16);
layer->flags = BB_ReadUBits(&bbr, 16);
layer->type = BB_ReadUBits(&bbr, 16);
layer->child_level = BB_ReadUBits(&bbr, 16);
// Ignoring layer default width & height
BB_ReadSeekBytes(&br, sizeof(u16) * 2);
BB_ReadSeekBytes(&bbr, sizeof(u16) * 2);
layer->blend_mode = BB_ReadUBits(&br, 16);
layer->blend_mode = BB_ReadUBits(&bbr, 16);
if (layer->blend_mode != 0)
{
ASE_PushError(
@ -587,21 +587,21 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
goto abort;
}
layer->opacity = BB_ReadUBits(&br, 8);
layer->opacity = BB_ReadUBits(&bbr, 8);
if (!(ase_header.flags & 1))
{
layer->opacity = 255;
}
BB_ReadSeekBytes(&br, sizeof(u8) * 3);
BB_ReadSeekBytes(&bbr, sizeof(u8) * 3);
u16 str_len = BB_ReadUBits(&br, 16);
u16 str_len = BB_ReadUBits(&bbr, 16);
layer->name = (String) { str_len, PushStructsNoZero(scratch.arena, u8, str_len) };
BB_ReadBytes(&br, layer->name);
BB_ReadBytes(&bbr, layer->name);
if (layer->type == 2)
{
layer->tileset_index = BB_ReadUBits(&br, 32);
layer->tileset_index = BB_ReadUBits(&bbr, 32);
}
layer->index = num_layers++;
@ -623,13 +623,13 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
}
cel_tail = cel;
cel->layer_index = BB_ReadUBits(&br, 16);
cel->x_pos = BB_ReadIBits(&br, 16);
cel->y_pos = BB_ReadIBits(&br, 16);
cel->opacity = BB_ReadUBits(&br, 8);
cel->type = BB_ReadUBits(&br, 16);
cel->z_index = BB_ReadIBits(&br, 16);
BB_ReadSeekBytes(&br, sizeof(u8) * 5);
cel->layer_index = BB_ReadUBits(&bbr, 16);
cel->x_pos = BB_ReadIBits(&bbr, 16);
cel->y_pos = BB_ReadIBits(&bbr, 16);
cel->opacity = BB_ReadUBits(&bbr, 8);
cel->type = BB_ReadUBits(&bbr, 16);
cel->z_index = BB_ReadIBits(&bbr, 16);
BB_ReadSeekBytes(&bbr, sizeof(u8) * 5);
cel->frame_index = num_frames;
@ -638,22 +638,22 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
case ASE_CelKind_RawImage:
{
// Unsupported
BB_ReadSeekToByte(&br, chunk_end_pos);
BB_ReadSeekToByte(&bbr, chunk_end_pos);
} break;
case ASE_CelKind_Linked:
{
cel->frame_pos = BB_ReadUBits(&br, 16);
cel->frame_pos = BB_ReadUBits(&bbr, 16);
// Actual linking happens later after iteration
} break;
case ASE_CelKind_CompressedImage:
{
cel->width = BB_ReadUBits(&br, 16);
cel->height = BB_ReadUBits(&br, 16);
cel->width = BB_ReadUBits(&bbr, 16);
cel->height = BB_ReadUBits(&bbr, 16);
cel->pixels = PushStructsNoZero(scratch.arena, u32, cel->width * cel->height);
u8 *huffman_encoded = BB_ReadBytesRaw(&br, chunk_end_pos - BB_GetCurrentReaderByte(&br));
u8 *huffman_encoded = BB_ReadBytesRaw(&bbr, chunk_end_pos - BB_GetCurrentReaderByte(&bbr));
if (huffman_encoded)
{
ASE_Inflate((u8 *)cel->pixels, huffman_encoded);
@ -770,7 +770,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
}
// Assert all data was read
Assert(BB_NumBytesRemaining(&br) == 0);
Assert(BB_NumBytesRemaining(&bbr) == 0);
abort:
@ -791,9 +791,9 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
ASE_DecodedSheet result = Zi;
BB_Buff bb = BB_BuffFromString(encoded);
BB_Reader br = BB_ReaderFromBuffNoDebug(&bb);
BB_Reader bbr = BB_ReaderFromBuffNoDebug(&bb);
ASE_Header ase_header;
BB_ReadBytes(&br, StringFromStruct(&ase_header));
BB_ReadBytes(&bbr, StringFromStruct(&ase_header));
if (ase_header.magic != 0xA5E0)
{
@ -825,7 +825,7 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
for (u16 i = 0; i < ase_header.frames; ++i)
{
ASE_FrameHeader frame_header;
BB_ReadBytes(&br, StringFromStruct(&frame_header));
BB_ReadBytes(&bbr, StringFromStruct(&frame_header));
u32 num_chunks = frame_header.chunks_new;
if (num_chunks == 0)
@ -857,27 +857,27 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
for (u32 j = 0; j < num_chunks; ++j)
{
u32 chunk_size = BB_ReadUBits(&br, 32);
ASE_ChunkKind chunk_type = BB_ReadUBits(&br, 16);
u32 chunk_size = BB_ReadUBits(&bbr, 32);
ASE_ChunkKind chunk_type = BB_ReadUBits(&bbr, 16);
// Chunk size includes size & type
Assert(chunk_size >= 6);
chunk_size -= 6;
u64 chunk_end_pos = BB_GetCurrentReaderByte(&br) + chunk_size;
u64 chunk_end_pos = BB_GetCurrentReaderByte(&bbr) + chunk_size;
switch (chunk_type)
{
default:
{
BB_ReadSeekToByte(&br, chunk_end_pos);
BB_ReadSeekToByte(&bbr, chunk_end_pos);
} break;
//- Decode tags
case ASE_ChunkKind_Tags:
{
u16 frame_span_count = BB_ReadUBits(&br, 16);
BB_ReadSeekBytes(&br, 8);
u16 frame_span_count = BB_ReadUBits(&bbr, 16);
BB_ReadSeekBytes(&bbr, 8);
for (u16 k = 0; k < frame_span_count; ++k)
{
@ -885,13 +885,13 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
span->next = first_span;
first_span = span;
span->start = BB_ReadUBits(&br, 16);
span->end = BB_ReadUBits(&br, 16);
BB_ReadSeekBytes(&br, 13);
span->start = BB_ReadUBits(&bbr, 16);
span->end = BB_ReadUBits(&bbr, 16);
BB_ReadSeekBytes(&bbr, 13);
u16 str_len = BB_ReadUBits(&br, 16);
u16 str_len = BB_ReadUBits(&bbr, 16);
span->name = (String) { str_len, PushStructsNoZero(arena, u8, str_len) };
BB_ReadBytes(&br, span->name);
BB_ReadBytes(&bbr, span->name);
++num_spans;
}
@ -907,15 +907,15 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
slice_key->next = first_slice_key;
first_slice_key = slice_key;
u32 num_slices = BB_ReadUBits(&br, 32);
u32 num_slices = BB_ReadUBits(&bbr, 32);
slice_key->num_slices = num_slices;
u32 flags = BB_ReadUBits(&br, 32);
BB_ReadSeekBytes(&br, 4);
u32 flags = BB_ReadUBits(&bbr, 32);
BB_ReadSeekBytes(&bbr, 4);
u16 str_len = BB_ReadUBits(&br, 16);
u16 str_len = BB_ReadUBits(&bbr, 16);
slice_key->name = (String) { str_len, PushStructsNoZero(arena, u8, str_len) };
BB_ReadBytes(&br, slice_key->name);
BB_ReadBytes(&bbr, slice_key->name);
for (u32 k = 0; k < num_slices; ++k)
{
@ -923,20 +923,20 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
slice->next = slice_key->first_slice;
slice_key->first_slice = slice;
u32 start = BB_ReadUBits(&br, 32);
i32 x = BB_ReadIBits(&br, 32);
i32 y = BB_ReadIBits(&br, 32);
u32 width = BB_ReadUBits(&br, 32);
u32 height = BB_ReadUBits(&br, 32);
u32 start = BB_ReadUBits(&bbr, 32);
i32 x = BB_ReadIBits(&bbr, 32);
i32 y = BB_ReadIBits(&bbr, 32);
u32 width = BB_ReadUBits(&bbr, 32);
u32 height = BB_ReadUBits(&bbr, 32);
if (flags & 0x01)
{
// Skip 9-patches info
BB_ReadSeekBytes(&br, 128);
BB_ReadSeekBytes(&bbr, 128);
}
if (flags & 0x02)
{
// Skip pivot info
BB_ReadSeekBytes(&br, 64);
BB_ReadSeekBytes(&bbr, 64);
}
slice->start = start;
@ -955,7 +955,7 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
}
// Assert all data was read
Assert(BB_NumBytesRemaining(&br) == 0);
Assert(BB_NumBytesRemaining(&bbr) == 0);
result.image_size = VEC2(image_width, image_height);
result.frame_size = VEC2(frame_width, frame_height);

View File

@ -59,46 +59,56 @@ BB_Writer BB_WriterFromBuffNoDebug(BB_Buff *bb)
return result;
}
// FIXME: Handle overflowed bw
u64 BB_GetNumBitsWritten(BB_Writer *bw)
void BB_ResetWriter(BB_Writer *bbw)
{
return bw->cur_bit;
bbw->overflowed = 0;
bbw->cur_bit = 0;
if (bbw->bb->is_backed_by_arena)
{
ResetArena(bbw->bb->arena);
}
}
// FIXME: Handle overflowed bw
u64 BB_GetNumBytesWritten(BB_Writer *bw)
// FIXME: Handle overflowed bbw
u64 BB_GetNumBitsWritten(BB_Writer *bbw)
{
return (bw->cur_bit + 7) >> 3;
return bbw->cur_bit;
}
// FIXME: Handle overflowed bw
String BB_GetWritten(Arena *arena, BB_Writer *bw)
// FIXME: Handle overflowed bbw
u64 BB_GetNumBytesWritten(BB_Writer *bbw)
{
return (bbw->cur_bit + 7) >> 3;
}
// FIXME: Handle overflowed bbw
String BB_GetWritten(Arena *arena, BB_Writer *bbw)
{
String result = Zi;
result.len = (bw->cur_bit + 7) >> 3;
result.len = (bbw->cur_bit + 7) >> 3;
result.text = PushStructsNoZero(arena, u8, result.len);
CopyBytes(result.text, bw->base, result.len);
CopyBytes(result.text, bbw->base, result.len);
return result;
}
// FIXME: Handle overflowed bw
u8 *BB_GetWrittenRaw(BB_Writer *bw)
// FIXME: Handle overflowed bbw
u8 *BB_GetWrittenRaw(BB_Writer *bbw)
{
return bw->base;
return bbw->base;
}
// Returns 1 if num_bits would cause the writer to overflow its fixed buffer size (if writer is not backed by a dynamic arena bitbuff)
b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits)
b32 BB_CheckWriterOverflowBits(BB_Writer *bbw, u64 num_bits)
{
b32 result = 0;
BB_Buff *bb = bw->bb;
if (bw->overflowed)
BB_Buff *bb = bbw->bb;
if (bbw->overflowed)
{
result = 1;
}
else
{
u64 bytes_needed = (bw->cur_bit + num_bits + 7) >> 3;
u64 bytes_needed = (bbw->cur_bit + num_bits + 7) >> 3;
if (bb->is_backed_by_arena)
{
Arena *arena = bb->arena;
@ -119,8 +129,8 @@ b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits)
Assert(0);
#endif
result = 1;
bw->cur_bit = max_len << 3;
bw->overflowed = 1;
bbw->cur_bit = max_len << 3;
bbw->overflowed = 1;
}
}
}
@ -131,74 +141,74 @@ b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits)
//~ Align writer
// Align the pos to the next byte
void BB_WriteAlignToNextByte(BB_Writer *bw)
void BB_WriteAlignToNextByte(BB_Writer *bbw)
{
#if BITBUFF_DEBUG
if ((bw->cur_bit & 7) != 0)
if ((bbw->cur_bit & 7) != 0)
{
BB_WriteDebugMagic(bw, BB_DebugMagicKind_AlignNextByte, 0);
BB_WriteDebugMagic(bbw, BB_DebugMagicKind_AlignNextByte, 0);
}
#endif
bw->cur_bit += (8 - (bw->cur_bit & 7)) & 7;
bbw->cur_bit += (8 - (bbw->cur_bit & 7)) & 7;
}
void BB_WriteAlignBytes(BB_Writer *bw, u64 align)
void BB_WriteAlignBytes(BB_Writer *bbw, u64 align)
{
BB_WriteAlignToNextByte(bw);
BB_WriteDebugMagic(bw, BB_DebugMagicKind_AlignBytes, align);
BB_WriteAlignToNextByte(bbw);
BB_WriteDebugMagic(bbw, BB_DebugMagicKind_AlignBytes, align);
if (align > 0)
{
u64 new_pos = (bw->cur_bit >> 3);
u64 new_pos = (bbw->cur_bit >> 3);
new_pos += (align - 1);
new_pos -= new_pos % align;
if (BB_CheckWriterOverflowBits(bw, (new_pos << 3) - bw->cur_bit))
if (BB_CheckWriterOverflowBits(bbw, (new_pos << 3) - bbw->cur_bit))
{
return;
}
bw->cur_bit = new_pos << 3;
bbw->cur_bit = new_pos << 3;
}
}
////////////////////////////////////////////////////////////
//~ Write bits
void BB_WriteUBitsNoMagic(BB_Writer *bw, u64 value, u8 num_bits)
void BB_WriteUBitsNoMagic(BB_Writer *bbw, u64 value, u8 num_bits)
{
Assert(num_bits > 0 && (num_bits == 64 || value <= ~(U64Max << num_bits))); // Bit count must be able to hold value
if (BB_CheckWriterOverflowBits(bw, num_bits))
if (BB_CheckWriterOverflowBits(bbw, num_bits))
{
return;
}
u8 offset = bw->cur_bit & 7;
u8 offset = bbw->cur_bit & 7;
if (offset != 0)
{
// Write unaligned bits
u8 *at = bw->base + (bw->cur_bit >> 3);
u8 *at = bbw->base + (bbw->cur_bit >> 3);
u8 num_mix_bits = MinU8((8 - offset), num_bits);
u8 mix_byte = (u8)((value & ((1 << num_mix_bits) - 1)) << offset);
*at |= mix_byte;
value >>= num_mix_bits;
num_bits -= num_mix_bits;
bw->cur_bit += num_mix_bits;
bbw->cur_bit += num_mix_bits;
}
// cur_bit is now aligned to byte
u8 *at = bw->base + (bw->cur_bit >> 3);
u8 *at = bbw->base + (bbw->cur_bit >> 3);
u8 num_bytes = (num_bits + 7) >> 3;
CopyBytes(at, &value, num_bytes);
bw->cur_bit += num_bits;
bbw->cur_bit += num_bits;
}
void BB_WriteUBits(BB_Writer *bw, u64 value, u8 num_bits)
void BB_WriteUBits(BB_Writer *bbw, u64 value, u8 num_bits)
{
BB_WriteDebugMagic(bw, BB_DebugMagicKind_UBits, num_bits);
BB_WriteUBitsNoMagic(bw, value, num_bits);
BB_WriteDebugMagic(bbw, BB_DebugMagicKind_UBits, num_bits);
BB_WriteUBitsNoMagic(bbw, value, num_bits);
}
void BB_WriteIBits(BB_Writer *bw, i64 value, u8 num_bits)
void BB_WriteIBits(BB_Writer *bbw, i64 value, u8 num_bits)
{
BB_WriteDebugMagic(bw, BB_DebugMagicKind_IBits, num_bits);
BB_WriteDebugMagic(bbw, BB_DebugMagicKind_IBits, num_bits);
u64 ubits;
if (value >= 0)
{
@ -208,13 +218,13 @@ void BB_WriteIBits(BB_Writer *bw, i64 value, u8 num_bits)
{
ubits = BB_TwosComplimentFromUint(-value, num_bits);
}
BB_WriteUBits(bw, ubits, num_bits);
BB_WriteUBits(bbw, ubits, num_bits);
}
// Returns written bit to make writing delta encoding logic cleaner
b32 BB_WriteBit(BB_Writer *bw, u8 value)
b32 BB_WriteBit(BB_Writer *bbw, u8 value)
{
BB_WriteUBits(bw, value, 1);
BB_WriteUBits(bbw, value, 1);
return value;
}
@ -223,24 +233,24 @@ b32 BB_WriteBit(BB_Writer *bw, u8 value)
// Writes a variable length unsigned integer.
// Value is written in chunks of 7 bits w/ 8th bit signaling continuation.
void BB_WriteUV(BB_Writer *bw, u64 value)
void BB_WriteUV(BB_Writer *bbw, u64 value)
{
BB_WriteDebugMagic(bw, BB_DebugMagicKind_UV, 0);
BB_WriteDebugMagic(bbw, BB_DebugMagicKind_UV, 0);
while (value > 0x7F)
{
u8 cont_byte = 0x80 | (value & 0x7F);
BB_WriteUBits(bw, cont_byte, 8);
BB_WriteUBits(bbw, cont_byte, 8);
value >>= 7;
}
BB_WriteUBits(bw, value, 8);
BB_WriteUBits(bbw, value, 8);
}
// Writes a variable length signed integer.
// Similar to BB_WriteUV, except the 7th bit of the first byte is a sign bit
// indicating that the value is stored in twos compliment.
void BB_WriteIV(BB_Writer *bw, i64 value)
void BB_WriteIV(BB_Writer *bbw, i64 value)
{
BB_WriteDebugMagic(bw, BB_DebugMagicKind_IV, 0);
BB_WriteDebugMagic(bbw, BB_DebugMagicKind_IV, 0);
u8 sign_bit;
u64 tc;
if (value >= 0)
@ -268,107 +278,107 @@ void BB_WriteIV(BB_Writer *bw, i64 value)
tc >>= 6;
first_byte |= (tc > 0) << 7; // Cont bit
first_byte |= sign_bit << 6; // Sign bit
BB_WriteUBits(bw, first_byte, 8);
BB_WriteUBits(bbw, first_byte, 8);
if (tc > 0)
{
while (tc > 0x7F)
{
u8 cont_byte = 0x80 | (tc & 0x7F);
BB_WriteUBits(bw, cont_byte, 8);
BB_WriteUBits(bbw, cont_byte, 8);
tc >>= 7;
}
BB_WriteUBits(bw, tc, 8);
BB_WriteUBits(bbw, tc, 8);
}
}
////////////////////////////////////////////////////////////
//~ Write floating point
void BB_WriteF32(BB_Writer *bw, f32 value)
void BB_WriteF32(BB_Writer *bbw, f32 value)
{
BB_WriteDebugMagic(bw, BB_DebugMagicKind_F32, 0);
BB_WriteUBits(bw, *(u32 *)&value, 32);
BB_WriteDebugMagic(bbw, BB_DebugMagicKind_F32, 0);
BB_WriteUBits(bbw, *(u32 *)&value, 32);
}
void BB_WriteF64(BB_Writer *bw, f64 value)
void BB_WriteF64(BB_Writer *bbw, f64 value)
{
BB_WriteDebugMagic(bw, BB_DebugMagicKind_F64, 0);
BB_WriteUBits(bw, *(u64 *)&value, 64);
BB_WriteDebugMagic(bbw, BB_DebugMagicKind_F64, 0);
BB_WriteUBits(bbw, *(u64 *)&value, 64);
}
////////////////////////////////////////////////////////////
//~ Write Uid
void BB_WriteUid(BB_Writer *bw, Uid value)
void BB_WriteUid(BB_Writer *bbw, Uid value)
{
BB_WriteDebugMagic(bw, BB_DebugMagicKind_Uid, 128);
BB_WriteUBits(bw, value.hi, 64);
BB_WriteUBits(bw, value.lo, 64);
BB_WriteDebugMagic(bbw, BB_DebugMagicKind_Uid, 128);
BB_WriteUBits(bbw, value.hi, 64);
BB_WriteUBits(bbw, value.lo, 64);
}
////////////////////////////////////////////////////////////
//~ Write raw data
void BB_WriteString(BB_Writer *bw, String s)
void BB_WriteString(BB_Writer *bbw, String s)
{
BB_WriteDebugMagic(bw, BB_DebugMagicKind_String, 0);
BB_WriteUV(bw, s.len);
BB_WriteBytes(bw, s);
BB_WriteDebugMagic(bbw, BB_DebugMagicKind_String, 0);
BB_WriteUV(bbw, s.len);
BB_WriteBytes(bbw, s);
}
void BB_WriteBytes(BB_Writer *bw, String bytes)
void BB_WriteBytes(BB_Writer *bbw, String bytes)
{
// Align start of bytes
BB_WriteAlignToNextByte(bw);
BB_WriteAlignToNextByte(bbw);
u64 num_bits = bytes.len << 3;
if (BB_CheckWriterOverflowBits(bw, num_bits))
if (BB_CheckWriterOverflowBits(bbw, num_bits))
{
return;
}
u8 *at = bw->base + (bw->cur_bit >> 3);
u8 *at = bbw->base + (bbw->cur_bit >> 3);
CopyBytes(at, bytes.text, bytes.len);
bw->cur_bit += num_bits;
bbw->cur_bit += num_bits;
}
void BB_WriteSeekBytes(BB_Writer *bw, u64 num_bytes)
void BB_WriteSeekBytes(BB_Writer *bbw, u64 num_bytes)
{
BB_WriteAlignToNextByte(bw);
BB_WriteAlignToNextByte(bbw);
u64 num_bits = num_bytes << 3;
if (BB_CheckWriterOverflowBits(bw, num_bits))
if (BB_CheckWriterOverflowBits(bbw, num_bits))
{
return;
}
bw->cur_bit += num_bits;
bbw->cur_bit += num_bits;
}
////////////////////////////////////////////////////////////
//~ Writer debug
#if BITBUFF_DEBUG
void BB_WriteDebugMarker(BB_Writer *bw, String name)
void BB_WriteDebugMarker(BB_Writer *bbw, String name)
{
bw->cur_bit += (8 - (bw->cur_bit & 7)) & 7;
bbw->cur_bit += (8 - (bbw->cur_bit & 7)) & 7;
for (u64 i = 0; i < name.len; ++i)
{
BB_WriteUBitsNoMagic(bw, name.text[i], 8);
BB_WriteUBitsNoMagic(bbw, name.text[i], 8);
}
}
void BB_WriteDebugMagic(BB_Writer *bw, BB_DebugMagicKind magic, u8 num_bits)
void BB_WriteDebugMagic(BB_Writer *bbw, BB_DebugMagicKind magic, u8 num_bits)
{
if (bw->debug_enabled)
if (bbw->debug_enabled)
{
if (BB_CheckWriterOverflowBits(bw, 24))
if (BB_CheckWriterOverflowBits(bbw, 24))
{
return;
}
u64 magic_ubits = (u64)magic | ((u64)num_bits << 16);
BB_WriteUBitsNoMagic(bw, magic_ubits, 24);
BB_WriteUBitsNoMagic(bbw, magic_ubits, 24);
}
}
#endif
@ -408,44 +418,44 @@ BB_Reader BB_ReaderFromBuffNoDebug(BB_Buff *bb)
}
// Returns the number of bits read from the bitbuff
// FIXME: Handle overflowed br
u64 BB_GetCurrentReaderBit(BB_Reader *br)
// FIXME: Handle overflowed bbr
u64 BB_GetCurrentReaderBit(BB_Reader *bbr)
{
return br->cur_bit;
return bbr->cur_bit;
}
// Returns the number of *full* bytes read from the bitbuff
// FIXME: Handle overflowed br
u64 BB_GetCurrentReaderByte(BB_Reader *br)
// FIXME: Handle overflowed bbr
u64 BB_GetCurrentReaderByte(BB_Reader *bbr)
{
return br->cur_bit >> 3;
return bbr->cur_bit >> 3;
}
// Returns the number of bits left until the bitbuff overflows
// FIXME: Handle overflowed br
u64 BB_NumBitsRemaining(BB_Reader *br)
// FIXME: Handle overflowed bbr
u64 BB_NumBitsRemaining(BB_Reader *bbr)
{
return (br->base_len << 3) - br->cur_bit;
return (bbr->base_len << 3) - bbr->cur_bit;
}
// Returns the number of *full* bytes left until the bitbuff overflows
// FIXME: Handle overflowed br
u64 BB_NumBytesRemaining(BB_Reader *br)
// FIXME: Handle overflowed bbr
u64 BB_NumBytesRemaining(BB_Reader *bbr)
{
return br->base_len - (br->cur_bit >> 3);
return bbr->base_len - (bbr->cur_bit >> 3);
}
b32 BB_CheckReaderOverflowBits(BB_Reader *br, u64 num_bits)
b32 BB_CheckReaderOverflowBits(BB_Reader *bbr, u64 num_bits)
{
b32 result = 0;
if (br->overflowed)
if (bbr->overflowed)
{
result = 1;
}
else
{
u64 bits_needed = br->cur_bit + num_bits;
u64 base_len_bits = br->base_len << 3;
u64 bits_needed = bbr->cur_bit + num_bits;
u64 base_len_bits = bbr->base_len << 3;
if (bits_needed > base_len_bits)
{
// Tried to read past bitbuff memory
@ -453,8 +463,8 @@ b32 BB_CheckReaderOverflowBits(BB_Reader *br, u64 num_bits)
Assert(0);
#endif
result = 1;
br->cur_bit = base_len_bits;
br->overflowed = 1;
bbr->cur_bit = base_len_bits;
bbr->overflowed = 1;
}
}
return result;
@ -464,62 +474,62 @@ b32 BB_CheckReaderOverflowBits(BB_Reader *br, u64 num_bits)
//~ Align reader
// Align the pos to the next byte
void BB_ReadAlignToNextByte(BB_Reader *br)
void BB_ReadAlignToNextByte(BB_Reader *bbr)
{
#if BITBUFF_DEBUG
if ((br->cur_bit & 7) != 0)
if ((bbr->cur_bit & 7) != 0)
{
BB_ReadDebugMagic(br, BB_DebugMagicKind_AlignNextByte, 0);
BB_ReadDebugMagic(bbr, BB_DebugMagicKind_AlignNextByte, 0);
}
#endif
br->cur_bit += (8 - (br->cur_bit & 7)) & 7;
bbr->cur_bit += (8 - (bbr->cur_bit & 7)) & 7;
}
void BB_ReadAlignBytes(BB_Reader *br, u64 align)
void BB_ReadAlignBytes(BB_Reader *bbr, u64 align)
{
BB_ReadAlignToNextByte(br);
BB_ReadDebugMagic(br, BB_DebugMagicKind_AlignBytes, align);
BB_ReadAlignToNextByte(bbr);
BB_ReadDebugMagic(bbr, BB_DebugMagicKind_AlignBytes, align);
if (align > 0)
{
u64 new_pos = (br->cur_bit >> 3);
u64 new_pos = (bbr->cur_bit >> 3);
new_pos += (align - 1);
new_pos -= new_pos % align;
if (BB_CheckReaderOverflowBits(br, (new_pos << 3) - br->cur_bit))
if (BB_CheckReaderOverflowBits(bbr, (new_pos << 3) - bbr->cur_bit))
{
return;
}
br->cur_bit = new_pos << 3;
bbr->cur_bit = new_pos << 3;
}
}
////////////////////////////////////////////////////////////
//~ Read bits
u64 BB_ReadUBitsNoMagic(BB_Reader *br, u8 num_bits)
u64 BB_ReadUBitsNoMagic(BB_Reader *bbr, u8 num_bits)
{
if (BB_CheckReaderOverflowBits(br, num_bits))
if (BB_CheckReaderOverflowBits(bbr, num_bits))
{
return 0;
}
u64 result = 0;
u8 offset = br->cur_bit & 7;
u8 offset = bbr->cur_bit & 7;
u8 num_trailing_bits = 0;
if (offset)
{
u8 *at = br->base + (br->cur_bit >> 3);
u8 *at = bbr->base + (bbr->cur_bit >> 3);
num_trailing_bits = MinU8(8 - offset, num_bits);
u8 mix_byte = *at;
mix_byte >>= offset;
mix_byte &= (1 << num_trailing_bits) - 1;
result = mix_byte;
num_bits -= num_trailing_bits;
br->cur_bit += num_trailing_bits;
bbr->cur_bit += num_trailing_bits;
}
// cur_bit is now aligned to byte
u8 *at = br->base + (br->cur_bit >> 3);
u8 *at = bbr->base + (bbr->cur_bit >> 3);
u8 num_bytes = (num_bits + 7) >> 3;
u64 tmp = 0;
CopyBytes(&tmp, at, num_bytes);
@ -530,27 +540,27 @@ u64 BB_ReadUBitsNoMagic(BB_Reader *br, u8 num_bits)
}
tmp &= mask;
result |= tmp << num_trailing_bits;
br->cur_bit += num_bits;
bbr->cur_bit += num_bits;
return result;
}
u64 BB_ReadUBits(BB_Reader *br, u8 num_bits)
u64 BB_ReadUBits(BB_Reader *bbr, u8 num_bits)
{
BB_ReadDebugMagic(br, BB_DebugMagicKind_UBits, num_bits);
return BB_ReadUBitsNoMagic(br, num_bits);
BB_ReadDebugMagic(bbr, BB_DebugMagicKind_UBits, num_bits);
return BB_ReadUBitsNoMagic(bbr, num_bits);
}
i64 BB_ReadIBits(BB_Reader *br, u8 num_bits)
i64 BB_ReadIBits(BB_Reader *bbr, u8 num_bits)
{
Assert(num_bits > 1);
BB_ReadDebugMagic(br, BB_DebugMagicKind_IBits, num_bits);
u64 tc = BB_ReadUBits(br, num_bits);
BB_ReadDebugMagic(bbr, BB_DebugMagicKind_IBits, num_bits);
u64 tc = BB_ReadUBits(bbr, num_bits);
return BB_IntFromTwosCompliment(tc, num_bits);
}
u8 BB_ReadBit(BB_Reader *br)
u8 BB_ReadBit(BB_Reader *bbr)
{
return BB_ReadUBits(br, 1);
return BB_ReadUBits(bbr, 1);
}
////////////////////////////////////////////////////////////
@ -558,14 +568,14 @@ u8 BB_ReadBit(BB_Reader *br)
// Read a variable length unsigned integer.
// See BB_WriteUV for details.
u64 BB_ReadUV(BB_Reader *br)
u64 BB_ReadUV(BB_Reader *bbr)
{
BB_ReadDebugMagic(br, BB_DebugMagicKind_UV, 0);
BB_ReadDebugMagic(bbr, BB_DebugMagicKind_UV, 0);
u64 result = 0;
for (u64 i = 0; i <= 9; ++i)
{
u64 part = BB_ReadUBits(br, 8);
u64 part = BB_ReadUBits(bbr, 8);
u8 is_last_part = part <= 0x7F;
result |= (part & 0x7F) << (i * 7);
if (is_last_part)
@ -578,10 +588,10 @@ u64 BB_ReadUV(BB_Reader *br)
// Read a variable length signed integer.
// See BB_WriteIV for details.
i64 BB_ReadIV(BB_Reader *br)
i64 BB_ReadIV(BB_Reader *bbr)
{
BB_ReadDebugMagic(br, BB_DebugMagicKind_IV, 0);
u8 first_byte = BB_ReadUBits(br, 8);
BB_ReadDebugMagic(bbr, BB_DebugMagicKind_IV, 0);
u8 first_byte = BB_ReadUBits(bbr, 8);
u8 cont_bit = first_byte & 0x80;
u8 sign_bit = first_byte & 0x40;
@ -591,7 +601,7 @@ i64 BB_ReadIV(BB_Reader *br)
{
for (u64 i = 0; i <= 9; ++i)
{
u64 part = BB_ReadUBits(br, 8);
u64 part = BB_ReadUBits(bbr, 8);
u8 is_last_part = part <= 0x7F;
tc |= (part & 0x7F) << num_bits;
num_bits += 7;
@ -620,40 +630,40 @@ i64 BB_ReadIV(BB_Reader *br)
////////////////////////////////////////////////////////////
//~ Read floating point
f32 BB_ReadF32(BB_Reader *br)
f32 BB_ReadF32(BB_Reader *bbr)
{
BB_ReadDebugMagic(br, BB_DebugMagicKind_F32, 0);
u32 ubits = BB_ReadUBits(br, 32);
BB_ReadDebugMagic(bbr, BB_DebugMagicKind_F32, 0);
u32 ubits = BB_ReadUBits(bbr, 32);
return *(f32 *)&ubits;
}
f64 BB_ReadF64(BB_Reader *br)
f64 BB_ReadF64(BB_Reader *bbr)
{
BB_ReadDebugMagic(br, BB_DebugMagicKind_F64, 0);
u64 ubits = BB_ReadUBits(br, 64);
BB_ReadDebugMagic(bbr, BB_DebugMagicKind_F64, 0);
u64 ubits = BB_ReadUBits(bbr, 64);
return *(f64 *)&ubits;
}
////////////////////////////////////////////////////////////
//~ Read Uid
Uid BB_ReadUid(BB_Reader *br)
Uid BB_ReadUid(BB_Reader *bbr)
{
BB_ReadDebugMagic(br, BB_DebugMagicKind_Uid, 128);
u64 hi = BB_ReadUBits(br, 64);
u64 lo = BB_ReadUBits(br, 64);
BB_ReadDebugMagic(bbr, BB_DebugMagicKind_Uid, 128);
u64 hi = BB_ReadUBits(bbr, 64);
u64 lo = BB_ReadUBits(bbr, 64);
return UID(hi, lo);
}
////////////////////////////////////////////////////////////
//~ Read raw data
String BB_ReadString(Arena *arena, BB_Reader *br)
String BB_ReadString(Arena *arena, BB_Reader *bbr)
{
BB_ReadDebugMagic(br, BB_DebugMagicKind_String, 0);
BB_ReadDebugMagic(bbr, BB_DebugMagicKind_String, 0);
String result = Zi;
u64 len = BB_ReadUV(br);
u8 *src = BB_ReadBytesRaw(br, len);
u64 len = BB_ReadUV(bbr);
u8 *src = BB_ReadBytesRaw(bbr, len);
if (src != 0)
{
result.len = len;
@ -664,9 +674,9 @@ String BB_ReadString(Arena *arena, BB_Reader *br)
}
// Will fill dst with zeroes if bitbuff overflows
void BB_ReadBytes(BB_Reader *br, String out)
void BB_ReadBytes(BB_Reader *bbr, String out)
{
u8 *src = BB_ReadBytesRaw(br, out.len);
u8 *src = BB_ReadBytesRaw(bbr, out.len);
if (src)
{
CopyBytes(out.text, src, out.len);
@ -678,48 +688,48 @@ void BB_ReadBytes(BB_Reader *br, String out)
}
// Will return 0 on bitbuff overflow. Result should be checked.
u8 *BB_ReadBytesRaw(BB_Reader *br, u64 num_bytes)
u8 *BB_ReadBytesRaw(BB_Reader *bbr, u64 num_bytes)
{
BB_ReadAlignToNextByte(br);
BB_ReadAlignToNextByte(bbr);
u64 num_bits = num_bytes << 3;
if (BB_CheckReaderOverflowBits(br, num_bits))
if (BB_CheckReaderOverflowBits(bbr, num_bits))
{
return 0;
}
u8 *raw = br->base + (br->cur_bit >> 3);
br->cur_bit += num_bits;
u8 *raw = bbr->base + (bbr->cur_bit >> 3);
bbr->cur_bit += num_bits;
return raw;
}
void BB_ReadSeekBytes(BB_Reader *br, u64 num_bytes)
void BB_ReadSeekBytes(BB_Reader *bbr, u64 num_bytes)
{
BB_ReadAlignToNextByte(br);
BB_ReadAlignToNextByte(bbr);
u64 num_bits = num_bytes << 3;
if (BB_CheckReaderOverflowBits(br, num_bits))
if (BB_CheckReaderOverflowBits(bbr, num_bits))
{
return;
}
br->cur_bit += num_bits;
bbr->cur_bit += num_bits;
}
void BB_ReadSeekToByte(BB_Reader *br, u64 pos)
void BB_ReadSeekToByte(BB_Reader *bbr, u64 pos)
{
u64 cur_byte_pos = br->cur_bit >> 3;
u64 cur_byte_pos = bbr->cur_bit >> 3;
if (pos >= cur_byte_pos)
{
BB_ReadSeekBytes(br, pos - cur_byte_pos);
BB_ReadSeekBytes(bbr, pos - cur_byte_pos);
}
else
{
// Tried to seek byte backwards in reader
Assert(0);
br->overflowed = 1;
br->cur_bit = (br->base_len << 3);
bbr->overflowed = 1;
bbr->cur_bit = (bbr->base_len << 3);
}
}
@ -728,15 +738,15 @@ void BB_ReadSeekToByte(BB_Reader *br, u64 pos)
#if BITBUFF_DEBUG
void BB_ReadDebugMagic(BB_Reader *br, BB_DebugMagicKind expected_magic, u8 expected_num_bits)
void BB_ReadDebugMagic(BB_Reader *bbr, BB_DebugMagicKind expected_magic, u8 expected_num_bits)
{
if (br->debug_enabled)
if (bbr->debug_enabled)
{
if (BB_CheckReaderOverflowBits(br, 24))
if (BB_CheckReaderOverflowBits(bbr, 24))
{
return;
}
u64 stored = BB_ReadUBitsNoMagic(br, 24);
u64 stored = BB_ReadUBitsNoMagic(bbr, 24);
BB_DebugMagicKind stored_magic = stored & 0xFFFF;
u8 stored_num_bits = (stored >> 16) & 0xFF;
@ -748,12 +758,12 @@ void BB_ReadDebugMagic(BB_Reader *br, BB_DebugMagicKind expected_magic, u8 expec
}
}
void BB_ReadDebugMarker(BB_Reader *br, String name)
void BB_ReadDebugMarker(BB_Reader *bbr, String name)
{
br->cur_bit += (8 - (br->cur_bit & 7)) & 7;
bbr->cur_bit += (8 - (bbr->cur_bit & 7)) & 7;
for (u64 i = 0; i < name.len; ++i)
{
u8 c_stored = BB_ReadUBitsNoMagic(br, 8);
u8 c_stored = BB_ReadUBitsNoMagic(bbr, 8);
u8 c_expected = name.text[i];
Assert(c_expected == c_stored);
}
@ -858,72 +868,72 @@ void BB_Test(void)
String encoded = Zi;
{
BB_Buff bb = BB_AcquireDynamicBuff(Gibi(64));
BB_Writer bw = BB_WriterFromBuff(&bb);
BB_Writer bbw = BB_WriterFromBuff(&bb);
for (u64 i = 0; i < countof(cases); ++i)
{
struct test_case c = cases[i];
if (c.kind == kind_ubits)
{
BB_WriteUBits(&bw, c.ubits.v, c.ubits.num_bits);
BB_WriteUBits(&bbw, c.ubits.v, c.ubits.num_bits);
}
else if (c.kind == kind_ibits)
{
BB_WriteIBits(&bw, c.ibits.v, c.ibits.num_bits);
BB_WriteIBits(&bbw, c.ibits.v, c.ibits.num_bits);
}
else if (c.kind == kind_uv)
{
BB_WriteUV(&bw, c.uv.v);
BB_WriteUV(&bbw, c.uv.v);
}
else if (c.kind == kind_iv)
{
BB_WriteIV(&bw, c.iv.v);
BB_WriteIV(&bbw, c.iv.v);
}
else if (c.kind == kind_string)
{
BB_WriteString(&bw, c.s.v);
BB_WriteString(&bbw, c.s.v);
}
else
{
Assert(0);
}
}
encoded = BB_GetWritten(scratch.arena, &bw);
encoded = BB_GetWritten(scratch.arena, &bbw);
}
{
BB_Buff bb = BB_BuffFromString(encoded);
BB_Reader br = BB_ReaderFromBuff(&bb);
BB_Reader bbr = BB_ReaderFromBuff(&bb);
for (u64 i = 0; i < countof(cases); ++i)
{
struct test_case c = cases[i];
if (c.kind == kind_ubits)
{
u64 w = c.ubits.v;
u64 r = BB_ReadUBits(&br, c.ubits.num_bits);
u64 r = BB_ReadUBits(&bbr, c.ubits.num_bits);
Assert(r == w);
}
else if (c.kind == kind_ibits)
{
i64 w = c.ibits.v;
i64 r = BB_ReadIBits(&br, c.ubits.num_bits);
i64 r = BB_ReadIBits(&bbr, c.ubits.num_bits);
Assert(r == w);
}
else if (c.kind == kind_uv)
{
u64 w = c.uv.v;
u64 r = BB_ReadUV(&br);
u64 r = BB_ReadUV(&bbr);
Assert(r == w);
}
else if (c.kind == kind_iv)
{
i64 w = c.iv.v;
i64 r = BB_ReadIV(&br);
i64 r = BB_ReadIV(&bbr);
Assert(r == w);
}
else if (c.kind == kind_string)
{
String w = c.s.v;
String r = BB_ReadString(scratch.arena, &br);
String r = BB_ReadString(scratch.arena, &bbr);
Assert(MatchString(r, w));
}
else

View File

@ -74,52 +74,54 @@ BB_Buff BB_BuffFromString(String s);
BB_Writer BB_WriterFromBuff(BB_Buff *bb);
BB_Writer BB_WriterFromBuffNoDebug(BB_Buff *bb);
u64 BB_GetNumBitsWritten(BB_Writer *bw);
u64 BB_GetNumBytesWritten(BB_Writer *bw);
void BB_ResetWriter(BB_Writer *bbw);
String BB_GetWritten(Arena *arena, BB_Writer *bw);
u8 *BB_GetWrittenRaw(BB_Writer *bw);
u64 BB_GetNumBitsWritten(BB_Writer *bbw);
u64 BB_GetNumBytesWritten(BB_Writer *bbw);
b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits);
String BB_GetWritten(Arena *arena, BB_Writer *bbw);
u8 *BB_GetWrittenRaw(BB_Writer *bbw);
b32 BB_CheckWriterOverflowBits(BB_Writer *bbw, u64 num_bits);
////////////////////////////////////////////////////////////
//~ Writer ops
//- Align
void BB_WriteAlignToNextByte(BB_Writer *bw);
void BB_WriteAlignBytes(BB_Writer *bw, u64 align);
void BB_WriteAlignToNextByte(BB_Writer *bbw);
void BB_WriteAlignBytes(BB_Writer *bbw, u64 align);
//- Bits
void BB_WriteUBitsNoMagic(BB_Writer *bw, u64 value, u8 num_bits);
void BB_WriteUBits(BB_Writer *bw, u64 value, u8 num_bits);
void BB_WriteIBits(BB_Writer *bw, i64 value, u8 num_bits);
b32 BB_WriteBit(BB_Writer *bw, u8 value);
void BB_WriteUBitsNoMagic(BB_Writer *bbw, u64 value, u8 num_bits);
void BB_WriteUBits(BB_Writer *bbw, u64 value, u8 num_bits);
void BB_WriteIBits(BB_Writer *bbw, i64 value, u8 num_bits);
b32 BB_WriteBit(BB_Writer *bbw, u8 value);
//- Variable length integers
void BB_WriteUV(BB_Writer *bw, u64 value);
void BB_WriteIV(BB_Writer *bw, i64 value);
void BB_WriteUV(BB_Writer *bbw, u64 value);
void BB_WriteIV(BB_Writer *bbw, i64 value);
//- Floating point
void BB_WriteF32(BB_Writer *bw, f32 value);
void BB_WriteF64(BB_Writer *bw, f64 value);
void BB_WriteF32(BB_Writer *bbw, f32 value);
void BB_WriteF64(BB_Writer *bbw, f64 value);
//- Uid
void BB_WriteUid(BB_Writer *bw, Uid value);
void BB_WriteUid(BB_Writer *bbw, Uid value);
//- Raw data
void BB_WriteString(BB_Writer *bw, String s);
void BB_WriteBytes(BB_Writer *bw, String bytes);
void BB_WriteSeekBytes(BB_Writer *bw, u64 num_bytes);
void BB_WriteString(BB_Writer *bbw, String s);
void BB_WriteBytes(BB_Writer *bbw, String bytes);
void BB_WriteSeekBytes(BB_Writer *bbw, u64 num_bytes);
////////////////////////////////////////////////////////////
//~ Writer debug
#if BITBUFF_DEBUG
void BB_WriteDebugMagic(BB_Writer *bw, BB_DebugMagicKind magic, u8 num_bits);
void BB_WriteDebugMarker(BB_Writer *bw, String name);
void BB_WriteDebugMagic(BB_Writer *bbw, BB_DebugMagicKind magic, u8 num_bits);
void BB_WriteDebugMarker(BB_Writer *bbw, String name);
#else
#define BB_WriteDebugMagic(bw, magic, num_bits)
#define BB_WriteDebugMarker(bw, name)
#define BB_WriteDebugMagic(bbw, magic, num_bits)
#define BB_WriteDebugMarker(bbw, name)
#endif
////////////////////////////////////////////////////////////
@ -128,54 +130,54 @@ void BB_WriteSeekBytes(BB_Writer *bw, u64 num_bytes);
BB_Reader BB_ReaderFromBuff(BB_Buff *bb);
BB_Reader BB_ReaderFromBuffNoDebug(BB_Buff *bb);
u64 BB_GetCurrentReaderBit(BB_Reader *br);
u64 BB_GetCurrentReaderByte(BB_Reader *br);
u64 BB_GetCurrentReaderBit(BB_Reader *bbr);
u64 BB_GetCurrentReaderByte(BB_Reader *bbr);
u64 BB_NumBitsRemaining(BB_Reader *br);
u64 BB_NumBytesRemaining(BB_Reader *br);
u64 BB_NumBitsRemaining(BB_Reader *bbr);
u64 BB_NumBytesRemaining(BB_Reader *bbr);
b32 BB_CheckReaderOverflowBits(BB_Reader *br, u64 num_bits);
b32 BB_CheckReaderOverflowBits(BB_Reader *bbr, u64 num_bits);
////////////////////////////////////////////////////////////
//~ Reader ops
//- Align
void BB_ReadAlignToNextByte(BB_Reader *br);
void BB_ReadAlignBytes(BB_Reader *br, u64 align);
void BB_ReadAlignToNextByte(BB_Reader *bbr);
void BB_ReadAlignBytes(BB_Reader *bbr, u64 align);
//- Bits
u64 BB_ReadUBitsNoMagic(BB_Reader *br, u8 num_bits);
u64 BB_ReadUBits(BB_Reader *br, u8 num_bits);
i64 BB_ReadIBits(BB_Reader *br, u8 num_bits);
u8 BB_ReadBit(BB_Reader *br);
u64 BB_ReadUBitsNoMagic(BB_Reader *bbr, u8 num_bits);
u64 BB_ReadUBits(BB_Reader *bbr, u8 num_bits);
i64 BB_ReadIBits(BB_Reader *bbr, u8 num_bits);
u8 BB_ReadBit(BB_Reader *bbr);
//- Variable length integers
u64 BB_ReadUV(BB_Reader *br);
i64 BB_ReadIV(BB_Reader *br);
u64 BB_ReadUV(BB_Reader *bbr);
i64 BB_ReadIV(BB_Reader *bbr);
//- Floating point
f32 BB_ReadF32(BB_Reader *br);
f64 BB_ReadF64(BB_Reader *br);
f32 BB_ReadF32(BB_Reader *bbr);
f64 BB_ReadF64(BB_Reader *bbr);
//- Uid
Uid BB_ReadUid(BB_Reader *br);
Uid BB_ReadUid(BB_Reader *bbr);
//- Raw data
String BB_ReadString(Arena *arena, BB_Reader *br);
void BB_ReadBytes(BB_Reader *br, String dst);
u8 *BB_ReadBytesRaw(BB_Reader *br, u64 num_bytes);
void BB_ReadSeekBytes(BB_Reader *br, u64 num_bytes);
void BB_ReadSeekToByte(BB_Reader *br, u64 pos);
String BB_ReadString(Arena *arena, BB_Reader *bbr);
void BB_ReadBytes(BB_Reader *bbr, String dst);
u8 *BB_ReadBytesRaw(BB_Reader *bbr, u64 num_bytes);
void BB_ReadSeekBytes(BB_Reader *bbr, u64 num_bytes);
void BB_ReadSeekToByte(BB_Reader *bbr, u64 pos);
////////////////////////////////////////////////////////////
//~ Reader debug
#if BITBUFF_DEBUG
void BB_ReadDebugMagic(BB_Reader *br, BB_DebugMagicKind expected_magic, u8 expected_num_bits);
void BB_ReadDebugMarker(BB_Reader *br, String name);
void BB_ReadDebugMagic(BB_Reader *bbr, BB_DebugMagicKind expected_magic, u8 expected_num_bits);
void BB_ReadDebugMarker(BB_Reader *bbr, String name);
#else
#define BB_ReadDebugMagic(br, expected_magic, expected_num_bits)
#define BB_ReadDebugMarker(br, name)
#define BB_ReadDebugMagic(bbr, expected_magic, expected_num_bits)
#define BB_ReadDebugMarker(bbr, name)
#endif
////////////////////////////////////////////////////////////

View File

@ -10,20 +10,20 @@ void BootstrapResources(u64 archive_strings_count, String *archive_strings)
if (archive.len > 0)
{
BB_Buff bb = BB_BuffFromString(archive);
BB_Reader br = BB_ReaderFromBuff(&bb);
BB_Reader bbr = BB_ReaderFromBuff(&bb);
u64 magic = BB_ReadUBits(&br, 64);
u64 magic = BB_ReadUBits(&bbr, 64);
Assert(magic == ResourceEmbeddedMagic);
// Create & insert entries
u64 num_entries = BB_ReadUBits(&br, 64);
u64 num_entries = BB_ReadUBits(&bbr, 64);
for (u64 i = 0; i < num_entries; ++i)
{
u64 store_hash = BB_ReadUBits(&br, 64);
u64 name_start = BB_ReadUBits(&br, 64);
u64 name_len = BB_ReadUBits(&br, 64);
u64 data_start = BB_ReadUBits(&br, 64);
u64 data_len = BB_ReadUBits(&br, 64);
u64 store_hash = BB_ReadUBits(&bbr, 64);
u64 name_start = BB_ReadUBits(&bbr, 64);
u64 name_len = BB_ReadUBits(&bbr, 64);
u64 data_start = BB_ReadUBits(&bbr, 64);
u64 data_len = BB_ReadUBits(&bbr, 64);
ResourceEntry *entry = PushStruct(perm, ResourceEntry);
entry->name = STRING(name_len, archive.text + name_start);

View File

@ -155,13 +155,13 @@ EmbedObj Embed(String store_name, String dir_path)
// TODO: Cache dynamic bitbuffs?
BB_Buff bb = BB_AcquireDynamicBuff(Gibi(2));
BB_Writer bw = BB_WriterFromBuff(&bb);
BB_Writer bbw = BB_WriterFromBuff(&bb);
// Write magic
BB_WriteUBits(&bw, ResourceEmbeddedMagic, 64);
BB_WriteUBits(&bbw, ResourceEmbeddedMagic, 64);
// Write header
BB_WriteUBits(&bw, entries_count, 64);
BB_WriteUBits(&bbw, entries_count, 64);
// Reserve entries space
u64 entry_size = 0
@ -170,10 +170,10 @@ EmbedObj Embed(String store_name, String dir_path)
+ 8 // Name end
+ 8 // Data start
+ 8; // Data end
u8 *entries_start = BB_GetWrittenRaw(&bw) + BB_GetNumBytesWritten(&bw);
u8 *entries_start = BB_GetWrittenRaw(&bbw) + BB_GetNumBytesWritten(&bbw);
u64 entries_size = entry_size * entries_count;
String entries_str = STRING(entries_size, entries_start);
BB_WriteSeekBytes(&bw, entries_size);
BB_WriteSeekBytes(&bbw, entries_size);
BB_Buff entries_bb = BB_BuffFromString(entries_str);
BB_Writer entries_bw = BB_WriterFromBuff(&entries_bb);
@ -184,17 +184,17 @@ EmbedObj Embed(String store_name, String dir_path)
String file_data = F_DataFromFile(perm, en->file_name);
// Write name
BB_WriteAlignBytes(&bw, 64);
u64 name_start = BB_GetNumBytesWritten(&bw) + 1;
BB_WriteString(&bw, en->entry_name);
u64 name_len = BB_GetNumBytesWritten(&bw) - name_start;
BB_WriteAlignBytes(&bbw, 64);
u64 name_start = BB_GetNumBytesWritten(&bbw) + 1;
BB_WriteString(&bbw, en->entry_name);
u64 name_len = BB_GetNumBytesWritten(&bbw) - name_start;
// Write data
BB_WriteAlignBytes(&bw, 64);
BB_WriteAlignBytes(&bbw, 64);
// FIXME: Why no +1 here?
u64 data_start = BB_GetNumBytesWritten(&bw);
BB_WriteBytes(&bw, file_data);
u64 data_len = BB_GetNumBytesWritten(&bw) - data_start;
u64 data_start = BB_GetNumBytesWritten(&bbw);
BB_WriteBytes(&bbw, file_data);
u64 data_len = BB_GetNumBytesWritten(&bbw) - data_start;
// Write entry
BB_WriteUBits(&entries_bw, store_hash, 64);
@ -204,8 +204,8 @@ EmbedObj Embed(String store_name, String dir_path)
BB_WriteUBits(&entries_bw, data_len, 64);
}
arc_contents.len = BB_GetNumBytesWritten(&bw);
arc_contents.text = BB_GetWrittenRaw(&bw);
arc_contents.len = BB_GetNumBytesWritten(&bbw);
arc_contents.text = BB_GetWrittenRaw(&bbw);
}
// Write archive to file

View File

@ -58,6 +58,9 @@ void NET_Bootstrap(void);
//~ @hookdecl Net ops
NET_Key NET_KeyFromString(String host, String port);
String NET_StringFromKey(Arena *arena, NET_Key key);
b32 NET_MatchKey(NET_Key a, NET_Key b);
u64 NET_HashFromKey(NET_Key key);
NET_PipeHandle NET_AcquirePipe(void);

View File

@ -87,12 +87,6 @@ struct sockaddr_in6 NET_W32_AddressFromKey(NET_Key key)
return result;
}
u64 NET_W32_HashFromKey(NET_Key key)
{
u64 result = HashString(StringFromStruct(&key));
return result;
}
void NET_W32_SignalWorker(void)
{
i32 err = sendto(
@ -109,7 +103,7 @@ NET_W32_Peer *NET_W32_TouchPeerFromKey(NET_W32_Pipe *pipe, NET_Key key)
{
// TODO: Address challenge on first receive
NET_W32_Peer *peer = 0;
u64 hash = NET_W32_HashFromKey(key);
u64 hash = NET_HashFromKey(key);
NET_W32_PeerBin *bin = &pipe->peer_bins[hash % pipe->peer_bins_count];
peer = bin->first;
for (; peer; peer = peer->next_in_bin)
@ -168,40 +162,71 @@ NET_Key NET_KeyFromString(String host, String port)
NET_Key result = Zi;
TempArena scratch = BeginScratchNoConflict();
{
struct addrinfo hints = Zi;
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
char *host_cstr = CstrFromString(scratch.arena, host);
char *port_cstr = CstrFromString(scratch.arena, port);
i64 port_i64 = CR_IntFromString(port);
if (port_i64 < 0 || port_i64 >= Kibi(64))
{
port_i64 = 0;
}
struct sockaddr_in6 addr = Zi;
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(port_i64);
if (InetPtonA(AF_INET6, host_cstr, &addr.sin6_addr) != 1)
{
struct addrinfo *first_ai = 0;
if (getaddrinfo(host_cstr, port_cstr, &hints, &first_ai) == 0)
IN_ADDR v4 = Zi;
if (InetPtonA(AF_INET, host_cstr, &v4) == 1)
{
for (struct addrinfo *ai = first_ai; ai; ai = ai->ai_next)
{
if (ai->ai_family == AF_INET6 && ai->ai_addrlen >= sizeof(addr))
{
CopyBytes(&addr, ai->ai_addr, sizeof(addr));
break;
}
}
}
if (first_ai)
{
freeaddrinfo(first_ai);
ZeroStruct(&addr.sin6_addr);
addr.sin6_addr.u.Byte[10] = 0xFF;
addr.sin6_addr.u.Byte[11] = 0xFF;
CopyBytes(&addr.sin6_addr.u.Byte[12], &v4, 4);
}
}
result = NET_W32_KeyFromAddress(addr);
}
EndScratch(scratch);
return result;
}
String NET_StringFromKey(Arena *arena, NET_Key key)
{
String result = Zi;
struct sockaddr_in6 sin6 = NET_W32_AddressFromKey(key);
char addr_chars[INET6_ADDRSTRLEN];
u32 port = ntohs(sin6.sin6_port);
if (IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr))
{
struct in_addr v4 = Zi;
CopyBytes(&v4, &sin6.sin6_addr.s6_addr[12], sizeof(v4));
if (InetNtopA(AF_INET, &v4, addr_chars, (DWORD)sizeof(addr_chars)))
{
result = StringF(arena, "%F:%F", FmtString(StringFromCstr(addr_chars, countof(addr_chars))), FmtUint(port));
}
}
else
{
if (InetNtopA(AF_INET6, &sin6.sin6_addr, addr_chars, (DWORD)sizeof(addr_chars)))
{
result = StringF(arena, "[%F]:%F", FmtString(StringFromCstr(addr_chars, countof(addr_chars))), FmtUint(port));
}
}
return result;
}
b32 NET_MatchKey(NET_Key a, NET_Key b)
{
return MatchStruct(&a, &b);
}
u64 NET_HashFromKey(NET_Key key)
{
u64 result = HashString(StringFromStruct(&key));
return result;
}
NET_PipeHandle NET_AcquirePipe(void)
{
Arena *perm = PermArena();
@ -432,7 +457,7 @@ void NET_W32_TickForever(WaveLaneCtx *lane)
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol= IPPROTO_UDP;
hints.ai_flags = AI_PASSIVE;
hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
struct addrinfo *ai = 0;
if (ok)
{
@ -772,11 +797,11 @@ void NET_W32_TickForever(WaveLaneCtx *lane)
msg_data.text = ArenaNext(msg_buff->arena, u8);
msg_data.len = 0;
LogSuccessF(
"Assembled msg with msg seq: %F, data (%F bytes)",
FmtSint(packet->msg_seq),
FmtUint(msg->data.len)
);
// LogSuccessF(
// "Assembled msg with msg seq: %F, data (%F bytes)",
// FmtSint(packet->msg_seq),
// FmtUint(msg->data.len)
// );
}
}
else

View File

@ -178,7 +178,6 @@ NET_W32_DummySocket NET_W32_CreateDummySocket(void);
NET_W32_Pipe *NET_W32_PipeFromHandle(NET_PipeHandle pipe_handle);
NET_Key NET_W32_KeyFromAddress(struct sockaddr_in6 addr);
struct sockaddr_in6 NET_W32_AddressFromKey(NET_Key key);
u64 NET_W32_HashFromKey(NET_Key key);
void NET_W32_SignalWorker(void);
NET_W32_Peer *NET_W32_TouchPeerFromKey(NET_W32_Pipe *pipe, NET_Key key);
u32 NET_W32_ChecksumFromString(String str);

File diff suppressed because it is too large Load Diff

View File

@ -1,318 +0,0 @@
////////////////////////////////////////////////////////////
//~ Channel ID
Struct(N_ChannelId)
{
u32 gen;
u32 idx;
};
////////////////////////////////////////////////////////////
//~ Host command types
Enum(N_CmdKind)
{
N_CmdKind_None,
N_CmdKind_TryConnect,
N_CmdKind_ConnectSuccess,
N_CmdKind_Disconnect,
N_CmdKind_Heartbeat,
N_CmdKind_Write
};
Enum(N_WriteFlag)
{
N_WriteFlag_None = 0,
N_WriteFlag_Reliable = (1 << 0)
};
Struct(N_Cmd)
{
N_CmdKind kind;
N_ChannelId channel_id;
u16 heartbeat_id;
u16 heartbeat_ack_id;
b32 write_reliable;
String write_msg;
N_Cmd *next;
};
////////////////////////////////////////////////////////////
//~ Event types
Enum(N_EventKind)
{
N_EventKind_None,
N_EventKind_ChannelOpened,
N_EventKind_ChannelClosed,
N_EventKind_Msg
};
Struct(N_Event)
{
N_EventKind kind;
N_ChannelId channel_id;
String msg;
N_Event *next;
};
Struct(N_EventList)
{
N_Event *first;
N_Event *last;
};
Struct(N_ChannelLookupBin)
{
struct N_Channel *first;
struct N_Channel *last;
};
////////////////////////////////////////////////////////////
//~ Packet types
#define N_PacketMagic 0xd9e3b8b6
#define N_MaxPacketChunkLen 1024
#define N_MaxPacketLen 1280 // Give enough space for msg chunk + header
Enum(N_PacketKind)
{
N_PacketKind_None,
N_PacketKind_TryConnect,
N_PacketKind_ConnectSuccess,
N_PacketKind_Disconnect,
N_PacketKind_Heartbeat,
N_PacketKind_MsgChunk
};
Enum(N_PacketFlag)
{
N_PacketFlag_None = 0,
N_PacketFlag_Reliable = (1 << 0)
};
Struct(N_SndPacket)
{
N_SndPacket *next;
u64 seq;
u64 data_len;
u8 data[N_MaxPacketLen];
};
Struct(N_RcvPacket)
{
PLT_Sock *sock;
PLT_Address address;
String data;
N_RcvPacket *next;
};
Struct(N_RcvBuffer)
{
Arena *arena;
N_RcvPacket *first_packet;
N_RcvPacket *last_packet;
};
////////////////////////////////////////////////////////////
//~ Channel types
Struct(N_Channel)
{
N_ChannelId id;
b32 valid;
b32 connected;
struct N_Host *host;
N_Channel *next_free;
PLT_Address address;
u64 address_hash;
N_Channel *next_address_hash;
N_Channel *prev_address_hash;
// NOTE: Packets are allocated in host's `arena`
N_SndPacket *first_reliable_packet;
N_SndPacket *last_reliable_packet;
N_SndPacket *first_unreliable_packet;
N_SndPacket *last_unreliable_packet;
u64 num_reliable_packets;
u64 num_unreliable_packets;
// NOTE: Msg assemblers are allocated in host's `arena`
struct N_MsgAssembler *least_recent_msg_assembler;
struct N_MsgAssembler *most_recent_msg_assembler;
u16 last_heartbeat_received_id;
u16 last_heartbeat_acked_id;
i64 last_heartbeat_acked_ns;
i64 last_heartbeat_rtt_ns;
u64 last_sent_msg_id;
u64 their_acked_seq;
u64 our_acked_seq;
u64 last_sent_seq;
i64 last_packet_received_ns;
};
Struct(N_ChannelNode)
{
N_Channel *channel;
N_ChannelNode *next;
};
Struct(N_ChannelList)
{
N_ChannelNode *first;
N_ChannelNode *last;
};
////////////////////////////////////////////////////////////
//~ Message asssembler types
Struct(N_MsgAssembler)
{
N_Channel *channel;
b32 is_reliable;
// Free list
N_MsgAssembler *next_free;
// Bucket list
N_MsgAssembler *next_hash;
N_MsgAssembler *prev_hash;
// Channel list
N_MsgAssembler *less_recent;
N_MsgAssembler *more_recent;
u64 msg_id;
u64 hash;
u64 last_chunk_len;
u64 num_chunks_total;
u64 num_chunks_received;
i64 touched_ns;
BuddyBlock *buddy_block;
u8 *chunk_bitmap;
u8 *chunk_data;
};
Struct(N_MsgAssemblerLookupBin)
{
N_MsgAssembler *first;
N_MsgAssembler *last;
};
////////////////////////////////////////////////////////////
//~ Host types
#define N_NumChannelLookupBins 512
#define N_NumMsgAssemblerLookupBins 16384
Struct(N_Host)
{
Arena *arena;
PLT_Sock *sock;
BuddyCtx *buddy; // For storing msg assembler data
Arena *cmd_arena;
N_Cmd *first_cmd;
N_Cmd *last_cmd;
N_Cmd *first_free_cmd;
Arena *channel_arena;
N_Channel *channels;
N_Channel *first_free_channel;
u64 num_channels_reserved;
N_SndPacket *first_free_packet; // Acquired in `arena`
N_MsgAssembler *first_free_msg_assembler; // Acquired in `arena`
N_ChannelLookupBin *channel_lookup_bins; // Acquired in `arena`
u64 num_channel_lookup_bins;
N_MsgAssemblerLookupBin *msg_assembler_lookup_bins; // Acquired in `arena`
u64 num_msg_assembler_lookup_bins;
// Double buffer for incoming data
Mutex rcv_buffer_write_mutex;
N_RcvBuffer *rcv_buffer_read;
N_RcvBuffer *rcv_buffer_write;
u64 bytes_received;
u64 bytes_sent;
};
////////////////////////////////////////////////////////////
//~ Nil constants
Readonly Global N_Channel N_nil_channel = { .valid = 0 };
////////////////////////////////////////////////////////////
//~ Host initialization
N_Host *N_AcquireHost(u16 listen_port);
void N_ReleaseHost(N_Host *host);
////////////////////////////////////////////////////////////
//~ Channel
#define N_NilChannelId (N_ChannelId) { .gen = 0, .idx = 0 }
#define N_AllChannelsId (N_ChannelId) { .gen = U32Max, .idx = U32Max }
#define N_MatchChannelId(a, b) ((a).gen == (b).gen && (a).idx == (b).idx)
#define N_IsChannelIdNil(v) ((v).gen == 0 && (v).idx == 0)
u64 N_HashFromAddress(PLT_Address address);
N_Channel *N_ChannelFromAddress(N_Host *host, PLT_Address address);
N_Channel *N_ChannelFromId(N_Host *host, N_ChannelId channel_id);
N_ChannelList N_ChannelsFromId(Arena *arena, N_Host *host, N_ChannelId channel_id);
N_Channel *N_AcquireChannel(N_Host *host, PLT_Address address);
void N_ReleaseChannel(N_Channel *channel);
////////////////////////////////////////////////////////////
//~ Message assembler
u64 N_HashFromMsg(N_ChannelId channel_id, u64 msg_id);
N_MsgAssembler *N_MsgAssemblerFromMsg(N_Host *host, N_ChannelId channel_id, u64 msg_id);
N_MsgAssembler *N_AcquireMsgAssembler(N_Channel *channel, u64 msg_id, u64 chunk_count, u64 now_ns, b32 is_reliable);
void N_ReleaseMessageAssembler(N_MsgAssembler *ma);
void N_TouchMessageAssembler(N_MsgAssembler *ma, i64 now_ns);
b32 N_IsChunkFilled(N_MsgAssembler *ma, u64 chunk_id);
void N_MarkChunkReceived(N_MsgAssembler *ma, u64 chunk_id);
////////////////////////////////////////////////////////////
//~ Packet
N_SndPacket *N_PushSndPacket(N_Channel *channel, b32 is_reliable);
////////////////////////////////////////////////////////////
//~ Host command
N_Cmd *N_PushCmd(N_Host *host);
void N_Connect(N_Host *host, PLT_Address connect_address);
void N_Disconnect(N_Host *host, N_ChannelId channel_id);
void N_Write(N_Host *host, N_ChannelId channel_id, String msg, N_WriteFlag flags);
////////////////////////////////////////////////////////////
//~ Channel info
i64 N_GetChannelLastRttNs(N_Host *host, N_ChannelId channel_id);
////////////////////////////////////////////////////////////
//~ Update
N_Event *N_PushEvent(Arena *arena, N_EventList *list);
N_EventList N_BeginUpdate(Arena *arena, N_Host *host);
void N_EndUpdate(N_Host *host);

View File

@ -1,16 +0,0 @@
@Layer net_old
//////////////////////////////
//- Dependencies
@Dep platform
//////////////////////////////
//- Api
@IncludeC net.h
//////////////////////////////
//- Impl
@IncludeC net.c

View File

@ -307,34 +307,24 @@ Enum(P_MsgKind)
P_MsgKind_None,
// User -> sim
P_MsgKind_UserSnapshot,
// P_MsgKind_UserSnapshot,
P_MsgKind_SaveWorld,
P_MsgKind_ResetWorld,
P_MsgKind_TileEdit,
P_MsgKind_EntEdit,
// Sim -> user
P_MsgKind_SimSnapshot,
// P_MsgKind_SimSnapshot,
P_MsgKind_Tiles,
};
Struct(P_Msg)
{
//- In
P_Key dst_user; // If dst is 0, then cmd is meant to be broadcast
b32 burst;
//- Out
P_Key src_user;
//- In / Out
P_MsgKind kind;
NET_Key dst;
P_UserSnapshot user_snapshot;
P_SimSnapshot sim_snapshot;
// P_UserSnapshot user_snapshot;
// P_SimSnapshot sim_snapshot;
P_TileKind tile_kind;
Rng2I32 tile_range;

View File

@ -1,10 +1,20 @@
S_Ctx S = Zi;
Readonly S_Client S_NilClient = {
.next = &S_NilClient,
.prev = &S_NilClient,
};
////////////////////////////////////////////////////////////
//~ Bootstrap
void S_Bootstrap(void)
{
Arena *perm = PermArena();
S.client_bins_count = Kibi(4);
S.client_bins = PushStructsNoZero(perm, S_ClientBin, S.client_bins_count);
DispatchWave(Lit("Sim"), 1, S_TickForever, 0);
OnExit(S_Shutdown);
}
@ -15,6 +25,30 @@ void S_Shutdown(void)
YieldOnFence(&S.shutdown_fence, 1);
}
////////////////////////////////////////////////////////////
//~ Helpers
b32 S_IsClientNil(S_Client *client)
{
return client == 0 || client == &S_NilClient;
}
S_Client *S_ClientFromNetKey(NET_Key key)
{
S_Client *result = &S_NilClient;
u64 hash = NET_HashFromKey(key);
S_ClientBin *bin = &S.client_bins[hash % S.client_bins_count];
for (S_Client *client = bin->first; client; client = client->next_in_bin)
{
if (client->hash == hash)
{
result = client;
break;
}
}
return result;
}
////////////////////////////////////////////////////////////
//~ Sim tick
@ -31,9 +65,8 @@ void S_TickForever(WaveLaneCtx *lane)
b32 has_sent_initial_tick = 0;
NET_PipeHandle net_pipe = NET_AcquirePipe();
BB_Buff packer_bb = BB_AcquireDynamicBuff(Gibi(64));
BB_Writer packer_bbw = BB_WriterFromBuff(&packer_bb);
@ -128,33 +161,110 @@ void S_TickForever(WaveLaneCtx *lane)
u64 port = 22121;
NET_Bind(net_pipe, port);
P_MsgList in_msgs = Zi;
{
NET_MsgList net_msgs = NET_Swap(frame_arena, net_pipe);
for (NET_Msg *net_msg = net_msgs.first; net_msg; net_msg = net_msg->next)
{
NET_Key net_key = net_msg->sender;
String address_str = NET_StringFromKey(frame_arena, net_key);
LogDebugF("Received message from client \"%F\"", FmtString(address_str));
// Create client
S_Client *client = S_ClientFromNetKey(net_key);
if (S_IsClientNil(client))
{
u64 hash = NET_HashFromKey(net_key);
S_ClientBin *bin = &S.client_bins[hash % S.client_bins_count];
// FIXME: Freelist client
client = PushStruct(perm, S_Client);
client->hash = hash;
client->net_key = net_key;
DllQueuePushNPZ(&S_NilClient, S.first_client, S.last_client, client, next, prev);
DllQueuePushNP(bin->first, bin->last, client, next_in_bin, prev_in_bin);
}
String packed = net_msg->data;
P_MsgNode *dst_msg_node = PushStruct(frame_arena, P_MsgNode);
P_Msg *dst_msg = &dst_msg_node->msg;
*dst_msg = P_UnpackMsg(frame_arena, packed);
// FIXME: Set src user here based on net key
// dst_msg->src_user =
DllQueuePush(in_msgs.first, in_msgs.last, dst_msg_node);
++in_msgs.count;
P_MsgList client_msgs = P_UnpackMessages(frame_arena, packed);
// FIXME: Set src user here based on net key (or maybe just attach net key to msg instead of user)
// {
// LogDebugF(
// "Server received msg (%F bytes): \"%F\"",
// FmtUint(packed.len),
// FmtString(packed)
// );
// }
if (client_msgs.first)
{
if (in_msgs.last)
{
in_msgs.last->next = client_msgs.first;
}
else
{
in_msgs.first = client_msgs.first;
}
client_msgs.first->prev = in_msgs.last;
in_msgs.last = client_msgs.last;
in_msgs.count += client_msgs.count;
}
}
}
// P_MsgList in_msgs = Zi;
// {
// NET_MsgList net_msgs = NET_Swap(frame_arena, net_pipe);
// for (NET_Msg *net_msg = net_msgs.first; net_msg; net_msg = net_msg->next)
// {
// NET_Key net_key = net_msg->sender;
// String address_str = NET_StringFromKey(frame_arena, net_key);
// LogDebugF("Received message from client \"%F\"", FmtString(address_str));
// NET_Push(net_pipe, net_key, Lit("HIII"), 0);
// String packed = net_msg->data;
// P_MsgNode *dst_msg_node = PushStruct(frame_arena, P_MsgNode);
// P_Msg *dst_msg = &dst_msg_node->msg;
// *dst_msg = P_UnpackMsg(frame_arena, packed);
// // FIXME: Set src user here based on net key
// // dst_msg->src_user =
// DllQueuePush(in_msgs.first, in_msgs.last, dst_msg_node);
// ++in_msgs.count;
// // {
// // LogDebugF(
// // "Server received msg (%F bytes): \"%F\"",
// // FmtUint(packed.len),
// // FmtString(packed)
// // );
// // }
// }
// }
//////////////////////////////
//- Process connection messages
@ -238,17 +348,6 @@ void S_TickForever(WaveLaneCtx *lane)
//////////////////////////////
//- Apply user snapshots
for (P_MsgNode *msg_node = in_msgs.first; msg_node; msg_node = msg_node->next)
{
P_Msg *msg = &msg_node->msg;
if (msg->kind == P_MsgKind_UserSnapshot)
{
}
}
// P_MsgList user_msgs = Zi;
// {
// i64 user_msgs_min_tick = world_frame->tick + user_msg_tick_range.min;
@ -323,63 +422,63 @@ void S_TickForever(WaveLaneCtx *lane)
// FIXME: Only accept edits from privileged users
// {
// b32 should_save = 0;
// for (P_MsgNode *msg_node = user_msgs.first; msg_node; msg_node = msg_node->next)
// {
// P_Msg *msg = &msg_node->msg;
// b32 allow = 0;
// if (msg->kind == P_MsgKind_SaveWorld)
// {
// // FIXME: Only accept save from local user
// should_save = 1;
// }
// if (msg->kind == P_MsgKind_ResetWorld)
// {
// // TODO: Real reset
// for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
// {
// ent->exists = 0;
// }
// }
// if (msg->kind == P_MsgKind_EntEdit)
// {
// P_EntList ents = Zi;
// P_Ent *dst = P_PushTempEnt(frame_arena, &ents);
// *dst = msg->ent;
// P_SpawnEntsFromList(world_frame, ents);
// }
// if (msg->kind == P_MsgKind_TileEdit)
// {
// P_TileKind tile = msg->tile_kind;
// Rng2I32 range = msg->tile_range;
// for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y)
// {
// for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
// {
// Vec2 tile_pos = VEC2(tile_x, tile_y);
// i32 tile_idx = P_TileIdxFromTilePos(tile_pos);
// world->tiles[tile_idx] = (u8)tile;
// }
// }
// // Hash tiles
// {
// u64 old_tiles_hash = world->tiles_hash;
// world->tiles_hash = HashString(STRING(P_TilesCount, world->tiles));
// if (world->tiles_hash != old_tiles_hash)
// {
// tiles_dirty = 1;
// }
// }
// }
// }
// // Save world
// if (should_save)
// {
// String path = Lit("...");
// LogInfoF("Saving world to %F", FmtString(path));
// }
// }
{
b32 should_save = 0;
for (P_MsgNode *msg_node = in_msgs.first; msg_node; msg_node = msg_node->next)
{
P_Msg *msg = &msg_node->msg;
b32 allow = 0;
if (msg->kind == P_MsgKind_SaveWorld)
{
// FIXME: Only accept save from local user
should_save = 1;
}
if (msg->kind == P_MsgKind_ResetWorld)
{
// TODO: Real reset
for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
{
ent->exists = 0;
}
}
if (msg->kind == P_MsgKind_EntEdit)
{
P_EntList ents = Zi;
P_Ent *dst = P_PushTempEnt(frame_arena, &ents);
*dst = msg->ent;
P_SpawnEntsFromList(world_frame, ents);
}
if (msg->kind == P_MsgKind_TileEdit)
{
P_TileKind tile = msg->tile_kind;
Rng2I32 range = msg->tile_range;
for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y)
{
for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
{
Vec2 tile_pos = VEC2(tile_x, tile_y);
i32 tile_idx = P_TileIdxFromTilePos(tile_pos);
world->tiles[tile_idx] = (u8)tile;
}
}
// Hash tiles
{
u64 old_tiles_hash = world->tiles_hash;
world->tiles_hash = HashString(STRING(P_TilesCount, world->tiles));
if (world->tiles_hash != old_tiles_hash)
{
tiles_dirty = 1;
}
}
}
}
// Save world
if (should_save)
{
String path = Lit("...");
LogInfoF("Saving world to %F", FmtString(path));
}
}
//////////////////////////////
//- Update ent controls
@ -414,22 +513,22 @@ void S_TickForever(WaveLaneCtx *lane)
//////////////////////////////
//- Push tile messages
// if (tiles_dirty)
// {
// P_Msg *msg = 0;
// {
// P_MsgNode *msg_node = PushStruct(frame_arena, P_MsgNode);
// DllQueuePush(output->msgs.first, output->msgs.last, msg_node);
// ++output->msgs.count;
// msg = &msg_node->msg;
// }
// msg->kind = P_MsgKind_Tiles;
// msg->tiles_hash = world->tiles_hash;
// msg->raw_tiles = PushStructsNoZero(frame_arena, u8, P_TilesCount);
// msg->tile_range = RNG2I32(VEC2I32(0, 0), VEC2I32(P_TilesPitch, P_TilesPitch));
// CopyBytes(msg->raw_tiles, world->tiles, P_TilesCount);
// has_sent_initial_tick = 1;
// }
{
// TODO: Receive remote tile hashes via user snapshots
for (S_Client *client = S.first_client; !S_IsClientNil(client); client = client->next)
{
if (tiles_dirty || client->remote_tiles_hash != world->tiles_hash)
{
P_Msg *msg = P_PushMsg(P_MsgKind_Tiles, Zstr);
msg->kind = P_MsgKind_Tiles;
msg->tiles_hash = world->tiles_hash;
msg->tile_range = RNG2I32(VEC2I32(0, 0), VEC2I32(P_TilesPitch, P_TilesPitch));
msg->dst = client->net_key;
msg->data = STRING(P_TilesCount, world->tiles);
client->remote_tiles_hash = world->tiles_hash;
}
}
}
//////////////////////////////
//- Push snapshot messages
@ -486,35 +585,151 @@ void S_TickForever(WaveLaneCtx *lane)
//////////////////////////////
//- Send messages
for (P_MsgNode *msg_node = P_tl.out_msgs.first; msg_node; msg_node = msg_node->next)
{
P_Msg *msg = &msg_node->msg;
if (P_IsKeyNil(msg->dst_user))
// Group messages by client
for (P_MsgNode *msg_node = P_tl.out_msgs.first; msg_node; msg_node = msg_node->next)
{
// Broadcast
String packed = P_PackMessage(frame_arena, msg);
for (P_Ent *user = P_FirstEnt(world_frame); !P_IsEntNil(user); user = P_NextEnt(user))
P_Msg *msg = &msg_node->msg;
if (NET_IsKeyNil(msg->dst))
{
if (user->is_user)
// Broadcast msg
for (S_Client *client = S.first_client; !S_IsClientNil(client); client = client->next)
{
NET_Push(net_pipe, user->net, packed, msg->burst);
P_MsgNode *dst_msg_node = PushStruct(frame_arena, P_MsgNode);
*dst_msg_node = *msg_node;
DllQueuePush(client->out_msgs.first, client->out_msgs.last, dst_msg_node);
++client->out_msgs.count;
}
}
else
{
// Targeted msg
S_Client *client = S_ClientFromNetKey(msg->dst);
if (!S_IsClientNil(client))
{
P_MsgNode *dst_msg_node = PushStruct(frame_arena, P_MsgNode);
*dst_msg_node = *msg_node;
DllQueuePush(client->out_msgs.first, client->out_msgs.last, dst_msg_node);
++client->out_msgs.count;
}
}
}
else
// Send messages to clients
for (S_Client *client = S.first_client; !S_IsClientNil(client); client = client->next)
{
P_Ent *user = P_EntFromKey(world_frame, msg->dst_user);
if (!NET_IsKeyNil(user->net))
P_MsgList msgs = client->out_msgs;
if (msgs.count > 0)
{
String packed = P_PackMessage(frame_arena, msg);
NET_Push(net_pipe, user->net, packed, msg->burst);
String packed = P_PackMessages(&packer_bbw, msgs);
NET_Push(net_pipe, client->net_key, packed, 0);
ZeroStruct(&client->out_msgs);
}
}
ResetArena(P_tl.out_msgs_arena);
ZeroStruct(&P_tl.out_msgs);
}
// {
// // Group messages by client
// for (P_MsgNode *msg_node = P_tl.out_msgs.first; msg_node; msg_node = msg_node->next)
// {
// P_Msg *msg = &msg_node->msg;
// if (NET_IsKeyNil(msg->dst))
// {
// // Broadcast msg
// for (S_Client *client = S.first_client; client; client = client->next)
// {
// P_MsgNode *dst_msg_node = PushStruct(frame_arena, P_MsgNode);
// *dst_msg_node = *msg_node;
// DllQueuePush(client->out_msgs.first, client->out_msgs.last, dst_msg_node);
// ++client->out_msgs.count;
// }
// }
// else
// {
// // Targeted msg
// S_Client client = S_ClientFromNetKey(msg->dst);
// if (!S_IsClientNil(client))
// {
// }
// }
// }
// for (S_Client *client = first_client; client; client = client->next)
// {
// }
// }
// for (P_MsgNode *msg_node = P_tl.out_msgs.first; msg_node; msg_node = msg_node->next)
// {
// P_Msg *msg = &msg_node->msg;
// if (P_IsKeyNil(msg->dst_user))
// {
// // Broadcast
// String packed = P_PackMessage(frame_arena, msg);
// for (P_Ent *user = P_FirstEnt(world_frame); !P_IsEntNil(user); user = P_NextEnt(user))
// {
// if (user->is_user)
// {
// NET_Push(net_pipe, user->net, packed, msg->burst);
// }
// }
// }
// else
// {
// P_Ent *user = P_EntFromKey(world_frame, msg->dst_user);
// if (!NET_IsKeyNil(user->net))
// {
// String packed = P_PackMessage(frame_arena, msg);
// NET_Push(net_pipe, user->net, packed, msg->burst);
// }
// }
// }
// for (P_MsgNode *msg_node = P_tl.out_msgs.first; msg_node; msg_node = msg_node->next)
// {
// P_Msg *msg = &msg_node->msg;
// if (P_IsKeyNil(msg->dst_user))
// {
// // Broadcast
// String packed = P_PackMessage(frame_arena, msg);
// for (P_Ent *user = P_FirstEnt(world_frame); !P_IsEntNil(user); user = P_NextEnt(user))
// {
// if (user->is_user)
// {
// NET_Push(net_pipe, user->net, packed, msg->burst);
// }
// }
// }
// else
// {
// P_Ent *user = P_EntFromKey(world_frame, msg->dst_user);
// if (!NET_IsKeyNil(user->net))
// {
// String packed = P_PackMessage(frame_arena, msg);
// NET_Push(net_pipe, user->net, packed, msg->burst);
// }
// }
// }
// // TODO: Only copy active entities
// LockTicketMutex(&P.sim_output_back_tm);
// {

View File

@ -1,3 +1,26 @@
////////////////////////////////////////////////////////////
//~ Client types
Struct(S_Client)
{
S_Client *next;
S_Client *prev;
S_Client *next_in_bin;
S_Client *prev_in_bin;
u64 hash;
NET_Key net_key;
P_MsgList out_msgs;
u64 remote_tiles_hash;
};
Struct(S_ClientBin)
{
S_Client *first;
S_Client *last;
};
////////////////////////////////////////////////////////////
//~ State types
@ -5,9 +28,16 @@ Struct(S_Ctx)
{
Atomic32 shutdown;
Fence shutdown_fence;
S_Client *first_client;
S_Client *last_client;
i64 client_bins_count;
S_ClientBin *client_bins;
};
extern S_Ctx S;
extern Readonly S_Client S_NilClient;
////////////////////////////////////////////////////////////
//~ Bootstrap
@ -15,6 +45,13 @@ extern S_Ctx S;
void S_Bootstrap(void);
void S_Shutdown(void);
////////////////////////////////////////////////////////////
//~ Helpers
b32 S_IsClientNil(S_Client *client);
S_Client *S_ClientFromNetKey(NET_Key key);
////////////////////////////////////////////////////////////
//~ Sim tick

View File

@ -198,16 +198,49 @@ P_UnpackedWorld P_UnpackWorld(Arena *arena, String packed)
////////////////////////////////////////////////////////////
//~ Message
String P_PackMessage(Arena *arena, P_Msg *msg)
String P_PackMessages(BB_Writer *bbw, P_MsgList msgs)
{
u64 pos_start = BB_GetNumBytesWritten(bbw);
{
for (P_MsgNode *msg_node = msgs.first; msg_node; msg_node = msg_node->next)
{
// TODO: Compress
P_Msg *msg = &msg_node->msg;
BB_WriteBytes(bbw, StringFromStruct(msg));
BB_WriteString(bbw, msg->data);
}
}
u64 pos_end = BB_GetNumBytesWritten(bbw);
String result = Zi;
// TODO
result.text = BB_GetWrittenRaw(bbw) + pos_start;
result.len = pos_end - pos_start;
return result;
}
P_Msg P_UnpackMsg(Arena *arena, String packed)
P_MsgList P_UnpackMessages(Arena *arena, String packed)
{
P_Msg result = Zi;
// TODO
P_MsgList result = Zi;
BB_Buff bb = BB_BuffFromString(packed);
BB_Reader bbr = BB_ReaderFromBuff(&bb);
b32 done = 0;
while (!done)
{
u8 *msg_raw = BB_ReadBytesRaw(&bbr, sizeof(P_Msg));
if (msg_raw != 0)
{
// Read msg header
P_MsgNode *dst_msg_node = PushStruct(arena, P_MsgNode);
CopyStruct(&dst_msg_node->msg, msg_raw);
DllQueuePush(result.first, result.last, dst_msg_node);
result.count += 1;
// Read msg data string
String data_str = BB_ReadString(arena, &bbr);
dst_msg_node->msg.data = data_str;
}
else
{
done = 1;
}
}
return result;
}

View File

@ -32,5 +32,5 @@ P_UnpackedWorld P_UnpackWorld(Arena *arena, String packed);
////////////////////////////////////////////////////////////
//~ Message
String P_PackMessage(Arena *arena, P_Msg *msg);
P_Msg P_UnpackMsg(Arena *arena, String packed);
String P_PackMessages(BB_Writer *bbw, P_MsgList msgs);
P_MsgList P_UnpackMessages(Arena *arena, String packed);

View File

@ -346,6 +346,8 @@ void V_TickForever(WaveLaneCtx *lane)
const f32 meters_per_draw_width = 18;
NET_PipeHandle net_pipe = NET_AcquirePipe();
BB_Buff packer_bb = BB_AcquireDynamicBuff(Gibi(64));
BB_Writer packer_bbw = BB_WriterFromBuff(&packer_bb);
//////////////////////////////
//- Init vis state
@ -563,46 +565,46 @@ void V_TickForever(WaveLaneCtx *lane)
{
//- Init bitbuff
BB_Buff bb = Zi;
BB_Writer bw = Zi;
BB_Reader br = Zi;
BB_Writer bbw = Zi;
BB_Reader bbr = Zi;
if (swapout)
{
u64 max_size = Mebi(64);
u8 *bytes = PushStructsNoZero(frame->arena, u8, max_size);
bb = BB_BuffFromString(STRING(max_size, bytes));
bw = BB_WriterFromBuff(&bb);
bbw = BB_WriterFromBuff(&bb);
}
else
{
String swap_encoded = SwappedStateFromName(frame->arena, Lit("pp_vis.swp"));
bb = BB_BuffFromString(swap_encoded);
br = BB_ReaderFromBuff(&bb);
bbr = BB_ReaderFromBuff(&bb);
}
//- Transcode swap state
if (swapout)
{
BB_WriteUBits(&bw, V.user_key.v, 64);
BB_WriteBit(&bw, prev_frame->is_editing);
BB_WriteF32(&bw, prev_frame->edit_camera_pos.x);
BB_WriteF32(&bw, prev_frame->edit_camera_pos.y);
BB_WriteF32(&bw, prev_frame->edit_camera_zoom);
BB_WriteString(&bw, prev_frame->window_restore);
BB_WriteUBits(&bbw, V.user_key.v, 64);
BB_WriteBit(&bbw, prev_frame->is_editing);
BB_WriteF32(&bbw, prev_frame->edit_camera_pos.x);
BB_WriteF32(&bbw, prev_frame->edit_camera_pos.y);
BB_WriteF32(&bbw, prev_frame->edit_camera_zoom);
BB_WriteString(&bbw, prev_frame->window_restore);
}
else
{
V.user_key.v = BB_ReadUBits(&br, 64);
frame->is_editing = BB_ReadBit(&br);
frame->edit_camera_pos.x = BB_ReadF32(&br);
frame->edit_camera_pos.y = BB_ReadF32(&br);
frame->edit_camera_zoom = BB_ReadF32(&br);
frame->window_restore = BB_ReadString(frame->arena, &br);
V.user_key.v = BB_ReadUBits(&bbr, 64);
frame->is_editing = BB_ReadBit(&bbr);
frame->edit_camera_pos.x = BB_ReadF32(&bbr);
frame->edit_camera_pos.y = BB_ReadF32(&bbr);
frame->edit_camera_zoom = BB_ReadF32(&bbr);
frame->window_restore = BB_ReadString(frame->arena, &bbr);
}
//- Write swapout
if (swapout)
{
WriteSwappedState(Lit("pp_vis.swp"), STRING(BB_GetNumBytesWritten(&bw), BB_GetWrittenRaw(&bw)));
WriteSwappedState(Lit("pp_vis.swp"), STRING(BB_GetNumBytesWritten(&bbw), BB_GetWrittenRaw(&bbw)));
}
}
}
@ -2655,25 +2657,84 @@ void V_TickForever(WaveLaneCtx *lane)
//////////////////////////////
//- Pop messages from sim
// FIXME: Reject messages if not from currently connected sim
P_MsgList in_msgs = Zi;
{
NET_Bind(net_pipe, 0);
NET_MsgList net_msgs = NET_Swap(frame->arena, net_pipe);
for (NET_Msg *net_msg = net_msgs.first; net_msg; net_msg = net_msg->next)
{
NET_Key net_key = net_msg->sender;
String address_str = NET_StringFromKey(frame->arena, net_key);
LogDebugF("Received message from server \"%F\"", FmtString(address_str));
String packed = net_msg->data;
P_MsgNode *dst_msg_node = PushStruct(frame->arena, P_MsgNode);
P_Msg *dst_msg = &dst_msg_node->msg;
*dst_msg = P_UnpackMsg(frame->arena, packed);
// FIXME: Set src user here based on net key
// dst_msg->src_user =
DllQueuePush(in_msgs.first, in_msgs.last, dst_msg_node);
++in_msgs.count;
P_MsgList server_msgs = P_UnpackMessages(frame->arena, packed);
if (server_msgs.first)
{
if (in_msgs.last)
{
in_msgs.last->next = server_msgs.first;
}
else
{
in_msgs.first = server_msgs.first;
}
server_msgs.first->prev = in_msgs.last;
in_msgs.last = server_msgs.last;
in_msgs.count += server_msgs.count;
}
}
}
// P_MsgList in_msgs = Zi;
// {
// NET_Bind(net_pipe, 0);
// NET_MsgList net_msgs = NET_Swap(frame->arena, net_pipe);
// for (NET_Msg *net_msg = net_msgs.first; net_msg; net_msg = net_msg->next)
// {
// NET_Key net_key = net_msg->sender;
// String address_str = NET_StringFromKey(frame->arena, net_key);
// LogDebugF("Received message from server \"%F\"", FmtString(address_str));
// String packed = net_msg->data;
// P_MsgNode *dst_msg_node = PushStruct(frame->arena, P_MsgNode);
// P_Msg *dst_msg = &dst_msg_node->msg;
// *dst_msg = P_UnpackMsg(frame->arena, packed);
// // FIXME: Set src user here based on net key
// // dst_msg->src_user =
// DllQueuePush(in_msgs.first, in_msgs.last, dst_msg_node);
// ++in_msgs.count;
// }
// }
// {
// LockTicketMutex(&P.s2u_snapshot_mutex);
// P_SimSnapshot *src_snapshot = &P.s2u_snapshot;
@ -2724,13 +2785,13 @@ void V_TickForever(WaveLaneCtx *lane)
{
P_Msg *msg = &msg_node->msg;
if (msg->kind == P_MsgKind_SimSnapshot && msg->sim_snapshot.tick > sim_world->last_frame->tick)
{
if (!newest_snapshot_msg || msg->sim_snapshot.tick > newest_snapshot_msg->sim_snapshot.tick)
{
newest_snapshot_msg = msg;
}
}
// if (msg->kind == P_MsgKind_SimSnapshot && msg->sim_snapshot.tick > sim_world->last_frame->tick)
// {
// if (!newest_snapshot_msg || msg->sim_snapshot.tick > newest_snapshot_msg->sim_snapshot.tick)
// {
// newest_snapshot_msg = msg;
// }
// }
//- Chat
// if (msg->kind == P_MsgKind_Chat)
@ -2769,50 +2830,50 @@ void V_TickForever(WaveLaneCtx *lane)
//////////////////////////////
//- Apply sim snapshot
if (newest_snapshot_msg)
{
P_SimSnapshot *snapshot = &newest_snapshot_msg->sim_snapshot;
// if (newest_snapshot_msg)
// {
// P_SimSnapshot *snapshot = &newest_snapshot_msg->sim_snapshot;
P_Frame *src_frame = P_FrameFromTick(sim_world, snapshot->src_tick);
P_Frame *dst_frame = P_PushFrame(sim_world, src_frame, snapshot->tick);
sim_world->seed = snapshot->world_seed;
dst_frame->time_ns = snapshot->time_ns;
// P_Frame *src_frame = P_FrameFromTick(sim_world, snapshot->src_tick);
// P_Frame *dst_frame = P_PushFrame(sim_world, src_frame, snapshot->tick);
// sim_world->seed = snapshot->world_seed;
// dst_frame->time_ns = snapshot->time_ns;
//- Apply deltas
for (P_SimDeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next)
{
P_SimDelta *delta = &dn->delta;
//- Raw ent
if (delta->kind == P_SimDeltaKind_RawEnt)
{
P_Ent tmp_ent = delta->ent;
P_EntListNode tmp_ent_node = Zi;
tmp_ent_node.ent = tmp_ent;
P_EntList ent_list = Zi;
ent_list.first = &tmp_ent_node;
ent_list.last = &tmp_ent_node;
P_SpawnEntsFromList(dst_frame, ent_list);
}
}
// //- Apply deltas
// for (P_SimDeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next)
// {
// P_SimDelta *delta = &dn->delta;
// //- Raw ent
// if (delta->kind == P_SimDeltaKind_RawEnt)
// {
// P_Ent tmp_ent = delta->ent;
// P_EntListNode tmp_ent_node = Zi;
// tmp_ent_node.ent = tmp_ent;
// P_EntList ent_list = Zi;
// ent_list.first = &tmp_ent_node;
// ent_list.last = &tmp_ent_node;
// P_SpawnEntsFromList(dst_frame, ent_list);
// }
// }
//- Update sim debug info
// {
// ResetArena(sim_debug_arena);
// first_sim_debug_draw_node = 0;
// last_sim_debug_draw_node = 0;
// {
// i64 dst_idx = 0;
// P_DebugDrawNode *dst_nodes = PushStructsNoZero(sim_debug_arena, P_DebugDrawNode, snapshot->debug_draw_nodes_count);
// for (P_DebugDrawNode *src = snapshot->first_debug_draw_node; src; src = src->next)
// {
// P_DebugDrawNode *dst = &dst_nodes[dst_idx];
// *dst = *src;
// dst_idx += 1;
// SllQueuePush(first_sim_debug_draw_node, last_sim_debug_draw_node, dst);
// }
// }
// }
}
// //- Update sim debug info
// // {
// // ResetArena(sim_debug_arena);
// // first_sim_debug_draw_node = 0;
// // last_sim_debug_draw_node = 0;
// // {
// // i64 dst_idx = 0;
// // P_DebugDrawNode *dst_nodes = PushStructsNoZero(sim_debug_arena, P_DebugDrawNode, snapshot->debug_draw_nodes_count);
// // for (P_DebugDrawNode *src = snapshot->first_debug_draw_node; src; src = src->next)
// // {
// // P_DebugDrawNode *dst = &dst_nodes[dst_idx];
// // *dst = *src;
// // dst_idx += 1;
// // SllQueuePush(first_sim_debug_draw_node, last_sim_debug_draw_node, dst);
// // }
// // }
// // }
// }
// TODO: Remove this
P_ClearFrames(sim_world, I64Min, sim_world->last_frame->tick - 1);
@ -3790,12 +3851,23 @@ void V_TickForever(WaveLaneCtx *lane)
for (P_MsgNode *msg_node = P_tl.out_msgs.first; msg_node; msg_node = msg_node->next)
// for (P_MsgNode *msg_node = P_tl.out_msgs.first; msg_node; msg_node = msg_node->next)
// {
// P_Msg *msg = &msg_node->msg;
// String packed = P_PackMessage(frame->arena, msg);
// NET_Push(net_pipe, server_key, packed, msg->burst);
// }
{
P_Msg *msg = &msg_node->msg;
String packed = P_PackMessage(frame->arena, msg);
NET_Push(net_pipe, server_key, packed, msg->burst);
if (P_tl.out_msgs.count > 0)
{
BB_ResetWriter(&packer_bbw);
String packed = P_PackMessages(&packer_bbw, P_tl.out_msgs);
NET_Push(net_pipe, server_key, packed, 0);
}
}
ResetArena(P_tl.out_msgs_arena);
ZeroStruct(&P_tl.out_msgs);

View File

@ -1,139 +0,0 @@
Readonly TAR_Entry TAR_nil_entry = Zi;
////////////////////////////////////////////////////////////
//~ Helpers
u64 TAR_U64FromOctString(String str)
{
u64 n = 0;
for (u64 i = 0; i < str.len; ++i)
{
n *= 8;
n += (u64)(str.text[i]) - '0';
}
return n;
}
////////////////////////////////////////////////////////////
//~ Archive
// `prefix` will be prepended to all file names in the archive
//
// NOTE: The resulting archive merely points into the supplied tar data, no
// copying is done. Accessing the archive assumes that the data string is still valid.
TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix)
{
TAR_Archive archive = ZI;
BB_Buff bb = BitbuffFromString(data);
BB_Reader br = BB_ReaderFromBuffNoDebug(&bb);
u64 num_files = 0;
while (BB_NumBytesRemaining(&br) > 1024)
{
TAR_Header header = ZI;
BB_ReadBytes(&br, StringFromStruct(&header));
if (!MatchString(StringFromFixedArray(header.ustar_indicator), Lit("ustar\0")))
{
// Invalid header
Assert(0);
continue;
}
if (header.file_name_prefix[0] != 0)
{
// Header file name prefix not supported
Assert(0);
continue;
}
String file_size_oct_str = { .len = 11, .text = header.file_size };
u64 file_size = TAR_U64FromOctString(file_size_oct_str);
u8 *file_data_ptr = BB_ReadBytesRaw(&br, file_size);
if (!file_data_ptr)
{
file_size = 0;
}
String file_data = STRING(file_size, file_data_ptr);
// Skip sector padding
u64 remaining = (512 - (file_size % 512)) % 512;
BB_SeekBytes(&br, remaining);
b32 is_dir = header.file_type == TAR_FileKind_Directory;
if (!is_dir && header.file_type != TAR_FileKind_File)
{
// Unsupported type
Assert(header.file_type == TAR_FileKind_PaxHeaderX || header.file_type == TAR_FileKind_PaxHeaderG);
continue;
}
String file_name_cstr = StringFromCstrNoLimit((char *)header.file_name);
if (file_name_cstr.len >= 2)
{
// Chop off './' prefix
file_name_cstr.len -= 2;
file_name_cstr.text += 2;
}
String file_name = CatString(arena, prefix, file_name_cstr);
TAR_Entry *entry = PushStruct(arena, TAR_Entry);
entry->valid = 1;
entry->is_dir = is_dir;
entry->file_name = file_name;
entry->data = file_data;
entry->next = archive.head;
archive.head = entry;
++num_files;
}
// Build lookup table
archive.lookup = InitDict(arena, (u64)((f64)num_files * TAR_ArchiveLookupTableCapacityFactor));
for (TAR_Entry *entry = archive.head; entry; entry = entry->next)
{
u64 hash = HashString(entry->file_name);
SetDictValue(arena, archive.lookup, hash, (u64)entry);
}
// Build hierarchy
//
// NOTE: This is a separate pass because tar entry order is not guaranteed
// (IE file entries may be encountered before their parent directory entry)
for (TAR_Entry *entry = archive.head; entry; entry = entry->next)
{
// Enter into hierarchy
if (!entry->is_dir)
{
// Find parent entry
TAR_Entry *parent_entry = 0;
for (String parent_dir_name = entry->file_name; parent_dir_name.len > 0; --parent_dir_name.len)
{
if (parent_dir_name.text[parent_dir_name.len - 1] == '/')
{
u64 hash = HashString(parent_dir_name);
parent_entry = (TAR_Entry *)DictValueFromHash(archive.lookup, hash);
break;
}
}
// Insert child into parent's list
if (parent_entry)
{
entry->next_child = parent_entry->next_child;
parent_entry->next_child = entry;
}
}
}
return archive;
}
Readonly Global TAR_Entry g_nil_tar_entry = ZI;
TAR_Entry *TAR_EntryFromName(TAR_Archive *archive, String name)
{
u64 hash = HashString(name);
TAR_Entry *lookup = (TAR_Entry *)DictValueFromHash(archive->lookup, hash);
return lookup ? lookup : &g_nil_tar_entry;
}

View File

@ -1,80 +0,0 @@
////////////////////////////////////////////////////////////
//~ Archive types
#define TAR_ArchiveLookupTableCapacityFactor 2.0
Struct(TAR_Entry)
{
b32 valid;
String file_name;
String data;
b32 is_dir;
TAR_Entry *next;
TAR_Entry *next_child; // If entry is dir, points to first child. Otherwise points to next sibling.
};
Struct(TAR_Archive)
{
Dict *lookup;
TAR_Entry *head;
};
////////////////////////////////////////////////////////////
//~ Header types
Enum(TAR_FileKind)
{
TAR_FileKind_File = '0',
TAR_FileKind_HardLink = '1',
TAR_FileKind_SymLink = '2',
TAR_FileKind_CharacterSpecial = '3',
TAR_FileKind_BlockSpecial = '4',
TAR_FileKind_Directory = '5',
TAR_FileKind_Fifo = '6',
TAR_FileKind_ContiguousFile = '7',
TAR_FileKind_PaxHeaderG = 'g',
TAR_FileKind_PaxHeaderX = 'x'
};
Packed(Struct(TAR_Header)
{
// Pre-posix
u8 file_name[100];
u8 file_mode[8];
u8 owner_id[8];
u8 group_id[8];
u8 file_size[12];
u8 last_modified[12];
u8 checksum[8];
// Both
u8 file_type;
u8 linked_file_name[100];
// UStar
u8 ustar_indicator[6];
u8 ustar_version[2];
u8 owner_user_name[32];
u8 owner_group_name[32];
u8 device_major_number[8];
u8 device_minor_number[8];
u8 file_name_prefix[155];
u8 padding[12];
});
////////////////////////////////////////////////////////////
//~ State types
extern Readonly TAR_nil_entry;
////////////////////////////////////////////////////////////
//~ Helpers
u64 TAR_U64FromOctString(String str);
////////////////////////////////////////////////////////////
//~ Archive
TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix);
TAR_Entry *TAR_EntryFromName(TAR_Archive *archive, String name);

View File

@ -1,17 +0,0 @@
@Layer tar
//////////////////////////////
//- Dependencies
@Dep platform
@Dep bitbuff
//////////////////////////////
//- Api
@IncludeC tar.h
//////////////////////////////
//- Impl
@IncludeC tar.c