Networking Question

Vēlies radīt spēli, bet nezini ar ko sākt? Sperot pirmos soļus, vari meklēt padomu šeit
Post Reply
Message
Author
CodeWolf
Posts: 119
Joined: 10 Dec 2010, 19:10
Location: LV-Riga-Marupe

Networking Question

#1 Post by CodeWolf » 10 Jan 2012, 21:45

Labvakar.. Atkal ir pienācis tas brīdis kad griežos pie jums ar kārētjo problēmu jeb neskaidrību kas mani pārņem.Šoreiz jautājums ir samērā plaš.. + domāju ka tas arī citiem varētu noderēt.. (:
Tātad lieta tāda ka vēlējos uzzināt vairāk par networkingu .Sākumā meklēju pa netu kaut kādu apskaidrību bet nekur tā īsti to neguvu jo lapa bija savādāki skaitļi un teorijas..
Bet tagad pie lietas būtības(jeb jautājumiem)..
* Cik liels ir "ideālais" laiks kura starpā sūtīt paketes?
Meiģināju dažādus laikus bet liekas ka neviens nebija istais.. Sākumā meiģināju katru rāmi sutīt pozīciju //zinu ka tā nedrīkst bet nu parbaudes pēc uzliku.. Uzliekot sapratu to ka tas nekam neder.. Klients ar kuru es kustejos uz otra klienta veica kustību ar ~40 sek aizkavi.. Tad radās doma laiku palielināt ar 60ms ..pēc skata paketes smuki aizgāja un objekti kustējās samērā "slīdoši" bet pieslēdzoties 12 klientiem parādījas ta pati problēma kas pirmstam .. mainot poziciju ~ pec paris sekundem tikai bija novērojama pozicijaas maiņa
tad izdomāju uzlikt "200ms" viss bidījas smuki.. tikai vienīgais bija problēma ar pozicijam jo pozicijas tika sutitas ik 200ms un izskatijas lag veidīgas.. tad tā arī isti nesapratu cik lielu taimeri vajag..
* nākamā lieta bija pozicijas .. Cik zinu nedrīkst sūtīt floatus.. bet izmēra ziņā tie sanāk tik pat lieli kā inti (4 baiti)
vismaz mērot nelielā testiņā tas tā sanāca
ar syzeof(..) laicinju atpakaļ viens no foruma lietotājiem minēja kādu savādāku veidu kā samazināt šo izmēru.. bet tā ari īsti nesapratu kā..

+ varbūt kāds vēl var pateikt kādus tipus vai ko tādu...jo ir doma veidot ko līdzīgu 2D mmorpg.. , beidzot izdevās dabūt kaut cik sakarīgu biblioteiku.. +grafiķus. takā nekam isti vairs nevajadzētu būt šķērslim..
Cik zinu priekš kā tāda vajadzēs maksimāli samazināt pakešu izmērus.. :)
//OpenGL

bubu
Guru
Guru
Posts: 398
Joined: 07 Dec 2010, 11:54

Re: Networking Question

#2 Post by bubu » 10 Jan 2012, 22:41

Nav tāda ideālā laika.
Katram spēles tipam, vai pat individuālai spēlei tas ir savādāks.
Quake-tipa spēlēm tas varētu būt 10-20x sekundē.
Bet Age of Empires tipa spēlēm tu to vari mierīgi darīt reizi sekundē.
Katrā ziņā - taisi tā, lai šo intervālu varētu viegli pamainīt, un tad kad būs kautkas strādājošs, tad maini un skaties kā mainās spēles gaita un lagošana.
Squares3D, ja nemaldos, tad es sūtīju 15x sekundē visu spēlētāju pozīcijas/rotācijas citiem. LAN'ā strādāja ne vainas.

