Merge branch 'master' into userlights

This commit is contained in:
Christoph Oelckers 2019-07-07 08:11:09 +02:00
commit 5df8919b90
37 changed files with 173 additions and 163 deletions

View file

@ -2,8 +2,8 @@
This file is part of bzip2/libbzip2, a program and library for This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression. lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010 bzip2/libbzip2 version 1.0.7 of 27 June 2019
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org> Copyright (C) 1996-2010 Julian Seward <jseward@acm.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file. README file.
@ -325,3 +325,16 @@ Security fix only. Fixes CERT-FI 20469 as it applies to bzip2.
Izdebski. Izdebski.
* Make the documentation build on Ubuntu 10.04 * Make the documentation build on Ubuntu 10.04
1.0.7 (27 Jun 19)
~~~~~~~~~~~~~~~~~
* Fix undefined behavior in the macros SET_BH, CLEAR_BH, & ISSET_BH
* bzip2: Fix return value when combining --test,-t and -q.
* bzip2recover: Fix buffer overflow for large argv[0]
* bzip2recover: Fix use after free issue with outFile (CVE-2016-3189)
* Make sure nSelectors is not out of range (CVE-2019-12900)

View file

@ -36,7 +36,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Julian Seward, jseward@bzip.org Julian Seward, jseward@acm.org
bzip2/libbzip2 version 1.0.6 of 6 September 2010 bzip2/libbzip2 version 1.0.7 of 27 June 2019
-------------------------------------------------------------------------- --------------------------------------------------------------------------

View file

