preliminary bidi support.

add blind+speconly penalties.
add dpi-aware flag.
fix issue when switching between singleplayer and multiplayer between maps.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4703 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2014-06-30 21:57:35 +00:00
parent 75e22d98fe
commit a704b1423b
11 changed files with 274 additions and 13 deletions

View file

@ -1299,6 +1299,12 @@ void CL_ClearState (void)
if (cl.lerpents) if (cl.lerpents)
BZ_Free(cl.lerpents); BZ_Free(cl.lerpents);
if (cl.particle_ssprecaches)
{
for (i = 0; i < MAX_SSPARTICLESPRE; i++)
if (cl.particle_ssname[i])
free(cl.particle_ssname[i]);
}
{ {
downloadlist_t *next; downloadlist_t *next;

View file

@ -1,9 +1,14 @@
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <asmv3:trustInfo>
<security> <security>
<requestedPrivileges> <requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel> <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
</requestedPrivileges> </requestedPrivileges>
</security> </security>
</trustInfo> </asmv3:trustInfo>
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly> </assembly>

View file

@ -2684,6 +2684,186 @@ static unsigned int koi2wc (unsigned char uc)
return uc; return uc;
} }
enum
{
BIDI_NEUTRAL,
BIDI_LTR,
BIDI_RTL,
};
static char *bidi_chartype;
static unsigned int bidi_charcount;
//semi-colon delimited tokens
char *COM_ParseStringSetSep (const char *data, char sep)
{
int c;
size_t len;
len = 0;
com_token[0] = 0;
if (data)
for (;*data;)
{
if (len >= sizeof(com_token)-1)
{
com_token[len] = 0;
return (char*)data;
}
c = *data++;
if (c == ';')
break;
com_token[len++] = c;
}
com_token[len] = 0;
return (char*)data;
}
void COM_BiDi_Setup(void)
{
char *file;
char *line;
char *end;
char *tok;
unsigned int c;
qofs_t size;
file = FS_MallocFile("bidi.dat", FS_ROOT, &size);
if (file)
{
bidi_chartype = file;
bidi_charcount = size;
return;
}
file = FS_MallocFile("UnicodeData.txt", FS_ROOT, NULL);
if (!file)
return;
bidi_charcount = 0xffff;
bidi_chartype = BZ_Malloc(bidi_charcount);
if (!bidi_chartype)
bidi_charcount = 0;
else
{
for (c = 0; c < bidi_charcount; c++)
bidi_chartype[c] = BIDI_NEUTRAL;
for(line = file; line; line = end)
{
end = strchr(line, '\n');
if (end)
*end++ = 0;
tok = COM_ParseStringSetSep(line,';'); //number
c = strtoul(com_token, NULL, 16);
tok = COM_ParseStringSetSep(tok,';'); //name
tok = COM_ParseStringSetSep(tok,';'); //class?
tok = COM_ParseStringSetSep(tok,';'); //?
tok = COM_ParseStringSetSep(tok,';'); //bidi
if (c < bidi_charcount)
{
if (!Q_strcasecmp(com_token, "R") || !Q_strcasecmp(com_token, "AL"))
bidi_chartype[c] = BIDI_RTL;
else if (!Q_strcasecmp(com_token, "L"))
bidi_chartype[c] = BIDI_LTR;
else
bidi_chartype[c] = BIDI_NEUTRAL;
}
}
//trim
while(bidi_charcount>0 && bidi_chartype[bidi_charcount-1] == BIDI_NEUTRAL)
bidi_charcount--;
FS_WriteFile("bidi.dat", bidi_chartype, bidi_charcount, FS_ROOT);
}
BZ_Free(file);
}
//bi-direction text is fun.
//the text is specified in input order. the first in the string is the first entered on the keyboard.
//this makes switching direction mid-line quite awkward. so lets hope you don't do that too often, mmkay?
void COM_BiDi_Parse(conchar_t *fte_restrict start, size_t length)
{
char fl[2048], next, run, prev, para = BIDI_LTR;
size_t i, runstart, j, k;
unsigned int c;
conchar_t swap;
if (!bidi_charcount || !length || length > sizeof(fl))
return;
for (i = 0; i < length; i++)
{
c = start[i] & CON_CHARMASK;
if (c >= bidi_charcount)
fl[i] = BIDI_NEUTRAL;
else
fl[i] = bidi_chartype[c];
}
//de-neutralise it
prev = fl[0];
for (i = 0; i < length; )
{
if (fl[i] == BIDI_NEUTRAL)
{
next = prev; //trailing weak chars can just use the first side
for (runstart = i; i < length; i++)
{
next = fl[i];
if (next != BIDI_NEUTRAL)
{
i--;
break;
}
}
//this can happen if the only text is neutral
if (prev == BIDI_NEUTRAL)
run = next;
//if the strong cars are the same direction on both side, we can just use that direction
else if (prev == next)
run = prev;
//if the strong chars differ, we revert to the paragraph's direction.
else
run = para;
while(runstart <= i)
fl[runstart++] = run;
i++;
}
else
{
prev = fl[i];
i++;
}
}
for (run = para, runstart = 0, i = 0; i <= length; i++)
{
if (i >= length)
next = para;
else
next = fl[i];
if (next != run)
{
if (run == BIDI_NEUTRAL)
break;
if (run == BIDI_RTL)
{ //now swap the rtl text
k = (i-runstart)/2;
for (j = 0; j < k; j++)
{
//FIXME: ( -> ) and vice versa.
swap = start[runstart+j];
start[runstart+j] = start[i-j-1];
start[i-j-1] = swap;
}
}
run = next;
runstart = i;
}
}
}
//Takes a q3-style fun string, and returns an expanded string-with-flags (actual return value is the null terminator) //Takes a q3-style fun string, and returns an expanded string-with-flags (actual return value is the null terminator)
//outsize parameter is in _BYTES_ (so sizeof is safe). //outsize parameter is in _BYTES_ (so sizeof is safe).
conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t *out, int outsize, int flags) conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t *out, int outsize, int flags)
@ -2698,6 +2878,7 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t
conchar_t *linkstart = NULL; conchar_t *linkstart = NULL;
conchar_t ext; conchar_t ext;
conchar_t *oldout = out;
if (flags & PFS_FORCEUTF8) if (flags & PFS_FORCEUTF8)
utf8 = 2; utf8 = 2;
@ -3113,6 +3294,8 @@ messedup:
} }
} }
*out = 0; *out = 0;
COM_BiDi_Parse(oldout, out - oldout);
return out; return out;
} }
@ -3272,7 +3455,7 @@ char *COM_ParseStringSet (const char *data)
com_token[len] = c; com_token[len] = c;
data++; data++;
len++; len++;
c = *data; c = *(unsigned char*)data;
} while (c>32 && c != ';'); } while (c>32 && c != ';');
com_token[len] = 0; com_token[len] = 0;
@ -4362,6 +4545,8 @@ void COM_Init (void)
TranslateInit(); TranslateInit();
COM_BiDi_Setup();
nullentitystate.hexen2flags = SCALE_ORIGIN_ORIGIN; nullentitystate.hexen2flags = SCALE_ORIGIN_ORIGIN;
nullentitystate.colormod[0] = 32; nullentitystate.colormod[0] = 32;