Tas, ka tev 200ms izskatījās lagveidīgi, tas ir normāli. Tā jābūt. Tāpēc jātaisa ekstrapolācija. Klients, kurš saņem šos datus, turpina kustināt pozcīju ar tādu pašu ātrumu (tipa ja iepriekšējā laikā bija pozīcija 10, un tagad ir pozīcija 30, tad turpināt kustināt, lai pēc 200ms būtu pozīcija 50). Un, sagaidot nākamo paketi, tas updeito pozīciju uz īsto vērtību.

Reku īss apraksts par to: http://www.flipcode.com/archives/Networ ... okie.shtml
http://en.wikipedia.org/wiki/Client-side_prediction
http://blogs.msdn.com/b/shawnhar/archiv ... ction.aspx
http://stackoverflow.com/questions/8703 ... correction

Floatus var sūtīt, bet tas nav kūl, jo: to precizitāte var atšķirties starp datoriem (un arhitektūrām). Bet daudz svarīgāk - tāpē, ka 4 baiti ir DAUDZ par daudz baiti priekš viena skaitļa (parasti).
Piemēram, iedomājies tev ir pasaule ar koordinātēm no 0 līdz 100. Un tev vajag pozīcijas ar precizitāti līdz 0.1. Respektīvi tev pietiktos aizsūtīt vienu skaitli no 0 līdz 1000. Un saņemšanas galā izdalīt ar 10, lai dabūtu īsto vērtību. Un skaitlim 1000 nevajag 4 baitus. Skaitlim 1000 vajag tikai 10 bitus, kas ir ~3x mazāk nekā 4 baiti. Tātad 4 baitos tu vari aizsūtīt gan x, gan y, gan z koordināti, ja to vērtības ir no 0 līdz 100 ar precizitāti 0.1 (tā vietā lai sūtītu 3 floatus, kas ir 12 baiti). Tas saucās quantization:
http://blogs.msdn.com/b/shawnhar/archiv ... ation.aspx

Par to pirmo iemeslu - precizitāti. Tas ir vēl jo svarīgāk, ja tu taisi (un to tev vajadzētu taisīt) to pozīciju ekstrapolēšanu/paredzēšanu nākotnē. Tad pat mazākās floatu kļūdas var radīt diezgan lielus defektus. Te cits lasāmais par precizitātes tēmu: http://gafferongames.com/networking-for ... terminism/

CodeWolf
Posts: 119
Joined: 10 Dec 2010, 19:10
Location: LV-Riga-Marupe

Re: Networking Question

#3 Post by CodeWolf » 11 Jan 2012, 01:22

Tas, ka tev 200ms izskatījās lagveidīgi, tas ir normāli. Tā jābūt. Tāpēc jātaisa ekstrapolācija. Klients, kurš saņem šos datus, turpina kustināt pozcīju ar tādu pašu ātrumu (tipa ja iepriekšējā laikā bija pozīcija 10, un tagad ir pozīcija 30, tad turpināt kustināt, lai pēc 200ms būtu pozīcija 50). Un, sagaidot nākamo paketi, tas updeito pozīciju uz īsto vērtību.
To gadījumā nesauca par Dead Reckoning?

+ bet nu reali es nosūtot piem skaitli no 0 lidz 100 ar intu tas jau sanak tas pats.. kas vienkārši pa taisno nosūtit piem int x=90;
.write(x); ?
efekts jau tads pats.. tāpāt tur ir kautkas jāsūta.. vienk int.. vai kautkādu dalījumu..
Vai ari tas dalījums bij domāts client side..?
//OpenGL

bubu
Guru
Guru
Posts: 398
Joined: 07 Dec 2010, 11:54

Re: Networking Question

#4 Post by bubu » 11 Jan 2012, 03:49

Par dead reckoning to sauc tad, ja ekstrapolē pozīciju. Bet tikpat labi tu vari ekstrapolēt jebkuru citu vērtību, kas mainās - rotāciju, enerģiju, krāsu, utt...

Ja tu sūti int'u (visu pilnībā), tad, protams, tas arī aizņems 4 baitus (uz lielāko tiesu sistēmu).
Tev pašam jāpako skaitļi pa bitiem, lai taupītu vietu.

