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 || (
|
where /Q cl.exe || (
|
||||||
echo **************************************************************************
|
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
|
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
|
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
|
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 Visual studio development environment activated
|
||||||
echo **************************************************************************
|
echo **************************************************************************
|
||||||
|
echo.
|
||||||
)
|
)
|
||||||
|
|
||||||
::- Meta build
|
::- Meta build
|
||||||
|
|||||||
@ -439,15 +439,6 @@
|
|||||||
#define IsIndexable(a) (sizeof(a[0]) != 0)
|
#define IsIndexable(a) (sizeof(a[0]) != 0)
|
||||||
#define IsFixedArray(a) (IsIndexable(a) && (((void *)&a) == ((void *)a)))
|
#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
|
//- struct region
|
||||||
#define BeginFieldRegion(name) i8 __begfieldreg__##name
|
#define BeginFieldRegion(name) i8 __begfieldreg__##name
|
||||||
#define EndFieldRegion(name) i8 __endfieldreg__##name
|
#define EndFieldRegion(name) i8 __endfieldreg__##name
|
||||||
|
|||||||
@ -6,25 +6,25 @@
|
|||||||
#define COBJMACROS
|
#define COBJMACROS
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#define UNICODE
|
#define UNICODE
|
||||||
#pragma warning(push, 0)
|
// #pragma warning(push, 0)
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <combaseapi.h>
|
#include <combaseapi.h>
|
||||||
#include <dcommon.h>
|
#include <dcommon.h>
|
||||||
#include <initguid.h>
|
#include <initguid.h>
|
||||||
#include <unknwn.h>
|
#include <unknwn.h>
|
||||||
#include <objbase.h>
|
#include <objbase.h>
|
||||||
#include <uuids.h>
|
#include <uuids.h>
|
||||||
#include <Knownfolders.h>
|
#include <Knownfolders.h>
|
||||||
#include <WinSock2.h>
|
#include <WinSock2.h>
|
||||||
#include <TlHelp32.h>
|
#include <TlHelp32.h>
|
||||||
#include <WS2tcpip.h>
|
#include <WS2tcpip.h>
|
||||||
#include <windowsx.h>
|
#include <windowsx.h>
|
||||||
#include <ShlObj_core.h>
|
#include <ShlObj_core.h>
|
||||||
#include <fileapi.h>
|
#include <fileapi.h>
|
||||||
#include <dwmapi.h>
|
#include <dwmapi.h>
|
||||||
#include <avrt.h>
|
#include <avrt.h>
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
#pragma warning(pop)
|
// #pragma warning(pop)
|
||||||
|
|
||||||
#ifndef BCRYPT_RNG_ALG_HANDLE
|
#ifndef BCRYPT_RNG_ALG_HANDLE
|
||||||
#define BCRYPT_RNG_ALG_HANDLE ((void *)0x00000081)
|
#define BCRYPT_RNG_ALG_HANDLE ((void *)0x00000081)
|
||||||
|
|||||||
@ -249,9 +249,9 @@ Enum(G_Layout)
|
|||||||
{
|
{
|
||||||
G_Layout_NoChange,
|
G_Layout_NoChange,
|
||||||
|
|
||||||
// Allows a resource to be used on any queue with any access type, as long
|
// "Simultaneous" allows a resource to be used on any queue with any access
|
||||||
// as there is only one writer at a time, and the writer is not writing to
|
// type, as long as there is only one writer at a time, and the writer is not
|
||||||
// any texels currently being read.
|
// writing to any texels currently being read.
|
||||||
// Resources cannot transition to/from this layout. They must be created
|
// Resources cannot transition to/from this layout. They must be created
|
||||||
// with it and are locked to it.
|
// with it and are locked to it.
|
||||||
G_Layout_Simultaneous, // D3D12_BARRIER_LAYOUT_COMMON + D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS
|
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);
|
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( \
|
.v = G_PushRef( \
|
||||||
(arena), (resource), \
|
(arena), (resource), \
|
||||||
(G_RefDesc) { .kind = G_RefKind_StructuredBuffer, .element_size = sizeof(type), __VA_ARGS__ } \
|
(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( \
|
.v = G_PushRef( \
|
||||||
(arena), (resource), \
|
(arena), (resource), \
|
||||||
(G_RefDesc) { .kind = G_RefKind_RWStructuredBuffer, .element_size = sizeof(type), __VA_ARGS__ } \
|
(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( \
|
.v = G_PushRef( \
|
||||||
(arena), (resource), \
|
(arena), (resource), \
|
||||||
(G_RefDesc) { .kind = G_RefKind_ByteAddressBuffer, __VA_ARGS__ } \
|
(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( \
|
.v = G_PushRef( \
|
||||||
(arena), (resource), \
|
(arena), (resource), \
|
||||||
(G_RefDesc) { .kind = G_RefKind_RWByteAddressBuffer, __VA_ARGS__ } \
|
(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( \
|
.v = G_PushRef( \
|
||||||
(arena), (resource), \
|
(arena), (resource), \
|
||||||
(G_RefDesc) { .kind = G_RefKind_Texture1D, __VA_ARGS__ } \
|
(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( \
|
.v = G_PushRef( \
|
||||||
(arena), (resource), \
|
(arena), (resource), \
|
||||||
(G_RefDesc) { .kind = G_RefKind_RWTexture1D, __VA_ARGS__ } \
|
(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( \
|
.v = G_PushRef( \
|
||||||
(arena), (resource), \
|
(arena), (resource), \
|
||||||
(G_RefDesc) { .kind = G_RefKind_Texture2D, __VA_ARGS__ } \
|
(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( \
|
.v = G_PushRef( \
|
||||||
(arena), (resource), \
|
(arena), (resource), \
|
||||||
(G_RefDesc) { .kind = G_RefKind_RWTexture2D, __VA_ARGS__ } \
|
(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( \
|
.v = G_PushRef( \
|
||||||
(arena), (resource), \
|
(arena), (resource), \
|
||||||
(G_RefDesc) { .kind = G_RefKind_Texture3D, __VA_ARGS__ } \
|
(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( \
|
.v = G_PushRef( \
|
||||||
(arena), (resource), \
|
(arena), (resource), \
|
||||||
(G_RefDesc) { .kind = G_RefKind_RWTexture3D, __VA_ARGS__ } \
|
(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( \
|
.v = G_PushRef( \
|
||||||
(arena), (resource), \
|
(arena), (resource), \
|
||||||
(G_RefDesc) { .kind = G_RefKind_SamplerState, __VA_ARGS__ } \
|
(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);
|
G_CommandListHandle G_PrepareCommandList(G_QueueKind queue);
|
||||||
i64 G_CommitCommandList(G_CommandListHandle cl);
|
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_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);
|
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);
|
void G_SetConstant_(G_CommandListHandle cl, i32 slot, void *src_32bit, u32 size);
|
||||||
|
|
||||||
#define G_SetConstant(cl, name, value) do { \
|
#define G_SetConstant(cl, name, value) do { \
|
||||||
name##__shaderconstanttype __src; \
|
name##__shaderconstanttype __src; \
|
||||||
__src.v = value; \
|
__src.v = value; \
|
||||||
G_SetConstant_((cl), (name), &__src, sizeof(__src)); \
|
G_SetConstant_((cl), (name), &__src, sizeof(__src)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
//- Memory sync
|
//- Memory sync
|
||||||
|
|
||||||
|
|||||||
@ -2429,7 +2429,7 @@ i64 G_CommitCommandList(G_CommandListHandle cl_handle)
|
|||||||
return completion_target;
|
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)
|
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)
|
void G_SyncEx(G_QueueBarrierDesc desc)
|
||||||
{
|
{
|
||||||
|
|
||||||
u64 fences_count = 0;
|
u64 fences_count = 0;
|
||||||
ID3D12Fence *fences[G_QueueKind_COUNT] = Zi;
|
ID3D12Fence *fences[G_QueueKind_COUNT] = Zi;
|
||||||
i64 fence_targets[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.
|
// D3D12 exposes 64 root constants and Vulkan exposes 32 push constants.
|
||||||
// Supposedly amd hardware will start spilling constants once there
|
// Supposedly AMD hardware will start spilling constants once there
|
||||||
// are more than 12: https://gpuopen.com/learn/rdna-performance-guide/
|
// are more than 12 - https://gpuopen.com/learn/rdna-performance-guide/
|
||||||
//
|
//
|
||||||
#define G_NumGeneralPurposeConstants (8) // Constants available for any usage
|
#define G_NumGeneralPurposeConstants (8) // Constants available for any usage
|
||||||
#define G_NumReservedConstants (4) // Constants reserved for internal usage by the GPU layer
|
#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
|
#if IsLanguageG
|
||||||
// TODO: Non-uniform resource access currently is assumed as the default
|
// TODO: Non-uniform resource access currently is assumed as the default
|
||||||
// behavior. We may want to add explicit "uniform" variants for
|
// 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> 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)]; }
|
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");
|
layer_name = Lit("pp");
|
||||||
if (lane->idx == 0)
|
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;
|
cmdline.leaf_layer_name = layer_name;
|
||||||
@ -440,19 +440,21 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Phase 1/3: Prep
|
//- Phase 1/3: Prep
|
||||||
|
|
||||||
|
// Build phases:
|
||||||
|
//
|
||||||
// Phase 1/3: Prep (narrow)
|
// Phase 1/3: Prep (narrow)
|
||||||
// - Parse layers
|
// - Parse layers
|
||||||
// - Generate final C file
|
// - Generate final C file
|
||||||
// - Generate final HLSL file
|
// - Generate final HLSL file
|
||||||
// - Generate resource dirs info
|
// - Generate resource dirs info
|
||||||
//
|
//
|
||||||
// Phase 2/3: Compile (wide)
|
// Phase 2/3: Compile (wide)
|
||||||
// - Compile C
|
// - Compile C
|
||||||
// - Compile & embed shaders
|
// - Compile & embed shaders
|
||||||
// - Embed resource dirs
|
// - Embed resource dirs
|
||||||
//
|
//
|
||||||
// Phase 3/3: Link (narrow)
|
// Phase 3/3: Link (narrow)
|
||||||
// - Link
|
// - Link
|
||||||
|
|
||||||
// TODO: Dispatch OS commands asynchronously
|
// TODO: Dispatch OS commands asynchronously
|
||||||
|
|
||||||
|
|||||||
318
src/net/net.h
318
src/net/net.h
@ -1,318 +1,52 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Channel ID
|
//~ Opaque types
|
||||||
|
|
||||||
Struct(N_ChannelId)
|
Struct(NET_PipeHandle) { u64 v; };
|
||||||
{
|
|
||||||
u32 gen;
|
#define NET_IsPipeNil(h) ((h).v == 0)
|
||||||
u32 idx;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Host command types
|
//~ Key types
|
||||||
|
|
||||||
Enum(N_CmdKind)
|
Struct(NET_Key)
|
||||||
{
|
{
|
||||||
N_CmdKind_None,
|
u64 v;
|
||||||
N_CmdKind_TryConnect,
|
|
||||||
N_CmdKind_ConnectSuccess,
|
|
||||||
N_CmdKind_Disconnect,
|
|
||||||
N_CmdKind_Heartbeat,
|
|
||||||
N_CmdKind_Write
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Enum(N_WriteFlag)
|
#define NET_NilKey ((NET_Key) { 0 })
|
||||||
{
|
#define NET_IsKeyNil(k) ((k).v == 0)
|
||||||
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
|
//~ Message types
|
||||||
|
|
||||||
Enum(N_EventKind)
|
Struct(NET_Msg)
|
||||||
{
|
{
|
||||||
N_EventKind_None,
|
NET_Msg *next;
|
||||||
N_EventKind_ChannelOpened,
|
NET_Msg *prev;
|
||||||
N_EventKind_ChannelClosed,
|
|
||||||
N_EventKind_Msg
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(N_Event)
|
NET_Key src;
|
||||||
{
|
|
||||||
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;
|
String data;
|
||||||
N_RcvPacket *next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(N_RcvBuffer)
|
Struct(NET_MsgList)
|
||||||
{
|
{
|
||||||
Arena *arena;
|
i64 count;
|
||||||
N_RcvPacket *first_packet;
|
NET_Msg *first;
|
||||||
N_RcvPacket *last_packet;
|
NET_Msg *last;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Channel types
|
//~ @hookdecl Bootstrap
|
||||||
|
|
||||||
Struct(N_Channel)
|
void NET_Bootstrap(void);
|
||||||
{
|
|
||||||
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
|
//~ @hookdecl Net ops
|
||||||
|
|
||||||
Struct(N_MsgAssembler)
|
NET_PipeHandle NET_AcquirePipe(void);
|
||||||
{
|
|
||||||
N_Channel *channel;
|
|
||||||
b32 is_reliable;
|
|
||||||
|
|
||||||
// Free list
|
void NET_Bind(NET_PipeHandle pipe, u64 port);
|
||||||
N_MsgAssembler *next_free;
|
u64 NET_BoundPortFromPipe(NET_PipeHandle pipe_handle);
|
||||||
|
|
||||||
// Bucket list
|
void NET_Push(NET_PipeHandle pipe, NET_Key dst, String data, b32 unreliable);
|
||||||
N_MsgAssembler *next_hash;
|
NET_MsgList NET_Pop(Arena *arena, NET_PipeHandle pipe);
|
||||||
N_MsgAssembler *prev_hash;
|
|
||||||
|
|
||||||
// Channel list
|
|
||||||
N_MsgAssembler *less_recent;
|
|
||||||
N_MsgAssembler *more_recent;
|
|
||||||
|
|
||||||
u64 msg_id;
|
|
||||||
u64 hash;
|
|
||||||
|
|
||||||
u64 last_chunk_len;
|
|
||||||
u64 num_chunks_total;
|
|
||||||
u64 num_chunks_received;
|
|
||||||
|
|
||||||
i64 touched_ns;
|
|
||||||
|
|
||||||
BuddyBlock *buddy_block;
|
|
||||||
u8 *chunk_bitmap;
|
|
||||||
u8 *chunk_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(N_MsgAssemblerLookupBin)
|
|
||||||
{
|
|
||||||
N_MsgAssembler *first;
|
|
||||||
N_MsgAssembler *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Host types
|
|
||||||
|
|
||||||
#define N_NumChannelLookupBins 512
|
|
||||||
#define N_NumMsgAssemblerLookupBins 16384
|
|
||||||
|
|
||||||
Struct(N_Host)
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
|
|
||||||
PLT_Sock *sock;
|
|
||||||
|
|
||||||
BuddyCtx *buddy; // For storing msg assembler data
|
|
||||||
|
|
||||||
Arena *cmd_arena;
|
|
||||||
N_Cmd *first_cmd;
|
|
||||||
N_Cmd *last_cmd;
|
|
||||||
N_Cmd *first_free_cmd;
|
|
||||||
|
|
||||||
Arena *channel_arena;
|
|
||||||
N_Channel *channels;
|
|
||||||
N_Channel *first_free_channel;
|
|
||||||
u64 num_channels_reserved;
|
|
||||||
|
|
||||||
N_SndPacket *first_free_packet; // Acquired in `arena`
|
|
||||||
N_MsgAssembler *first_free_msg_assembler; // Acquired in `arena`
|
|
||||||
|
|
||||||
N_ChannelLookupBin *channel_lookup_bins; // Acquired in `arena`
|
|
||||||
u64 num_channel_lookup_bins;
|
|
||||||
|
|
||||||
N_MsgAssemblerLookupBin *msg_assembler_lookup_bins; // Acquired in `arena`
|
|
||||||
u64 num_msg_assembler_lookup_bins;
|
|
||||||
|
|
||||||
// Double buffer for incoming data
|
|
||||||
Mutex rcv_buffer_write_mutex;
|
|
||||||
N_RcvBuffer *rcv_buffer_read;
|
|
||||||
N_RcvBuffer *rcv_buffer_write;
|
|
||||||
|
|
||||||
u64 bytes_received;
|
|
||||||
u64 bytes_sent;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Nil constants
|
|
||||||
|
|
||||||
Readonly Global N_Channel N_nil_channel = { .valid = 0 };
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Host initialization
|
|
||||||
|
|
||||||
N_Host *N_AcquireHost(u16 listen_port);
|
|
||||||
void N_ReleaseHost(N_Host *host);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Channel
|
|
||||||
|
|
||||||
#define N_NilChannelId (N_ChannelId) { .gen = 0, .idx = 0 }
|
|
||||||
#define N_AllChannelsId (N_ChannelId) { .gen = U32Max, .idx = U32Max }
|
|
||||||
|
|
||||||
#define N_MatchChannelId(a, b) ((a).gen == (b).gen && (a).idx == (b).idx)
|
|
||||||
#define N_IsChannelIdNil(v) ((v).gen == 0 && (v).idx == 0)
|
|
||||||
|
|
||||||
u64 N_HashFromAddress(PLT_Address address);
|
|
||||||
N_Channel *N_ChannelFromAddress(N_Host *host, PLT_Address address);
|
|
||||||
N_Channel *N_ChannelFromId(N_Host *host, N_ChannelId channel_id);
|
|
||||||
N_ChannelList N_ChannelsFromId(Arena *arena, N_Host *host, N_ChannelId channel_id);
|
|
||||||
N_Channel *N_AcquireChannel(N_Host *host, PLT_Address address);
|
|
||||||
void N_ReleaseChannel(N_Channel *channel);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Message assembler
|
|
||||||
|
|
||||||
u64 N_HashFromMsg(N_ChannelId channel_id, u64 msg_id);
|
|
||||||
N_MsgAssembler *N_MsgAssemblerFromMsg(N_Host *host, N_ChannelId channel_id, u64 msg_id);
|
|
||||||
N_MsgAssembler *N_AcquireMsgAssembler(N_Channel *channel, u64 msg_id, u64 chunk_count, u64 now_ns, b32 is_reliable);
|
|
||||||
void N_ReleaseMessageAssembler(N_MsgAssembler *ma);
|
|
||||||
void N_TouchMessageAssembler(N_MsgAssembler *ma, i64 now_ns);
|
|
||||||
b32 N_IsChunkFilled(N_MsgAssembler *ma, u64 chunk_id);
|
|
||||||
void N_MarkChunkReceived(N_MsgAssembler *ma, u64 chunk_id);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Packet
|
|
||||||
|
|
||||||
N_SndPacket *N_PushSndPacket(N_Channel *channel, b32 is_reliable);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Host command
|
|
||||||
|
|
||||||
N_Cmd *N_PushCmd(N_Host *host);
|
|
||||||
void N_Connect(N_Host *host, PLT_Address connect_address);
|
|
||||||
void N_Disconnect(N_Host *host, N_ChannelId channel_id);
|
|
||||||
void N_Write(N_Host *host, N_ChannelId channel_id, String msg, N_WriteFlag flags);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Channel info
|
|
||||||
|
|
||||||
i64 N_GetChannelLastRttNs(N_Host *host, N_ChannelId channel_id);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Update
|
|
||||||
|
|
||||||
N_Event *N_PushEvent(Arena *arena, N_EventList *list);
|
|
||||||
N_EventList N_BeginUpdate(Arena *arena, N_Host *host);
|
|
||||||
void N_EndUpdate(N_Host *host);
|
|
||||||
|
|||||||
@ -1,16 +1,13 @@
|
|||||||
@Layer net
|
@Layer net
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- Dependencies
|
|
||||||
|
|
||||||
@Dep platform
|
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Api
|
//- Api
|
||||||
|
|
||||||
@IncludeC net.h
|
@IncludeC net.h
|
||||||
|
|
||||||
|
@Bootstrap NET_Bootstrap
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Impl
|
//- 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 = {
|
Readonly P_Ent P_NilEnt = {
|
||||||
.xf = CompXformIdentity,
|
.xf = CompXformIdentity,
|
||||||
.look = { 0, -1 },
|
.control.look = { 0, -1 },
|
||||||
};
|
};
|
||||||
|
|
||||||
Readonly P_Frame P_NilFrame = {
|
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)
|
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))
|
// 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)
|
// if (ent->has_weapon)
|
||||||
// {
|
// {
|
||||||
@ -1422,12 +1428,12 @@ void P_StepFrame(P_Frame *frame)
|
|||||||
{
|
{
|
||||||
// Xform xf = ent->xf;
|
// Xform xf = ent->xf;
|
||||||
// Xform desired_xf = 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);
|
// 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);
|
// Vec2 pos_diff = SubVec2(desired_xf.og, xf.og);
|
||||||
// f32 angle_diff = UnwindAngleF32(RotationFromXform(desired_xf) - RotationFromXform(xf));
|
// 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);
|
f32 max_speed = TweakFloat("Player max speed", 10, 0, 20);
|
||||||
|
|
||||||
Vec2 new_velocity = ent->solved_v;
|
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)
|
// if (Vec2Len(new_velocity) > max_speed)
|
||||||
// {
|
// {
|
||||||
@ -1907,7 +1913,7 @@ void P_StepFrame(P_Frame *frame)
|
|||||||
P_EntList bullets_to_spawn = Zi;
|
P_EntList bullets_to_spawn = Zi;
|
||||||
for (P_Ent *firer = P_FirstEnt(frame); !P_IsEntNil(firer); firer = P_NextEnt(firer))
|
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)
|
// if (firer->fire_presses)
|
||||||
{
|
{
|
||||||
// i64 fire_delta_ns = frame->time_ns - firer->last_fire_ns;
|
// 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);
|
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)
|
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 rand_angle = ((f32)P_RandU64FromEnt(firer) / (f32)0xFFFFFFFFFFFFFFFFull) - 0.5;
|
||||||
|
|
||||||
f32 speed = tweak_speed * sim_dt;
|
f32 speed = tweak_speed * sim_dt;
|
||||||
f32 angle = AngleFromVec2(firer->look);
|
f32 angle = AngleFromVec2(firer->control.look);
|
||||||
|
|
||||||
speed += (speed * 0.5) * rand_speed;
|
speed += (speed * 0.5) * rand_speed;
|
||||||
angle += rand_angle * spread;
|
angle += rand_angle * spread;
|
||||||
@ -2068,7 +2074,7 @@ void P_StepFrame(P_Frame *frame)
|
|||||||
{
|
{
|
||||||
Vec4 color = VEC4(0.4, 0.8, 0.4, 1);
|
Vec4 color = VEC4(0.4, 0.8, 0.4, 1);
|
||||||
Vec2 p0 = world_shape.centroid;
|
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);
|
P_DebugDrawLine(p0, p1, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
40
src/pp/pp.h
40
src/pp/pp.h
@ -1,7 +1,7 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Key types
|
//~ Key types
|
||||||
|
|
||||||
#define P_NilKey ((P_Key) { 0 })
|
#define P_NilKey ((P_Key) { 0 })
|
||||||
|
|
||||||
Struct(P_Key)
|
Struct(P_Key)
|
||||||
{
|
{
|
||||||
@ -69,6 +69,14 @@ Struct(P_DebugDrawNode)
|
|||||||
|
|
||||||
// TODO: Pack efficiently, deduplicate redundant fields
|
// TODO: Pack efficiently, deduplicate redundant fields
|
||||||
|
|
||||||
|
Struct(P_Control)
|
||||||
|
{
|
||||||
|
Vec2 move;
|
||||||
|
Vec2 look;
|
||||||
|
f32 fire_held;
|
||||||
|
f32 fire_presses;
|
||||||
|
};
|
||||||
|
|
||||||
Struct(P_Ent)
|
Struct(P_Ent)
|
||||||
{
|
{
|
||||||
//- Internal world state
|
//- Internal world state
|
||||||
@ -95,11 +103,6 @@ Struct(P_Ent)
|
|||||||
Xform prev_xf;
|
Xform prev_xf;
|
||||||
Xform xf;
|
Xform xf;
|
||||||
|
|
||||||
Vec2 move;
|
|
||||||
Vec2 look;
|
|
||||||
f32 fire_held;
|
|
||||||
f32 fire_presses;
|
|
||||||
|
|
||||||
// TODO: Remove this (weapon testing)
|
// TODO: Remove this (weapon testing)
|
||||||
i64 last_fire_ns;
|
i64 last_fire_ns;
|
||||||
b32 has_weapon;
|
b32 has_weapon;
|
||||||
@ -113,12 +116,17 @@ Struct(P_Ent)
|
|||||||
Vec2 hit_entry;
|
Vec2 hit_entry;
|
||||||
Vec2 hit_entry_normal;
|
Vec2 hit_entry_normal;
|
||||||
|
|
||||||
|
P_Control control;
|
||||||
|
|
||||||
//- User
|
//- User
|
||||||
|
|
||||||
b32 is_user;
|
b32 is_user;
|
||||||
|
|
||||||
P_Key player;
|
P_Key player;
|
||||||
|
|
||||||
|
// FIXME: Ensure this field isn't transmitted in snapshots
|
||||||
|
NET_Key net;
|
||||||
|
|
||||||
u8 string_len;
|
u8 string_len;
|
||||||
u8 string_text[32];
|
u8 string_text[32];
|
||||||
|
|
||||||
@ -287,8 +295,6 @@ Struct(P_SimSnapshot)
|
|||||||
|
|
||||||
Struct(P_UserSnapshot)
|
Struct(P_UserSnapshot)
|
||||||
{
|
{
|
||||||
P_Key user;
|
|
||||||
i64 src_tick;
|
|
||||||
i64 tick;
|
i64 tick;
|
||||||
|
|
||||||
Vec2 move;
|
Vec2 move;
|
||||||
@ -305,20 +311,34 @@ Enum(P_MsgKind)
|
|||||||
P_MsgKind_None,
|
P_MsgKind_None,
|
||||||
|
|
||||||
// User -> sim
|
// User -> sim
|
||||||
|
P_MsgKind_UserSnapshot,
|
||||||
P_MsgKind_SaveWorld,
|
P_MsgKind_SaveWorld,
|
||||||
P_MsgKind_ResetWorld,
|
P_MsgKind_ResetWorld,
|
||||||
P_MsgKind_TileEdit,
|
P_MsgKind_TileEdit,
|
||||||
P_MsgKind_EntEdit,
|
P_MsgKind_EntEdit,
|
||||||
|
|
||||||
// Sim -> user
|
// Sim -> user
|
||||||
|
P_MsgKind_SimSnapshot,
|
||||||
P_MsgKind_Tiles,
|
P_MsgKind_Tiles,
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(P_Msg)
|
Struct(P_Msg)
|
||||||
{
|
{
|
||||||
P_MsgKind kind;
|
//- In
|
||||||
P_Key src_user;
|
|
||||||
P_Key dst_user; // If dst is 0, then cmd is meant to be broadcast
|
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;
|
P_TileKind tile_kind;
|
||||||
Rng2I32 tile_range;
|
Rng2I32 tile_range;
|
||||||
|
|||||||
@ -1,5 +1,10 @@
|
|||||||
@Layer pp
|
@Layer pp
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- Dependencies
|
||||||
|
|
||||||
|
@Dep net
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Resources
|
//- Resources
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
//- Dependencies
|
//- Dependencies
|
||||||
|
|
||||||
@Dep pp
|
@Dep pp
|
||||||
|
@Dep net
|
||||||
@Dep platform
|
@Dep platform
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
|||||||
@ -25,6 +25,8 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
P_tl.debug_arena = AcquireArena(Gibi(64));
|
P_tl.debug_arena = AcquireArena(Gibi(64));
|
||||||
P_tl.out_msgs_arena = AcquireArena(Gibi(64));
|
P_tl.out_msgs_arena = AcquireArena(Gibi(64));
|
||||||
|
|
||||||
|
NET_PipeHandle net_pipe = NET_AcquirePipe();
|
||||||
|
|
||||||
P_World *world = P_AcquireWorld();
|
P_World *world = P_AcquireWorld();
|
||||||
|
|
||||||
// TODO: Real per-client deltas
|
// TODO: Real per-client deltas
|
||||||
@ -45,12 +47,6 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Sim loop
|
//- 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;
|
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)
|
String packed = net_msg->data;
|
||||||
{
|
P_MsgNode *dst_msg_node = PushStruct(frame_arena, P_MsgNode);
|
||||||
P_MsgNode *dst_msg_node = PushStruct(frame_arena, P_MsgNode);
|
P_Msg *dst_msg = &dst_msg_node->msg;
|
||||||
P_Msg *src_msg = &src_msg_node->msg;
|
*dst_msg = P_UnpackMsg(frame_arena, packed);
|
||||||
P_Msg *dst_msg = &dst_msg_node->msg;
|
// FIXME: Set src user here based on net key
|
||||||
*dst_msg = *src_msg;
|
// dst_msg->src_user =
|
||||||
dst_msg->data = PushString(frame_arena, src_msg->data);
|
DllQueuePush(in_msgs.first, in_msgs.last, dst_msg_node);
|
||||||
DllQueuePush(in_msgs.first, in_msgs.last, dst_msg_node);
|
++in_msgs.count;
|
||||||
++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)
|
// for (P_MsgNode *msg_node = in_msgs.first; msg_node; msg_node = msg_node->next)
|
||||||
{
|
// {
|
||||||
P_Msg *msg = &msg_node->msg;
|
// P_Msg *msg = &msg_node->msg;
|
||||||
|
|
||||||
P_Key user_key = msg->src_user;
|
// //- Register user
|
||||||
P_Ent *user = P_EntFromKey(world_frame, user_key);
|
// if (msg->kind == P_MsgKind_RegisterUser)
|
||||||
if (P_EntIsNil(user))
|
// {
|
||||||
{
|
// P_Key user_key = msg->src_user;
|
||||||
P_EntList tmp_list = Zi;
|
// P_Ent *user = P_EntFromKey(world_frame, user_key);
|
||||||
user = P_PushTempEnt(frame_arena, &tmp_list);
|
// if (P_EntIsNil(user))
|
||||||
user->key = user_key;
|
// {
|
||||||
user->is_user = 1;
|
// P_EntList tmp_list = Zi;
|
||||||
user->exists = 1;
|
// user = P_PushTempEnt(frame_arena, &tmp_list);
|
||||||
|
// user->key = user_key;
|
||||||
|
// user->is_user = 1;
|
||||||
|
// user->exists = 1;
|
||||||
|
|
||||||
i32 min_name_len = 3;
|
// // FIXME: Set net key here
|
||||||
i32 max_name_len = countof(user->string_text) - 8;
|
|
||||||
|
|
||||||
// De-duplicate user name
|
// i32 min_name_len = 3;
|
||||||
String user_name = msg->data;
|
// i32 max_name_len = countof(user->string_text) - 8;
|
||||||
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);
|
// // De-duplicate user name
|
||||||
}
|
// String user_name = msg->data;
|
||||||
{
|
// user_name = TrimWhitespace(user_name);
|
||||||
P_Msg *msg = P_PushMsg(P_MsgKind_RegisterSuccess, Zstr);
|
// user_name.len = MinI64(user_name.len, max_name_len);
|
||||||
msg->dst_user = user->key;
|
// 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
|
//- 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;
|
// P_MsgList user_msgs = Zi;
|
||||||
// {
|
// {
|
||||||
// i64 user_msgs_min_tick = world_frame->tick + user_msg_tick_range.min;
|
// 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
|
//- Update ent controls
|
||||||
|
|
||||||
for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
// for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||||
{
|
// {
|
||||||
ent->fire_presses = 0;
|
// ent->fire_presses = 0;
|
||||||
}
|
// }
|
||||||
|
|
||||||
for (P_Ent *user = P_FirstEnt(frame); !P_IsEntNil(user); user = P_NextEnt(user))
|
// for (P_Ent *user = P_FirstEnt(frame); !P_IsEntNil(user); user = P_NextEnt(user))
|
||||||
{
|
// {
|
||||||
if (user->is_iser)
|
// if (user->is_iser)
|
||||||
{
|
// {
|
||||||
P_Ent *target = P_EntFromKey(user->player);
|
// P_Ent *target = P_EntFromKey(user->player);
|
||||||
if (!P_IsEntNil(target))
|
// if (!P_IsEntNil(target))
|
||||||
{
|
// {
|
||||||
target->move = ClampVec2Len(user->move, 1);
|
// target->move = ClampVec2Len(user->move, 1);
|
||||||
target->look = user->look;
|
// target->look = user->look;
|
||||||
target->fire_held = user->fire_held;
|
// target->fire_held = user->fire_held;
|
||||||
target->fire_presses += user->fire_presses;
|
// target->fire_presses += user->fire_presses;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Step frame
|
//- 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);
|
// Broadcast
|
||||||
if (user->is_local)
|
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;
|
// // TODO: Only copy active entities
|
||||||
snapshot->tick = world_frame->tick;
|
// LockTicketMutex(&P.sim_output_back_tm);
|
||||||
snapshot->time_ns = world_frame->time_ns;
|
// {
|
||||||
|
// P_OutputState *output = &P.sim_output_states[P.sim_output_back_idx];
|
||||||
|
|
||||||
// Push entity deltas
|
// // Build messages
|
||||||
for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
// {
|
||||||
{
|
// // Push tiles
|
||||||
P_Delta *delta = 0;
|
// if (tiles_dirty)
|
||||||
{
|
// {
|
||||||
P_DeltaNode *dn = PushStruct(output->arena, P_DeltaNode);
|
// P_Msg *msg = 0;
|
||||||
snapshot->deltas_count += 1;
|
// {
|
||||||
SllQueuePush(snapshot->first_delta_node, snapshot->last_delta_node, dn);
|
// P_MsgNode *msg_node = PushStruct(output->arena, P_MsgNode);
|
||||||
delta = &dn->delta;
|
// DllQueuePush(output->msgs.first, output->msgs.last, msg_node);
|
||||||
}
|
// ++output->msgs.count;
|
||||||
delta->kind = P_DeltaKind_RawEnt;
|
// msg = &msg_node->msg;
|
||||||
delta->ent = *ent;
|
// }
|
||||||
}
|
// 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
|
// // Build snapshot
|
||||||
{
|
// {
|
||||||
i64 dst_idx = 0;
|
// P_Snapshot *snapshot = &output->snapshot;
|
||||||
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);
|
// snapshot->world_seed = world->seed;
|
||||||
P_tl.first_debug_draw_node = 0;
|
// snapshot->tick = world_frame->tick;
|
||||||
P_tl.last_debug_draw_node = 0;
|
// snapshot->time_ns = world_frame->time_ns;
|
||||||
P_tl.debug_draw_nodes_count = 0;
|
|
||||||
}
|
// // Push entity deltas
|
||||||
}
|
// for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||||
}
|
// {
|
||||||
UnlockTicketMutex(&P.sim_output_back_tm);
|
// 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
|
//- Prune ents
|
||||||
@ -503,13 +605,13 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- End sim frame
|
//- End sim frame
|
||||||
|
|
||||||
// Reset front input state
|
// // Reset front input state
|
||||||
{
|
// {
|
||||||
Arena *arena = input->arena;
|
// Arena *arena = input->arena;
|
||||||
ResetArena(arena);
|
// ResetArena(arena);
|
||||||
ZeroStruct(input);
|
// ZeroStruct(input);
|
||||||
input->arena = arena;
|
// input->arena = arena;
|
||||||
}
|
// }
|
||||||
|
|
||||||
i64 frame_end_ns = TimeNs();
|
i64 frame_end_ns = TimeNs();
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Transcode
|
//~ World
|
||||||
|
|
||||||
String P_PackWorld(Arena *arena, P_World *src_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, " pos: \"%F\"\n", FmtFloat2(ent->xf.og)).len;
|
||||||
result.len += StringF(arena, " rot: \"%F\"\n", FmtFloat2(RightFromXform(ent->xf))).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, " 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;
|
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")))
|
if (MatchString(attr->name, Lit("look")))
|
||||||
{
|
{
|
||||||
Vec2 look = CR_Vec2FromString(attr->value);
|
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);
|
EndScratch(scratch);
|
||||||
return result;
|
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);
|
String P_PackWorld(Arena *arena, P_World *src_world);
|
||||||
P_UnpackedWorld P_UnpackWorld(Arena *arena, String packed);
|
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
|
//- Dependencies
|
||||||
|
|
||||||
@Dep pp
|
@Dep pp
|
||||||
|
@Dep net
|
||||||
@Dep sprite
|
@Dep sprite
|
||||||
@Dep gpu
|
@Dep gpu
|
||||||
@Dep glyph_cache
|
@Dep glyph_cache
|
||||||
|
|||||||
@ -348,8 +348,9 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Init vis state
|
//- Init vis state
|
||||||
|
|
||||||
Arena *sim_snapshot_arena = AcquireArena(Gibi(64));
|
Arena *sim_debug_arena = AcquireArena(Gibi(64));
|
||||||
P_SimSnapshot sim_snapshot = Zi;
|
P_DebugDrawNode *first_sim_debug_draw_node = 0;
|
||||||
|
P_DebugDrawNode *last_sim_debug_draw_node = 0;
|
||||||
|
|
||||||
P_World *sim_world = P_AcquireWorld();
|
P_World *sim_world = P_AcquireWorld();
|
||||||
P_World *predict_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 tiles_dims = VEC2I32(P_TilesPitch, P_TilesPitch);
|
||||||
Vec2I32 cells_dims = VEC2I32(V_CellsPerMeter * P_WorldPitch, V_CellsPerMeter * P_WorldPitch);
|
Vec2I32 cells_dims = VEC2I32(V_CellsPerMeter * P_WorldPitch, V_CellsPerMeter * P_WorldPitch);
|
||||||
|
|
||||||
|
NET_PipeHandle net_pipe = NET_AcquirePipe();
|
||||||
|
|
||||||
// Init gpu state
|
// Init gpu state
|
||||||
G_ResourceHandle gpu_state = Zi;
|
G_ResourceHandle gpu_state = Zi;
|
||||||
G_ResourceHandle gpu_tiles = Zi;
|
G_ResourceHandle gpu_tiles = Zi;
|
||||||
@ -2622,78 +2625,85 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Pop messages from sim
|
//- Pop messages from sim
|
||||||
|
|
||||||
|
// FIXME: Reject messages if not from currently connected sim
|
||||||
|
|
||||||
P_MsgList in_msgs = Zi;
|
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)
|
String packed = net_msg->data;
|
||||||
{
|
P_MsgNode *dst_msg_node = PushStruct(frame->arena, P_MsgNode);
|
||||||
P_MsgNode *dst_msg_node = PushStruct(frame->arena, P_MsgNode);
|
P_Msg *dst_msg = &dst_msg_node->msg;
|
||||||
P_Msg *src_msg = &src_msg_node->msg;
|
*dst_msg = P_UnpackMsg(frame->arena, packed);
|
||||||
P_Msg *dst_msg = &dst_msg_node->msg;
|
// FIXME: Set src user here based on net key
|
||||||
*dst_msg = *src_msg;
|
// dst_msg->src_user =
|
||||||
dst_msg->data = PushString(frame->arena, src_msg->data);
|
DllQueuePush(in_msgs.first, in_msgs.last, dst_msg_node);
|
||||||
DllQueuePush(in_msgs.first, in_msgs.last, dst_msg_node);
|
++in_msgs.count;
|
||||||
++in_msgs.count;
|
|
||||||
}
|
|
||||||
ResetArena(P.s2u_msgs_arena);
|
|
||||||
ZeroStruct(&P.s2u_msgs);
|
|
||||||
}
|
}
|
||||||
UnlockTicketMutex(&P.s2u_msgs_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Pop snapshot from sim
|
//- Pop snapshot from sim
|
||||||
|
|
||||||
{
|
// {
|
||||||
LockTicketMutex(&P.s2u_snapshot_mutex);
|
// LockTicketMutex(&P.s2u_snapshot_mutex);
|
||||||
P_SimSnapshot *src_snapshot = &P.s2u_snapshot;
|
// P_SimSnapshot *src_snapshot = &P.s2u_snapshot;
|
||||||
if (src_snapshot->tick > sim_snapshot.tick)
|
// if (src_snapshot->tick > sim_snapshot.tick)
|
||||||
{
|
// {
|
||||||
ResetArena(sim_snapshot_arena);
|
// ResetArena(sim_snapshot_arena);
|
||||||
ZeroStruct(&sim_snapshot);
|
// ZeroStruct(&sim_snapshot);
|
||||||
sim_snapshot.world_seed = src_snapshot->world_seed;
|
// sim_snapshot.world_seed = src_snapshot->world_seed;
|
||||||
sim_snapshot.src_tick = src_snapshot->src_tick;
|
// sim_snapshot.src_tick = src_snapshot->src_tick;
|
||||||
sim_snapshot.tick = src_snapshot->tick;
|
// sim_snapshot.tick = src_snapshot->tick;
|
||||||
sim_snapshot.time_ns = src_snapshot->time_ns;
|
// sim_snapshot.time_ns = src_snapshot->time_ns;
|
||||||
{
|
// {
|
||||||
//- Copy deltas
|
// //- Copy deltas
|
||||||
{
|
// {
|
||||||
P_SimDeltaNode *dst_nodes = PushStructsNoZero(sim_snapshot_arena, P_SimDeltaNode, src_snapshot->deltas_count);
|
// 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)
|
// 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];
|
// P_SimDeltaNode *dst_delta_node = &dst_nodes[sim_snapshot.deltas_count];
|
||||||
*dst_delta_node = *src_delta_node;
|
// *dst_delta_node = *src_delta_node;
|
||||||
SllQueuePush(sim_snapshot.first_delta_node, sim_snapshot.last_delta_node, dst_delta_node);
|
// SllQueuePush(sim_snapshot.first_delta_node, sim_snapshot.last_delta_node, dst_delta_node);
|
||||||
sim_snapshot.deltas_count += 1;
|
// sim_snapshot.deltas_count += 1;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
//- Copy debug info
|
// //- Copy debug info
|
||||||
{
|
// {
|
||||||
P_DebugDrawNode *dst_nodes = PushStructsNoZero(sim_snapshot_arena, P_DebugDrawNode, src_snapshot->debug_draw_nodes_count);
|
// 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)
|
// 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];
|
// P_DebugDrawNode *dst = &dst_nodes[sim_snapshot.debug_draw_nodes_count];
|
||||||
*dst = *src;
|
// *dst = *src;
|
||||||
SllQueuePush(sim_snapshot.first_debug_draw_node, sim_snapshot.last_debug_draw_node, dst);
|
// SllQueuePush(sim_snapshot.first_debug_draw_node, sim_snapshot.last_debug_draw_node, dst);
|
||||||
sim_snapshot.debug_draw_nodes_count += 1;
|
// sim_snapshot.debug_draw_nodes_count += 1;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
ResetArena(P.s2u_snapshot_arena);
|
// ResetArena(P.s2u_snapshot_arena);
|
||||||
ZeroStruct(&P.s2u_snapshot);
|
// ZeroStruct(&P.s2u_snapshot);
|
||||||
}
|
// }
|
||||||
UnlockTicketMutex(&P.s2u_snapshot_mutex);
|
// UnlockTicketMutex(&P.s2u_snapshot_mutex);
|
||||||
}
|
// }
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Apply sim msgs
|
//- Apply sim msgs
|
||||||
|
|
||||||
|
P_Msg *newest_snapshot_msg = 0;
|
||||||
{
|
{
|
||||||
for (P_MsgNode *msg_node = in_msgs.first; msg_node; msg_node = msg_node->next)
|
for (P_MsgNode *msg_node = in_msgs.first; msg_node; msg_node = msg_node->next)
|
||||||
{
|
{
|
||||||
P_Msg *msg = &msg_node->msg;
|
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
|
//- Chat
|
||||||
// if (msg->kind == P_MsgKind_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)
|
if (newest_snapshot_msg)
|
||||||
// {
|
{
|
||||||
// P_Frame *src_frame = P_FrameFromTick(sim_world, snapshot->src_tick);
|
P_SimSnapshot *snapshot = &newest_snapshot_msg->sim_snapshot;
|
||||||
// P_Frame *dst_frame = P_PushFrame(sim_world, src_frame, snapshot->tick);
|
|
||||||
// sim_world->seed = snapshot->world_seed;
|
|
||||||
// dst_frame->time_ns = snapshot->time_ns;
|
|
||||||
|
|
||||||
// //- Apply deltas
|
P_Frame *src_frame = P_FrameFromTick(sim_world, snapshot->src_tick);
|
||||||
// for (P_SimDeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next)
|
P_Frame *dst_frame = P_PushFrame(sim_world, src_frame, snapshot->tick);
|
||||||
// {
|
sim_world->seed = snapshot->world_seed;
|
||||||
// P_SimDelta *delta = &dn->delta;
|
dst_frame->time_ns = snapshot->time_ns;
|
||||||
// //- 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
|
//- Apply deltas
|
||||||
// {
|
for (P_SimDeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next)
|
||||||
// ResetArena(sim_debug_arena);
|
{
|
||||||
// first_sim_debug_draw_node = 0;
|
P_SimDelta *delta = &dn->delta;
|
||||||
// last_sim_debug_draw_node = 0;
|
//- Raw ent
|
||||||
// {
|
if (delta->kind == P_SimDeltaKind_RawEnt)
|
||||||
// i64 dst_idx = 0;
|
{
|
||||||
// P_DebugDrawNode *dst_nodes = PushStructsNoZero(sim_debug_arena, P_DebugDrawNode, snapshot->debug_draw_nodes_count);
|
P_Ent tmp_ent = delta->ent;
|
||||||
// for (P_DebugDrawNode *src = snapshot->first_debug_draw_node; src; src = src->next)
|
P_EntListNode tmp_ent_node = Zi;
|
||||||
// {
|
tmp_ent_node.ent = tmp_ent;
|
||||||
// P_DebugDrawNode *dst = &dst_nodes[dst_idx];
|
P_EntList ent_list = Zi;
|
||||||
// *dst = *src;
|
ent_list.first = &tmp_ent_node;
|
||||||
// dst_idx += 1;
|
ent_list.last = &tmp_ent_node;
|
||||||
// SllQueuePush(first_sim_debug_draw_node, last_sim_debug_draw_node, dst);
|
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
|
// TODO: Remove this
|
||||||
P_ClearFrames(sim_world, I64Min, sim_world->last_frame->tick - 1);
|
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
|
// FIXME: Real ping
|
||||||
// f64 ping = 0.250;
|
// f64 ping = 0.250;
|
||||||
@ -2823,39 +2835,39 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
i64 ping_ns = NsFromSeconds(ping);
|
i64 ping_ns = NsFromSeconds(ping);
|
||||||
|
|
||||||
frame->predict_to = sim_world->last_frame->tick + MaxF64(CeilF64(ping * SIM_TICKS_PER_SECOND), 1.0);
|
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)
|
// if (frame->predict_to != prev_frame->predict_to)
|
||||||
{
|
// {
|
||||||
{
|
// {
|
||||||
P_UserSnapshot snapshot = Zi;
|
// P_UserSnapshot snapshot = Zi;
|
||||||
snapshot->user = V.user_user;
|
// snapshot->user = V.user_user;
|
||||||
snapshot->src_tick = 0;
|
// snapshot->src_tick = 0;
|
||||||
// FIXME: Generate snapshots for all new frames, not just last
|
// // FIXME: Generate snapshots for all new frames, not just last
|
||||||
snapshot->tick = frame->predict_to;
|
// snapshot->tick = frame->predict_to;
|
||||||
snapshot->move = frame->move;
|
// snapshot->move = frame->move;
|
||||||
snapshot->look = frame->look;
|
// snapshot->look = frame->look;
|
||||||
snapshot->fire_held = frame->fire_held;
|
// snapshot->fire_held = frame->fire_held;
|
||||||
snapshot->fire_presses = frame->fire_presses;
|
// snapshot->fire_presses = frame->fire_presses;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Submit sim commands
|
//- Submit sim commands
|
||||||
|
|
||||||
{
|
// {
|
||||||
LockTicketMutex(&P.sim_input_back_tm);
|
// LockTicketMutex(&P.sim_input_back_tm);
|
||||||
{
|
// {
|
||||||
P_InputState *v2s = &P.sim_input_states[P.sim_input_back_idx];
|
// 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)
|
// 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);
|
// P_MsgNode *dst_cmd_node = PushStruct(v2s->arena, P_MsgNode);
|
||||||
dst_cmd_node->cmd = src_cmd_node->cmd;
|
// dst_cmd_node->cmd = src_cmd_node->cmd;
|
||||||
dst_cmd_node->cmd.tick = frame->predict_to;
|
// dst_cmd_node->cmd.tick = frame->predict_to;
|
||||||
DllQueuePush(v2s->cmds.first, v2s->cmds.last, dst_cmd_node);
|
// DllQueuePush(v2s->cmds.first, v2s->cmds.last, dst_cmd_node);
|
||||||
++v2s->cmds.count;
|
// ++v2s->cmds.count;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
UnlockTicketMutex(&P.sim_input_back_tm);
|
// UnlockTicketMutex(&P.sim_input_back_tm);
|
||||||
}
|
// }
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Predict
|
//- Predict
|
||||||
@ -3354,66 +3366,66 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Debug draw
|
//- Debug draw
|
||||||
|
|
||||||
{
|
// {
|
||||||
// Merge vis debug draws with sim debug draws
|
// // Merge vis debug draws with sim debug draws
|
||||||
P_DebugDrawNode *first_debug_draw_node = first_sim_debug_draw_node;
|
// P_DebugDrawNode *first_debug_draw_node = first_sim_debug_draw_node;
|
||||||
P_DebugDrawNode *last_debug_draw_node = last_sim_debug_draw_node;
|
// P_DebugDrawNode *last_debug_draw_node = last_sim_debug_draw_node;
|
||||||
if (P_tl.first_debug_draw_node)
|
// if (P_tl.first_debug_draw_node)
|
||||||
{
|
// {
|
||||||
if (last_debug_draw_node)
|
// if (last_debug_draw_node)
|
||||||
{
|
// {
|
||||||
last_debug_draw_node->next = P_tl.first_debug_draw_node;
|
// last_debug_draw_node->next = P_tl.first_debug_draw_node;
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
first_debug_draw_node = P_tl.first_debug_draw_node;
|
// first_debug_draw_node = P_tl.first_debug_draw_node;
|
||||||
}
|
// }
|
||||||
last_debug_draw_node = P_tl.last_debug_draw_node;
|
// last_debug_draw_node = P_tl.last_debug_draw_node;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Push draws
|
// // Push draws
|
||||||
for (P_DebugDrawNode *n = first_debug_draw_node; n; n = n->next)
|
// for (P_DebugDrawNode *n = first_debug_draw_node; n; n = n->next)
|
||||||
{
|
// {
|
||||||
Vec4 color = Vec4FromU32(n->srgb32);
|
// Vec4 color = Vec4FromU32(n->srgb32);
|
||||||
i32 detail = 24;
|
// i32 detail = 24;
|
||||||
f32 radius = 5;
|
// f32 radius = 5;
|
||||||
switch(n->kind)
|
// switch(n->kind)
|
||||||
{
|
// {
|
||||||
case P_DebugDrawKind_Point:
|
// case P_DebugDrawKind_Point:
|
||||||
{
|
// {
|
||||||
Vec2 ui_p = MulXformV2(frame->xf.world_to_ui, n->point.p);
|
// Vec2 ui_p = MulXformV2(frame->xf.world_to_ui, n->point.p);
|
||||||
V_DrawPoint(ui_p, color);
|
// V_DrawPoint(ui_p, color);
|
||||||
} break;
|
// } break;
|
||||||
|
|
||||||
case P_DebugDrawKind_Line:
|
// case P_DebugDrawKind_Line:
|
||||||
{
|
// {
|
||||||
Vec2 ui_p0 = MulXformV2(frame->xf.world_to_ui, n->line.p0);
|
// Vec2 ui_p0 = MulXformV2(frame->xf.world_to_ui, n->line.p0);
|
||||||
Vec2 ui_p1 = MulXformV2(frame->xf.world_to_ui, n->line.p1);
|
// Vec2 ui_p1 = MulXformV2(frame->xf.world_to_ui, n->line.p1);
|
||||||
V_DrawLine(ui_p0, ui_p1, color);
|
// V_DrawLine(ui_p0, ui_p1, color);
|
||||||
} break;
|
// } break;
|
||||||
|
|
||||||
case P_DebugDrawKind_Rect:
|
// case P_DebugDrawKind_Rect:
|
||||||
{
|
// {
|
||||||
Rng2 ui_rect = Zi;
|
// Rng2 ui_rect = Zi;
|
||||||
ui_rect.p0 = MulXformV2(frame->xf.world_to_ui, n->rect.p0);
|
// ui_rect.p0 = MulXformV2(frame->xf.world_to_ui, n->rect.p0);
|
||||||
ui_rect.p1 = MulXformV2(frame->xf.world_to_ui, n->rect.p1);
|
// ui_rect.p1 = MulXformV2(frame->xf.world_to_ui, n->rect.p1);
|
||||||
V_DrawRect(ui_rect, color, V_DrawFlag_Line);
|
// V_DrawRect(ui_rect, color, V_DrawFlag_Line);
|
||||||
} break;
|
// } break;
|
||||||
|
|
||||||
case P_DebugDrawKind_Shape:
|
// case P_DebugDrawKind_Shape:
|
||||||
{
|
// {
|
||||||
P_Shape ui_shape = P_MulXformShape(frame->xf.world_to_ui, n->shape);
|
// P_Shape ui_shape = P_MulXformShape(frame->xf.world_to_ui, n->shape);
|
||||||
V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line);
|
// V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line);
|
||||||
} break;
|
// } break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Reset vis debug draws
|
// // Reset vis debug draws
|
||||||
ResetArena(P_tl.debug_arena);
|
// ResetArena(P_tl.debug_arena);
|
||||||
P_tl.first_debug_draw_node = 0;
|
// P_tl.first_debug_draw_node = 0;
|
||||||
P_tl.last_debug_draw_node = 0;
|
// P_tl.last_debug_draw_node = 0;
|
||||||
P_tl.debug_draw_nodes_count = 0;
|
// P_tl.debug_draw_nodes_count = 0;
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
@ -3689,21 +3701,21 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Prune sim cmds
|
//- Prune sim cmds
|
||||||
|
|
||||||
{
|
// {
|
||||||
for (P_MsgNode *msg_node = V.sim_cmds.first; cmd_node;)
|
// for (P_MsgNode *msg_node = V.sim_cmds.first; cmd_node;)
|
||||||
{
|
// {
|
||||||
P_MsgNode *next = cmd_node->next;
|
// P_MsgNode *next = cmd_node->next;
|
||||||
{
|
// {
|
||||||
if (!cmd_node->cmd.predicted || cmd_node->cmd.tick <= sim_world->last_frame->tick)
|
// 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);
|
// DllQueueRemove(V.sim_cmds.first, V.sim_cmds.last, cmd_node);
|
||||||
SllStackPush(V.first_free_sim_cmd_node, cmd_node);
|
// SllStackPush(V.first_free_sim_cmd_node, cmd_node);
|
||||||
--V.sim_cmds.count;
|
// --V.sim_cmds.count;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
cmd_node = next;
|
// cmd_node = next;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Prune sim ents
|
//- 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
|
//- End frame
|
||||||
|
|
||||||
i32 vsync = !!TweakBool("Vsync", 1);
|
i32 vsync = !!TweakBool("Vsync", 1);
|
||||||
|
|
||||||
{
|
// {
|
||||||
Arena *old_arena = sim_output->arena;
|
// Arena *old_arena = sim_output->arena;
|
||||||
ZeroStruct(sim_output);
|
// ZeroStruct(sim_output);
|
||||||
sim_output->arena = old_arena;
|
// sim_output->arena = old_arena;
|
||||||
ResetArena(sim_output->arena);
|
// ResetArena(sim_output->arena);
|
||||||
}
|
// }
|
||||||
|
|
||||||
G_CommitCommandList(frame->cl);
|
G_CommitCommandList(frame->cl);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user