From fe5aca14d27729044f1a486870398056ee618ad0 Mon Sep 17 00:00:00 2001 From: jacob Date: Thu, 15 Jan 2026 13:22:24 -0600 Subject: [PATCH] net_win32 layer --- build.bat | 6 +- src/base/base.cgh | 9 - src/base/base_win32/base_win32.h | 38 +-- src/gpu/gpu_core.h | 40 +-- src/gpu/gpu_dx12/gpu_dx12_core.c | 3 +- src/gpu/gpu_shader_core.cgh | 6 +- src/meta/meta.c | 20 +- src/net/net.h | 318 ++---------------- src/net/net.lay | 9 +- src/net/net_win32/net_win32.c | 244 ++++++++++++++ src/net/net_win32/net_win32.h | 28 ++ src/net/net_win32/net_win32.lay | 11 + src/{net/net.c => net_old/net_old.c} | 0 src/net_old/net_old.h | 318 ++++++++++++++++++ src/net_old/net_old.lay | 16 + src/pp/pp.c | 28 +- src/pp/pp.h | 40 ++- src/pp/pp.lay | 5 + src/pp/pp_sim/pp_sim.lay | 1 + src/pp/pp_sim/pp_sim_core.c | 474 ++++++++++++++++----------- src/pp/pp_transcode.c | 23 +- src/pp/pp_transcode.h | 8 +- src/pp/pp_vis/pp_vis.lay | 1 + src/pp/pp_vis/pp_vis_core.c | 428 ++++++++++++------------ 24 files changed, 1299 insertions(+), 775 deletions(-) create mode 100644 src/net/net_win32/net_win32.c create mode 100644 src/net/net_win32/net_win32.h create mode 100644 src/net/net_win32/net_win32.lay rename src/{net/net.c => net_old/net_old.c} (100%) create mode 100644 src/net_old/net_old.h create mode 100644 src/net_old/net_old.lay diff --git a/build.bat b/build.bat index 25f67ed1..93ed40a6 100644 --- a/build.bat +++ b/build.bat @@ -25,7 +25,10 @@ if "%PROCESSOR_ARCHITECTURE%" equ "AMD64" ( ) where /Q cl.exe || ( echo ************************************************************************** - echo WARNING: cl.exe not found, attempting to locate Visual Studio installation + echo cl.exe not found in the current environment, attempting to locate Visual + echo Studio installation. Run this script from a devenv-equipped environment + echo to remove this notice and speed up build time. + echo. set __VSCMD_ARG_NO_LOGO=1 for /f "tokens=*" %%i in ('"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -requires Microsoft.VisualStudio.Workload.NativeDesktop -property installationPath') do set VS=%%i @@ -37,6 +40,7 @@ where /Q cl.exe || ( call "!VS!\Common7\Tools\VsDevCmd.bat" -arch=%HOST_ARCH% -host_arch=%HOST_ARCH% -startdir=none -no_logo || exit /b 1 echo Visual studio development environment activated echo ************************************************************************** + echo. ) ::- Meta build diff --git a/src/base/base.cgh b/src/base/base.cgh index 12c7d525..920e665b 100644 --- a/src/base/base.cgh +++ b/src/base/base.cgh @@ -439,15 +439,6 @@ #define IsIndexable(a) (sizeof(a[0]) != 0) #define IsFixedArray(a) (IsIndexable(a) && (((void *)&a) == ((void *)a))) -//- offsetof -#if IsCompilerMsvc - #ifdef _CRT_USE_BUILTIN_OFFSETOF - #define offsetof(type, field) __builtin_offsetof(type, field) - #else - #define offsetof(type, field) ((u64)&(((type *)0)->field)) - #endif -#endif - //- struct region #define BeginFieldRegion(name) i8 __begfieldreg__##name #define EndFieldRegion(name) i8 __endfieldreg__##name diff --git a/src/base/base_win32/base_win32.h b/src/base/base_win32/base_win32.h index 50ca3162..a66ba422 100644 --- a/src/base/base_win32/base_win32.h +++ b/src/base/base_win32/base_win32.h @@ -6,25 +6,25 @@ #define COBJMACROS #define WIN32_LEAN_AND_MEAN #define UNICODE -#pragma warning(push, 0) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#pragma warning(pop) +// #pragma warning(push, 0) + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +// #pragma warning(pop) #ifndef BCRYPT_RNG_ALG_HANDLE #define BCRYPT_RNG_ALG_HANDLE ((void *)0x00000081) diff --git a/src/gpu/gpu_core.h b/src/gpu/gpu_core.h index 2e912a7a..63d55bb1 100644 --- a/src/gpu/gpu_core.h +++ b/src/gpu/gpu_core.h @@ -249,9 +249,9 @@ Enum(G_Layout) { G_Layout_NoChange, - // Allows a resource to be used on any queue with any access type, as long - // as there is only one writer at a time, and the writer is not writing to - // any texels currently being read. + // "Simultaneous" allows a resource to be used on any queue with any access + // type, as long as there is only one writer at a time, and the writer is not + // writing to any texels currently being read. // Resources cannot transition to/from this layout. They must be created // with it and are locked to it. G_Layout_Simultaneous, // D3D12_BARRIER_LAYOUT_COMMON + D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS @@ -626,77 +626,77 @@ void *G_HostPointerFromResource(G_ResourceHandle resource); u32 G_PushRef(G_ArenaHandle arena, G_ResourceHandle resource, G_RefDesc desc); -#define G_PushStructuredBufferRef(arena, resource, type, ...)(G_StructuredBufferRef) { \ +#define G_PushStructuredBufferRef(arena, resource, type, ...) (G_StructuredBufferRef) { \ .v = G_PushRef( \ (arena), (resource), \ (G_RefDesc) { .kind = G_RefKind_StructuredBuffer, .element_size = sizeof(type), __VA_ARGS__ } \ ) \ } -#define G_PushRWStructuredBufferRef(arena, resource, type, ...)(G_RWStructuredBufferRef) { \ +#define G_PushRWStructuredBufferRef(arena, resource, type, ...) (G_RWStructuredBufferRef) { \ .v = G_PushRef( \ (arena), (resource), \ (G_RefDesc) { .kind = G_RefKind_RWStructuredBuffer, .element_size = sizeof(type), __VA_ARGS__ } \ ) \ } -#define G_PushByteAddressBufferRef(arena, resource, ...)(G_ByteAddressBufferRef) { \ +#define G_PushByteAddressBufferRef(arena, resource, ...) (G_ByteAddressBufferRef) { \ .v = G_PushRef( \ (arena), (resource), \ (G_RefDesc) { .kind = G_RefKind_ByteAddressBuffer, __VA_ARGS__ } \ ) \ } -#define G_PushRWByteAddressBufferRef(arena, resource, ...)(G_RWByteAddressBufferRef) { \ +#define G_PushRWByteAddressBufferRef(arena, resource, ...) (G_RWByteAddressBufferRef) { \ .v = G_PushRef( \ (arena), (resource), \ (G_RefDesc) { .kind = G_RefKind_RWByteAddressBuffer, __VA_ARGS__ } \ ) \ } -#define G_PushTexture1DRef(arena, resource, ...)(G_Texture1DRef) { \ +#define G_PushTexture1DRef(arena, resource, ...) (G_Texture1DRef) { \ .v = G_PushRef( \ (arena), (resource), \ (G_RefDesc) { .kind = G_RefKind_Texture1D, __VA_ARGS__ } \ ) \ } -#define G_PushRWTexture1DRef(arena, resource, ...)(G_RWTexture1DRef) { \ +#define G_PushRWTexture1DRef(arena, resource, ...) (G_RWTexture1DRef) { \ .v = G_PushRef( \ (arena), (resource), \ (G_RefDesc) { .kind = G_RefKind_RWTexture1D, __VA_ARGS__ } \ ) \ } -#define G_PushTexture2DRef(arena, resource, ...)(G_Texture2DRef) { \ +#define G_PushTexture2DRef(arena, resource, ...) (G_Texture2DRef) { \ .v = G_PushRef( \ (arena), (resource), \ (G_RefDesc) { .kind = G_RefKind_Texture2D, __VA_ARGS__ } \ ) \ } -#define G_PushRWTexture2DRef(arena, resource, ...)(G_RWTexture2DRef) { \ +#define G_PushRWTexture2DRef(arena, resource, ...) (G_RWTexture2DRef) { \ .v = G_PushRef( \ (arena), (resource), \ (G_RefDesc) { .kind = G_RefKind_RWTexture2D, __VA_ARGS__ } \ ) \ } -#define G_PushTexture3DRef(arena, resource, ...)(G_Texture3DRef) { \ +#define G_PushTexture3DRef(arena, resource, ...) (G_Texture3DRef) { \ .v = G_PushRef( \ (arena), (resource), \ (G_RefDesc) { .kind = G_RefKind_Texture3D, __VA_ARGS__ } \ ) \ } -#define G_PushRWTexture3DRef(arena, resource, ...)(G_RWTexture3DRef) { \ +#define G_PushRWTexture3DRef(arena, resource, ...) (G_RWTexture3DRef) { \ .v = G_PushRef( \ (arena), (resource), \ (G_RefDesc) { .kind = G_RefKind_RWTexture3D, __VA_ARGS__ } \ ) \ } -#define G_PushSamplerStateRef(arena, resource, ...)(G_SamplerStateRef) { \ +#define G_PushSamplerStateRef(arena, resource, ...) (G_SamplerStateRef) { \ .v = G_PushRef( \ (arena), (resource), \ (G_RefDesc) { .kind = G_RefKind_SamplerState, __VA_ARGS__ } \ @@ -711,7 +711,7 @@ u32 G_PushRef(G_ArenaHandle arena, G_ResourceHandle resource, G_RefDesc desc); G_CommandListHandle G_PrepareCommandList(G_QueueKind queue); i64 G_CommitCommandList(G_CommandListHandle cl); -//- Cpu -> Gpu copy +//- Cpu -> Gpu staged copy void G_CopyCpuToBuffer(G_CommandListHandle cl, G_ResourceHandle dst, u64 dst_offset, void *src, RngU64 src_copy_range); void G_CopyCpuToTexture(G_CommandListHandle cl, G_ResourceHandle dst, Vec3I32 dst_offset, void *src, Vec3I32 src_dims, Rng3I32 src_copy_range); @@ -727,11 +727,11 @@ void G_CopyTextureToBuffer(G_CommandListHandle cl, G_ResourceHandle dst, Vec3I32 void G_SetConstant_(G_CommandListHandle cl, i32 slot, void *src_32bit, u32 size); -#define G_SetConstant(cl, name, value) do { \ - name##__shaderconstanttype __src; \ - __src.v = value; \ - G_SetConstant_((cl), (name), &__src, sizeof(__src)); \ -} while (0) +#define G_SetConstant(cl, name, value) do { \ + name##__shaderconstanttype __src; \ + __src.v = value; \ + G_SetConstant_((cl), (name), &__src, sizeof(__src)); \ + } while (0) //- Memory sync diff --git a/src/gpu/gpu_dx12/gpu_dx12_core.c b/src/gpu/gpu_dx12/gpu_dx12_core.c index bcfbb103..dcbb6b25 100644 --- a/src/gpu/gpu_dx12/gpu_dx12_core.c +++ b/src/gpu/gpu_dx12/gpu_dx12_core.c @@ -2429,7 +2429,7 @@ i64 G_CommitCommandList(G_CommandListHandle cl_handle) return completion_target; } -//- Cpu -> Gpu copy +//- Cpu -> Gpu staged copy void G_CopyCpuToBuffer(G_CommandListHandle cl_handle, G_ResourceHandle dst_handle, u64 dst_offset, void *src, RngU64 src_copy_range) { @@ -2763,7 +2763,6 @@ G_QueueCompletions G_CompletionTargetsFromQueues(G_QueueMask queue_mask) void G_SyncEx(G_QueueBarrierDesc desc) { - u64 fences_count = 0; ID3D12Fence *fences[G_QueueKind_COUNT] = Zi; i64 fence_targets[G_QueueKind_COUNT] = Zi; diff --git a/src/gpu/gpu_shader_core.cgh b/src/gpu/gpu_shader_core.cgh index 9bab012b..d1d744d0 100644 --- a/src/gpu/gpu_shader_core.cgh +++ b/src/gpu/gpu_shader_core.cgh @@ -35,8 +35,8 @@ Struct(G_SamplerStateRef) { u32 v; }; // // D3D12 exposes 64 root constants and Vulkan exposes 32 push constants. -// Supposedly amd hardware will start spilling constants once there -// are more than 12: https://gpuopen.com/learn/rdna-performance-guide/ +// Supposedly AMD hardware will start spilling constants once there +// are more than 12 - https://gpuopen.com/learn/rdna-performance-guide/ // #define G_NumGeneralPurposeConstants (8) // Constants available for any usage #define G_NumReservedConstants (4) // Constants reserved for internal usage by the GPU layer @@ -77,7 +77,7 @@ G_ForceDeclConstant(f32, G_ShaderConst_TweakF32, 10 #if IsLanguageG // TODO: Non-uniform resource access currently is assumed as the default // behavior. We may want to add explicit "uniform" variants for - // optimization on amd in the future. + // optimization on AMD in the future. template StructuredBuffer G_Dereference(G_StructuredBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } template RWStructuredBuffer G_Dereference(G_RWStructuredBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; } diff --git a/src/meta/meta.c b/src/meta/meta.c index 32d11efc..d4992155 100644 --- a/src/meta/meta.c +++ b/src/meta/meta.c @@ -326,7 +326,7 @@ void BuildEntryPoint(WaveLaneCtx *lane) layer_name = Lit("pp"); if (lane->idx == 0) { - EchoLine(Lit("No layer supplied, assuming \"pp\" build")); + EchoLine(Lit("No layer specified, assuming \"pp\" build")); } } cmdline.leaf_layer_name = layer_name; @@ -440,19 +440,21 @@ void BuildEntryPoint(WaveLaneCtx *lane) ////////////////////////////// //- Phase 1/3: Prep + // Build phases: + // // Phase 1/3: Prep (narrow) - // - Parse layers - // - Generate final C file - // - Generate final HLSL file - // - Generate resource dirs info + // - Parse layers + // - Generate final C file + // - Generate final HLSL file + // - Generate resource dirs info // // Phase 2/3: Compile (wide) - // - Compile C - // - Compile & embed shaders - // - Embed resource dirs + // - Compile C + // - Compile & embed shaders + // - Embed resource dirs // // Phase 3/3: Link (narrow) - // - Link + // - Link // TODO: Dispatch OS commands asynchronously diff --git a/src/net/net.h b/src/net/net.h index 70c7d659..fe397c39 100644 --- a/src/net/net.h +++ b/src/net/net.h @@ -1,318 +1,52 @@ //////////////////////////////////////////////////////////// -//~ Channel ID +//~ Opaque types -Struct(N_ChannelId) -{ - u32 gen; - u32 idx; -}; +Struct(NET_PipeHandle) { u64 v; }; + +#define NET_IsPipeNil(h) ((h).v == 0) //////////////////////////////////////////////////////////// -//~ Host command types +//~ Key types -Enum(N_CmdKind) +Struct(NET_Key) { - N_CmdKind_None, - N_CmdKind_TryConnect, - N_CmdKind_ConnectSuccess, - N_CmdKind_Disconnect, - N_CmdKind_Heartbeat, - N_CmdKind_Write + u64 v; }; -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; -}; +#define NET_NilKey ((NET_Key) { 0 }) +#define NET_IsKeyNil(k) ((k).v == 0) //////////////////////////////////////////////////////////// -//~ Event types +//~ Message types -Enum(N_EventKind) +Struct(NET_Msg) { - N_EventKind_None, - N_EventKind_ChannelOpened, - N_EventKind_ChannelClosed, - N_EventKind_Msg -}; + NET_Msg *next; + NET_Msg *prev; -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; + NET_Key src; String data; - N_RcvPacket *next; }; -Struct(N_RcvBuffer) +Struct(NET_MsgList) { - Arena *arena; - N_RcvPacket *first_packet; - N_RcvPacket *last_packet; + i64 count; + NET_Msg *first; + NET_Msg *last; }; //////////////////////////////////////////////////////////// -//~ Channel types +//~ @hookdecl Bootstrap -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; -}; +void NET_Bootstrap(void); //////////////////////////////////////////////////////////// -//~ Message asssembler types +//~ @hookdecl Net ops -Struct(N_MsgAssembler) -{ - N_Channel *channel; - b32 is_reliable; +NET_PipeHandle NET_AcquirePipe(void); - // Free list - N_MsgAssembler *next_free; +void NET_Bind(NET_PipeHandle pipe, u64 port); +u64 NET_BoundPortFromPipe(NET_PipeHandle pipe_handle); - // 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); +void NET_Push(NET_PipeHandle pipe, NET_Key dst, String data, b32 unreliable); +NET_MsgList NET_Pop(Arena *arena, NET_PipeHandle pipe); diff --git a/src/net/net.lay b/src/net/net.lay index 45740da9..35f0d6b4 100644 --- a/src/net/net.lay +++ b/src/net/net.lay @@ -1,16 +1,13 @@ @Layer net -////////////////////////////// -//- Dependencies - -@Dep platform - ////////////////////////////// //- Api @IncludeC net.h +@Bootstrap NET_Bootstrap + ////////////////////////////// //- Impl -@IncludeC net.c +@DefaultDownstream Win32 net_win32 diff --git a/src/net/net_win32/net_win32.c b/src/net/net_win32/net_win32.c new file mode 100644 index 00000000..5d981350 --- /dev/null +++ b/src/net/net_win32/net_win32.c @@ -0,0 +1,244 @@ +NET_W32_Ctx NET_W32 = Zi; + +//////////////////////////////////////////////////////////// +//~ @hookimpl Bootstrap + +void NET_Bootstrap(void) +{ + Arena *perm = PermArena(); + WSADATA wsa = Zi; + i32 err = WSAStartup(MAKEWORD(2,2), &wsa); + if (WSAStartup(MAKEWORD(2,2), &wsa) != 0) + { + Panic(StringF(perm, "Failed to initialize WinSock (error code - %F)", FmtSint(err))); + } + DispatchWave(Lit("Net"), 1, NET_W32_TickForever, 0); +} + +//////////////////////////////////////////////////////////// +//~ Helpers + +NET_W32_Pipe *NET_W32_PipeFromHandle(NET_PipeHandle pipe_handle) +{ + return (NET_W32_Pipe *)pipe_handle.v; +} + +//////////////////////////////////////////////////////////// +//~ @hookimpl Net ops + +NET_PipeHandle NET_AcquirePipe(void) +{ + Arena *perm = PermArena(); + NET_W32_Pipe *pipe = PushStruct(perm, NET_W32_Pipe); + return (NET_PipeHandle) { .v = (u64) pipe }; +} + +void NET_Bind(NET_PipeHandle pipe_handle, u64 port) +{ + // TODO: Mabye remove binding from the net interface entirely? + // Messages can just be popped from specific ports (with port 0 + // always returning no messages). Ephemeral ports can be "fetched", + // which under the hood binds them. A caching/timeout mechanism then + // just closes sockets as needed. + + + + TempArena scratch = BeginScratchNoConflict(); + NET_W32_Pipe *pipe = NET_W32_PipeFromHandle(pipe_handle); + + b32 is_ephemeral = port == 0; + // FIXME: Retry on timeout + if (!pipe->udp || (!is_ephemeral && pipe->bound_port != port)) + { + b32 ok = 1; + String port_str = StringF(scratch.arena, "%F", FmtUint(port)); + char *port_cstr = CstrFromString(scratch.arena, port_str); + + if (pipe->udp) + { + closesocket(pipe->udp); + pipe->bound_port = 0; + pipe->udp = 0; + } + + //- Init bind address + struct addrinfo hints = Zi; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol= IPPROTO_UDP; + hints.ai_flags = AI_PASSIVE; + struct addrinfo *ai = 0; + if (ok) + { + ok = getaddrinfo(0, port_cstr, &hints, &ai) == 0; + } + + //- Create udp socket + SOCKET sock = 0; + if (ok) + { + sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + ok = sock != INVALID_SOCKET; + } + + //- Enable address reuse + if (ok) + { + b32 reuse = 1; + ok = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == 0; + } + + //- Enable dual stack + if (ok) + { + DWORD v6_only = 0; + ok = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6_only, sizeof(v6_only)) == 0; + } + + //- Bind + if (ok) + { + ok = bind(sock, ai->ai_addr, (i32)ai->ai_addrlen) == 0; + } + + //- Enable non-blocking + if (ok) + { + u_long nonblocking = 1; + ok = ioctlsocket(sock, FIONBIO, &nonblocking) == 0; + } + + //- Fetch bound port + u64 bound_port = 0; + { + struct sockaddr_storage ss = Zi; + if (ok) + { + i32 ss_sizeof = sizeof(ss); + ok = getsockname(sock, (struct sockaddr *)&ss, &ss_sizeof) != SOCKET_ERROR; + } + if (ok) + { + if (ss.ss_family == AF_INET) + { + struct sockaddr_in *a = (struct sockaddr_in *)&ss; + bound_port = ntohs(a->sin_port); + } + else if (ss.ss_family == AF_INET6) + { + struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)&ss; + bound_port = ntohs(a6->sin6_port); + } + else + { + ok = 0; + } + } + } + + //- Finalize + if (ok) + { + pipe->bound_port = bound_port; + pipe->udp = sock; + } + else + { + if (sock != INVALID_SOCKET) + { + closesocket(sock); + } + } + + if (ai) + { + freeaddrinfo(ai); + } + } + + EndScratch(scratch); +} + +u64 NET_BoundPortFromPipe(NET_PipeHandle pipe_handle) +{ + // TODO: Instead maybe return "BindingStatus", which includes port + binding error/progress + NET_W32_Pipe *pipe = NET_W32_PipeFromHandle(pipe_handle); + return pipe->bound_port; +} + +void NET_Push(NET_PipeHandle pipe_handle, NET_Key dst, String data, b32 unreliable) +{ + NET_W32_Pipe *pipe = NET_W32_PipeFromHandle(pipe_handle); + + if (!pipe->udp) + { + // Bind to ephemeral port if not bound + NET_Bind(pipe_handle, 0); + } + + if (pipe->udp) + { + + } +} + +NET_MsgList NET_Pop(Arena *arena, NET_PipeHandle pipe_handle) +{ + NET_MsgList result = Zi; + return result; +} + +//////////////////////////////////////////////////////////// +//~ Net worker + +void NET_W32_TickForever(WaveLaneCtx *lane) +{ + for (;;) + { + TempArena scratch = BeginScratchNoConflict(); + + // TODO: Block until send/recv/signal + + ////////////////////////////// + //- Pop pipes + + NET_W32_Pipe *first_pipe = 0; + NET_W32_Pipe *last_pipe = 0; + + ////////////////////////////// + //- Pop cmds + + // NET_W32_Cmd *first_cmd = 0; + // NET_W32_Cmd *last_cmd = 0; + // { + // Lock lock = LockE(&NET_W32.pipes_mutex); + // { + + // } + // Unlock(&lock); + // } + + ////////////////////////////// + //- Receive messages + + ////////////////////////////// + //- Send messages + + // { + // for (NET_W32_Pipe *pipe = first_pipe; pipe; pipe = pipe->next) + // { + // if (pipe->udp) + // { + // sendto( + // pipe->udp, + // packet.text, + // packet.len, + + // ); + // } + // } + // } + + EndScratch(scratch); + } +} diff --git a/src/net/net_win32/net_win32.h b/src/net/net_win32/net_win32.h new file mode 100644 index 00000000..2e7249d5 --- /dev/null +++ b/src/net/net_win32/net_win32.h @@ -0,0 +1,28 @@ +//////////////////////////////////////////////////////////// +//~ Pipe types + +Struct(NET_W32_Pipe) +{ + u64 bound_port; + SOCKET udp; +}; + +//////////////////////////////////////////////////////////// +//~ State types + +Struct(NET_W32_Ctx) +{ + i32 _; +}; + +extern NET_W32_Ctx NET_W32; + +//////////////////////////////////////////////////////////// +//~ Helpers + +NET_W32_Pipe *NET_W32_PipeFromHandle(NET_PipeHandle pipe_handle); + +//////////////////////////////////////////////////////////// +//~ Net worker + +void NET_W32_TickForever(WaveLaneCtx *lane); diff --git a/src/net/net_win32/net_win32.lay b/src/net/net_win32/net_win32.lay new file mode 100644 index 00000000..fb1c0fcd --- /dev/null +++ b/src/net/net_win32/net_win32.lay @@ -0,0 +1,11 @@ +@Layer net_win32 + +////////////////////////////// +//- Api + +@IncludeC net_win32.h + +////////////////////////////// +//- Impl + +@IncludeC net_win32.c diff --git a/src/net/net.c b/src/net_old/net_old.c similarity index 100% rename from src/net/net.c rename to src/net_old/net_old.c diff --git a/src/net_old/net_old.h b/src/net_old/net_old.h new file mode 100644 index 00000000..70c7d659 --- /dev/null +++ b/src/net_old/net_old.h @@ -0,0 +1,318 @@ +//////////////////////////////////////////////////////////// +//~ 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); diff --git a/src/net_old/net_old.lay b/src/net_old/net_old.lay new file mode 100644 index 00000000..82c9d661 --- /dev/null +++ b/src/net_old/net_old.lay @@ -0,0 +1,16 @@ +@Layer net_old + +////////////////////////////// +//- Dependencies + +@Dep platform + +////////////////////////////// +//- Api + +@IncludeC net.h + +////////////////////////////// +//- Impl + +@IncludeC net.c diff --git a/src/pp/pp.c b/src/pp/pp.c index 65ba1d29..bbf02236 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -3,7 +3,7 @@ ThreadLocal P_ThreadLocalCtx P_tl = Zi; Readonly P_Ent P_NilEnt = { .xf = CompXformIdentity, - .look = { 0, -1 }, + .control.look = { 0, -1 }, }; Readonly P_Frame P_NilFrame = { @@ -1172,7 +1172,13 @@ void P_DebugDrawShape(P_Shape shape, Vec4 srgb) P_Msg *P_PushMsg(P_MsgKind kind, String data) { - // TODO + P_MsgNode *msg_node = PushStruct(P_tl.out_msgs_arena, P_MsgNode); + P_Msg *msg = &msg_node->msg; + msg->kind = kind; + msg->data = PushString(P_tl.out_msgs_arena, data); + DllQueuePush(P_tl.out_msgs.first, P_tl.out_msgs.last, msg_node); + ++P_tl.out_msgs.count; + return msg; } //////////////////////////////////////////////////////////// @@ -1405,7 +1411,7 @@ void P_StepFrame(P_Frame *frame) // for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) // { - // if (ent->fire_held) + // if (ent->control.fire_held) // { // if (ent->has_weapon) // { @@ -1422,12 +1428,12 @@ void P_StepFrame(P_Frame *frame) { // Xform xf = ent->xf; // Xform desired_xf = xf; - // if (!IsVec2Zero(ent->look)) + // if (!IsVec2Zero(ent->control.look)) // { - // desired_xf = XformWithWorldRotation(xf, AngleFromVec2(ent->look)); + // desired_xf = XformWithWorldRotation(xf, AngleFromVec2(ent->control.look)); // } // f32 move_speed = TweakFloat("Player move speed", 6.5, 0, 20); - // desired_xf.og = AddVec2(xf.og, MulVec2(ent->move, move_speed * sim_dt)); + // desired_xf.og = AddVec2(xf.og, MulVec2(ent->control.move, move_speed * sim_dt)); // Vec2 pos_diff = SubVec2(desired_xf.og, xf.og); // f32 angle_diff = UnwindAngleF32(RotationFromXform(desired_xf) - RotationFromXform(xf)); @@ -1456,7 +1462,7 @@ void P_StepFrame(P_Frame *frame) f32 max_speed = TweakFloat("Player max speed", 10, 0, 20); Vec2 new_velocity = ent->solved_v; - new_velocity = AddVec2(new_velocity, MulVec2(ent->move, move_force * sim_dt)); + new_velocity = AddVec2(new_velocity, MulVec2(ent->control.move, move_force * sim_dt)); // if (Vec2Len(new_velocity) > max_speed) // { @@ -1907,7 +1913,7 @@ void P_StepFrame(P_Frame *frame) P_EntList bullets_to_spawn = Zi; for (P_Ent *firer = P_FirstEnt(frame); !P_IsEntNil(firer); firer = P_NextEnt(firer)) { - if (firer->fire_held) + if (firer->control.fire_held) // if (firer->fire_presses) { // i64 fire_delta_ns = frame->time_ns - firer->last_fire_ns; @@ -1930,7 +1936,7 @@ void P_StepFrame(P_Frame *frame) { P_Shape firer_world_shape = P_WorldShapeFromEnt(firer); - Vec2 pos = P_EdgePointFromShape(firer_world_shape, firer->look); + Vec2 pos = P_EdgePointFromShape(firer_world_shape, firer->control.look); for (i64 bullet_idx = 0; bullet_idx < tick_bullets_count; ++bullet_idx) { @@ -1942,7 +1948,7 @@ void P_StepFrame(P_Frame *frame) f32 rand_angle = ((f32)P_RandU64FromEnt(firer) / (f32)0xFFFFFFFFFFFFFFFFull) - 0.5; f32 speed = tweak_speed * sim_dt; - f32 angle = AngleFromVec2(firer->look); + f32 angle = AngleFromVec2(firer->control.look); speed += (speed * 0.5) * rand_speed; angle += rand_angle * spread; @@ -2068,7 +2074,7 @@ void P_StepFrame(P_Frame *frame) { Vec4 color = VEC4(0.4, 0.8, 0.4, 1); Vec2 p0 = world_shape.centroid; - Vec2 p1 = P_EdgePointFromShape(world_shape, ent->look); + Vec2 p1 = P_EdgePointFromShape(world_shape, ent->control.look); P_DebugDrawLine(p0, p1, color); } } diff --git a/src/pp/pp.h b/src/pp/pp.h index 443067a4..6f8539cc 100644 --- a/src/pp/pp.h +++ b/src/pp/pp.h @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// //~ Key types -#define P_NilKey ((P_Key) { 0 }) +#define P_NilKey ((P_Key) { 0 }) Struct(P_Key) { @@ -69,6 +69,14 @@ Struct(P_DebugDrawNode) // TODO: Pack efficiently, deduplicate redundant fields +Struct(P_Control) +{ + Vec2 move; + Vec2 look; + f32 fire_held; + f32 fire_presses; +}; + Struct(P_Ent) { //- Internal world state @@ -95,11 +103,6 @@ Struct(P_Ent) Xform prev_xf; Xform xf; - Vec2 move; - Vec2 look; - f32 fire_held; - f32 fire_presses; - // TODO: Remove this (weapon testing) i64 last_fire_ns; b32 has_weapon; @@ -113,12 +116,17 @@ Struct(P_Ent) Vec2 hit_entry; Vec2 hit_entry_normal; + P_Control control; + //- User b32 is_user; P_Key player; + // FIXME: Ensure this field isn't transmitted in snapshots + NET_Key net; + u8 string_len; u8 string_text[32]; @@ -287,8 +295,6 @@ Struct(P_SimSnapshot) Struct(P_UserSnapshot) { - P_Key user; - i64 src_tick; i64 tick; Vec2 move; @@ -305,20 +311,34 @@ Enum(P_MsgKind) P_MsgKind_None, // User -> sim + P_MsgKind_UserSnapshot, P_MsgKind_SaveWorld, P_MsgKind_ResetWorld, P_MsgKind_TileEdit, P_MsgKind_EntEdit, // Sim -> user + P_MsgKind_SimSnapshot, P_MsgKind_Tiles, }; Struct(P_Msg) { - P_MsgKind kind; - P_Key src_user; + //- In + P_Key dst_user; // If dst is 0, then cmd is meant to be broadcast + b32 unreliable; + + //- Out + + P_Key src_user; + + //- In / Out + + P_MsgKind kind; + + P_UserSnapshot user_snapshot; + P_SimSnapshot sim_snapshot; P_TileKind tile_kind; Rng2I32 tile_range; diff --git a/src/pp/pp.lay b/src/pp/pp.lay index 4d5f38fb..cb73d670 100644 --- a/src/pp/pp.lay +++ b/src/pp/pp.lay @@ -1,5 +1,10 @@ @Layer pp +////////////////////////////// +//- Dependencies + +@Dep net + ////////////////////////////// //- Resources diff --git a/src/pp/pp_sim/pp_sim.lay b/src/pp/pp_sim/pp_sim.lay index 1b791089..388ab284 100644 --- a/src/pp/pp_sim/pp_sim.lay +++ b/src/pp/pp_sim/pp_sim.lay @@ -4,6 +4,7 @@ //- Dependencies @Dep pp +@Dep net @Dep platform ////////////////////////////// diff --git a/src/pp/pp_sim/pp_sim_core.c b/src/pp/pp_sim/pp_sim_core.c index bfae91ed..7b114ff2 100644 --- a/src/pp/pp_sim/pp_sim_core.c +++ b/src/pp/pp_sim/pp_sim_core.c @@ -25,6 +25,8 @@ void S_TickForever(WaveLaneCtx *lane) P_tl.debug_arena = AcquireArena(Gibi(64)); P_tl.out_msgs_arena = AcquireArena(Gibi(64)); + NET_PipeHandle net_pipe = NET_AcquirePipe(); + P_World *world = P_AcquireWorld(); // TODO: Real per-client deltas @@ -45,12 +47,6 @@ void S_TickForever(WaveLaneCtx *lane) - - - - - - ////////////////////////////// //- Sim loop @@ -126,105 +122,121 @@ void S_TickForever(WaveLaneCtx *lane) } ////////////////////////////// - //- Pop messages from user + //- Pop messages + + u64 desired_port = 22121; + NET_Bind(net_pipe, desired_port); P_MsgList in_msgs = Zi; { - LockTicketMutex(&P.u2s_msgs_mutex); + NET_MsgList net_msgs = NET_Pop(frame_arena, net_pipe); + for (NET_Msg *net_msg = net_msgs.first; net_msg; net_msg = net_msg->next) { - for (P_MsgNode *src_msg_node = P.u2s_msgs.first; src_msg_node; src_msg_node = src_msg_node->next) - { - P_MsgNode *dst_msg_node = PushStruct(frame_arena, P_MsgNode); - P_Msg *src_msg = &src_msg_node->msg; - P_Msg *dst_msg = &dst_msg_node->msg; - *dst_msg = *src_msg; - dst_msg->data = PushString(frame_arena, src_msg->data); - DllQueuePush(in_msgs.first, in_msgs.last, dst_msg_node); - ++in_msgs.count; - } - ResetArena(P.u2s_msgs_arena); - ZeroStruct(&P.u2s_msgs); + 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; } - UnlockTicketMutex(&P.u2s_msgs_mutex); } ////////////////////////////// - //- Register users + //- Process connection messages - { - for (P_MsgNode *msg_node = in_msgs.first; msg_node; msg_node = msg_node->next) - { - P_Msg *msg = &msg_node->msg; + // { + // for (P_MsgNode *msg_node = in_msgs.first; msg_node; msg_node = msg_node->next) + // { + // P_Msg *msg = &msg_node->msg; - P_Key user_key = msg->src_user; - P_Ent *user = P_EntFromKey(world_frame, user_key); - if (P_EntIsNil(user)) - { - P_EntList tmp_list = Zi; - user = P_PushTempEnt(frame_arena, &tmp_list); - user->key = user_key; - user->is_user = 1; - user->exists = 1; + // //- Register user + // if (msg->kind == P_MsgKind_RegisterUser) + // { + // P_Key user_key = msg->src_user; + // P_Ent *user = P_EntFromKey(world_frame, user_key); + // if (P_EntIsNil(user)) + // { + // P_EntList tmp_list = Zi; + // user = P_PushTempEnt(frame_arena, &tmp_list); + // user->key = user_key; + // user->is_user = 1; + // user->exists = 1; - i32 min_name_len = 3; - i32 max_name_len = countof(user->string_text) - 8; + // // FIXME: Set net key here - // De-duplicate user name - String user_name = msg->data; - user_name = TrimWhitespace(user_name); - user_name.len = MinI64(user_name.len, max_name_len); - user_name = TrimWhitespace(user_name); - if (user_name.len < min_name_len) - { - user_name = Lit("Player"); - } - { - String orig_user_name = user_name; - i64 duplicate_id = 0; - while (duplicate_id < 1000) - { - b32 is_duplicate = 0; - for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) - { - if (ent->is_user && MatchString(P_StringFromEnt(ent), user_name)) - { - is_duplicate = 1; - break; - } - } - if (is_duplicate) - { - duplicate_id += 1; - user_name = StringF(frame_arena, "%F (%F)", FmtString(orig_user_name), FmtSint(duplicate_id)); - } - else - { - break; - } - } - } - P_SetEntString(user, user_name); - P_Msg *msg = P_PushMsg( - P_MsgKind_Chat, - StringF( - frame_arena, - "Player %F connected", - FmtString(user_name) - )); - ) + // i32 min_name_len = 3; + // i32 max_name_len = countof(user->string_text) - 8; - P_SpawnEntsFromList(world_frame, tmp_list); - } - { - P_Msg *msg = P_PushMsg(P_MsgKind_RegisterSuccess, Zstr); - msg->dst_user = user->key; - } - } - } + // // De-duplicate user name + // String user_name = msg->data; + // user_name = TrimWhitespace(user_name); + // user_name.len = MinI64(user_name.len, max_name_len); + // user_name = TrimWhitespace(user_name); + // if (user_name.len < min_name_len) + // { + // user_name = Lit("Player"); + // } + // { + // String orig_user_name = user_name; + // i64 duplicate_id = 0; + // while (duplicate_id < 1000) + // { + // b32 is_duplicate = 0; + // for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) + // { + // if (ent->is_user && MatchString(P_StringFromEnt(ent), user_name)) + // { + // is_duplicate = 1; + // break; + // } + // } + // if (is_duplicate) + // { + // duplicate_id += 1; + // user_name = StringF(frame_arena, "%F (%F)", FmtString(orig_user_name), FmtSint(duplicate_id)); + // } + // else + // { + // break; + // } + // } + // } + // P_SetEntString(user, user_name); + // P_Msg *msg = P_PushMsg( + // P_MsgKind_Chat, + // StringF( + // frame_arena, + // "Player %F connected", + // FmtString(user_name) + // )); + // ) + + // P_SpawnEntsFromList(world_frame, tmp_list); + // } + // { + // P_Msg *msg = P_PushMsg(P_MsgKind_RegisterSuccess, Zstr); + // msg->dst_user = user->key; + // } + // } + // } + // } ////////////////////////////// //- 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; @@ -360,118 +372,208 @@ void S_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Update ent controls - for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) - { - ent->fire_presses = 0; - } + // for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) + // { + // ent->fire_presses = 0; + // } - for (P_Ent *user = P_FirstEnt(frame); !P_IsEntNil(user); user = P_NextEnt(user)) - { - if (user->is_iser) - { - P_Ent *target = P_EntFromKey(user->player); - if (!P_IsEntNil(target)) - { - target->move = ClampVec2Len(user->move, 1); - target->look = user->look; - target->fire_held = user->fire_held; - target->fire_presses += user->fire_presses; - } - } - } + // for (P_Ent *user = P_FirstEnt(frame); !P_IsEntNil(user); user = P_NextEnt(user)) + // { + // if (user->is_iser) + // { + // P_Ent *target = P_EntFromKey(user->player); + // if (!P_IsEntNil(target)) + // { + // target->move = ClampVec2Len(user->move, 1); + // target->look = user->look; + // target->fire_held = user->fire_held; + // target->fire_presses += user->fire_presses; + // } + // } + // } ////////////////////////////// //- Step frame - { - P_StepFrame(world_frame, user_msgs); - } + // { + // P_StepFrame(world_frame, user_msgs); + // } ////////////////////////////// - //- Publish sim state + //- Push tile messages - for (P_Ent *user = P_FirstEnt(world_frame); !P_IsEntNil(user); user = P_NextEnt(user)) + // 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; + // } + + ////////////////////////////// + //- Push snapshot messages + + // for (P_Ent *user = P_FirstEnt(world_frame); !P_IsEntNil(user); user = P_NextEnt(user)) + // { + // if (user->is_user) + // { + // Arena *msgs_arena = P_tl.out_msgs_arena; + // P_Msg *msg = P_PushMsg(P_MsgKind_SimSnapshot, Zstr); + // msg->dst_user = user->key; + // msg->unreliable = 1; + // P_SimSnapshot *snapshot = &msg->sim_snapshot; + // { + // snapshot->world_seed = world->seed; + // snapshot->tick = world_frame->tick; + // snapshot->time_ns = world_frame->time_ns; + // //- Push entity deltas + // for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) + // { + // P_Delta *delta = 0; + // { + // P_DeltaNode *dn = PushStruct(frame_arena, P_DeltaNode); + // snapshot->deltas_count += 1; + // SllQueuePush(snapshot->first_delta_node, snapshot->last_delta_node, dn); + // delta = &dn->delta; + // } + // delta->kind = P_DeltaKind_RawEnt; + // delta->ent = *ent; + // } + // //- Push debug draw information + // { + // i64 dst_idx = 0; + // snapshot->first_debug_draw_node = 0; + // snapshot->last_debug_draw_node = 0; + // snapshot->debug_draw_nodes_count = P_tl.debug_draw_nodes_count; + // P_DebugDrawNode *dst_nodes = PushStructsNoZero(frame_arena, P_DebugDrawNode, snapshot->debug_draw_nodes_count); + // for (P_DebugDrawNode *src = P_tl.first_debug_draw_node; src; src = src->next) + // { + // P_DebugDrawNode *dst = &dst_nodes[dst_idx]; + // *dst = *src; + // dst_idx += 1; + // SllQueuePush(snapshot->first_debug_draw_node, snapshot->last_debug_draw_node, dst); + // } + // ResetArena(P_tl.debug_arena); + // P_tl.first_debug_draw_node = 0; + // P_tl.last_debug_draw_node = 0; + // P_tl.debug_draw_nodes_count = 0; + // } + // } + // } + // } + + ////////////////////////////// + //- Send messages + + for (P_MsgNode *msg_node = P_tl.out_msgs.first; msg_node; msg_node = msg_node->next) { - if (user->is_user) + P_Msg *msg = &msg_node->msg; + if (P_IsKeyNil(msg->dst_user)) { - P_Frame *src_frame = P_FrameFromTick(world, user->acked_tick); - if (user->is_local) + // 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->unreliable); + } + } + } + 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->unreliable); } } } - // TODO: Only copy active entities - LockTicketMutex(&P.sim_output_back_tm); - { - P_OutputState *output = &P.sim_output_states[P.sim_output_back_idx]; - // Build messages - { - // Push tiles - if (tiles_dirty) - { - P_Msg *msg = 0; - { - P_MsgNode *msg_node = PushStruct(output->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(output->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; - } - } - // Build snapshot - { - P_Snapshot *snapshot = &output->snapshot; - snapshot->world_seed = world->seed; - snapshot->tick = world_frame->tick; - snapshot->time_ns = world_frame->time_ns; + // // TODO: Only copy active entities + // LockTicketMutex(&P.sim_output_back_tm); + // { + // P_OutputState *output = &P.sim_output_states[P.sim_output_back_idx]; - // Push entity deltas - for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) - { - P_Delta *delta = 0; - { - P_DeltaNode *dn = PushStruct(output->arena, P_DeltaNode); - snapshot->deltas_count += 1; - SllQueuePush(snapshot->first_delta_node, snapshot->last_delta_node, dn); - delta = &dn->delta; - } - delta->kind = P_DeltaKind_RawEnt; - delta->ent = *ent; - } + // // Build messages + // { + // // Push tiles + // if (tiles_dirty) + // { + // P_Msg *msg = 0; + // { + // P_MsgNode *msg_node = PushStruct(output->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(output->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; + // } + // } - // Push debug draw information - { - i64 dst_idx = 0; - snapshot->first_debug_draw_node = 0; - snapshot->last_debug_draw_node = 0; - snapshot->debug_draw_nodes_count = P_tl.debug_draw_nodes_count; - P_DebugDrawNode *dst_nodes = PushStructsNoZero(output->arena, P_DebugDrawNode, snapshot->debug_draw_nodes_count); - for (P_DebugDrawNode *src = P_tl.first_debug_draw_node; src; src = src->next) - { - P_DebugDrawNode *dst = &dst_nodes[dst_idx]; - *dst = *src; - dst_idx += 1; - SllQueuePush(snapshot->first_debug_draw_node, snapshot->last_debug_draw_node, dst); - } + // // Build snapshot + // { + // P_Snapshot *snapshot = &output->snapshot; - ResetArena(P_tl.debug_arena); - P_tl.first_debug_draw_node = 0; - P_tl.last_debug_draw_node = 0; - P_tl.debug_draw_nodes_count = 0; - } - } - } - UnlockTicketMutex(&P.sim_output_back_tm); + // snapshot->world_seed = world->seed; + // snapshot->tick = world_frame->tick; + // snapshot->time_ns = world_frame->time_ns; + + // // Push entity deltas + // for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) + // { + // P_Delta *delta = 0; + // { + // P_DeltaNode *dn = PushStruct(output->arena, P_DeltaNode); + // snapshot->deltas_count += 1; + // SllQueuePush(snapshot->first_delta_node, snapshot->last_delta_node, dn); + // delta = &dn->delta; + // } + // delta->kind = P_DeltaKind_RawEnt; + // delta->ent = *ent; + // } + + // // Push debug draw information + // { + // i64 dst_idx = 0; + // snapshot->first_debug_draw_node = 0; + // snapshot->last_debug_draw_node = 0; + // snapshot->debug_draw_nodes_count = P_tl.debug_draw_nodes_count; + // P_DebugDrawNode *dst_nodes = PushStructsNoZero(output->arena, P_DebugDrawNode, snapshot->debug_draw_nodes_count); + // for (P_DebugDrawNode *src = P_tl.first_debug_draw_node; src; src = src->next) + // { + // P_DebugDrawNode *dst = &dst_nodes[dst_idx]; + // *dst = *src; + // dst_idx += 1; + // SllQueuePush(snapshot->first_debug_draw_node, snapshot->last_debug_draw_node, dst); + // } + + // ResetArena(P_tl.debug_arena); + // P_tl.first_debug_draw_node = 0; + // P_tl.last_debug_draw_node = 0; + // P_tl.debug_draw_nodes_count = 0; + // } + // } + // } + // UnlockTicketMutex(&P.sim_output_back_tm); ////////////////////////////// //- Prune ents @@ -503,13 +605,13 @@ void S_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- End sim frame - // Reset front input state - { - Arena *arena = input->arena; - ResetArena(arena); - ZeroStruct(input); - input->arena = arena; - } + // // Reset front input state + // { + // Arena *arena = input->arena; + // ResetArena(arena); + // ZeroStruct(input); + // input->arena = arena; + // } i64 frame_end_ns = TimeNs(); diff --git a/src/pp/pp_transcode.c b/src/pp/pp_transcode.c index 0529831f..50bd4ca4 100644 --- a/src/pp/pp_transcode.c +++ b/src/pp/pp_transcode.c @@ -1,5 +1,5 @@ //////////////////////////////////////////////////////////// -//~ Transcode +//~ World String P_PackWorld(Arena *arena, P_World *src_world) { @@ -50,7 +50,7 @@ String P_PackWorld(Arena *arena, P_World *src_world) result.len += StringF(arena, " pos: \"%F\"\n", FmtFloat2(ent->xf.og)).len; result.len += StringF(arena, " rot: \"%F\"\n", FmtFloat2(RightFromXform(ent->xf))).len; result.len += StringF(arena, " exists: \"%F\"\n", FmtFloat(ent->exists)).len; - result.len += StringF(arena, " look: \"%F\"\n", FmtFloat2(ent->look)).len; + result.len += StringF(arena, " look: \"%F\"\n", FmtFloat2(ent->control.look)).len; } result.len += PushString(arena, Lit(" }\n")).len; } @@ -164,7 +164,7 @@ P_UnpackedWorld P_UnpackWorld(Arena *arena, String packed) if (MatchString(attr->name, Lit("look"))) { Vec2 look = CR_Vec2FromString(attr->value); - ent->look = look; + ent->control.look = look; } } } @@ -194,3 +194,20 @@ P_UnpackedWorld P_UnpackWorld(Arena *arena, String packed) EndScratch(scratch); return result; }; + +//////////////////////////////////////////////////////////// +//~ Message + +String P_PackMessage(Arena *arena, P_Msg *msg) +{ + String result = Zi; + // TODO + return result; +} + +P_Msg P_UnpackMsg(Arena *arena, String packed) +{ + P_Msg result = Zi; + // TODO + return result; +} diff --git a/src/pp/pp_transcode.h b/src/pp/pp_transcode.h index 4f4fbea4..2bc744fe 100644 --- a/src/pp/pp_transcode.h +++ b/src/pp/pp_transcode.h @@ -24,7 +24,13 @@ Struct(P_UnpackedWorld) }; //////////////////////////////////////////////////////////// -//~ Transcode +//~ World String P_PackWorld(Arena *arena, P_World *src_world); 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); diff --git a/src/pp/pp_vis/pp_vis.lay b/src/pp/pp_vis/pp_vis.lay index 93799617..4de4d636 100644 --- a/src/pp/pp_vis/pp_vis.lay +++ b/src/pp/pp_vis/pp_vis.lay @@ -4,6 +4,7 @@ //- Dependencies @Dep pp +@Dep net @Dep sprite @Dep gpu @Dep glyph_cache diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 6f58c99a..a576bdf1 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -348,8 +348,9 @@ void V_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Init vis state - Arena *sim_snapshot_arena = AcquireArena(Gibi(64)); - P_SimSnapshot sim_snapshot = Zi; + Arena *sim_debug_arena = AcquireArena(Gibi(64)); + P_DebugDrawNode *first_sim_debug_draw_node = 0; + P_DebugDrawNode *last_sim_debug_draw_node = 0; P_World *sim_world = P_AcquireWorld(); P_World *predict_world = P_AcquireWorld(); @@ -358,6 +359,8 @@ void V_TickForever(WaveLaneCtx *lane) Vec2I32 tiles_dims = VEC2I32(P_TilesPitch, P_TilesPitch); Vec2I32 cells_dims = VEC2I32(V_CellsPerMeter * P_WorldPitch, V_CellsPerMeter * P_WorldPitch); + NET_PipeHandle net_pipe = NET_AcquirePipe(); + // Init gpu state G_ResourceHandle gpu_state = Zi; G_ResourceHandle gpu_tiles = Zi; @@ -2622,78 +2625,85 @@ void V_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Pop messages from sim + // FIXME: Reject messages if not from currently connected sim + P_MsgList in_msgs = Zi; { - LockTicketMutex(&P.s2u_msgs_mutex); + NET_MsgList net_msgs = NET_Pop(frame->arena, net_pipe); + for (NET_Msg *net_msg = net_msgs.first; net_msg; net_msg = net_msg->next) { - for (P_MsgNode *src_msg_node = P.s2u_msgs.first; src_msg_node; src_msg_node = src_msg_node->next) - { - P_MsgNode *dst_msg_node = PushStruct(frame->arena, P_MsgNode); - P_Msg *src_msg = &src_msg_node->msg; - P_Msg *dst_msg = &dst_msg_node->msg; - *dst_msg = *src_msg; - dst_msg->data = PushString(frame->arena, src_msg->data); - DllQueuePush(in_msgs.first, in_msgs.last, dst_msg_node); - ++in_msgs.count; - } - ResetArena(P.s2u_msgs_arena); - ZeroStruct(&P.s2u_msgs); + 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; } - UnlockTicketMutex(&P.s2u_msgs_mutex); } ////////////////////////////// //- Pop snapshot from sim - { - LockTicketMutex(&P.s2u_snapshot_mutex); - P_SimSnapshot *src_snapshot = &P.s2u_snapshot; - if (src_snapshot->tick > sim_snapshot.tick) - { - ResetArena(sim_snapshot_arena); - ZeroStruct(&sim_snapshot); - sim_snapshot.world_seed = src_snapshot->world_seed; - sim_snapshot.src_tick = src_snapshot->src_tick; - sim_snapshot.tick = src_snapshot->tick; - sim_snapshot.time_ns = src_snapshot->time_ns; - { - //- Copy deltas - { - P_SimDeltaNode *dst_nodes = PushStructsNoZero(sim_snapshot_arena, P_SimDeltaNode, src_snapshot->deltas_count); - for (P_SimDeltaNode *src_delta_node = src_snapshot->first_delta_node; src_delta_node; src_delta_node = src_delta_node->next) - { - P_SimDeltaNode *dst_delta_node = &dst_nodes[sim_snapshot.deltas_count]; - *dst_delta_node = *src_delta_node; - SllQueuePush(sim_snapshot.first_delta_node, sim_snapshot.last_delta_node, dst_delta_node); - sim_snapshot.deltas_count += 1; - } - } - //- Copy debug info - { - P_DebugDrawNode *dst_nodes = PushStructsNoZero(sim_snapshot_arena, P_DebugDrawNode, src_snapshot->debug_draw_nodes_count); - for (P_DebugDrawNode *src = src_snapshot->first_debug_draw_node; src; src = src->next) - { - P_DebugDrawNode *dst = &dst_nodes[sim_snapshot.debug_draw_nodes_count]; - *dst = *src; - SllQueuePush(sim_snapshot.first_debug_draw_node, sim_snapshot.last_debug_draw_node, dst); - sim_snapshot.debug_draw_nodes_count += 1; - } - } - } - ResetArena(P.s2u_snapshot_arena); - ZeroStruct(&P.s2u_snapshot); - } - UnlockTicketMutex(&P.s2u_snapshot_mutex); - } + // { + // LockTicketMutex(&P.s2u_snapshot_mutex); + // P_SimSnapshot *src_snapshot = &P.s2u_snapshot; + // if (src_snapshot->tick > sim_snapshot.tick) + // { + // ResetArena(sim_snapshot_arena); + // ZeroStruct(&sim_snapshot); + // sim_snapshot.world_seed = src_snapshot->world_seed; + // sim_snapshot.src_tick = src_snapshot->src_tick; + // sim_snapshot.tick = src_snapshot->tick; + // sim_snapshot.time_ns = src_snapshot->time_ns; + // { + // //- Copy deltas + // { + // P_SimDeltaNode *dst_nodes = PushStructsNoZero(sim_snapshot_arena, P_SimDeltaNode, src_snapshot->deltas_count); + // for (P_SimDeltaNode *src_delta_node = src_snapshot->first_delta_node; src_delta_node; src_delta_node = src_delta_node->next) + // { + // P_SimDeltaNode *dst_delta_node = &dst_nodes[sim_snapshot.deltas_count]; + // *dst_delta_node = *src_delta_node; + // SllQueuePush(sim_snapshot.first_delta_node, sim_snapshot.last_delta_node, dst_delta_node); + // sim_snapshot.deltas_count += 1; + // } + // } + // //- Copy debug info + // { + // P_DebugDrawNode *dst_nodes = PushStructsNoZero(sim_snapshot_arena, P_DebugDrawNode, src_snapshot->debug_draw_nodes_count); + // for (P_DebugDrawNode *src = src_snapshot->first_debug_draw_node; src; src = src->next) + // { + // P_DebugDrawNode *dst = &dst_nodes[sim_snapshot.debug_draw_nodes_count]; + // *dst = *src; + // SllQueuePush(sim_snapshot.first_debug_draw_node, sim_snapshot.last_debug_draw_node, dst); + // sim_snapshot.debug_draw_nodes_count += 1; + // } + // } + // } + // ResetArena(P.s2u_snapshot_arena); + // ZeroStruct(&P.s2u_snapshot); + // } + // UnlockTicketMutex(&P.s2u_snapshot_mutex); + // } ////////////////////////////// //- Apply sim msgs + P_Msg *newest_snapshot_msg = 0; { 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_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) // { @@ -2729,50 +2739,52 @@ void V_TickForever(WaveLaneCtx *lane) } ////////////////////////////// - //- Apply sim snapshots + //- Apply sim snapshot - // if (sim_snapshot.tick > sim_world->last_frame->tick) - // { - // 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; + if (newest_snapshot_msg) + { + P_SimSnapshot *snapshot = &newest_snapshot_msg->sim_snapshot; - // //- 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); - // } - // } + 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; - // //- 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); - // } - // } - // } - // } + //- Apply deltas + for (P_SimDeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next) + { + P_SimDelta *delta = &dn->delta; + //- Raw ent + if (delta->kind == P_SimDeltaKind_RawEnt) + { + P_Ent tmp_ent = delta->ent; + P_EntListNode tmp_ent_node = Zi; + tmp_ent_node.ent = tmp_ent; + P_EntList ent_list = Zi; + ent_list.first = &tmp_ent_node; + ent_list.last = &tmp_ent_node; + P_SpawnEntsFromList(dst_frame, ent_list); + } + } + + //- Update sim debug info + { + ResetArena(sim_debug_arena); + first_sim_debug_draw_node = 0; + last_sim_debug_draw_node = 0; + { + i64 dst_idx = 0; + P_DebugDrawNode *dst_nodes = PushStructsNoZero(sim_debug_arena, P_DebugDrawNode, snapshot->debug_draw_nodes_count); + for (P_DebugDrawNode *src = snapshot->first_debug_draw_node; src; src = src->next) + { + P_DebugDrawNode *dst = &dst_nodes[dst_idx]; + *dst = *src; + dst_idx += 1; + SllQueuePush(first_sim_debug_draw_node, last_sim_debug_draw_node, dst); + } + } + } + } // TODO: Remove this P_ClearFrames(sim_world, I64Min, sim_world->last_frame->tick - 1); @@ -2815,7 +2827,7 @@ void V_TickForever(WaveLaneCtx *lane) } ////////////////////////////// - //- Push user snapshot + //- Push user snapshots // FIXME: Real ping // f64 ping = 0.250; @@ -2823,39 +2835,39 @@ void V_TickForever(WaveLaneCtx *lane) i64 ping_ns = NsFromSeconds(ping); frame->predict_to = sim_world->last_frame->tick + MaxF64(CeilF64(ping * SIM_TICKS_PER_SECOND), 1.0); - if (frame->predict_to != prev_frame->predict_to) - { - { - P_UserSnapshot snapshot = Zi; - snapshot->user = V.user_user; - snapshot->src_tick = 0; - // FIXME: Generate snapshots for all new frames, not just last - snapshot->tick = frame->predict_to; - snapshot->move = frame->move; - snapshot->look = frame->look; - snapshot->fire_held = frame->fire_held; - snapshot->fire_presses = frame->fire_presses; - } - } + // if (frame->predict_to != prev_frame->predict_to) + // { + // { + // P_UserSnapshot snapshot = Zi; + // snapshot->user = V.user_user; + // snapshot->src_tick = 0; + // // FIXME: Generate snapshots for all new frames, not just last + // snapshot->tick = frame->predict_to; + // snapshot->move = frame->move; + // snapshot->look = frame->look; + // snapshot->fire_held = frame->fire_held; + // snapshot->fire_presses = frame->fire_presses; + // } + // } ////////////////////////////// //- Submit sim commands - { - LockTicketMutex(&P.sim_input_back_tm); - { - P_InputState *v2s = &P.sim_input_states[P.sim_input_back_idx]; - for (P_MsgNode *src_cmd_node = V.sim_cmds.first; src_cmd_node; src_cmd_node = src_cmd_node->next) - { - P_MsgNode *dst_cmd_node = PushStruct(v2s->arena, P_MsgNode); - dst_cmd_node->cmd = src_cmd_node->cmd; - dst_cmd_node->cmd.tick = frame->predict_to; - DllQueuePush(v2s->cmds.first, v2s->cmds.last, dst_cmd_node); - ++v2s->cmds.count; - } - } - UnlockTicketMutex(&P.sim_input_back_tm); - } + // { + // LockTicketMutex(&P.sim_input_back_tm); + // { + // P_InputState *v2s = &P.sim_input_states[P.sim_input_back_idx]; + // for (P_MsgNode *src_cmd_node = V.sim_cmds.first; src_cmd_node; src_cmd_node = src_cmd_node->next) + // { + // P_MsgNode *dst_cmd_node = PushStruct(v2s->arena, P_MsgNode); + // dst_cmd_node->cmd = src_cmd_node->cmd; + // dst_cmd_node->cmd.tick = frame->predict_to; + // DllQueuePush(v2s->cmds.first, v2s->cmds.last, dst_cmd_node); + // ++v2s->cmds.count; + // } + // } + // UnlockTicketMutex(&P.sim_input_back_tm); + // } ////////////////////////////// //- Predict @@ -3354,66 +3366,66 @@ void V_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Debug draw - { - // Merge vis debug draws with sim debug draws - P_DebugDrawNode *first_debug_draw_node = first_sim_debug_draw_node; - P_DebugDrawNode *last_debug_draw_node = last_sim_debug_draw_node; - if (P_tl.first_debug_draw_node) - { - if (last_debug_draw_node) - { - last_debug_draw_node->next = P_tl.first_debug_draw_node; - } - else - { - first_debug_draw_node = P_tl.first_debug_draw_node; - } - last_debug_draw_node = P_tl.last_debug_draw_node; - } + // { + // // Merge vis debug draws with sim debug draws + // P_DebugDrawNode *first_debug_draw_node = first_sim_debug_draw_node; + // P_DebugDrawNode *last_debug_draw_node = last_sim_debug_draw_node; + // if (P_tl.first_debug_draw_node) + // { + // if (last_debug_draw_node) + // { + // last_debug_draw_node->next = P_tl.first_debug_draw_node; + // } + // else + // { + // first_debug_draw_node = P_tl.first_debug_draw_node; + // } + // last_debug_draw_node = P_tl.last_debug_draw_node; + // } - // Push draws - for (P_DebugDrawNode *n = first_debug_draw_node; n; n = n->next) - { - Vec4 color = Vec4FromU32(n->srgb32); - i32 detail = 24; - f32 radius = 5; - switch(n->kind) - { - case P_DebugDrawKind_Point: - { - Vec2 ui_p = MulXformV2(frame->xf.world_to_ui, n->point.p); - V_DrawPoint(ui_p, color); - } break; + // // Push draws + // for (P_DebugDrawNode *n = first_debug_draw_node; n; n = n->next) + // { + // Vec4 color = Vec4FromU32(n->srgb32); + // i32 detail = 24; + // f32 radius = 5; + // switch(n->kind) + // { + // case P_DebugDrawKind_Point: + // { + // Vec2 ui_p = MulXformV2(frame->xf.world_to_ui, n->point.p); + // V_DrawPoint(ui_p, color); + // } break; - case P_DebugDrawKind_Line: - { - Vec2 ui_p0 = MulXformV2(frame->xf.world_to_ui, n->line.p0); - Vec2 ui_p1 = MulXformV2(frame->xf.world_to_ui, n->line.p1); - V_DrawLine(ui_p0, ui_p1, color); - } break; + // case P_DebugDrawKind_Line: + // { + // Vec2 ui_p0 = MulXformV2(frame->xf.world_to_ui, n->line.p0); + // Vec2 ui_p1 = MulXformV2(frame->xf.world_to_ui, n->line.p1); + // V_DrawLine(ui_p0, ui_p1, color); + // } break; - case P_DebugDrawKind_Rect: - { - Rng2 ui_rect = Zi; - ui_rect.p0 = MulXformV2(frame->xf.world_to_ui, n->rect.p0); - ui_rect.p1 = MulXformV2(frame->xf.world_to_ui, n->rect.p1); - V_DrawRect(ui_rect, color, V_DrawFlag_Line); - } break; + // case P_DebugDrawKind_Rect: + // { + // Rng2 ui_rect = Zi; + // ui_rect.p0 = MulXformV2(frame->xf.world_to_ui, n->rect.p0); + // ui_rect.p1 = MulXformV2(frame->xf.world_to_ui, n->rect.p1); + // V_DrawRect(ui_rect, color, V_DrawFlag_Line); + // } break; - case P_DebugDrawKind_Shape: - { - P_Shape ui_shape = P_MulXformShape(frame->xf.world_to_ui, n->shape); - V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line); - } break; - } - } + // case P_DebugDrawKind_Shape: + // { + // P_Shape ui_shape = P_MulXformShape(frame->xf.world_to_ui, n->shape); + // V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line); + // } break; + // } + // } - // Reset vis debug draws - ResetArena(P_tl.debug_arena); - P_tl.first_debug_draw_node = 0; - P_tl.last_debug_draw_node = 0; - P_tl.debug_draw_nodes_count = 0; - } + // // Reset vis debug draws + // ResetArena(P_tl.debug_arena); + // P_tl.first_debug_draw_node = 0; + // P_tl.last_debug_draw_node = 0; + // P_tl.debug_draw_nodes_count = 0; + // } ////////////////////////////// @@ -3689,21 +3701,21 @@ void V_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Prune sim cmds - { - for (P_MsgNode *msg_node = V.sim_cmds.first; cmd_node;) - { - P_MsgNode *next = cmd_node->next; - { - if (!cmd_node->cmd.predicted || cmd_node->cmd.tick <= sim_world->last_frame->tick) - { - DllQueueRemove(V.sim_cmds.first, V.sim_cmds.last, cmd_node); - SllStackPush(V.first_free_sim_cmd_node, cmd_node); - --V.sim_cmds.count; - } - } - cmd_node = next; - } - } + // { + // for (P_MsgNode *msg_node = V.sim_cmds.first; cmd_node;) + // { + // P_MsgNode *next = cmd_node->next; + // { + // if (!cmd_node->cmd.predicted || cmd_node->cmd.tick <= sim_world->last_frame->tick) + // { + // DllQueueRemove(V.sim_cmds.first, V.sim_cmds.last, cmd_node); + // SllStackPush(V.first_free_sim_cmd_node, cmd_node); + // --V.sim_cmds.count; + // } + // } + // cmd_node = next; + // } + // } ////////////////////////////// //- Prune sim ents @@ -3731,17 +3743,27 @@ void V_TickForever(WaveLaneCtx *lane) } } + ////////////////////////////// + //- Send messages + + for (P_MsgNode *msg_node = P_tl.out_msgs.first; msg_node; msg_node = msg_node->next) + { + P_Msg *msg = &msg_node->msg; + String packed = P_PackMessage(frame->arena, msg); + NET_Push(net_pipe, user->net, packed, msg->unreliable); + } + ////////////////////////////// //- End frame i32 vsync = !!TweakBool("Vsync", 1); - { - Arena *old_arena = sim_output->arena; - ZeroStruct(sim_output); - sim_output->arena = old_arena; - ResetArena(sim_output->arena); - } + // { + // Arena *old_arena = sim_output->arena; + // ZeroStruct(sim_output); + // sim_output->arena = old_arena; + // ResetArena(sim_output->arena); + // } G_CommitCommandList(frame->cl);