@ -6,8 +6,8 @@ This version is fully compatible with the previous public releases.
This file is part of bzip2/libbzip2, a program and library for This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression. lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010 bzip2/libbzip2 version 1.0.7 of 27 June 2019
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org> Copyright (C) 1996-2010 Julian Seward <jseward@acm.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in this file. Please read the WARNING, DISCLAIMER and PATENTS sections in this file.
@ -73,7 +73,7 @@ HOW TO BUILD -- Windows 95, NT, DOS, Mac, etc.
It's difficult for me to support compilation on all these platforms. It's difficult for me to support compilation on all these platforms.
My approach is to collect binaries for these platforms, and put them My approach is to collect binaries for these platforms, and put them
on the master web site (http://www.bzip.org). Look there. However on the master web site (https://sourceware.org/bzip2/). Look there. However
(FWIW), bzip2-1.0.X is very standard ANSI C and should compile (FWIW), bzip2-1.0.X is very standard ANSI C and should compile
unmodified with MS Visual C. If you have difficulties building, you unmodified with MS Visual C. If you have difficulties building, you
might want to read README.COMPILATION.PROBLEMS. might want to read README.COMPILATION.PROBLEMS.
@ -161,43 +161,22 @@ WHAT'S NEW IN 0.9.5 ?
* Many small improvements in file and flag handling. * Many small improvements in file and flag handling.
* A Y2K statement. * A Y2K statement.
WHAT'S NEW IN 1.0.0 ? WHAT'S NEW IN 1.0.x ?
See the CHANGES file. See the CHANGES file.
WHAT'S NEW IN 1.0.2 ?
See the CHANGES file.
WHAT'S NEW IN 1.0.3 ?
See the CHANGES file.
WHAT'S NEW IN 1.0.4 ?
See the CHANGES file.
WHAT'S NEW IN 1.0.5 ?
See the CHANGES file.
WHAT'S NEW IN 1.0.6 ?
See the CHANGES file.
I hope you find bzip2 useful. Feel free to contact me at I hope you find bzip2 useful. Feel free to contact me at
jseward@bzip.org jseward@acm.org
if you have any suggestions or queries. Many people mailed me with if you have any suggestions or queries. Many people mailed me with
comments, suggestions and patches after the releases of bzip-0.15, comments, suggestions and patches after the releases of bzip-0.15,
bzip-0.21, and bzip2 versions 0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1, bzip-0.21, and bzip2 versions 0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1,
1.0.2 and 1.0.3, and the changes in bzip2 are largely a result of this 1.0.2 and 1.0.3, and the changes in bzip2 are largely a result of this
feedback. I thank you for your comments. feedback. I thank you for your comments.
bzip2's "home" is http://www.bzip.org/ bzip2's "home" is https://sourceware.org/bzip2/
Julian Seward Julian Seward
jseward@bzip.org jseward@acm.org
Cambridge, UK. Cambridge, UK.
18 July 1996 (version 0.15) 18 July 1996 (version 0.15)
@ -213,3 +192,4 @@ Cambridge, UK.
20 December 2006 (bzip2, version 1.0.4) 20 December 2006 (bzip2, version 1.0.4)
10 December 2007 (bzip2, version 1.0.5) 10 December 2007 (bzip2, version 1.0.5)
6 Sept 2010 (bzip2, version 1.0.6) 6 Sept 2010 (bzip2, version 1.0.6)
27 June 2019 (bzip2, version 1.0.7)

View file

@ -8,8 +8,8 @@
This file is part of bzip2/libbzip2, a program and library for This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression. lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010 bzip2/libbzip2 version 1.0.7 of 27 June 2019
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org> Copyright (C) 1996-2010 Julian Seward <jseward@acm.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file. README file.
@ -202,9 +202,9 @@ void fallbackQSort3 ( UInt32* fmap,
bhtab [ 0 .. 2+(nblock/32) ] destroyed bhtab [ 0 .. 2+(nblock/32) ] destroyed
*/ */
#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) #define SET_BH(zz) bhtab[(zz) >> 5] |= ((UInt32)1 << ((zz) & 31))
#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) #define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~((UInt32)1 << ((zz) & 31))
#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) #define ISSET_BH(zz) (bhtab[(zz) >> 5] & ((UInt32)1 << ((zz) & 31)))
#define WORD_BH(zz) bhtab[(zz) >> 5] #define WORD_BH(zz) bhtab[(zz) >> 5]
#define UNALIGNED_BH(zz) ((zz) & 0x01f) #define UNALIGNED_BH(zz) ((zz) & 0x01f)

View file

@ -8,8 +8,8 @@
This file is part of bzip2/libbzip2, a program and library for This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression. lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010 bzip2/libbzip2 version 1.0.7 of 27 June 2019
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org> Copyright (C) 1996-2010 Julian Seward <jseward@acm.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file. README file.
@ -43,7 +43,7 @@ void BZ2_bz__AssertH__fail ( int errcode )
fprintf(stderr, fprintf(stderr,
"\n\nbzip2/libbzip2: internal error number %d.\n" "\n\nbzip2/libbzip2: internal error number %d.\n"
"This is a bug in bzip2/libbzip2, %s.\n" "This is a bug in bzip2/libbzip2, %s.\n"
"Please report it to me at: jseward@bzip.org. If this happened\n" "Please report it to me at: jseward@acm.org. If this happened\n"
"when you were using some program which uses libbzip2 as a\n" "when you were using some program which uses libbzip2 as a\n"
"component, you should also report this bug to the author(s)\n" "component, you should also report this bug to the author(s)\n"
"of that program. Please make an effort to report this bug;\n" "of that program. Please make an effort to report this bug;\n"
@ -1234,7 +1234,7 @@ void BZ_API(BZ2_bzReadGetUnused)
BZ_SETERR(BZ_OK); BZ_SETERR(BZ_OK);
*nUnused = bzf->strm.avail_in; *nUnused = bzf->strm.avail_in;
*unused = (void **)bzf->strm.next_in; *unused = bzf->strm.next_in;
} }
#endif #endif
@ -1247,7 +1247,7 @@ void BZ_API(BZ2_bzReadGetUnused)
int BZ_API(BZ2_bzBuffToBuffCompress) int BZ_API(BZ2_bzBuffToBuffCompress)
( char* dest, ( char* dest,
unsigned int* destLen, unsigned int* destLen,
const char* source, char* source,
unsigned int sourceLen, unsigned int sourceLen,
int blockSize100k, int blockSize100k,
int verbosity, int verbosity,
@ -1299,7 +1299,7 @@ int BZ_API(BZ2_bzBuffToBuffCompress)
int BZ_API(BZ2_bzBuffToBuffDecompress) int BZ_API(BZ2_bzBuffToBuffDecompress)
( char* dest, ( char* dest,
unsigned int* destLen, unsigned int* destLen,
const char* source, char* source,
unsigned int sourceLen, unsigned int sourceLen,
int small, int small,
int verbosity ) int verbosity )

View file

@ -8,8 +8,8 @@
This file is part of bzip2/libbzip2, a program and library for This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression. lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010 bzip2/libbzip2 version 1.0.7 of 27 June 2019
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org> Copyright (C) 1996-2010 Julian Seward <jseward@acm.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file. README file.
@ -47,7 +47,7 @@ extern "C" {
typedef typedef
struct { struct {
const char *next_in; char *next_in;
unsigned int avail_in; unsigned int avail_in;
unsigned int total_in_lo32; unsigned int total_in_lo32;
unsigned int total_in_hi32; unsigned int total_in_hi32;
@ -75,8 +75,24 @@ typedef
#include <stdio.h> #include <stdio.h>
#endif #endif
#define BZ_API(func) func #ifdef _WIN32
#define BZ_EXTERN extern # include <windows.h>
# ifdef small
/* windows.h define small to char */
# undef small
# endif
# ifdef BZ_EXPORT
# define BZ_API(func) WINAPI func
# define BZ_EXTERN extern
# else
/* import windows dll dynamically */
# define BZ_API(func) (WINAPI * func)
# define BZ_EXTERN
# endif
#else
# define BZ_API(func) func
# define BZ_EXTERN extern
#endif
/*-- Core (low-level) library functions --*/ /*-- Core (low-level) library functions --*/
@ -100,7 +116,7 @@ BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) (
BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) (
bz_stream *strm, bz_stream *strm,
int verbosity, int verbosity,
int lowmem int small
); );
BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( BZ_EXTERN int BZ_API(BZ2_bzDecompress) (
@ -124,7 +140,7 @@ BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) (
int* bzerror, int* bzerror,
FILE* f, FILE* f,
int verbosity, int verbosity,
int lowmem, int small,
void* unused, void* unused,
int nUnused int nUnused
); );
@ -188,7 +204,7 @@ BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) (
BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) (
char* dest, char* dest,
unsigned int* destLen, unsigned int* destLen,
const char* source, char* source,
unsigned int sourceLen, unsigned int sourceLen,
int blockSize100k, int blockSize100k,
int verbosity, int verbosity,
@ -198,9 +214,9 @@ BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) (
BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) (
char* dest, char* dest,
unsigned int* destLen, unsigned int* destLen,
const char* source, char* source,
unsigned int sourceLen, unsigned int sourceLen,
int lowmem, int small,
int verbosity int verbosity
); );

View file

@ -8,8 +8,8 @@
This file is part of bzip2/libbzip2, a program and library for This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression. lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010 bzip2/libbzip2 version 1.0.7 of 27 June 2019
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org> Copyright (C) 1996-2010 Julian Seward <jseward@acm.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file. README file.
@ -36,7 +36,7 @@
/*-- General stuff. --*/ /*-- General stuff. --*/
#define BZ_VERSION "1.0.6, 6-Sept-2010" #define BZ_VERSION "1.0.7, 27-Jun-2019"
typedef char Char; typedef char Char;
typedef unsigned char Bool; typedef unsigned char Bool;

View file

@ -8,8 +8,8 @@
This file is part of bzip2/libbzip2, a program and library for This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression. lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010 bzip2/libbzip2 version 1.0.7 of 27 June 2019
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org> Copyright (C) 1996-2010 Julian Seward <jseward@acm.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file. README file.
@ -202,7 +202,7 @@ void generateMTFValues ( EState* s )
*ryy_j = rtmp2; *ryy_j = rtmp2;
}; };
yy[0] = rtmp; yy[0] = rtmp;
j = (Int32)(ryy_j - &(yy[0])); j = ryy_j - &(yy[0]);
mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++; mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++;
} }

