net_win32 layer
This commit is contained in:
parent
b73daaf1f1
commit
fe5aca14d2
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#define COBJMACROS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define UNICODE
|
||||
#pragma warning(push, 0)
|
||||
// #pragma warning(push, 0)
|
||||
#include <Windows.h>
|
||||
#include <combaseapi.h>
|
||||
#include <dcommon.h>
|
||||
@ -24,7 +24,7 @@
|
||||
#include <dwmapi.h>
|
||||
#include <avrt.h>
|
||||
#include <shellapi.h>
|
||||
#pragma warning(pop)
|
||||
// #pragma warning(pop)
|
||||
|
||||
#ifndef BCRYPT_RNG_ALG_HANDLE
|
||||
#define BCRYPT_RNG_ALG_HANDLE ((void *)0x00000081)
|
||||
|
||||
@ -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
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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<typename T> StructuredBuffer<T> G_Dereference(G_StructuredBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
template<typename T> RWStructuredBuffer<T> G_Dereference(G_RWStructuredBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
|
||||
@ -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,6 +440,8 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Phase 1/3: Prep
|
||||
|
||||
// Build phases:
|
||||
//
|
||||
// Phase 1/3: Prep (narrow)
|
||||
// - Parse layers
|
||||
// - Generate final C file
|
||||
|
||||
318
src/net/net.h
318
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);
|
||||
|
||||
@ -1,16 +1,13 @@
|
||||
@Layer net
|
||||
|
||||
//////////////////////////////
|
||||
//- Dependencies
|
||||
|
||||
@Dep platform
|
||||
|
||||
//////////////////////////////
|
||||
//- Api
|
||||
|
||||
@IncludeC net.h
|
||||
|
||||
@Bootstrap NET_Bootstrap
|
||||
|
||||
//////////////////////////////
|
||||
//- Impl
|
||||
|
||||
@IncludeC net.c
|
||||
@DefaultDownstream Win32 net_win32
|
||||
|
||||
244
src/net/net_win32/net_win32.c
Normal file
244
src/net/net_win32/net_win32.c
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
28
src/net/net_win32/net_win32.h
Normal file
28
src/net/net_win32/net_win32.h
Normal file
@ -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);
|
||||
11
src/net/net_win32/net_win32.lay
Normal file
11
src/net/net_win32/net_win32.lay
Normal file
@ -0,0 +1,11 @@
|
||||
@Layer net_win32
|
||||
|
||||
//////////////////////////////
|
||||
//- Api
|
||||
|
||||
@IncludeC net_win32.h
|
||||
|
||||
//////////////////////////////
|
||||
//- Impl
|
||||
|
||||
@IncludeC net_win32.c
|
||||
318
src/net_old/net_old.h
Normal file
318
src/net_old/net_old.h
Normal file
@ -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);
|
||||
16
src/net_old/net_old.lay
Normal file
16
src/net_old/net_old.lay
Normal file
@ -0,0 +1,16 @@
|
||||
@Layer net_old
|
||||
|
||||
//////////////////////////////
|
||||
//- Dependencies
|
||||
|
||||
@Dep platform
|
||||
|
||||
//////////////////////////////
|
||||
//- Api
|
||||
|
||||
@IncludeC net.h
|
||||
|
||||
//////////////////////////////
|
||||
//- Impl
|
||||
|
||||
@IncludeC net.c
|
||||
28
src/pp/pp.c
28
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);
|
||||
}
|
||||
}
|
||||
|
||||
38
src/pp/pp.h
38
src/pp/pp.h
@ -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;
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
@Layer pp
|
||||
|
||||
//////////////////////////////
|
||||
//- Dependencies
|
||||
|
||||
@Dep net
|
||||
|
||||
//////////////////////////////
|
||||
//- Resources
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
//- Dependencies
|
||||
|
||||
@Dep pp
|
||||
@Dep net
|
||||
@Dep platform
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
@ -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,104 +122,120 @@ 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);
|
||||
{
|
||||
for (P_MsgNode *src_msg_node = P.u2s_msgs.first; src_msg_node; src_msg_node = src_msg_node->next)
|
||||
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)
|
||||
{
|
||||
String packed = net_msg->data;
|
||||
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);
|
||||
*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;
|
||||
}
|
||||
ResetArena(P.u2s_msgs_arena);
|
||||
ZeroStruct(&P.u2s_msgs);
|
||||
}
|
||||
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;
|
||||
|
||||
// //- 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;
|
||||
|
||||
// // FIXME: Set net key here
|
||||
|
||||
// i32 min_name_len = 3;
|
||||
// i32 max_name_len = countof(user->string_text) - 8;
|
||||
|
||||
// // 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;
|
||||
|
||||
P_Key user_key = msg->src_user;
|
||||
P_Ent *user = P_EntFromKey(world_frame, user_key);
|
||||
if (P_EntIsNil(user))
|
||||
if (msg->kind == P_MsgKind_UserSnapshot)
|
||||
{
|
||||
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;
|
||||
|
||||
// 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
|
||||
|
||||
// P_MsgList user_msgs = Zi;
|
||||
// {
|
||||
@ -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
|
||||
|
||||
// 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
P_Frame *src_frame = P_FrameFromTick(world, user->acked_tick);
|
||||
if (user->is_local)
|
||||
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();
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
//- Dependencies
|
||||
|
||||
@Dep pp
|
||||
@Dep net
|
||||
@Dep sprite
|
||||
@Dep gpu
|
||||
@Dep glyph_cache
|
||||
|
||||
@ -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);
|
||||
{
|
||||
for (P_MsgNode *src_msg_node = P.s2u_msgs.first; src_msg_node; src_msg_node = src_msg_node->next)
|
||||
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)
|
||||
{
|
||||
String packed = net_msg->data;
|
||||
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);
|
||||
*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;
|
||||
}
|
||||
ResetArena(P.s2u_msgs_arena);
|
||||
ZeroStruct(&P.s2u_msgs);
|
||||
}
|
||||
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);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user