View file

@ -444,6 +444,7 @@ qboolean FS_Remove(const char *fname, enum fs_relative relativeto); //0 on succe
qboolean FS_Copy(const char *source, const char *dest, enum fs_relative relativesource, enum fs_relative relativedest); qboolean FS_Copy(const char *source, const char *dest, enum fs_relative relativesource, enum fs_relative relativedest);
qboolean FS_NativePath(const char *fname, enum fs_relative relativeto, char *out, int outlen); //if you really need to fopen yourself qboolean FS_NativePath(const char *fname, enum fs_relative relativeto, char *out, int outlen); //if you really need to fopen yourself
qboolean FS_WriteFile (const char *filename, const void *data, int len, enum fs_relative relativeto); qboolean FS_WriteFile (const char *filename, const void *data, int len, enum fs_relative relativeto);
void *FS_MallocFile(const char *filename, enum fs_relative relativeto, qofs_t *filesize);
vfsfile_t *FS_OpenVFS(const char *filename, const char *mode, enum fs_relative relativeto); vfsfile_t *FS_OpenVFS(const char *filename, const char *mode, enum fs_relative relativeto);
vfsfile_t *FS_OpenTemp(void); vfsfile_t *FS_OpenTemp(void);
vfsfile_t *FS_OpenTCP(const char *name, int defaultport); vfsfile_t *FS_OpenTCP(const char *name, int defaultport);

View file

