Klurighet. Teewars nätverk
Tjo,
Här kommer en liten rolig uppgift med anknytning till Teewars.
När jag designade nätverket i Teewars så var det flera problem att slåss med. Bland annat hur man skall packa data över nätverket. Att använda structs är trevligt men har vissa problem. Här kommer ett exempel.
struct player_info
{
float x, y;
float angle;
unsigned char current_weapon;
unsigned char emote;
bool hook_active;
float hook_x, hook_y;
unsigned char health;
unsigned char armor;
};
Problemet med att skicka en sådan strukt över nätverket är att dessa.
* Olika platformar / kompilatorer kommer göra structen olika stor vilket pajar allt.
* Olika processorer har olika endianness
Dessa går att lösa genom att skriva två funktioner, en som packar och en som packar upp structen och ser till att swappa den korrekt. Dessa blir bara en pain att underhålla. Allt i dessa structar får bara innehålla datatypen int!. Då ser det ut såhär.
struct player_info
{
int x, y;
int angle;
int current_weapon;
int emote;
int health;
int armor;
int hook_active;
int hook_x, hook_y;
};
Detta gör att structen alltid blir lika stor. Du kan skriva en generell funktion för att packa ner den så att endianness inte blir ett problem. Den har ju vissa drawbacks och det är att den generellt blir större och det är här lilla klurigheten kommer in. Många av dessa members är värden från säg, -30 till 30 oftast vilket gör att det är ganska oeffektivt att skicka den över nätverket i sin nuvarande form. Jag har lagt på en kompression som heter LZW på detta men det går ju att gåra något mycket bättre.
Själva klurigheten. Vad som behövs är en funktion som packar ner en int till ett variablet antal bytes. Så att säg, -30 till 30 bara blir 1 byte stor, utöver det behöver den 2 bytes och sedan 3, 4 osv. tills den når sitt tak. Denna funktion skall fungera på alla 32bit int tal, negativa och positiva. Den skall vara effektiv just runt 0 +- 30 typ där den tar en byte för att lagra det. Denna funktion måste vara snabb eftersom den kommer köras på servern väldigt ofta.
Här kommer lite kod ni kan använda för att testa. Det är alltså vint_pack och vint_unpack som skall göras mycket smartare. Språket är C.
#include <stdio.h>
// pack i into dst and return where to pack the next int
unsigned char *vint_pack(unsigned char *dst, int i)
{
*(int*)dst = i;
return dst+sizeof(int);
}
// unpack an int from src into out and return where to find the next
const unsigned char *vint_unpack(const unsigned char *src, int *out)
{
*out = *(int*)src;
return src+sizeof(int);
}
// the test application
int main()
{
unsigned char buffer[32];
unsigned char *p1;
const unsigned char *p2;
int j;
unsigned i;
//for(i = 0x70000000; i < 0x8fffffff; i++) // full test
for(i = 0x7ff00000; i < 0x8ff0000; i++) // fast test
{
j = 0;
p1 = vint_pack(buffer, *((int *)&i));
p2 = vint_unpack(buffer, &j);
if(p1 != p2)
{
printf("%d (%x) failed. pointer problem %p != %p\n", i, i, p1, p2);
return -1;
}
if(i != j)
{
printf("%d (%x) failed. %d != %d %x != %x %02x%02x%02x%02x%02x%02x%02x%02x\n",
i, i, i, j, i, j,
buffer[0], buffer[1], buffer[2], buffer[3],
buffer[4], buffer[5], buffer[6], buffer[7]);
return -1;
}
if((i&0x7fffff) == 0) // remove this when profiling
printf(".\n");
}
printf("all done!\n");
return 0;
}
Skall bli intressant att se diskussionerna + lösningar som folk kommer på.
Teeworlds - För dig som gillar gulliga saker med stora vapen.