Coder Social home page Coder Social logo

zpl-c / librg Goto Github PK

View Code? Open in Web Editor NEW
1.2K 41.0 34.0 1.74 MB

🚀 Making multi-player gamedev simpler since 2017

Home Page: https://zpl-c.github.io/librg/

License: BSD 3-Clause "New" or "Revised" License

C 98.04% CMake 0.26% JavaScript 0.98% Makefile 0.52% Shell 0.20%
zpl enet networking gamedev library header-only multiplayer sync lightweight low-level

librg's People

Contributors

inlife avatar markatk avatar tederis avatar timgates42 avatar zpl-zak avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

librg's Issues

How to generate different ID for different clients?

Just a question. In example-enet.c server and all clients in one file and ID's generation is easy:

        for (int i = 0; i < MAX_CLIENTS; ++i) {
            client_update(i, clients[i]);
        }

in that case i is ID.
But in real case clients on different computers don't know about each other and therefore can't generate id's by itself.
But to recieve(read) something or to send(write) something it needs an ID as I understand.

   librg_world_read(
        world,
        ID,
        (char *)event.packet->data,
        event.packet->dataLength,
        NULL
    );

    librg_world_write(
        world,
        ID,
        buffer,
        &buffer_length,
        NULL
    );

I assume It's somehow must be generation on server.
How to generate different ID for different clients?
Maybe It's silly question and I don't understand something...

Encryption & Security

Hi,
Thanks for great library.
I wonder if the library support for encryption and checksum for packet/stream?

Feature request: add ability to set up whitelisted entity relations

Currently, librg supports virtual worlds and an ability to set visibility on a per-entity level. The later feature can be extended to support both visibility and invisibility relations.

That would allow some entities sharing the same virtual world see specified entity only if:

  • it is in the stream range (default)
  • it is marked as always visible for the subject entity
  • or never see it if it is marked as invisible for the specified entity

C# Wrapper.

Yo,

Will there be any possibility to add wrapper for C#?

Cheers.

LIBRG_CLIENT_STREAMER_UPDATE called after disconnect

On client side LIBRG_CLIENT_STREAMER_UPDATE is still getting called after the client was disconnected from the server. I think streamed entities should be cleared after any sort of disconnect or at least not being called anymore.

Noob question: How does a single header library not cause mutiple symbol definitions?

Please excuse my naivety but I've never encountered single-header libraries till now.

I think this is a very nice library but I am rather confused about how I would go about using it.

I understand that if all the functions are 'inline' then there really isn't any true symbol definitions that could collide when linking multiple object files... But looking at the source of librg I am seeing functions which do not have any inline keyword specified anywhere, for example:

u64 librg_event_add(librg_ctx *ctx, u64 id, librg_event_cb callback) {
        librg_assert(ctx);
        librg_event_block *block = librg_event_pool_get(&ctx->events, id);

        if (!block) {
            librg_event_block arr;
            zpl_array_init(arr, ctx->allocator);
            librg_event_pool_set(&ctx->events, id, arr);
            block = librg_event_pool_get(&ctx->events, id);
        }

        u64 offset = zpl_array_count(block);
        zpl_array_append(*block, callback);
        return offset;
}

I assume that there must be some non-conventional use of this header necessary to get it working otherwise if I were to include this file in multiple C files and then link them together I would get linker errors for multiple symbol definitions with the same name, wouldn't I?

Sorry if this is the wrong place to ask this question but I wasn't sure where else would be appropriate.

Also, why the #if 1 statements wrapping sections of code? Those seem pointless and I can't grasp what their purpose would be, other than to manually toggle the compilation of specific sections... But wouldn't that be better achieved by using actual #ifdef SOME_MACRO switches where all the switches can be listed at the top of the file for ease of toggling?

Sending user inputs in server-authoritative model

What is the intended way to send inputs from client to server using this library?
By inputs I mean things like key held, look direction... They are sampled and sent at regular intervals. I can think of two ways:

Using message is one. However, messages are always sent as reliable which is not very optimal since client will keep sending (a buffer of) inputs anyway.

Another method is to create a "controller" entity and let client stream it. The data of that entity will be the client's inputs. This feels a bit weird.

Ideally, should there be a way to send unreliable messages? If I were to add another parameter, the number of librg_message_send functions would double though.

Better support for 2D games

Hey,

while reading the code I noticed that the vector3 is used. In 2D games, the z axis is used very rarely. Do you have plans to improve and minimize the packet size by supporting 2D only or allowing to use a custom implementation of vectors?

Regards,
TheAifam5

Chunk limit issue.

