#Wow look, it's a thread!

128 messages · Page 1 of 1 (latest)

gaunt pagoda

😎

final oar

First my experience is mostly from emulating Ultima Online servers to work with offical EA clients.

Ultima Online used UDP packets that had distinct byte length patterns and a distinct ID prefix.

The server would have a listener for incoming packets. They'd be transformed from raw byte string to C# objects then pushed into a queue. (some packets had higher priorities).

A game manger would pop off the queue and made changes to the server state.

Entities within a range would receive update packets of where the piece needed to transform to.

The client does the same packet handling except it has to control the proxy puppets (actors) on the client side.

So when the character moves on the client, it sends a stream of packets of events to the server who says okay or denies it. If it okays it, the server usually sends out updates to other clients.

You can pool events serverside (think of counter-strike ticks)

today you can just have Json or Binary serialization

Proxy + Command pattern

thoughts?

gaunt pagoda

That part sounds decent enough, for the player specific actions at least.

I guess for me it's other stuff in the world being simulated that I'm less confident on

Does the host simulate all the enemies and try to stream all of their position/velocity data to every other peer?

Or do the peers simulate their game state and try to somehow check if they're still in sync

I'm wondering what the bandwidth looks like in a game with a lot of enemy NPCs 😄

Seems like the approach is sending a delta snapshot of the game state at a low tick and interpolating on the client side

final oar
final oar

and usually you only move NPCs that are in view of a player

final oar

so when it moves on the server, it broadcasts that movement to the people in view

ragdoll physics can be done client side

but you get some "different" results sometimes

gaunt pagoda

So it's important to a degree to explicitly relate a set of players to a state change

final oar

depends on your item count and update flow

some games are more chatty than others

you can batch data also

gaunt pagoda

Probably not as much if everyone's on the same screen most of the time

final oar

"here's a list of all entities that moved and their new locations"

final oar

might create more overhead than just sending them everything

and letting the client ignore stuff out of screen

also know the difference between UDP and TCP

gaunt pagoda

Seems like a safe bet for getting the thing up and running in the first place

Oh yeah I'm aware 😄

final oar

optimize later

gaunt pagoda

Making udp reliable will be "fun"

The thing you linked earlier touches on that I think

final oar

you'd be surprised on how resilient games can be when you just keep sending updates

gaunt pagoda

I guess that's true, even if they come out of order

"enough" of them would be in order BlobShrug

Only one way to find out

final oar

yep

you will want to give them an order

so you can ignore updates you've already done

object_a moves to 0,1 [packet 1]
object_a moves to 1,2 [packet 2]

but 2 gets there first and then 1, you want to ignore 1

gaunt pagoda

Right

final oar

server side usually handles validations

"is this entity close enough to attack this entity"

if i'm mansplaning something tell me

gaunt pagoda

I'm familiar with that yes but it's perfectly fine and helpful to get as much help as possible 😄

I'm anticipating client side prediction to be the most annoying thing to develop

But if I understand that correctly it's just extrapolation with correction

final oar

yep

gaunt pagoda

If something was already moving this way, keep moving it that way until you get a packet that says otherwise

final oar

pretty much. People use to cheat in early Quake PVP matches by setting the network LERP value really high

and you'd see people run around corners before they were there

gaunt pagoda

But it's more important for player movement/actions

Because you want the input to feel instant on the player end

final oar

still important for NPCs don't want them two stepping around

gaunt pagoda

You let the client pretend they're moving around, shooting and killing things

While it's frantically asking the host if they're allowed to actually do it

final oar

ya

"hey i shot this thing at xyz from xyz"
server: yep

"hey i shot thing xyz from wpg"
server: i don't think so

gaunt pagoda

It'll maybe even briefly show you shooting that thing client side and killing it but then it says uh uh and "rewinds" the state

final oar

yep

gaunt pagoda

But that's I guess maybe a thing that was tripping me up too

final oar

i'm sure you've been in a really laggy server before

gaunt pagoda

There is legit rollback but in this case wouldn't it just be replacing the state

final oar

ya

gaunt pagoda
final oar