View file

@ -8,8 +8,8 @@
This file is part of bzip2/libbzip2, a program and library for This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression. lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010 bzip2/libbzip2 version 1.0.7 of 27 June 2019
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org> Copyright (C) 1996-2010 Julian Seward <jseward@acm.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file. README file.

View file

@ -8,8 +8,8 @@
This file is part of bzip2/libbzip2, a program and library for This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression. lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010 bzip2/libbzip2 version 1.0.7 of 27 June 2019
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org> Copyright (C) 1996-2010 Julian Seward <jseward@acm.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file. README file.
@ -285,9 +285,9 @@ Int32 BZ2_decompress ( DState* s )
/*--- Now the selectors ---*/ /*--- Now the selectors ---*/
GET_BITS(BZ_X_SELECTOR_1, nGroups, 3); GET_BITS(BZ_X_SELECTOR_1, nGroups, 3);
if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR); if (nGroups < 2 || nGroups > BZ_N_GROUPS) RETURN(BZ_DATA_ERROR);
GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15); GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15);
if (nSelectors < 1) RETURN(BZ_DATA_ERROR); if (nSelectors < 1 || nSelectors > BZ_MAX_SELECTORS) RETURN(BZ_DATA_ERROR);
for (i = 0; i < nSelectors; i++) { for (i = 0; i < nSelectors; i++) {
j = 0; j = 0;
while (True) { while (True) {

View file

@ -8,8 +8,8 @@
This file is part of bzip2/libbzip2, a program and library for This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression. lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010 bzip2/libbzip2 version 1.0.7 of 27 June 2019
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org> Copyright (C) 1996-2010 Julian Seward <jseward@acm.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file. README file.

View file

@ -8,8 +8,8 @@
This file is part of bzip2/libbzip2, a program and library for This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression. lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010 bzip2/libbzip2 version 1.0.7 of 27 June 2019
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org> Copyright (C) 1996-2010 Julian Seward <jseward@acm.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file. README file.

View file

@ -17,19 +17,6 @@ typedef struct _GUID
} GUID; } GUID;
#endif #endif
union QWORD_UNION
{
uint64_t AsOne;
struct
{
#ifdef __BIG_ENDIAN__
unsigned int Hi, Lo;
#else
unsigned int Lo, Hi;
#endif
};
};
// //
// fixed point, 32bit as 16.16. // fixed point, 32bit as 16.16.
// //
@ -41,9 +28,6 @@ typedef int32_t fixed_t;
#define FIXED_MAX (signed)(0x7fffffff) #define FIXED_MAX (signed)(0x7fffffff)
#define FIXED_MIN (signed)(0x80000000) #define FIXED_MIN (signed)(0x80000000)
#define DWORD_MIN ((uint32_t)0)
#define DWORD_MAX ((uint32_t)0xffffffff)
// the last remnants of tables.h // the last remnants of tables.h
#define ANGLE_90 (0x40000000) #define ANGLE_90 (0x40000000)
#define ANGLE_180 (0x80000000) #define ANGLE_180 (0x80000000)

View file

@ -1400,7 +1400,7 @@ DEFINE_ACTION_FUNCTION(_CVar, GetCVar)
PARAM_PROLOGUE; PARAM_PROLOGUE;
PARAM_NAME(name); PARAM_NAME(name);
PARAM_POINTER(plyr, player_t); PARAM_POINTER(plyr, player_t);
ACTION_RETURN_POINTER(GetCVar(plyr ? plyr->mo : nullptr, name)); ACTION_RETURN_POINTER(GetCVar(plyr ? int(plyr - players) : -1, name));
} }
FBaseCVar *FindCVarSub (const char *var_name, int namelen) FBaseCVar *FindCVarSub (const char *var_name, int namelen)
@ -1425,7 +1425,7 @@ FBaseCVar *FindCVarSub (const char *var_name, int namelen)
return var; return var;
} }
FBaseCVar *GetCVar(AActor *activator, const char *cvarname) FBaseCVar *GetCVar(int playernum, const char *cvarname)
{ {
FBaseCVar *cvar = FindCVar(cvarname, nullptr); FBaseCVar *cvar = FindCVar(cvarname, nullptr);
// Either the cvar doesn't exist, or it's for a mod that isn't loaded, so return nullptr. // Either the cvar doesn't exist, or it's for a mod that isn't loaded, so return nullptr.
@ -1438,11 +1438,7 @@ FBaseCVar *GetCVar(AActor *activator, const char *cvarname)
// For userinfo cvars, redirect to GetUserCVar // For userinfo cvars, redirect to GetUserCVar
if (cvar->GetFlags() & CVAR_USERINFO) if (cvar->GetFlags() & CVAR_USERINFO)
{ {
if (activator == nullptr || activator->player == nullptr) return GetUserCVar(playernum, cvarname);
{
return nullptr;
}
return GetUserCVar(int(activator->player - players), cvarname);
} }
return cvar; return cvar;
} }