Hi, I'm testing librg in a huge world and I need relatively small chunks, so I'm currently using 1024x1024x1 chunks with a size of 10 x 10 x UINT16_MAX. The problem comes when entities mess around chunks above 2^15, a chunk is supposed to be up to 2^63 but for some reason, events, world_write etc won't work if the entities' chunks are above 2^15. I checked the code to see if there was any cast somewhere messing with the int64_t but couldn't find it, any idea why this could be happening?

Possible WebRTC support?

A bit of a big thing, but if it can be implemented it will truely make librg cross-platform.

There is the Intel WebRTC Datachannel Microstack, a C99 little library which is conveniently also licensed under Apache 2.0:
https://github.com/HumbleNet/webrtc?files=1

And Humblenet has an example of a shared ABI between it and browser's RTC implementation:
https://github.com/HumbleNet/HumbleNet/blob/master/src/humblenet/src/libwebrtc.h

It's also a little similar to Enet with reliable/unreliable packets and peer to peer nature.

Compile error in using C++

An error error: taking address of temporary array occurred when compile C++ program include librg.h.

/home/user/app/src/librg.h: In function 'int32_t librg_world_fetch_owner(librg_world*, int64_t, int64_t*, size_t*)':
/home/user/app/src/librg.h:21559:59: error: taking address of temporary array
21559 |     return librg_world_fetch_ownerarray(world, (int64_t[]){owner_id}, 1, entity_ids, entity_amount);

Temporary solution to the problem

It works to change the line L21559 in librg.h

    return librg_world_fetch_ownerarray(world, (int64_t[]){owner_id}, 1, entity_ids, entity_amount);

to

    int64_t owner_ids[1]; owner_ids[0] = owner_id;
    return librg_world_fetch_ownerarray(world, owner_ids, 1, entity_ids, entity_amount);

Environment

  • librg version: Release 7.2.0
  • Build Environment
    • Build Tool: CMake
    • Compiler: gcc 10.2.1 (with -lstdc++)
  • OS: Linux (Debian)

Relative Issue

Add connection states

Client should be able to determine what state he currently is in, such as whether he's disconnected, currently connecting, awaiting authorization (waiting for connection accept event) and connected.

We already have librg_is_connected(..) method, which however is limited in its functionality. I'd recommend adding upper-mentioned states as a part of the library, so we can determine states easily.

Proposed methods:

  • librg_get_state(ctx) for client-side
  • librg_peer_get_state(ctx, peer) for server-side (optional)

Emscripten Information

Can you post some examples or at least some notes regarding the projects emscripten port?

Entity aren't removed for the owners

As title says, entities visibility seems like to have 'always' to owners instead of 'default'. Is this supposed to work like this or am I missing something?

I'm currently relying of the entity create/remove events to set the ownership.

Ownership information in reader OnCreate event

In clients librg_event_owner_get(w, e) in client_read_create or client_read_update owner_id always the same for all entities_id.
I tested it in example-enet.c. Maybe it work like expected, but in that case client can't get real owner of entity... Maybe it's more related with enet than librg.

Can't get position data when entity created.

Can't get position data when entity created. In example example-enet.c I try to get position in client_read_create function but librg_event_size_get always returns actual_length 0.

librg_event_set(world, LIBRG_READ_CREATE, client_read_create);

int32_t client_read_create(librg_world *w, librg_event *e) {
    int64_t owner_id = librg_event_owner_get(w, e);
    int64_t entity_id = librg_event_entity_get(w, e);
    printf("[client] An entity %d was created for owner: %d\n", (int)entity_id, (int)owner_id);
   
    size_t actual_length = librg_event_size_get(w, e);
    printf("[client] actual_length = %zu", actual_length);
    if (actual_length != sizeof(vec3)) return 0;
   
    char *buffer = librg_event_buffer_get(w, e);
    
    vec3 position = {0};
    memcpy(&position, buffer, actual_length);

    return 0;
}

Your are using eNet code which does not exist

This not exist in eNet code (ENET_EVENT_TYPE_DISCONNECT_TIMEOUT)