@ -1482,6 +1482,29 @@ void FS_CreatePath(const char *pname, enum fs_relative relativeto)
COM_CreatePath(fullname); COM_CreatePath(fullname);
} }
void *FS_MallocFile(const char *filename, enum fs_relative relativeto, qofs_t *filesize)
{
vfsfile_t *f;
qbyte *buf;
qofs_t len;
f = FS_OpenVFS(filename, "rb", relativeto);
if (!f)
return NULL;
len = VFS_GETLEN(f);
if (filesize)
*filesize = len;
buf = (qbyte*)BZ_Malloc(len+1);
if (!buf)
Sys_Error ("FS_MallocFile: out of memory loading %s", filename);
((qbyte *)buf)[len] = 0;
VFS_READ(f, buf, len);
VFS_CLOSE(f);
return buf;
}
qboolean FS_WriteFile (const char *filename, const void *data, int len, enum fs_relative relativeto) qboolean FS_WriteFile (const char *filename, const void *data, int len, enum fs_relative relativeto)
{ {
vfsfile_t *f; vfsfile_t *f;

View file

@ -580,7 +580,10 @@ static void *Terr_GenerateWater(hmsection_t *s, float maxheight)
s->water = w; s->water = w;
#ifndef SERVERONLY #ifndef SERVERONLY
if (!isDedicated) if (!isDedicated)
{
w->shader = R_RegisterCustom (s->hmmod->defaultwatershader, SUF_NONE, Shader_DefaultWaterShader, NULL); w->shader = R_RegisterCustom (s->hmmod->defaultwatershader, SUF_NONE, Shader_DefaultWaterShader, NULL);
R_BuildDefaultTexnums(NULL, w->shader); //this might get expensive. hideously so.
}
#endif #endif
w->simple = true; w->simple = true;
w->contentmask = FTECONTENTS_WATER; w->contentmask = FTECONTENTS_WATER;

View file

@ -3015,7 +3015,7 @@ void Shader_Shutdown (void)
for (i = 0; i < r_numshaders; i++) for (i = 0; i < r_numshaders; i++)
{ {
shader = r_shaders[i]; shader = r_shaders[i];
if (!shader || !shader->uses) if (!shader)
continue; continue;
Shader_Free(shader); Shader_Free(shader);
@ -4886,6 +4886,9 @@ static shader_t *R_LoadShader (const char *name, unsigned int usageflags, shader
f = r_numshaders; f = r_numshaders;
if (f == r_maxshaders) if (f == r_maxshaders)
{ {
if (!r_maxshaders)
Sys_Error( "R_LoadShader: shader system not inited.");
nm = r_maxshaders * 2; nm = r_maxshaders * 2;
n = realloc(r_shaders, nm*sizeof(*n)); n = realloc(r_shaders, nm*sizeof(*n));
if (!n) if (!n)

View file

@ -837,7 +837,7 @@ void SV_EvaluatePenalties(client_t *cl)
if (delta & BAN_VIP) if (delta & BAN_VIP)
{ {
delta &= ~BAN_VIP; //don't refer to this as a penalty delta &= ~BAN_VIP; //don't refer to this as a penalty
if (penalties & p) if (penalties & BAN_VIP)
SV_PrintToClient(cl, PRINT_HIGH, "You are a VIP, apparently\n"); SV_PrintToClient(cl, PRINT_HIGH, "You are a VIP, apparently\n");
else else
SV_PrintToClient(cl, PRINT_HIGH, "VIP expired\n"); SV_PrintToClient(cl, PRINT_HIGH, "VIP expired\n");
@ -1068,7 +1068,7 @@ static void SV_FilterIP_f (void)
if (Cmd_Argc() < 2) if (Cmd_Argc() < 2)
{ {
Con_Printf("%s <address/mask|adress/maskbits> [flags] [+time] [reason]\n", Cmd_Argv(0)); Con_Printf("%s <address/mask|adress/maskbits> [flags] [+time] [reason]\n", Cmd_Argv(0));
Con_Printf("allowed flags: ban,safe,cuff,mute,cripple,deaf,lag. time is in seconds (omitting the plus will be taken to mean unix time).\n", Cmd_Argv(0)); Con_Printf("allowed flags: ban,safe,cuff,mute,cripple,deaf,lag,blind,spec. time is in seconds (omitting the plus will be taken to mean unix time).\n", Cmd_Argv(0));
return; return;
} }
@ -1109,6 +1109,8 @@ static void SV_FilterIP_f (void)
proto.banflags |= BAN_VIP; proto.banflags |= BAN_VIP;
else if (!Q_strcasecmp(com_token, "blind")) else if (!Q_strcasecmp(com_token, "blind"))
proto.banflags |= BAN_BLIND; proto.banflags |= BAN_BLIND;
else if (!Q_strcasecmp(com_token, "spec"))
proto.banflags |= BAN_SPECONLY;
else else
Con_Printf("Unknown ban/penalty flag: %s. ignoring.\n", com_token); Con_Printf("Unknown ban/penalty flag: %s. ignoring.\n", com_token);
} }
@ -1176,6 +1178,7 @@ static void SV_FilterList_f (void)
"lag", "lag",
"vip", "vip",
"blind", "blind",
"spec",
NULL NULL
}; };
@ -1256,12 +1259,16 @@ static void SV_Unfilter_f (void)
banflags |= BAN_LAGGED; banflags |= BAN_LAGGED;
else if (!Q_strcasecmp(com_token, "vip")) else if (!Q_strcasecmp(com_token, "vip"))
banflags |= BAN_VIP; banflags |= BAN_VIP;
else if (!Q_strcasecmp(com_token, "blind"))
banflags |= BAN_BLIND;
else if (!Q_strcasecmp(com_token, "spec"))
banflags |= BAN_SPECONLY;
else else
Con_Printf("Unknown ban/penalty flag: %s. ignoring.\n", com_token); Con_Printf("Unknown ban/penalty flag: %s. ignoring.\n", com_token);
} }
//if no flags were specified, assume all //if no flags were specified, assume all
if (!banflags) if (!banflags)
banflags = BAN_BAN|BAN_PERMIT|BAN_CUFF|BAN_MUTE|BAN_CRIPPLED|BAN_DEAF|BAN_LAGGED|BAN_VIP; banflags = BAN_BAN|BAN_PERMIT|BAN_CUFF|BAN_MUTE|BAN_CRIPPLED|BAN_DEAF|BAN_LAGGED|BAN_VIP|BAN_BLIND|BAN_SPECONLY;
for (link = &svs.bannedips ; (nb = *link) ; ) for (link = &svs.bannedips ; (nb = *link) ; )
{ {

View file

@ -599,6 +599,7 @@ void SV_UpdateMaxPlayers(int newmax)
int i; int i;
if (newmax != svs.allocated_client_slots) if (newmax != svs.allocated_client_slots)
{ {
client_t *old = svs.clients;
for (i = newmax; i < svs.allocated_client_slots; i++) for (i = newmax; i < svs.allocated_client_slots; i++)
{ {
if (svs.clients[i].state) if (svs.clients[i].state)
@ -618,6 +619,19 @@ void SV_UpdateMaxPlayers(int newmax)
svs.clients[i].name = svs.clients[i].namebuf; svs.clients[i].name = svs.clients[i].namebuf;
svs.clients[i].team = svs.clients[i].teambuf; svs.clients[i].team = svs.clients[i].teambuf;
} }
for (i = 0; i < min(newmax, svs.allocated_client_slots); i++)
{
if (svs.clients[i].netchan.message.data)
svs.clients[i].netchan.message.data = (qbyte*)&svs.clients[i] + (svs.clients[i].netchan.message.data - (qbyte*)&old[i]);
if (svs.clients[i].datagram.data)
svs.clients[i].datagram.data = (qbyte*)&svs.clients[i] + (svs.clients[i].datagram.data - (qbyte*)&old[i]);
if (svs.clients[i].backbuf.data)
svs.clients[i].backbuf.data = (qbyte*)&svs.clients[i] + (svs.clients[i].backbuf.data - (qbyte*)&old[i]);
if (svs.clients[i].controlled)
svs.clients[i].controlled = svs.clients + (svs.clients[i].controlled - old);
if (svs.clients[i].controller)
svs.clients[i].controller = svs.clients + (svs.clients[i].controller - old);
}
svs.allocated_client_slots = sv.allocated_client_slots = newmax; svs.allocated_client_slots = sv.allocated_client_slots = newmax;
} }
sv.allocated_client_slots = svs.allocated_client_slots; sv.allocated_client_slots = svs.allocated_client_slots;
@ -852,7 +866,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
if (allow_download_refpackages.ival) if (allow_download_refpackages.ival)
FS_ReferenceControl(1, 1); FS_ReferenceControl(1, 1);
strcpy (sv.name, server); Q_strncpyz (sv.name, server, sizeof(sv.name));
#ifndef SERVERONLY #ifndef SERVERONLY
current_loading_size+=10; current_loading_size+=10;
//SCR_BeginLoadingPlaque(); //SCR_BeginLoadingPlaque();
@ -900,8 +914,8 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
qboolean QDECL Mod_LoadQ2BrushModel (model_t *mod, void *buffer); qboolean QDECL Mod_LoadQ2BrushModel (model_t *mod, void *buffer);
extern model_t *loadmodel; extern model_t *loadmodel;
strcpy (sv.name, server); Q_strncpyz (sv.name, server, sizeof(sv.name));
strcpy (sv.modelname, ""); Q_strncpyz (sv.modelname, "", sizeof(sv.modelname));
loadmodel = sv.world.worldmodel = Mod_FindName (sv.modelname); loadmodel = sv.world.worldmodel = Mod_FindName (sv.modelname);
loadmodel->needload = !Mod_LoadQ2BrushModel (sv.world.worldmodel, NULL); loadmodel->needload = !Mod_LoadQ2BrushModel (sv.world.worldmodel, NULL);

View file

@ -68,8 +68,8 @@ sv_masterlist_t sv_masterlist[] = {
{MP_QUAKEWORLD, CVARC("sv_master8", "", SV_Masterlist_Callback)}, {MP_QUAKEWORLD, CVARC("sv_master8", "", SV_Masterlist_Callback)},
{MP_QUAKEWORLD, CVARC("sv_qwmasterextra1", "qwmaster.ocrana.de:27000", SV_Masterlist_Callback)}, //german. admin unknown {MP_QUAKEWORLD, CVARC("sv_qwmasterextra1", "qwmaster.ocrana.de:27000", SV_Masterlist_Callback)}, //german. admin unknown
{MP_QUAKEWORLD, CVARC("sv_qwmasterextra2", "masterserver.exhale.de:27000", SV_Masterlist_Callback)}, //german. admin unknown {MP_QUAKEWORLD, CVARC("sv_qwmasterextra2", ""/*"masterserver.exhale.de:27000" seems dead*/, SV_Masterlist_Callback)}, //german. admin unknown
{MP_QUAKEWORLD, CVARC("sv_qwmasterextra3", "asgaard.morphos-team.net:27000", SV_Masterlist_Callback)}, //german. admin bigfoot {MP_QUAKEWORLD, CVARC("sv_qwmasterextra3", "asgaard.morphos-team.net:27000", SV_Masterlist_Callback)}, //germany. admin bigfoot
{MP_QUAKEWORLD, CVARC("sv_qwmasterextra4", "master.quakeservers.net:27000", SV_Masterlist_Callback)}, //european. admin: raz0? {MP_QUAKEWORLD, CVARC("sv_qwmasterextra4", "master.quakeservers.net:27000", SV_Masterlist_Callback)}, //european. admin: raz0?
{MP_QUAKEWORLD, CVARC("sv_qwmasterextra5", "qwmaster.fodquake.net:27000", SV_Masterlist_Callback)}, {MP_QUAKEWORLD, CVARC("sv_qwmasterextra5", "qwmaster.fodquake.net:27000", SV_Masterlist_Callback)},
@ -3577,6 +3577,14 @@ client_t *SVC_DirectConnect(void)
SV_EvaluatePenalties(newcl); SV_EvaluatePenalties(newcl);
if (newcl->penalties & BAN_SPECONLY)
{
if (spectators >= maxspectators.ival)
newcl->drop = true; //oops.
newcl->spectator = spectator = true;
Info_SetValueForStarKey (cl->userinfo, "*spectator", "1", sizeof(cl->userinfo));
}
newcl->fteprotocolextensions &= ~PEXT_SPLITSCREEN; newcl->fteprotocolextensions &= ~PEXT_SPLITSCREEN;
for (clients = 1; clients < numssclients; clients++) for (clients = 1; clients < numssclients; clients++)
{ {

View file

@ -4402,6 +4402,12 @@ void Cmd_Join_f (void)
return; return;
} }
if (host_client->penalties & BAN_SPECONLY)
{
SV_ClientTPrintf(host_client, PRINT_HIGH, "You are banned from joining the game.\n");
return;
}
// count players already on server // count players already on server
numclients = 0; numclients = 0;
seats = 0; seats = 0;