View file

@ -88,7 +88,6 @@ enum ECVarType
}; };
class FConfigFile; class FConfigFile;
class AActor;
class FxCVar; class FxCVar;
@ -190,7 +189,7 @@ FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev);
FBaseCVar *FindCVarSub (const char *var_name, int namelen); FBaseCVar *FindCVarSub (const char *var_name, int namelen);
// Used for ACS and DECORATE. // Used for ACS and DECORATE.
FBaseCVar *GetCVar(AActor *activator, const char *cvarname); FBaseCVar *GetCVar(int playernum, const char *cvarname);
FBaseCVar *GetUserCVar(int playernum, const char *cvarname); FBaseCVar *GetUserCVar(int playernum, const char *cvarname);
// Create a new cvar with the specified name and type // Create a new cvar with the specified name and type

View file

@ -491,6 +491,14 @@ void EventManager::RenderOverlay(EHudState state)
handler->RenderOverlay(state); handler->RenderOverlay(state);
} }
void EventManager::RenderUnderlay(EHudState state)
{
if (ShouldCallStatic(false)) staticEventManager.RenderUnderlay(state);
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
handler->RenderUnderlay(state);
}
bool EventManager::CheckUiProcessors() bool EventManager::CheckUiProcessors()
{ {
if (ShouldCallStatic(false)) if (ShouldCallStatic(false))
@ -960,6 +968,19 @@ void DStaticEventHandler::RenderOverlay(EHudState state)
} }
} }
void DStaticEventHandler::RenderUnderlay(EHudState state)
{
IFVIRTUAL(DStaticEventHandler, RenderUnderlay)
{
// don't create excessive DObjects if not going to be processed anyway
if (isEmpty(func)) return;
FRenderEvent e = owner->SetupRenderEvent();
e.HudState = int(state);
VMValue params[2] = { (DStaticEventHandler*)this, &e };
VMCall(func, params, 2, nullptr, 0);
}
}
void DStaticEventHandler::PlayerEntered(int num, bool fromhub) void DStaticEventHandler::PlayerEntered(int num, bool fromhub)
{ {
IFVIRTUAL(DStaticEventHandler, PlayerEntered) IFVIRTUAL(DStaticEventHandler, PlayerEntered)

View file

@ -91,6 +91,7 @@ public:
// //
void RenderFrame(); void RenderFrame();
void RenderOverlay(EHudState state); void RenderOverlay(EHudState state);
void RenderUnderlay(EHudState state);
// //
void PlayerEntered(int num, bool fromhub); void PlayerEntered(int num, bool fromhub);
@ -289,6 +290,8 @@ struct EventManager
void RenderFrame(); void RenderFrame();
// called after everything's been rendered, but before console/menus // called after everything's been rendered, but before console/menus
void RenderOverlay(EHudState state); void RenderOverlay(EHudState state);
// called after everything's been rendered, but before console/menus/huds
void RenderUnderlay(EHudState state);
// this executes when a player enters the level (once). PlayerEnter+inhub = RETURN // this executes when a player enters the level (once). PlayerEnter+inhub = RETURN
void PlayerEntered(int num, bool fromhub); void PlayerEntered(int num, bool fromhub);
// this executes when a player respawns. includes resurrect cheat. // this executes when a player respawns. includes resurrect cheat.

View file

@ -1484,7 +1484,7 @@ class CommandDrawNumber : public CommandDrawString
break; break;
case INTCVAR: case INTCVAR:
{ {
FBaseCVar *CVar = GetCVar(statusBar->CPlayer->mo, cvarName); FBaseCVar *CVar = GetCVar(int(statusBar->CPlayer - players), cvarName);
if (CVar != nullptr) if (CVar != nullptr)
{ {
ECVarType cvartype = CVar->GetRealType(); ECVarType cvartype = CVar->GetRealType();
@ -3534,7 +3534,7 @@ class CommandIfCVarInt : public SBarInfoNegatableFlowControl
SBarInfoNegatableFlowControl::Tick(block, statusBar, hudChanged); SBarInfoNegatableFlowControl::Tick(block, statusBar, hudChanged);
bool result = false; bool result = false;
cvar = GetCVar(statusBar->CPlayer->mo, cvarname); cvar = GetCVar(int(statusBar->CPlayer - players), cvarname);
if (cvar != nullptr) if (cvar != nullptr)
{ {

View file

@ -1296,6 +1296,7 @@ void DBaseStatusBar::SetMugShotState(const char *stateName, bool waitTillDone, b
void DBaseStatusBar::DrawBottomStuff (EHudState state) void DBaseStatusBar::DrawBottomStuff (EHudState state)
{ {
primaryLevel->localEventManager->RenderUnderlay(state);
DrawMessages (HUDMSGLayer_UnderHUD, (state == HUD_StatusBar) ? GetTopOfStatusbar() : SCREENHEIGHT); DrawMessages (HUDMSGLayer_UnderHUD, (state == HUD_StatusBar) ? GetTopOfStatusbar() : SCREENHEIGHT);
} }

View file

@ -54,6 +54,7 @@
#include "actor.h" #include "actor.h"
#include "p_setup.h" #include "p_setup.h"
#include "maploader/maploader.h" #include "maploader/maploader.h"
#include "types.h"
// MACROS ------------------------------------------------------------------ // MACROS ------------------------------------------------------------------
@ -365,11 +366,21 @@ void MapLoader::SetCompatibilityParams(FName checksum)
if (cls->IsDescendantOf(RUNTIME_CLASS(DLevelCompatibility))) if (cls->IsDescendantOf(RUNTIME_CLASS(DLevelCompatibility)))
{ {
PFunction *const func = dyn_cast<PFunction>(cls->FindSymbol("Apply", false)); PFunction *const func = dyn_cast<PFunction>(cls->FindSymbol("Apply", false));
if (func != nullptr) if (func == nullptr)
{ {
VMValue param[] = { lc, checksum.GetIndex(), &Level->MapName }; Printf("Missing 'Apply' method in class '%s', level compatibility object ignored\n", cls->TypeName.GetChars());
VMCall(func->Variants[0].Implementation, param, 3, nullptr, 0); continue;
} }
auto argTypes = func->Variants[0].Proto->ArgumentTypes;
if (argTypes.Size() != 3 || argTypes[1] != TypeName || argTypes[2] != TypeString)
{
Printf("Wrong signature of 'Apply' method in class '%s', level compatibility object ignored\n", cls->TypeName.GetChars());
continue;
}
VMValue param[] = { lc, checksum.GetIndex(), &Level->MapName };
VMCall(func->Variants[0].Implementation, param, 3, nullptr, 0);
} }
} }
} }

View file

@ -5788,7 +5788,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
case ACSF_GetCVarString: case ACSF_GetCVarString:
if (argCount == 1) if (argCount == 1)
{ {
return DoGetCVar(GetCVar(activator, Level->Behaviors.LookupString(args[0])), true); return DoGetCVar(GetCVar(activator && activator->player ? int(activator->player - players) : -1, Level->Behaviors.LookupString(args[0])), true);
} }
break; break;
@ -9733,7 +9733,8 @@ scriptwait:
break; break;
case PCD_GETCVAR: case PCD_GETCVAR:
STACK(1) = DoGetCVar(GetCVar(activator, Level->Behaviors.LookupString(STACK(1))), false); // This should not use Level->PlayerNum!
STACK(1) = DoGetCVar(GetCVar(activator && activator->player? int(activator->player - players) : -1, Level->Behaviors.LookupString(STACK(1))), false);
break; break;
case PCD_SETHUDSIZE: case PCD_SETHUDSIZE:

View file

@ -383,7 +383,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetCVar)
PARAM_SELF_PROLOGUE(AActor); PARAM_SELF_PROLOGUE(AActor);
PARAM_STRING(cvarname); PARAM_STRING(cvarname);
FBaseCVar *cvar = GetCVar(self, cvarname); FBaseCVar *cvar = GetCVar(self->player ? int(self->player - players) : -1, cvarname);
if (cvar == nullptr) if (cvar == nullptr)
{ {
ret->SetFloat(0); ret->SetFloat(0);
@ -413,7 +413,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetCVarString)
PARAM_SELF_PROLOGUE(AActor); PARAM_SELF_PROLOGUE(AActor);
PARAM_STRING(cvarname); PARAM_STRING(cvarname);
FBaseCVar *cvar = GetCVar(self, cvarname); FBaseCVar *cvar = GetCVar(self->player? int(self->player - players) : -1, cvarname);
if (cvar == nullptr) if (cvar == nullptr)
{ {
ret->SetString(""); ret->SetString("");

View file

@ -4262,11 +4262,12 @@ void AActor::SplashCheck()
bool AActor::UpdateWaterLevel(bool dosplash) bool AActor::UpdateWaterLevel(bool dosplash)
{ {
int oldlevel = waterlevel;
if (dosplash) SplashCheck(); if (dosplash) SplashCheck();
double fh = -FLT_MAX; double fh = -FLT_MAX;
bool reset = false; bool reset = false;
int oldlevel = waterlevel;
waterlevel = 0; waterlevel = 0;

View file

@ -111,6 +111,7 @@ static void I_DetectOS()
case 12: name = "macOS Sierra"; break; case 12: name = "macOS Sierra"; break;
case 13: name = "macOS High Sierra"; break; case 13: name = "macOS High Sierra"; break;
case 14: name = "macOS Mojave"; break; case 14: name = "macOS Mojave"; break;
case 15: name = "macOS Catalina"; break;
} }
char release[16] = "unknown"; char release[16] = "unknown";

View file

@ -158,6 +158,7 @@ void VulkanDevice::SelectPhysicalDevice()
if (queueFamily.queueCount > 0 && (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)) if (queueFamily.queueCount > 0 && (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT))
{ {
dev.graphicsFamily = i; dev.graphicsFamily = i;
dev.graphicsTimeQueries = queueFamily.timestampValidBits != 0;
break; break;
} }
} }
@ -205,6 +206,7 @@ void VulkanDevice::SelectPhysicalDevice()
PhysicalDevice = *SupportedDevices[selected].device; PhysicalDevice = *SupportedDevices[selected].device;
graphicsFamily = SupportedDevices[selected].graphicsFamily; graphicsFamily = SupportedDevices[selected].graphicsFamily;
presentFamily = SupportedDevices[selected].presentFamily; presentFamily = SupportedDevices[selected].presentFamily;
graphicsTimeQueries = SupportedDevices[selected].graphicsTimeQueries;
} }
bool VulkanDevice::SupportsDeviceExtension(const char *ext) const bool VulkanDevice::SupportsDeviceExtension(const char *ext) const

View file

@ -30,6 +30,7 @@ public:
VulkanPhysicalDevice *device = nullptr; VulkanPhysicalDevice *device = nullptr;
int graphicsFamily = -1; int graphicsFamily = -1;
int presentFamily = -1; int presentFamily = -1;
bool graphicsTimeQueries = false;
}; };
class VulkanDevice class VulkanDevice
@ -76,6 +77,7 @@ public:
int graphicsFamily = -1; int graphicsFamily = -1;
int presentFamily = -1; int presentFamily = -1;
bool graphicsTimeQueries = false;
private: private:
void CreateInstance(); void CreateInstance();

View file

@ -172,11 +172,14 @@ void VulkanFrameBuffer::InitializeState()
mRenderState.reset(new VkRenderState()); mRenderState.reset(new VkRenderState());
#endif #endif
QueryPoolBuilder querybuilder; if (device->graphicsTimeQueries)
querybuilder.setQueryType(VK_QUERY_TYPE_TIMESTAMP, MaxTimestampQueries); {
mTimestampQueryPool = querybuilder.create(device); QueryPoolBuilder querybuilder;
querybuilder.setQueryType(VK_QUERY_TYPE_TIMESTAMP, MaxTimestampQueries);
mTimestampQueryPool = querybuilder.create(device);
GetDrawCommands()->resetQueryPool(mTimestampQueryPool.get(), 0, MaxTimestampQueries); GetDrawCommands()->resetQueryPool(mTimestampQueryPool.get(), 0, MaxTimestampQueries);
}
} }
void VulkanFrameBuffer::Update() void VulkanFrameBuffer::Update()
@ -831,7 +834,7 @@ void VulkanFrameBuffer::PushGroup(const FString &name)
if (!gpuStatActive) if (!gpuStatActive)
return; return;
if (mNextTimestampQuery < VulkanFrameBuffer::MaxTimestampQueries) if (mNextTimestampQuery < VulkanFrameBuffer::MaxTimestampQueries && device->graphicsTimeQueries)
{ {
TimestampQuery q; TimestampQuery q;
q.name = name; q.name = name;
@ -851,7 +854,7 @@ void VulkanFrameBuffer::PopGroup()
TimestampQuery &q = timeElapsedQueries[mGroupStack.back()]; TimestampQuery &q = timeElapsedQueries[mGroupStack.back()];
mGroupStack.pop_back(); mGroupStack.pop_back();
if (mNextTimestampQuery < VulkanFrameBuffer::MaxTimestampQueries) if (mNextTimestampQuery < VulkanFrameBuffer::MaxTimestampQueries && device->graphicsTimeQueries)
{ {
q.endIndex = mNextTimestampQuery++; q.endIndex = mNextTimestampQuery++;
GetDrawCommands()->writeTimestamp(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, mTimestampQueryPool.get(), q.endIndex); GetDrawCommands()->writeTimestamp(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, mTimestampQueryPool.get(), q.endIndex);

View file

@ -551,7 +551,7 @@ inline void VulkanCommandBuffer::begin()
{ {
VkCommandBufferBeginInfo beginInfo = {}; VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
beginInfo.pInheritanceInfo = nullptr; beginInfo.pInheritanceInfo = nullptr;
VkResult result = vkBeginCommandBuffer(buffer, &beginInfo); VkResult result = vkBeginCommandBuffer(buffer, &beginInfo);

View file

@ -2084,7 +2084,7 @@ void S_EvictAllChannels()
{ {
if (!(chan->ChanFlags & CHAN_ABSTIME)) if (!(chan->ChanFlags & CHAN_ABSTIME))
{ {
chan->StartTime.AsOne = GSnd ? GSnd->GetPosition(chan) : 0; chan->StartTime = GSnd ? GSnd->GetPosition(chan) : 0;
chan->ChanFlags |= CHAN_ABSTIME; chan->ChanFlags |= CHAN_ABSTIME;
} }
S_StopChannel(chan); S_StopChannel(chan);
@ -2414,7 +2414,7 @@ static FSerializer &Serialize(FSerializer &arc, const char *key, FSoundChan &cha
("entchannel", chan.EntChannel) ("entchannel", chan.EntChannel)
("priority", chan.Priority) ("priority", chan.Priority)
("nearlimit", chan.NearLimit) ("nearlimit", chan.NearLimit)
("starttime", chan.StartTime.AsOne) ("starttime", chan.StartTime)
("rolloftype", chan.Rolloff.RolloffType) ("rolloftype", chan.Rolloff.RolloffType)
("rolloffmin", chan.Rolloff.MinDistance) ("rolloffmin", chan.Rolloff.MinDistance)
("rolloffmax", chan.Rolloff.MaxDistance) ("rolloffmax", chan.Rolloff.MaxDistance)
@ -2468,10 +2468,10 @@ void S_SerializeSounds(FSerializer &arc)
for (unsigned int i = chans.Size(); i-- != 0; ) for (unsigned int i = chans.Size(); i-- != 0; )
{ {
// Replace start time with sample position. // Replace start time with sample position.
uint64_t start = chans[i]->StartTime.AsOne; uint64_t start = chans[i]->StartTime;
chans[i]->StartTime.AsOne = GSnd ? GSnd->GetPosition(chans[i]) : 0; chans[i]->StartTime = GSnd ? GSnd->GetPosition(chans[i]) : 0;
arc(nullptr, *chans[i]); arc(nullptr, *chans[i]);
chans[i]->StartTime.AsOne = start; chans[i]->StartTime = start;
} }
arc.EndArray(); arc.EndArray();
} }

View file

@ -2952,7 +2952,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, SphericalCoords, SphericalCoords)
PARAM_FLOAT(viewPitch); PARAM_FLOAT(viewPitch);
PARAM_BOOL(absolute); PARAM_BOOL(absolute);
DVector3 result; DVector3 result;
SphericalCoords(self, viewpointX, viewpointY, viewpointZ, targetX, targetY, targetZ, viewYaw, viewpointZ, absolute, &result); SphericalCoords(self, viewpointX, viewpointY, viewpointZ, targetX, targetY, targetZ, viewYaw, viewPitch, absolute, &result);
ACTION_RETURN_VEC3(result); ACTION_RETURN_VEC3(result);
} }

View file

@ -401,7 +401,7 @@ static void DoParse(int lumpnum)
} }
if (state.ParseVersion > MakeVersion(VER_MAJOR, VER_MINOR, VER_REVISION)) if (state.ParseVersion > MakeVersion(VER_MAJOR, VER_MINOR, VER_REVISION))
{ {
sc.ScriptError("Version mismatch. %d.%d.%d expected but only %d.%d.%d supported", state.ParseVersion.major, state.ParseVersion.minor, state.ParseVersion.revision, VER_MAJOR, VER_MINOR, VER_REVISION); sc.ScriptError("The file you are attempting to run requires a newer version of " GAMENAME ".\n\nA version with ZScript version %d.%d.%d is required, but your copy of " GAMENAME " only supports %d.%d.%d. Please upgrade!", state.ParseVersion.major, state.ParseVersion.minor, state.ParseVersion.revision, VER_MAJOR, VER_MINOR, VER_REVISION);
} }
} }
else else