case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: {                                                                                                                                                                                 
 

and this function :

enet_packet_create_offset

using latest version of eNet from github

Sending inputs in server-authoritative model

What is the intended way to send inputs from client to server using this library?
By inputs I mean things like key held, look direction... They are sampled and sent at regular intervals. I can think of two ways:

Using message is one. However, messages are always sent as reliable which is not very optimal since client will keep sending (a buffer of) inputs anyway.

Another method is to create a "controller" entity and let client stream it. The data of that entity will be the client's inputs. This feels a bit weird.

Ideally, should there be a way to send unreliable messages? If I were to add another parameter, the number librg_message_send functions would double though.

How to properly install and add this lib to C++ project?

The documentation says just to include "librg.h". But when I do just that and add this to my c++ project I got error:

librg/code/source/query.c: In function ‘int32_t librg_world_fetch_chunk(librg_world*, librg_chunk, int64_t*, size_t*)’:
error: taking address of temporary array
    39 |    return librg_world_fetch_chunkarray(world, (librg_chunk[]){chunk}, 1, entity_ids, entity_amount);
      |                                                                                                  ^~~~~~~

What I need to do to inlude library in c++ project? Maybe somehow link library like -lrg. Maybe I need add include some directories -I./librg/code. Or maybe I need to install somehow compiled lib. I use Ubuntu linux.

Does not work using C++

I'd like to use this library in my C++ project but due to some conversions that are only valid in C it won't compile:

ext/librg/librg.h|19756 col 20| error: cannot initialize a variable of type 'librg_world_t *' with an rvalue of type 'void *'
||     librg_world_t *wld = LIBRG_MEM_ALLOC(sizeof(librg_world_t));
||                    ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ext/librg/librg.h|19918 col 45| error: cannot initialize return object of type 'librg_event_type' with an rvalue of type 'int'
||     LIBRG_ASSERT(event); if (!event) return LIBRG_EVENT_INVALID;
||                                             ^~~~~~~~~~~~~~~~~~~
ext/librg/librg.h|2177 col 41| note: expanded from macro 'LIBRG_EVENT_INVALID'
|| #define LIBRG_EVENT_INVALID             (-0x0006)
||                                         ^~~~~~~~~
ext/librg/librg.h|19921 col 12| error: cannot initialize return object of type 'librg_event_type' with an lvalue of type 'uint8_t' (aka 'unsigned char')
||     return e->type;
||            ^~~~~~~
ext/librg/librg.h|20656 col 14| error: cannot initialize a variable of type 'int64_t *' (aka 'long *') with an rvalue of type 'void *'
||     int64_t *results = LIBRG_MEM_ALLOC(LIBRG_WORLDWRITE_MAXQUERY * sizeof(int64_t));
||              ^         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|| 4 errors generated.

Disconnected client entities trigger entity update once

When a client disconnects (or timeouts, doesn't matter) from the server there is one entity update event triggered after the disconnect event.

...
Update entity 1 for client 1773685128
Update entity 0 for client 647576079
Update entity 1 for client 1773685128
Update entity 0 for client 647576079
Update entity 1 for client 1773685128
Update entity 0 for client 647576079
Update entity 1 for client 1773685128
Update entity 0 for client 647576079
client 647576079 disconnected
Update entity 1 for client 1773685128
Update entity 0 for client 647576079

Fix compilation regression with the latest ZPL dep

Log from discord:

../include/librg.h: In function ‘librg__space_insert’:
../include/librg.h:3104:31: error: inlining failed in call to always_inline ‘librg__space_insert’: recursive inlining
     librg_inline librg_space *librg__space_insert(librg_ctx *ctx, librg_space *space, librg_space_node node) {
                               ^~~~~~~~~~~~~~~~~~~
../include/librg.h:3139:26: note: called from here
             librg_space *sub = librg__space_insert(ctx, (space->spaces+i), node);

Tested on: GCC 7.4

librg_network_stop on server doesn't trigger disconnect event on clients

Hello,

I could be missing something, but when I shutdown my server, none of the connected clients receive any event; they all just timeout. Looking at librg_network_stop, there doesn't appear to be anything to handle currently connected clients. They just get deleted with the zpl table.

Would be happy to contribute here, but not sure if I am missing something.

Thanks.

Handler data_size casting limits it to u16 precision per entity write

bbbbbbbbb

If this is intended, why should handler return int32_t and not u16? I stumbled upon this, because I am sending kind of big packets and this just cuts it, without warning.

Update

I think i see, int32_t because return negatives and handle those in some parts? So there is u16 precision limit per entity write?

Add result to librg_init

When initializing enet fails (for example due to an already bound port on server side), the librg_init function does not give any result about it (except from the assert message). It would be nice to change the function to return a result or state so programs can do proper error management.

Misleading description

Librg is advertised as an MMO solution but authoritative servers, while possible, seem like an afterthought and I don't see any API for interest management. In fact I would say that librg is ideal for anything besides MMO.

Am I missing something obvious here?

LIBRG_CONNECTION_ACCEPT payload

When the server accepts a client connection, it would be nice for the server to be able to send data to the client with the LIBRG_CONNECTION_ACCEPT event for initial setup (for example to set the initial position or health).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.