server -> client tile sync
This commit is contained in:
parent
27c337202d
commit
f88c33e332
114
src/ase/ase.c
114
src/ase/ase.c
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
@ -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);
|
||||
@ -1,16 +0,0 @@
|
||||
@Layer net_old
|
||||
|
||||
//////////////////////////////
|
||||
//- Dependencies
|
||||
|
||||
@Dep platform
|
||||
|
||||
//////////////////////////////
|
||||
//- Api
|
||||
|
||||
@IncludeC net.h
|
||||
|
||||
//////////////////////////////
|
||||
//- Impl
|
||||
|
||||
@IncludeC net.c
|
||||
20
src/pp/pp.h
20
src/pp/pp.h
@ -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;
|
||||
|
||||
@ -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,32 +161,109 @@ 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)
|
||||
|
||||
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;
|
||||
// {
|
||||
// LogDebugF(
|
||||
// "Server received msg (%F bytes): \"%F\"",
|
||||
// FmtUint(packed.len),
|
||||
// FmtString(packed)
|
||||
// );
|
||||
// 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,32 +585,148 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Send messages
|
||||
|
||||
{
|
||||
// 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 (P_IsKeyNil(msg->dst_user))
|
||||
if (NET_IsKeyNil(msg->dst))
|
||||
{
|
||||
// Broadcast
|
||||
String packed = P_PackMessage(frame_arena, msg);
|
||||
for (P_Ent *user = P_FirstEnt(world_frame); !P_IsEntNil(user); user = P_NextEnt(user))
|
||||
// Broadcast msg
|
||||
for (S_Client *client = S.first_client; !S_IsClientNil(client); client = client->next)
|
||||
{
|
||||
if (user->is_user)
|
||||
{
|
||||
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
|
||||
{
|
||||
P_Ent *user = P_EntFromKey(world_frame, msg->dst_user);
|
||||
if (!NET_IsKeyNil(user->net))
|
||||
// Targeted msg
|
||||
S_Client *client = S_ClientFromNetKey(msg->dst);
|
||||
if (!S_IsClientNil(client))
|
||||
{
|
||||
String packed = P_PackMessage(frame_arena, msg);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send messages to clients
|
||||
for (S_Client *client = S.first_client; !S_IsClientNil(client); client = client->next)
|
||||
{
|
||||
P_MsgList msgs = client->out_msgs;
|
||||
if (msgs.count > 0)
|
||||
{
|
||||
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);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,24 +2657,83 @@ 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);
|
||||
@ -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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
//- Update sim debug info
|
||||
// if (newest_snapshot_msg)
|
||||
// {
|
||||
// ResetArena(sim_debug_arena);
|
||||
// first_sim_debug_draw_node = 0;
|
||||
// last_sim_debug_draw_node = 0;
|
||||
// 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;
|
||||
|
||||
// //- Apply deltas
|
||||
// for (P_SimDeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next)
|
||||
// {
|
||||
// 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_SimDelta *delta = &dn->delta;
|
||||
// //- Raw ent
|
||||
// if (delta->kind == P_SimDeltaKind_RawEnt)
|
||||
// {
|
||||
// P_DebugDrawNode *dst = &dst_nodes[dst_idx];
|
||||
// *dst = *src;
|
||||
// dst_idx += 1;
|
||||
// SllQueuePush(first_sim_debug_draw_node, last_sim_debug_draw_node, dst);
|
||||
// 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);
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
// }
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
|
||||
139
src/tar/tar.c
139
src/tar/tar.c
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
@ -1,17 +0,0 @@
|
||||
@Layer tar
|
||||
|
||||
//////////////////////////////
|
||||
//- Dependencies
|
||||
|
||||
@Dep platform
|
||||
@Dep bitbuff
|
||||
|
||||
//////////////////////////////
|
||||
//- Api
|
||||
|
||||
@IncludeC tar.h
|
||||
|
||||
//////////////////////////////
|
||||
//- Impl
|
||||
|
||||
@IncludeC tar.c
|
||||
Loading…
Reference in New Issue
Block a user