View file

@ -101,7 +101,7 @@ struct SoundHandle
struct FISoundChannel struct FISoundChannel
{ {
void *SysChannel; // Channel information from the system interface. void *SysChannel; // Channel information from the system interface.
QWORD_UNION StartTime; // Sound start time in DSP clocks. uint64_t StartTime; // Sound start time in DSP clocks.
// The sound interface doesn't use these directly but it needs to pass them to a // The sound interface doesn't use these directly but it needs to pass them to a
// callback that can't be passed a sound channel pointer // callback that can't be passed a sound channel pointer

View file

@ -1602,17 +1602,17 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int
else else
alSourcef(source, AL_PITCH, PITCH(pitch)); alSourcef(source, AL_PITCH, PITCH(pitch));
if(!reuse_chan || reuse_chan->StartTime.AsOne == 0) if(!reuse_chan || reuse_chan->StartTime == 0)
alSourcef(source, AL_SEC_OFFSET, 0.f); alSourcef(source, AL_SEC_OFFSET, 0.f);
else else
{ {
if((chanflags&SNDF_ABSTIME)) if((chanflags&SNDF_ABSTIME))
alSourcei(source, AL_SAMPLE_OFFSET, reuse_chan->StartTime.Lo); alSourcei(source, AL_SAMPLE_OFFSET, ALint(reuse_chan->StartTime));
else else
{ {
float offset = std::chrono::duration_cast<std::chrono::duration<float>>( float offset = std::chrono::duration_cast<std::chrono::duration<float>>(
std::chrono::steady_clock::now().time_since_epoch() - std::chrono::steady_clock::now().time_since_epoch() -
std::chrono::steady_clock::time_point::duration(reuse_chan->StartTime.AsOne) std::chrono::steady_clock::time_point::duration(reuse_chan->StartTime)
).count(); ).count();
if(offset > 0.f) alSourcef(source, AL_SEC_OFFSET, offset); if(offset > 0.f) alSourcef(source, AL_SEC_OFFSET, offset);
} }
@ -1813,17 +1813,17 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener
else else
alSourcef(source, AL_PITCH, PITCH(pitch)); alSourcef(source, AL_PITCH, PITCH(pitch));
if(!reuse_chan || reuse_chan->StartTime.AsOne == 0) if(!reuse_chan || reuse_chan->StartTime == 0)
alSourcef(source, AL_SEC_OFFSET, 0.f); alSourcef(source, AL_SEC_OFFSET, 0.f);
else else
{ {
if((chanflags&SNDF_ABSTIME)) if((chanflags&SNDF_ABSTIME))
alSourcei(source, AL_SAMPLE_OFFSET, reuse_chan->StartTime.Lo); alSourcei(source, AL_SAMPLE_OFFSET, ALint(reuse_chan->StartTime));
else else
{ {
float offset = std::chrono::duration_cast<std::chrono::duration<float>>( float offset = std::chrono::duration_cast<std::chrono::duration<float>>(
std::chrono::steady_clock::now().time_since_epoch() - std::chrono::steady_clock::now().time_since_epoch() -
std::chrono::steady_clock::time_point::duration(reuse_chan->StartTime.AsOne) std::chrono::steady_clock::time_point::duration(reuse_chan->StartTime)
).count(); ).count();
if(offset > 0.f) alSourcef(source, AL_SEC_OFFSET, offset); if(offset > 0.f) alSourcef(source, AL_SEC_OFFSET, offset);
} }
@ -2220,7 +2220,7 @@ void OpenALSoundRenderer::MarkStartTime(FISoundChannel *chan)
{ {
// FIXME: Get current time (preferably from the audio clock, but the system // FIXME: Get current time (preferably from the audio clock, but the system
// time will have to do) // time will have to do)
chan->StartTime.AsOne = std::chrono::steady_clock::now().time_since_epoch().count(); chan->StartTime = std::chrono::steady_clock::now().time_since_epoch().count();
} }
float OpenALSoundRenderer::GetAudibility(FISoundChannel *chan) float OpenALSoundRenderer::GetAudibility(FISoundChannel *chan)

View file

@ -221,7 +221,6 @@ protected:
void OrderAxes(); void OrderAxes();
bool ReorderAxisPair(const GUID &x, const GUID &y, int pos); bool ReorderAxisPair(const GUID &x, const GUID &y, int pos);
HRESULT SetDataFormat(); HRESULT SetDataFormat();
bool SetConfigSection(bool create);
friend class FDInputJoystickManager; friend class FDInputJoystickManager;
}; };
@ -266,8 +265,6 @@ protected:
// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static void MapAxis(FIntCVar &var, int num);
// EXTERNAL DATA DECLARATIONS ---------------------------------------------- // EXTERNAL DATA DECLARATIONS ----------------------------------------------
extern LPDIRECTINPUT8 g_pdi; extern LPDIRECTINPUT8 g_pdi;

View file

@ -650,7 +650,7 @@ bool I_InitInput (void *hwnd)
blah di8c = (blah)GetProcAddress(DInputDLL, "DirectInput8Create"); blah di8c = (blah)GetProcAddress(DInputDLL, "DirectInput8Create");
if (di8c != NULL) if (di8c != NULL)
{ {
hr = di8c(g_hInst, DIRECTINPUT_VERSION, IID_IDirectInput8A, (void **)&g_pdi, NULL); hr = di8c(g_hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&g_pdi, NULL);
if (FAILED(hr)) if (FAILED(hr))
{ {
Printf(TEXTCOLOR_ORANGE "DirectInput8Create failed: %08lx\n", hr); Printf(TEXTCOLOR_ORANGE "DirectInput8Create failed: %08lx\n", hr);
@ -676,7 +676,11 @@ bool I_InitInput (void *hwnd)
} }
typedef HRESULT (WINAPI *blah)(HINSTANCE, DWORD, LPDIRECTINPUT*, LPUNKNOWN); typedef HRESULT (WINAPI *blah)(HINSTANCE, DWORD, LPDIRECTINPUT*, LPUNKNOWN);
blah dic = (blah)GetProcAddress (DInputDLL, "DirectInputCreateA"); #ifdef UNICODE
blah dic = (blah)GetProcAddress (DInputDLL, "DirectInputCreateW");
#else
blah dic = (blah)GetProcAddress(DInputDLL, "DirectInputCreateA");
#endif
if (dic == NULL) if (dic == NULL)
{ {

View file

@ -101,40 +101,14 @@ bool UseKnownFolders()
bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create, FString &path) bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create, FString &path)
{ {
using OptWin32::SHGetKnownFolderPath; PWSTR wpath;
if (FAILED(SHGetKnownFolderPath(known_folder, create ? KF_FLAG_CREATE : 0, NULL, &wpath)))
WCHAR pathstr[MAX_PATH];
// SHGetKnownFolderPath knows about more folders than SHGetFolderPath, but is
// new to Vista, hence the reason we support both.
if (!SHGetKnownFolderPath)
{ {
if (shell_folder < 0) return false;
{ // Not supported by SHGetFolderPath
return false;
}
if (create)
{
shell_folder |= CSIDL_FLAG_CREATE;
}
if (FAILED(SHGetFolderPathW(NULL, shell_folder, NULL, 0, pathstr)))
{
return false;
}
path = pathstr;
return true;
}
else
{
PWSTR wpath;
if (FAILED(SHGetKnownFolderPath(known_folder, create ? KF_FLAG_CREATE : 0, NULL, &wpath)))
{
return false;
}
path = wpath;
CoTaskMemFree(wpath);
return true;
} }
path = wpath;
CoTaskMemFree(wpath);
return true;
} }
//=========================================================================== //===========================================================================

View file

@ -336,6 +336,7 @@ class StaticEventHandler : Object native play version("2.4")
// //
//virtual ui void RenderFrame(RenderEvent e) {} //virtual ui void RenderFrame(RenderEvent e) {}
virtual ui void RenderOverlay(RenderEvent e) {} virtual ui void RenderOverlay(RenderEvent e) {}
virtual ui void RenderUnderlay(RenderEvent e) {}
// //
virtual void PlayerEntered(PlayerEvent e) {} virtual void PlayerEntered(PlayerEvent e) {}