mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-29 07:02:12 +00:00
Restore choke lines into the netgraph, and support discontinuities so it doesn't look so weird. Also tweak realip warnings. Don't honour dupes if it would exceed rate limits (new data is better than dupe data), which can also double-up as a CBR type thing to try to reserve the bandwidth (avoiding packetloss bursts at the worst times).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5525 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
2377c3fa54
commit
9202c3f015
5 changed files with 124 additions and 45 deletions
|
@ -2686,25 +2686,31 @@ void CL_Packet_f (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (Cmd_FromGamecode()) //some mvd servers stuffcmd a packet command which lets them know which ip the client is from.
|
if (Cmd_FromGamecode()) //some mvdsv servers stuffcmd a packet command which lets them know which ip the client is from.
|
||||||
{ //unfortunatly, 50% of servers are badly configured.
|
{ //unfortunatly, 50% of servers are badly configured resulting in them poking local services that THEY MUST NOT HAVE ACCESS TO.
|
||||||
|
char *addrdesc;
|
||||||
|
char *realdesc;
|
||||||
if (cls.demoplayback)
|
if (cls.demoplayback)
|
||||||
{
|
{
|
||||||
Con_DPrintf ("Not sending realip packet from demo\n");
|
Con_DPrintf ("Not sending realip packet from demo\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adr.type == NA_IP)
|
if (!NET_CompareAdr(&adr, &cls.netchan.remote_address))
|
||||||
if ((adr.address.ip[0] == 127 && adr.address.ip[1] == 0 && adr.address.ip[2] == 0 && adr.address.ip[3] == 1) ||
|
{
|
||||||
(adr.address.ip[0] == 0 && adr.address.ip[1] == 0 && adr.address.ip[2] == 0 && adr.address.ip[3] == 0))
|
if (NET_ClassifyAddress(&adr, &addrdesc) < ASCOPE_LAN)
|
||||||
{
|
{
|
||||||
adr.address.ip[0] = cls.netchan.remote_address.address.ip[0];
|
if (NET_ClassifyAddress(&cls.netchan.remote_address, &realdesc) < ASCOPE_LAN)
|
||||||
adr.address.ip[1] = cls.netchan.remote_address.address.ip[1];
|
{ //this isn't necessarily buggy... but its still a potential exploit so we need to block it regardless.
|
||||||
adr.address.ip[2] = cls.netchan.remote_address.address.ip[2];
|
Con_Printf (CON_WARNING "Ignoring buggy %s realip request for %s server.\n", addrdesc, realdesc);
|
||||||
adr.address.ip[3] = cls.netchan.remote_address.address.ip[3];
|
}
|
||||||
adr.port = cls.netchan.remote_address.port;
|
else
|
||||||
Con_Printf (CON_WARNING "Server is broken. Trying to send to server instead.\n");
|
{
|
||||||
|
adr = cls.netchan.remote_address;
|
||||||
|
Con_Printf (CON_WARNING "Ignoring buggy %s realip request, sending to %s server instead.\n", addrdesc, realdesc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cls.realserverip = adr;
|
cls.realserverip = adr;
|
||||||
Con_DPrintf ("Sending realip packet\n");
|
Con_DPrintf ("Sending realip packet\n");
|
||||||
|
|
|
@ -387,6 +387,16 @@ qboolean Netchan_CanPacket (netchan_t *chan, int rate)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Netchan_CanBytes (netchan_t *chan, int rate)
|
||||||
|
{
|
||||||
|
const double slop = 0.25;
|
||||||
|
if (chan->remote_address.type == NA_LOOPBACK)
|
||||||
|
return 0x7fffffff; //don't ever drop packets due to possible routing problems when there is no routing.
|
||||||
|
if (!rate)
|
||||||
|
return 0x7fffffff;
|
||||||
|
return ((realtime+slop)-chan->cleartime)*rate;
|
||||||
|
}
|
||||||
|
|
||||||
void Netchan_Block (netchan_t *chan, int bytes, int rate)
|
void Netchan_Block (netchan_t *chan, int bytes, int rate)
|
||||||
{
|
{
|
||||||
if (rate)
|
if (rate)
|
||||||
|
@ -583,6 +593,9 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
|
||||||
int i;
|
int i;
|
||||||
neterr_t e;
|
neterr_t e;
|
||||||
|
|
||||||
|
int dupes = chan->dupe;
|
||||||
|
int availbytes = Netchan_CanBytes(chan, rate);
|
||||||
|
|
||||||
#ifdef NQPROT
|
#ifdef NQPROT
|
||||||
if (chan->isnqprotocol)
|
if (chan->isnqprotocol)
|
||||||
{
|
{
|
||||||
|
@ -789,10 +802,11 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
int hsz = 10 + ((chan->sock == NS_CLIENT)?chan->qportsize:0); /*header size, if fragmentation is in use*/
|
int hsz = 10 + ((chan->sock == NS_CLIENT)?chan->qportsize:0); /*header size, if fragmentation is in use*/
|
||||||
|
dupes = min(chan->dupe, availbytes / send.cursize);
|
||||||
|
|
||||||
if ((!chan->pext_fragmentation))// || send.cursize < ((chan->mtu - hsz)&~7))
|
if ((!chan->pext_fragmentation))// || send.cursize < ((chan->mtu - hsz)&~7))
|
||||||
{ //vanilla sends
|
{ //vanilla sends
|
||||||
for (i = -1; i < chan->dupe && e == NETERR_SENT; i++)
|
for (i = -1; i < dupes && e == NETERR_SENT; i++)
|
||||||
e = NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address);
|
e = NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address);
|
||||||
send.cursize += send.cursize * i;
|
send.cursize += send.cursize * i;
|
||||||
|
|
||||||
|
@ -809,6 +823,8 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
|
||||||
{ //fte's fragmentaton protocol
|
{ //fte's fragmentaton protocol
|
||||||
int offset = 0, no;
|
int offset = 0, no;
|
||||||
qboolean more;
|
qboolean more;
|
||||||
|
int outbytes = 0;
|
||||||
|
int fragbytes;
|
||||||
|
|
||||||
/*FIXME: splurge over a number of frames, if we have an outgoing reliable*/
|
/*FIXME: splurge over a number of frames, if we have an outgoing reliable*/
|
||||||
|
|
||||||
|
@ -842,9 +858,11 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
|
||||||
|
|
||||||
if (e == NETERR_SENT)
|
if (e == NETERR_SENT)
|
||||||
{
|
{
|
||||||
for (i = -1; i < chan->dupe && e == NETERR_SENT; i++)
|
for (i = -1; i < dupes && e == NETERR_SENT; i++)
|
||||||
{
|
{
|
||||||
e = NET_SendPacket (chan->sock, (no - offset) + hsz, send.data + offset, &chan->remote_address);
|
fragbytes = (no - offset) + hsz;
|
||||||
|
e = NET_SendPacket (chan->sock, fragbytes, send.data + offset, &chan->remote_address);
|
||||||
|
outbytes += fragbytes;
|
||||||
if (e == NETERR_MTU && !offset && chan->mtu > 560)
|
if (e == NETERR_MTU && !offset && chan->mtu > 560)
|
||||||
{
|
{
|
||||||
chan->mtu -= 16;
|
chan->mtu -= 16;
|
||||||
|
@ -857,6 +875,7 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
|
||||||
}
|
}
|
||||||
offset = no;
|
offset = no;
|
||||||
} while(more);
|
} while(more);
|
||||||
|
send.cursize = outbytes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -939,8 +958,8 @@ qboolean Netchan_Process (netchan_t *chan)
|
||||||
reliable_message = sequence >> 31;
|
reliable_message = sequence >> 31;
|
||||||
reliable_ack = sequence_ack >> 31;
|
reliable_ack = sequence_ack >> 31;
|
||||||
|
|
||||||
sequence &= ~(1<<31);
|
sequence &= ~(1u<<31);
|
||||||
sequence_ack &= ~(1<<31);
|
sequence_ack &= ~(1u<<31);
|
||||||
|
|
||||||
if (showpackets.value)
|
if (showpackets.value)
|
||||||
Con_Printf ("%f %s <-- s=%i(%i) a=%i(%i) %i%s\n"
|
Con_Printf ("%f %s <-- s=%i(%i) a=%i(%i) %i%s\n"
|
||||||
|
|
|
@ -159,7 +159,7 @@ static void QDECL NET_Enable_DTLS_Changed(struct cvar_s *var, char *oldvalue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cvar_t net_enable_dtls = CVARAFCD("net_enable_dtls", "", "sv_listen_dtls", 0, NET_Enable_DTLS_Changed, "Controls serverside dtls support.\n0: dtls blocked, not advertised.\n1: available in desired.\n2: used where possible (recommended setting).\n3: disallow non-dtls clients (sv_port_tcp should be eg tls://[::]:27500 to also disallow unencrypted tcp connections).");
|
cvar_t net_enable_dtls = CVARAFCD("net_enable_dtls", "", "sv_listen_dtls", 0, NET_Enable_DTLS_Changed, "Controls serverside dtls support.\n0: dtls blocked, not advertised.\n1: clientside choice.\n2: used where possible (recommended setting).\n3: disallow non-dtls clients (sv_port_tcp should be eg tls://[::]:27500 to also disallow unencrypted tcp connections).");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_CLIENT
|
#ifdef HAVE_CLIENT
|
||||||
|
@ -372,6 +372,8 @@ qboolean NET_CompareAdr (netadr_t *a, netadr_t *b)
|
||||||
if (a->type != b->type)
|
if (a->type != b->type)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
if (a->port != b->port)
|
||||||
|
return false;
|
||||||
if (a->type == NA_IP && b->type == NA_IPV6)
|
if (a->type == NA_IP && b->type == NA_IPV6)
|
||||||
{
|
{
|
||||||
for (i = 0; i < 10; i++)
|
for (i = 0; i < 10; i++)
|
||||||
|
@ -7193,6 +7195,28 @@ int NET_EnumerateAddresses(ftenet_connections_t *collection, struct ftenet_gener
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum addressscope_e NET_ClassifyAddressipv4(int ip, char **outdesc)
|
||||||
|
{
|
||||||
|
int scope = ASCOPE_NET;
|
||||||
|
char *desc = NULL;
|
||||||
|
if ((ip&BigLong(0xffff0000)) == BigLong(0xA9FE0000)) //169.254.x.x/16
|
||||||
|
scope = ASCOPE_LINK, desc = "link-local";
|
||||||
|
else if ((ip&BigLong(0xff000000)) == BigLong(0x0a000000)) //10.x.x.x/8
|
||||||
|
scope = ASCOPE_LAN, desc = "private";
|
||||||
|
else if ((ip&BigLong(0xff000000)) == BigLong(0x7f000000)) //127.x.x.x/8
|
||||||
|
scope = ASCOPE_HOST, desc = "localhost";
|
||||||
|
else if ((ip&BigLong(0xfff00000)) == BigLong(0xac100000)) //172.16.x.x/12
|
||||||
|
scope = ASCOPE_LAN, desc = "private";
|
||||||
|
else if ((ip&BigLong(0xffff0000)) == BigLong(0xc0a80000)) //192.168.x.x/16
|
||||||
|
scope = ASCOPE_LAN, desc = "private";
|
||||||
|
else if ((ip&BigLong(0xffc00000)) == BigLong(0x64400000)) //100.64.x.x/10
|
||||||
|
scope = ASCOPE_LAN, desc = "CGNAT";
|
||||||
|
else if (ip == BigLong(0x00000000)) //0.0.0.0/32
|
||||||
|
scope = ASCOPE_LAN, desc = "any";
|
||||||
|
|
||||||
|
*outdesc = desc;
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
enum addressscope_e NET_ClassifyAddress(netadr_t *adr, char **outdesc)
|
enum addressscope_e NET_ClassifyAddress(netadr_t *adr, char **outdesc)
|
||||||
{
|
{
|
||||||
int scope = ASCOPE_NET;
|
int scope = ASCOPE_NET;
|
||||||
|
@ -7217,24 +7241,15 @@ enum addressscope_e NET_ClassifyAddress(netadr_t *adr, char **outdesc)
|
||||||
scope = ASCOPE_HOST, desc = "localhost";
|
scope = ASCOPE_HOST, desc = "localhost";
|
||||||
else if (memcmp(adr->address.ip6, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0) //::
|
else if (memcmp(adr->address.ip6, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0) //::
|
||||||
scope = ASCOPE_NET, desc = "any";
|
scope = ASCOPE_NET, desc = "any";
|
||||||
|
else if (memcmp(adr->address.ip6, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12) == 0) //::ffff:x.y.z.w
|
||||||
|
{
|
||||||
|
scope = NET_ClassifyAddressipv4(*(int*)(adr->address.ip6+12), &desc);
|
||||||
|
if (!desc)
|
||||||
|
desc = "vp-mapped";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (adr->type == NA_IP)
|
else if (adr->type == NA_IP)
|
||||||
{
|
scope = NET_ClassifyAddressipv4(*(int*)adr->address.ip, &desc);
|
||||||
if ((*(int*)adr->address.ip&BigLong(0xffff0000)) == BigLong(0xA9FE0000)) //169.254.x.x/16
|
|
||||||
scope = ASCOPE_LINK, desc = "link-local";
|
|
||||||
else if ((*(int*)adr->address.ip&BigLong(0xff000000)) == BigLong(0x0a000000)) //10.x.x.x/8
|
|
||||||
scope = ASCOPE_LAN, desc = "private";
|
|
||||||
else if ((*(int*)adr->address.ip&BigLong(0xff000000)) == BigLong(0x7f000000)) //127.x.x.x/8
|
|
||||||
scope = ASCOPE_HOST, desc = "localhost";
|
|
||||||
else if ((*(int*)adr->address.ip&BigLong(0xfff00000)) == BigLong(0xac100000)) //172.16.x.x/12
|
|
||||||
scope = ASCOPE_LAN, desc = "private";
|
|
||||||
else if ((*(int*)adr->address.ip&BigLong(0xffff0000)) == BigLong(0xc0a80000)) //192.168.x.x/16
|
|
||||||
scope = ASCOPE_LAN, desc = "private";
|
|
||||||
else if ((*(int*)adr->address.ip&BigLong(0xffc00000)) == BigLong(0x64400000)) //100.64.x.x/10
|
|
||||||
scope = ASCOPE_LAN, desc = "CGNAT";
|
|
||||||
else if (*(int*)adr->address.ip == BigLong(0x00000000)) //0.0.0.0/32
|
|
||||||
scope = ASCOPE_LAN, desc = "any";
|
|
||||||
}
|
|
||||||
if (outdesc)
|
if (outdesc)
|
||||||
*outdesc = desc;
|
*outdesc = desc;
|
||||||
return scope;
|
return scope;
|
||||||
|
|
|
@ -91,6 +91,7 @@ void R_NetGraph (void)
|
||||||
int a, x, i;
|
int a, x, i;
|
||||||
float y;
|
float y;
|
||||||
float pi, po, bi, bo;
|
float pi, po, bi, bo;
|
||||||
|
int errorbar;
|
||||||
|
|
||||||
vec2_t p[4];
|
vec2_t p[4];
|
||||||
vec2_t tc[4];
|
vec2_t tc[4];
|
||||||
|
@ -120,10 +121,10 @@ void R_NetGraph (void)
|
||||||
for (a=0 ; a<NET_TIMINGS ; a++)
|
for (a=0 ; a<NET_TIMINGS ; a++)
|
||||||
{
|
{
|
||||||
i = (cl.movesequence-a) & NET_TIMINGSMASK;
|
i = (cl.movesequence-a) & NET_TIMINGSMASK;
|
||||||
if (packet_latency[i] != 10000)
|
// if (packet_latency[i] != 10000)
|
||||||
last = packet_latency[i];
|
last = packet_latency[i];
|
||||||
else if (last >= 0)
|
// else if (last >= 0)
|
||||||
last = -last;
|
// last = -last;
|
||||||
R_LineGraph (NET_TIMINGS-1-a, last);
|
R_LineGraph (NET_TIMINGS-1-a, last);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,6 +189,7 @@ void R_NetGraph (void)
|
||||||
Vector2Set(p[3], 0,0);
|
Vector2Set(p[3], 0,0);
|
||||||
Vector4Set(rgba[2], 0,0,0,0);
|
Vector4Set(rgba[2], 0,0,0,0);
|
||||||
Vector4Set(rgba[3], 0,0,0,0);
|
Vector4Set(rgba[3], 0,0,0,0);
|
||||||
|
errorbar = 1; //first is discontinuous
|
||||||
for (a=0 ; a<NET_TIMINGS ; a++)
|
for (a=0 ; a<NET_TIMINGS ; a++)
|
||||||
{
|
{
|
||||||
Vector2Copy(p[3], p[0]); Vector4Copy(rgba[3], rgba[0]);
|
Vector2Copy(p[3], p[0]); Vector4Copy(rgba[3], rgba[0]);
|
||||||
|
@ -196,13 +198,22 @@ void R_NetGraph (void)
|
||||||
Vector2Set(p[2+0], x+a, y+(1-ngraph[a].height)*NET_GRAPHHEIGHT);
|
Vector2Set(p[2+0], x+a, y+(1-ngraph[a].height)*NET_GRAPHHEIGHT);
|
||||||
Vector2Set(p[2+1], x+a, y+NET_GRAPHHEIGHT);
|
Vector2Set(p[2+1], x+a, y+NET_GRAPHHEIGHT);
|
||||||
|
|
||||||
Vector2Set(tc[2+0], x/(float)NET_TIMINGS, (1-ngraph[a].height));
|
Vector2Set(tc[2+0], a/(float)NET_TIMINGS, (1-ngraph[a].height));
|
||||||
Vector2Set(tc[2+1], x/(float)NET_TIMINGS, 1);
|
Vector2Set(tc[2+1], a/(float)NET_TIMINGS, 1);
|
||||||
Vector4Set(rgba[2+0], ((ngraph[a].col>>0)&0xff)/255.0, ((ngraph[a].col>>8)&0xff)/255.0, ((ngraph[a].col>>16)&0xff)/255.0, ((ngraph[a].col>>24)&0xff)/255.0);
|
Vector4Set(rgba[2+0], ((ngraph[a].col>>0)&0xff)/255.0, ((ngraph[a].col>>8)&0xff)/255.0, ((ngraph[a].col>>16)&0xff)/255.0, ((ngraph[a].col>>24)&0xff)/255.0);
|
||||||
Vector4Copy(rgba[2+0], rgba[2+1]);
|
Vector4Copy(rgba[2+0], rgba[2+1]);
|
||||||
|
|
||||||
if (a)
|
if (ngraph[a].height==1)
|
||||||
R2D_Image2dQuad((const vec2_t*)p, (const vec2_t*)tc, (const vec4_t*)rgba, shader_draw_fill);
|
errorbar = 2; //this one and the following should be discontiguous
|
||||||
|
if (errorbar --> 0)
|
||||||
|
{ //if this is a full-height bar, break the smooth curve and just make it discontinuous
|
||||||
|
p[0][1] = p[3][1];
|
||||||
|
p[1][1] = p[2][1];
|
||||||
|
Vector4Copy(rgba[3], rgba[0]);
|
||||||
|
Vector4Copy(rgba[2], rgba[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
R2D_Image2dQuad((const vec2_t*)p, (const vec2_t*)tc, (const vec4_t*)rgba, shader_draw_fill);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -279,6 +279,30 @@ static qboolean JSON_Equals(json_t *t, const char *child, const char *expected)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
static quintptr_t JSON_GetUInteger(json_t *t, const char *child, unsigned int fallback)
|
||||||
|
{
|
||||||
|
if (child)
|
||||||
|
t = JSON_FindChild(t, child);
|
||||||
|
if (t)
|
||||||
|
{ //copy it to another buffer. can probably skip that tbh.
|
||||||
|
char tmp[MAX_QPATH];
|
||||||
|
char *trail;
|
||||||
|
size_t l = t->bodyend-t->bodystart;
|
||||||
|
quintptr_t r;
|
||||||
|
if (l > MAX_QPATH-1)
|
||||||
|
l = MAX_QPATH-1;
|
||||||
|
memcpy(tmp, t->bodystart, l);
|
||||||
|
tmp[l] = 0;
|
||||||
|
if (!strcmp(tmp, "false")) //special cases, for booleans
|
||||||
|
return 0u;
|
||||||
|
if (!strcmp(tmp, "true")) //special cases, for booleans
|
||||||
|
return 1u;
|
||||||
|
r = (quintptr_t)strtoull(tmp, &trail, 0);
|
||||||
|
if (!*trail)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
static qintptr_t JSON_GetInteger(json_t *t, const char *child, int fallback)
|
static qintptr_t JSON_GetInteger(json_t *t, const char *child, int fallback)
|
||||||
{
|
{
|
||||||
if (child)
|
if (child)
|
||||||
|
@ -286,7 +310,9 @@ static qintptr_t JSON_GetInteger(json_t *t, const char *child, int fallback)
|
||||||
if (t)
|
if (t)
|
||||||
{ //copy it to another buffer. can probably skip that tbh.
|
{ //copy it to another buffer. can probably skip that tbh.
|
||||||
char tmp[MAX_QPATH];
|
char tmp[MAX_QPATH];
|
||||||
|
char *trail;
|
||||||
size_t l = t->bodyend-t->bodystart;
|
size_t l = t->bodyend-t->bodystart;
|
||||||
|
qintptr_t r;
|
||||||
if (l > MAX_QPATH-1)
|
if (l > MAX_QPATH-1)
|
||||||
l = MAX_QPATH-1;
|
l = MAX_QPATH-1;
|
||||||
memcpy(tmp, t->bodystart, l);
|
memcpy(tmp, t->bodystart, l);
|
||||||
|
@ -295,7 +321,9 @@ static qintptr_t JSON_GetInteger(json_t *t, const char *child, int fallback)
|
||||||
return 0;
|
return 0;
|
||||||
if (!strcmp(tmp, "true")) //special cases, for booleans
|
if (!strcmp(tmp, "true")) //special cases, for booleans
|
||||||
return 1;
|
return 1;
|
||||||
return (qintptr_t)strtoll(tmp, NULL, 0);
|
r = (qintptr_t)strtoll(tmp, &trail, 0);
|
||||||
|
if (!*trail)
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
|
@ -588,7 +616,7 @@ static struct gltf_buffer *GLTF_GetBufferData(gltf_t *gltf, int bufferidx)
|
||||||
{
|
{
|
||||||
json_t *b = JSON_FindIndexedChild(gltf->r, "buffers", bufferidx);
|
json_t *b = JSON_FindIndexedChild(gltf->r, "buffers", bufferidx);
|
||||||
json_t *uri = JSON_FindChild(b, "uri");
|
json_t *uri = JSON_FindChild(b, "uri");
|
||||||
size_t length = JSON_GetInteger(b, "byteLength", 0);
|
size_t length = JSON_GetUInteger(b, "byteLength", 0);
|
||||||
struct gltf_buffer *out;
|
struct gltf_buffer *out;
|
||||||
|
|
||||||
// JSON_WarnIfChild(b, "name");
|
// JSON_WarnIfChild(b, "name");
|
||||||
|
@ -649,9 +677,9 @@ static qboolean GLTF_GetBufferViewData(gltf_t *gltf, int bufferview, struct gltf
|
||||||
buf = GLTF_GetBufferData(gltf, JSON_GetInteger(bv, "buffer", 0));
|
buf = GLTF_GetBufferData(gltf, JSON_GetInteger(bv, "buffer", 0));
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return false;
|
return false;
|
||||||
offset = JSON_GetInteger(bv, "byteOffset", 0);
|
offset = JSON_GetUInteger(bv, "byteOffset", 0);
|
||||||
view->data = (char*)buf->data + offset;
|
view->data = (char*)buf->data + offset;
|
||||||
view->length = JSON_GetInteger(bv, "byteLength", 0); //required
|
view->length = JSON_GetUInteger(bv, "byteLength", 0); //required
|
||||||
view->bytestride = JSON_GetInteger(bv, "byteStride", 0);
|
view->bytestride = JSON_GetInteger(bv, "byteStride", 0);
|
||||||
if (offset + view->length > buf->length)
|
if (offset + view->length > buf->length)
|
||||||
return false;
|
return false;
|
||||||
|
@ -691,7 +719,7 @@ static qboolean GLTF_GetAccessor(gltf_t *gltf, int accessorid, struct gltf_acces
|
||||||
|
|
||||||
if (!GLTF_GetBufferViewData(gltf, JSON_GetInteger(a, "bufferView", 0), &bv))
|
if (!GLTF_GetBufferViewData(gltf, JSON_GetInteger(a, "bufferView", 0), &bv))
|
||||||
return false;
|
return false;
|
||||||
offset = JSON_GetInteger(a, "byteOffset", 0);
|
offset = JSON_GetUInteger(a, "byteOffset", 0);
|
||||||
if (offset > bv.length)
|
if (offset > bv.length)
|
||||||
return false;
|
return false;
|
||||||
out->length = bv.length - offset;
|
out->length = bv.length - offset;
|
||||||
|
|
Loading…
Reference in a new issue