in client land, the game manager kills entity_a

server land, denys it and sends update entity_a packet to client

client land: receive entity_a state and setup proxy for user

gaunt pagoda

Not that OW was laggy, but it was plenty of time for the predictions to be wrong a lot of the time

final oar

people complain about hitregistration

that's the issue we're discussing

gaunt pagoda

Which was great for those "I saw it hit you" moments where they got you first

final oar

server and client had different views of where entity_a was

gaunt pagoda

Which then killed you

Making your predicted shot invalid

final oar

ya

that's another thing

if player dies server side, they're still transmitting client side

server side gotta reject those until respawn

gaunt pagoda
final oar

ya

gaunt pagoda

Instead of having the client just delete shit and have to add it back when it fucks up

final oar

easy to just "hide" stuff

gaunt pagoda

Yeah

Hide, pause tick

final oar

and if you want to be clever you can even respawn it from a spawn point

so it doesn't look rubberbandy

gaunt pagoda

I think I'm not understanding that idea

final oar

player shoots and thinks they killed the entity

servers like "naw"

so now you have to call the player a lier

or if it's a npc, just spawn it back like it was killed but don't count the score

just depends on how you want to handle the mistake

i perfer gaslighting them

"sure, you did kill it"

gaunt pagoda

lol I see what you mean now

Instead of it phasing back into existence

final oar

ya

good luck

gaunt pagoda

👍

split wren

wow a thread

gaunt pagoda

yeah

final oar

Any progress Gary?

gaunt pagoda
final oar Any progress Gary?

Not in the integration yet. We've been setting up a lot of the core framework with flecs intending to use Godot only as a front end for rendering, input, UI, audio etc

I'm setting up my webrtc server with a simple lobby system

Once all of that stuff is sorted out I can actually get to the net code...

final oar

Well hurry up

gaunt pagoda
    private squirrel3Hash(position: number, seed: Long): number {
        let n = Long.fromInt(position).multiply(0x1f1f1f1f).xor(seed);
        n = n.xor(n.shiftRight(15));
        n = n.multiply(n.or(Long.ONE));
        n = n.xor(n.shiftRight(7));
        n = n.multiply(n.or(Long.ONE));
        n = n.xor(n.shiftRight(14));
    
        return n.mod(Long.fromInt(CHARACTER_SET_LENGTH)).toNumber();
    }

    private generateSquirrel3Id(seed: Long): string {
        // Precompute 6 character positions
        const char1 = this.squirrel3Hash(0, seed);
        const char2 = this.squirrel3Hash(1, seed);
        const char3 = this.squirrel3Hash(2, seed);
        const char4 = this.squirrel3Hash(3, seed);
        const char5 = this.squirrel3Hash(4, seed);
        const char6 = this.squirrel3Hash(5, seed);

        // Return the 6-character string using precomputed characters
        return CHARACTER_SET[char1]! + CHARACTER_SET[char2]! + CHARACTER_SET[char3]! +
               CHARACTER_SET[char4]! + CHARACTER_SET[char5]! + CHARACTER_SET[char6]!;
    }

    public generateUniqueSimpleId(): string {
        let newId: string;
        do {
            this.idCounter = this.idCounter.add(1);

            const timestamp = Long.fromNumber(Date.now());

            // Combine the 32-bit counter and the 32-bit timestamp into a 64-bit seed
            const seed = this.idCounter.shiftLeft(32).or(timestamp.and(Long.fromInt(0xFFFFFFFF)));

            newId = this.generateSquirrel3Id(seed);
        } while (this.activeIds.has(newId) || profanity.exists(newId));

        this.activeIds.add(newId);
        return newId;
    }
final oar

profanity.exists(newId))
doing all that work just to get "ASSHOL" out of a random generator

gaunt pagoda
final oar

start with a random swear word and just random from there

gaunt pagoda

I didn't realize the algorithm ever saw updates

here's the original talk

the profanity exists thing just loops a list of regex over it

tall prism

😭

I don't know shit about C sharp anymore

final oar

||so you can see sharp||

tall prism

🥁

dark abyss

a