No mana piemēra (0..100):

Code: Select all

// ... sūtīšanas kodā
float x=3, y=44, z=55; // kautkādas koordinātes no 0..100;
int xi = (int)(x*10), yi = (int)(y*10), zi = (int)(z*10); // noapaļojam uz 0..1000

int pakete = xi | (yi << 10) | (zi << 20);
write(pakete);

//... saņemšanas daļā:
pakete = readInt();
xi = pakete & ((1<<10)-1);
yi = (pakete>>10) & ((1<<10)-1);
zi = (pakete>>20) & ((1<<10)-1);
x = xi/10.0f;
y = yi/10.0f;
z = zi/10.0f;
To visu, protams, var uzrakstīt universāli. Tipa kautkādā paketes klasē (ja C++):

Code: Select all

class Packet
{
    char buffer[..];
    // ...

    void write(float value, float min, float max, float precision);
    float read(float min, float max, float precision);
};

void Packet::write(float value, float min, float max, float precision)
{
    int tmp = (int)((value - min) / precision);
    int bitcnt = log2((max - min) / precision);

    // te saglabā no tmp bitcnt bitus buferī
    // ...
}

float Packet::read(float min, float max, float precision)
{
    int bitcnt = log2((max - min) / precision);

    int tmp = ...; // te nolasi bitcnt bitus no bufera
    return min + tmp * precision;
}
Vēl papildus triks - sūti nevis absolūto pozīciju, bet sūti izmaiņo kopš iepriekšējās reizes. Parasti jau visādi itemi spēlē nekustās daudz, un kustoties maz, tu vari diezgan ļoti ietaupīt vietu sūtot pavisam mazu skaitli, piemēram -10..+10. Protams, ja vajag kustēties par lielu vienību, tad var izdalīt divus kustības veidus - relatīvo (par mazu skaitli) un absolūto (sūti kautvai visu pilno floatu).

elvman
Posts: 434
Joined: 06 Dec 2010, 18:43
Location: Rīga
Contact:

Re: Networking Question

#5 Post by elvman » 11 Jan 2012, 12:56

Rēķināt log pie katras rakstīšanas un lasīšanas nav pārāk "dārgi"? Es ieteiktu izveidot globālu settingu priekš bitu skaita katrai koordinātai.
Beidz runāt, sāc darīt!

bubu
Guru
Guru
Posts: 398
Joined: 07 Dec 2010, 11:54

Re: Networking Question

#6 Post by bubu » 11 Jan 2012, 18:52

Nu tas taču tikai piemērs, lai saprastu lietas būtību.
Pie tam floatiem log2 var izrēķināt ļoti ātri - tie jau eksponentē jau glabā log2:
http://graphics.stanford.edu/~seander/b ... erLogFloat
http://graphics.stanford.edu/~seander/b ... EEE64Float
http://www.musicdsp.org/showone.php?id=63

Vai arī alternatīvi min/max/precision glabāt kā integerus, un tad log2 var ātri izrēķināt sameklējot augstāko bitu 1.

Anyway - optimizēt vajag tad, kad tas log2 tiešām sāks parādīties profilēšanas rezultātu augšgalā. Sākumā vajag uzrakstīt korektu kodu, tiešām kaut vai ar īstu log2.

CodeWolf
Posts: 119
Joined: 10 Dec 2010, 19:10
Location: LV-Riga-Marupe

Re: Networking Question

#7 Post by CodeWolf » 11 Jan 2012, 22:06

:D Vairs jau neko īsti nesaprotu..
Pēc kādām formulām var iegūt..
max, min , precision ?
+ tak nevar but ka ta visu laiku jārēķina...
RakNet 'am nav vienkārši kāda kommanda kura paveiktu šo darbu?

