WIP: Boostrapping NetSlime

- Just a old name for a set of changes to make the game framework hardened for multiplayer as well as some ease of use functionality.
This commit is contained in:
2024-04-23 01:10:02 -04:00
parent 28b1ad19dc
commit 2574960fff
50 changed files with 2109 additions and 119 deletions

View File

@ -18,6 +18,7 @@ using namespace gen;
#include "GasaGen_ChangeBPActionMenu.cpp"
#include "GasaGen_DevOptionsCache.cpp"
#include "GasaGen_HostWidgetController.cpp"
#include "GasaGen_NetSlime.cpp"
int gen_main()
{
@ -80,6 +81,7 @@ int gen_main()
gen_UGasaAttributeSet();
gen_FGasaDevOptionsCache();
gen_UHostWidgetController();
// gen_netslime_interfaces();
// One offs
if (0)

View File

@ -13,6 +13,9 @@ using namespace gen;
#define path_config path_source "Config/"
#define path_module_gasa path_source "Gasa/"
#define path_gasa_ability_system path_module_gasa "AbilitySystem/"
#define path_gasa_actors path_module_gasa "Actors/"
#define path_gasa_characters path_module_gasa "Characters/"
#define path_gasa_game path_module_gasa "Game/"
#define path_gasa_ui path_module_gasa "UI/"
constexpr StrC str_DECLARE_CLASS = txt("DECLARE_CLASS(");

View File

@ -0,0 +1,118 @@
// Used in the GasaGen.cpp translation unit
#if GASA_INTELLISENSE_DIRECTIVES
#pragma once
#define GEN_EXPOSE_BACKEND
#include "gen.hpp"
#include "gen.builder.hpp"
#include "GasaGenCommon.cpp"
#endif
void gen_netslime_interface(CodeClass aclass)
{
CodeBody net_slime_class_interface = def_body(ECode::Class_Body);
{
#pragma push_macro("FORCEINLINE")
#undef FORCEINLINE
CodeFn DrawNetCullingSphere = parse_function( code(
FORCEINLINE void DrawNetCullingSphere(float Duration, float Thickness) const final { Gasa::DrawNetCullingSphere(this, Duration, Thickness); }
));
CodeFn GetNetworkMode = parse_function( code( FORCEINLINE ENetworkMode GetNetworkMode() const { return Gasa::GetNetworkMode(this); } ));
CodeFn IsClient = parse_function( code( FORCEINLINE bool IsClient() const { return Gasa::IsClient(this); } ));
CodeFn IsListenServer = parse_function( code( FORCEINLINE bool IsListenServer() const { return Gasa::IsListenServer(this); } ));
CodeFn IsNetOwner = parse_function( code( FORCEINLINE bool IsNetOwner() const { return Gasa::IsNetOwner(this); } ));
CodeFn IsServer = parse_function( code( FORCEINLINE bool IsServer() const { return Gasa::IsServer(this); } ));
CodeFn IsSimulatedProxy = parse_function( code( FORCEINLINE bool IsSimulatedProxy() const { return Gasa::IsSimulatedProxy(this); } ));
CodeFn NetLog = parse_function( code(
FORCEINLINE void NetLog( FString Message, EGasaVerbosity Verbosity = EGasaVerbosity::Log
, FLogCategoryBase& Category = LogGasaNet
, bool DumpStack = false
, int32 Line = __builtin_LINE()
, const ANSICHAR* File = __builtin_FILE()
, const ANSICHAR* Func = __builtin_FUNCTION() )
{
Gasa::NetLog(this, Message, Verbosity, Category, DumpStack, Line, File, Func );
}
));
CodeFn ServerAuthorized = parse_function( code( FORCEINLINE bool ServerAuthorized() const { return Gasa::ServerAuthorized(this); } ));
#pragma pop_macro("FORCEINLINE")
net_slime_class_interface.append(GetNetworkMode);
net_slime_class_interface.append(IsClient);
net_slime_class_interface.append(IsListenServer);
net_slime_class_interface.append(IsNetOwner);
net_slime_class_interface.append(IsServer);
net_slime_class_interface.append(IsSimulatedProxy);
net_slime_class_interface.append(NetLog);
}
CodeBody new_body = def_body(ECode::Class_Body);
for(Code code = aclass->Body.begin(); code != aclass->Body.end(); ++ code )
{
switch (code->Type)
{
default:
new_body.append(code);
break;
// TODO(Ed): Could this be turned into a singly? void find_and_swap_region_pragma(CodeClass, StrC region)
// IT could return void if its assumed that the Code passed will have destructive edits to the body.
case ECode::Preprocess_Pragma:
{
local_persist bool found = false;
if (found || ! code->Content.starts_with( txt("region NetSlime")))
{
new_body.append(code);
continue;
}
// Add pragma
new_body.append(code);
++ code;
new_body.append( def_comment( txt("NetSlime interface is generated by GasaGen/GasaGen_NetSlime.cpp")));
new_body.append(net_slime_class_interface);
while (code->Type != ECode::Preprocess_Pragma
|| ! code->Content.starts_with(txt("endregion NetSlime")))
++ code;
new_body.append(code);
}
break;
}
}
aclass->Body = new_body;
}
void gen_netslime_interfaces()
{
Array<StringCached> header_paths = Array<StringCached>::init_reserve(GlobalAllocator, 32);
// header_paths.append(get_cached_string(txt( path_module_gasa "GasaObject.h")));
// header_paths.append(get_cached_string(txt( path_gasa_actors "GasaActor.h")));
// header_paths.append(get_cached_string(txt( path_gasa_characters "GasaCharacter.h")));
// header_paths.append(get_cached_string(txt( path_gasa_game "GasaGameMode.h")));
// header_paths.append(get_cached_string(txt( path_gasa_game "GasaGameState.h")));
for (StringCached path : header_paths)
{
CodeBody original_header = parse_file(path);
CodeBody header_body = def_body(ECode::Global_Body);
for (Code code : original_header)
{
switch (code->Type) {
case ECode::Class:
{
CodeClass aclass = code.cast<CodeClass>();
gen_netslime_interface(aclass);
header_body.append(aclass);
}
break;
default:
header_body.append(code);
}
}
Builder header = Builder::open(path);
header.print(header_body);
header.write();
format_file(path);
}
}

View File

@ -272,6 +272,7 @@ void def_attribute_field_value_setters( CodeBody body, Array<StringCached> prope
void def_attribute_field_property_setter_inlines( CodeBody body, StrC class_name, Array<StringCached> properties )
{
body.append(def_pragma( txt("region Attribute Setters")));
for ( String property : properties )
{
CodeFn generated_get_attribute = parse_function(
@ -288,6 +289,7 @@ void def_attribute_field_property_setter_inlines( CodeBody body, StrC class_name
)));
body.append( generated_get_attribute );
}
body.append(def_pragma( txt("endregion Attribute Setters")));
}
void def_attribute_field_initers ( CodeBody body, Array<StringCached> properties )
@ -307,11 +309,10 @@ void def_attribute_field_initers ( CodeBody body, Array<StringCached> properties
void impl_attribute_fields( CodeBody body, StrC class_name, Array<StringCached> properties )
{
body.append(fmt_newline);
body.append(def_pragma( txt("region Rep Notifies")));
for ( String property : properties )
{
body.append(fmt_newline);
CodeFn field_impl = parse_function( token_fmt(
"class_name", class_name, "property", (StrC)property, "from_notice", txt("\n// From GAMEPLAYATTRIBUTE_REPNOTIFY\n"),
stringize(
@ -326,6 +327,7 @@ void impl_attribute_fields( CodeBody body, StrC class_name, Array<StringCached>
body.append( field_impl );
}
body.append( def_pragma( txt("endregion Rep Notifies")));
body.append(fmt_newline);
}
inline

View File

@ -1610,7 +1610,7 @@ void CodeConstructor::to_string_fwd( String& result )
if ( ast->InlineCmt )
result.append_fmt( "; // %S\n", ast->InlineCmt->Content );
else
result.append( ";" );
result.append( ";\n" );
}
String CodeClass::to_string()
@ -6278,6 +6278,16 @@ namespace parser
move_forward();
preprocess_content.Length++;
if ( current == '\r' && scanner[1] == '\n' )
{
move_forward();
move_forward();
}
else if ( current == '\n' )
{
move_forward();
}
Tokens.append( preprocess_content );
return Lex_Continue; // Skip found token, its all handled here.
}
@ -7262,7 +7272,7 @@ namespace parser
Tokens = Array<Token>::init_reserve( LexArena, ( LexAllocator_Size - sizeof( Array<Token>::Header ) ) / sizeof( Token ) );
defines_map_arena = Arena_256KB::init();
defines = HashTable<StrC>::init( defines_map_arena );
defines = HashTable<StrC>::init_reserve( defines_map_arena, 256 );
}
internal void deinit()

View File

@ -1663,7 +1663,7 @@ struct Array
{
Header& header = *get_header();
if ( begin < 0 || end >= header.Num )
if ( begin < 0 || end > header.Num )
return false;
for ( sw idx = begin; idx < end; idx++ )
@ -1820,13 +1820,11 @@ struct HashTable
Type Value;
};
static constexpr f32 CriticalLoadScale = 0.7f;
static HashTable init( AllocatorInfo allocator )
{
HashTable<Type> result = { { nullptr }, { nullptr } };
result.Hashes = Array<sw>::init( allocator );
result.Entries = Array<Entry>::init( allocator );
HashTable<Type> result = init_reserve(allocator, 8);
return result;
}
@ -1834,21 +1832,19 @@ struct HashTable
{
HashTable<Type> result = { { nullptr }, { nullptr } };
result.Hashes = Array<sw>::init_reserve( allocator, num );
result.Hashes = Array<sw>::init_reserve( allocator, num );
result.Hashes.get_header()->Num = num;
result.Hashes.resize( num );
result.Hashes.fill( 0, num, -1);
result.Entries = Array<Entry>::init_reserve( allocator, num );
result.Entries = Array<Entry>::init_reserve( allocator, num );
return result;
}
void clear( void )
{
for ( sw idx = 0; idx < Hashes.num(); idx++ )
Hashes[idx] = -1;
Hashes.clear();
Entries.clear();
Hashes.fill( 0, Hashes.num(), -1);
}
void destroy( void )
@ -1901,32 +1897,19 @@ struct HashTable
void rehash( sw new_num )
{
sw idx;
sw last_added_index;
HashTable<Type> new_ht = init_reserve( Hashes.get_header()->Allocator, new_num );
Array<sw>::Header* hash_header = new_ht.Hashes.get_header();
for ( idx = 0; idx < new_ht.Hashes.num(); ++idx )
new_ht.Hashes[idx] = -1;
for ( idx = 0; idx < Entries.num(); ++idx )
HashTable<Type> new_ht = init_reserve( Hashes.get_header()->Allocator, new_num );
for ( sw idx = 0; idx < Entries.num(); ++idx )
{
Entry& entry = Entries[idx];
FindResult find_result;
if ( new_ht.Hashes.num() == 0 )
new_ht.grow();
entry = Entries[idx];
Entry& entry = Entries[idx];
find_result = new_ht.find( entry.Key );
last_added_index = new_ht.add_entry( entry.Key );
if ( find_result.PrevIndex < 0 )
new_ht.Hashes[find_result.HashIndex] = last_added_index;
else
new_ht.Entries[find_result.PrevIndex].Next = last_added_index;
@ -1984,11 +1967,10 @@ struct HashTable
sw idx;
FindResult find_result;
if ( Hashes.num() == 0 )
if ( full() )
grow();
find_result = find( key );
if ( find_result.EntryIndex >= 0 )
{
idx = find_result.EntryIndex;
@ -2060,7 +2042,9 @@ protected:
b32 full()
{
return 0.75f * Hashes.num() < Entries.num();
uw critical_load = uw( CriticalLoadScale * f32(Hashes.num()) );
b32 result = Entries.num() > critical_load;
return result;
}
};
@ -2096,7 +2080,7 @@ struct StrC
#define txt( text ) \
StrC \
{ \
sizeof( text ) - 1, text \
sizeof( (text) ) - 1, (text) \
}
StrC to_str( char const* str )