reāli tad kuram beigu beigās ir jārēķina? floatam vai intam..
likas ka intam jo tas itka sanak mazaks.. bet tad tu raksti ka float jo to var atrak izrēķinat ar log2..
//OpenGL

bubu
Guru
Guru
Posts: 398
Joined: 07 Dec 2010, 11:54

Re: Networking Question

#8 Post by bubu » 11 Jan 2012, 22:13

min/max/precision neiegūst pēc formulām.
To tu pats norādi.
Ja tev spēles pasaule ir no -100 līdz +100, un tu gribi precizitāti 0.01, tad tie ir arī ir tie min/max/precision:

Code: Select all

packet->write(x, -100.0f, +100.0f, 0.01f);
CodeWolf wrote:reāli tad kuram beigu beigās ir jārēķina? floatam vai intam..
likas ka intam jo tas itka sanak mazaks.. bet tad tu raksti ka float jo to var atrak izrēķinat ar log2..
Spēlē atmiņā glabāt intu's nav jēga, izņemot īpašus gadījumus (prasības uz vienmērīgu precizitāti lielos attālumos utml). Tipiski, protams, ka lieto floatus. Taču sūtīt pa tīklu floatus nav īpaši kūl, kā jau teicu. Tur vajag tos int'us, jeb bitus sapakotus buferī.

Es esmu lietojis tikai enet. Par RakNet nekā nezinu. Tam dokumentācija nav pieejama?
Reku ir kautkādas metodes. Izdomā pats, kura tev labāk der:
http://www.jenkinssoftware.com/raknet/m ... 710ba51366
http://www.jenkinssoftware.com/raknet/m ... 22942003a8
http://www.jenkinssoftware.com/raknet/m ... 70a73876e5

Bet tās ir vispārīgas WriteXYZ metodes - vienmēr bitus var sapakot efektīvāk, ņemot vērā spēles specifiku, kā es augstāk rakstīju.

CodeWolf
Posts: 119
Joined: 10 Dec 2010, 19:10
Location: LV-Riga-Marupe

Re: Networking Question

#9 Post by CodeWolf » 13 Jan 2012, 01:35

Reāli visu floata samazināšanu veic šis kods ?
int tmp = (int)((value - min) / precision);
int bitcnt = log2((max - min) / precision);

// te saglabā no tmp bitcnt bitus buferī
// ...
vienk..esmu izmeklējies pa netu un nekādīgi nevaru atrast vai ari sappiest mazāk par 16bitiem..
+ kā izpaužas
// te saglabā no tmp bitcnt bitus buferī
?

cik zinu char =8 bitus liels bet kad parveido uz char ...[skaitlis] tad baitu skaits ir atkarigs no skaitļa.. ko ievadiju iekavās.. Tad kā var saspiest. to visu..?
//OpenGL

bubu
Guru
Guru
Posts: 398
Joined: 07 Dec 2010, 11:54

Re: Networking Question

#10 Post by bubu » 13 Jan 2012, 02:03

Jā tieši tā - tas to dara.
Var saspiest ne tikai uz 16-bitiem, bet arī uz 8, 4 vai pat vienu bitu.
Viss atkarīgs kādus skaitļus tu tur "spied".
Ja tev pietiek, ka floats pieņem vērtības no 0 līdz 10 ar precizitāti 0.1, tad tev pietiks ar 7 bitiem.

Code: Select all

packet->write(x, 0, 10, 0.1f);
+ kā izpaužas
// te saglabā no tmp bitcnt bitus buferī
?
Triviālākajā gadījumā:

Code: Select all

unsigned char bits[100];
int filledBits;

void initBits()
{
    memset(bits, 0, sizeof(bits));
    filledBits = 0;
}

void storeBits(unsigned int x, int bitCount)
{
    for (int i=0; i<bitCount; i++)
    {
        buffer[filledBits/8] |= ((x >> i)&1) << (filledBits%8);
        filledBits++;
    }
}

Post Reply

Return to “Iesācējiem / For beginners”