mirror of
https://github.com/rehlds/rehlds.git
synced 2025-02-15 16:18:47 +03:00
Merge branch 'master' into delta_nojit
This commit is contained in:
commit
5513e70c1c
11
.gitignore
vendored
11
.gitignore
vendored
@ -2,22 +2,23 @@
|
||||
**/.gradle
|
||||
.idea
|
||||
*.iml
|
||||
*.bat
|
||||
*.log
|
||||
*.lnk
|
||||
**/msvc/Debug*
|
||||
**/msvc/Release*
|
||||
**/msvc/Tests
|
||||
**/msvc/Test Fixes
|
||||
**/msvc/.vs
|
||||
**/msvc/*.db
|
||||
**/msvc/*.opendb
|
||||
**/msvc/*.sdf
|
||||
**/msvc/*.opensdf
|
||||
**/msvc/*.user
|
||||
**/msvc/*.suo
|
||||
**/msvc/*.db
|
||||
**/msvc/*.opendb
|
||||
**/msvc/PublishPath*.txt
|
||||
**/msvc/ipch
|
||||
**/msvc/*.txt
|
||||
**/msvc/*.amplxeproj
|
||||
**/msvc/.vs
|
||||
**/msvc/ipch
|
||||
|
||||
rehlds/version/appversion.h
|
||||
rehlds/_rehldsTestImg
|
||||
|
@ -38,6 +38,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Director", "..\rehlds\HLTV\
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Proxy", "..\rehlds\HLTV\Proxy\msvc\Proxy.vcxproj", "{ADDFF069-D39D-4A1B-87C9-85A62B980547}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "filesystem_stdio", "..\rehlds\filesystem\FileSystem_Stdio\msvc\filesystem_stdio.vcxproj", "{A428392F-52FB-489E-87D8-623528C7F4F9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug Play|Win32 = Debug Play|Win32
|
||||
@ -251,6 +253,28 @@ Global
|
||||
{ADDFF069-D39D-4A1B-87C9-85A62B980547}.Test Fixes|Win32.Build.0 = Release|Win32
|
||||
{ADDFF069-D39D-4A1B-87C9-85A62B980547}.Tests|Win32.ActiveCfg = Release|Win32
|
||||
{ADDFF069-D39D-4A1B-87C9-85A62B980547}.Tests|Win32.Build.0 = Release|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Debug Play|Win32.ActiveCfg = Debug|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Debug Play|Win32.Build.0 = Debug|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Debug Record|Win32.ActiveCfg = Debug|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Debug Record|Win32.Build.0 = Debug|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Debug Swds Play|Win32.ActiveCfg = Debug|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Debug Swds Play|Win32.Build.0 = Debug|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Debug Swds|Win32.ActiveCfg = Debug|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Debug Swds|Win32.Build.0 = Debug|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Release Play|Win32.ActiveCfg = Release|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Release Play|Win32.Build.0 = Release|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Release Swds Play|Win32.ActiveCfg = Release|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Release Swds Play|Win32.Build.0 = Release|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Release Swds|Win32.ActiveCfg = Release|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Release Swds|Win32.Build.0 = Release|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Release|Win32.Build.0 = Release|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Test Fixes|Win32.ActiveCfg = Release|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Test Fixes|Win32.Build.0 = Release|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Tests|Win32.ActiveCfg = Release|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Tests|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -62,6 +62,10 @@ task publishPrepareFiles {
|
||||
_copyFile('publish/director.dll', 'publish/publishRoot/bin/win32/valve/dlls/director.dll')
|
||||
_copyFile('publish/director.so', 'publish/publishRoot/bin/linux32/valve/dlls/director.so')
|
||||
|
||||
// FileSystem binaries
|
||||
_copyFile('publish/filesystem_stdio.dll', 'publish/publishRoot/bin/win32/filesystem_stdio.dll')
|
||||
_copyFile('publish/filesystem_stdio.so', 'publish/publishRoot/bin/linux32/filesystem_stdio.so')
|
||||
|
||||
// hlsdk
|
||||
project.file('publish/publishRoot/hlsdk').mkdirs()
|
||||
copy {
|
||||
|
@ -184,11 +184,11 @@ void setupToolchain(NativeBinarySpec b) {
|
||||
}
|
||||
|
||||
if (unitTestExecutable) {
|
||||
cfg.singleDefines 'REHLDS_UNIT_TESTS', 'REHLDS_JIT'
|
||||
cfg.singleDefines 'REHLDS_UNIT_TESTS', 'REHLDS_SSE', 'REHLDS_JIT'
|
||||
}
|
||||
|
||||
if (rehldsFixes) {
|
||||
cfg.singleDefines 'REHLDS_FIXES', 'REHLDS_JIT', 'REHLDS_CHECKS', 'HAVE_OPT_STRTOOLS'
|
||||
cfg.singleDefines 'REHLDS_FIXES', 'REHLDS_SSE', 'REHLDS_JIT', 'REHLDS_CHECKS', 'HAVE_OPT_STRTOOLS'
|
||||
}
|
||||
|
||||
ToolchainConfigUtils.apply(project, cfg, b)
|
||||
|
@ -82,6 +82,30 @@ inline T clamp(T a, T min, T max)
|
||||
return (a > max) ? max : (a < min) ? min : a;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T M_min(T a, T b)
|
||||
{
|
||||
return min(a, b);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T M_max(T a, T b)
|
||||
{
|
||||
return max(a, b);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T M_clamp(T a, T min, T max)
|
||||
{
|
||||
return clamp(a, min, max);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline double M_sqrt(T value)
|
||||
{
|
||||
return sqrt(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T bswap(T s)
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -30,6 +30,17 @@
|
||||
|
||||
#include "maintypes.h"
|
||||
#include "model.h"
|
||||
#include "mathlib_sse.h"
|
||||
|
||||
#if !defined(REHLDS_FIXES) && !defined(REHLDS_SSE)
|
||||
// NOTE: In some cases we need high precision of floating-point,
|
||||
// so use double instead of float, otherwise unittest will fail
|
||||
typedef double real_t;
|
||||
#else
|
||||
typedef float real_t;
|
||||
#endif
|
||||
|
||||
typedef real_t real3_t[3];
|
||||
|
||||
enum
|
||||
{
|
||||
@ -45,63 +56,91 @@ enum
|
||||
#define vec3_origin (*pvec3_origin)
|
||||
#endif // HOOK_ENGINE
|
||||
|
||||
#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \
|
||||
(((p)->type < 3) ? \
|
||||
( \
|
||||
((p)->dist <= (emins)[(p)->type]) ? \
|
||||
1 \
|
||||
: \
|
||||
( \
|
||||
((p)->dist >= (emaxs)[(p)->type]) ? \
|
||||
2 \
|
||||
: \
|
||||
3 \
|
||||
) \
|
||||
) \
|
||||
: \
|
||||
BoxOnPlaneSide((emins), (emaxs), (p)))
|
||||
|
||||
extern vec3_t vec3_origin;
|
||||
|
||||
static const int nanmask = 0x7F800000;
|
||||
|
||||
#define IS_NAN(fvar) ((*reinterpret_cast<int*>(&(fvar)) & nanmask) == nanmask)
|
||||
|
||||
inline float M_sqrt(float value) {
|
||||
return _mm_cvtss_f32(_mm_sqrt_ss(_mm_load_ss(&value)));
|
||||
inline void VectorAdd(const vec_t *veca, const vec_t *vecb, vec_t *out)
|
||||
{
|
||||
out[0] = veca[0] + vecb[0];
|
||||
out[1] = veca[1] + vecb[1];
|
||||
out[2] = veca[2] + vecb[2];
|
||||
}
|
||||
|
||||
inline double M_sqrt(double value) {
|
||||
auto v = _mm_load_sd(&value);
|
||||
return _mm_cvtsd_f64(_mm_sqrt_sd(v, v));
|
||||
template <typename T = vec_t>
|
||||
inline void VectorSubtract(const vec_t *veca, const vec_t *vecb, T *out)
|
||||
{
|
||||
out[0] = veca[0] - vecb[0];
|
||||
out[1] = veca[1] - vecb[1];
|
||||
out[2] = veca[2] - vecb[2];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline double M_sqrt(T value) {
|
||||
return sqrt(value);
|
||||
#ifndef REHLDS_FIXES
|
||||
template <typename T = vec_t>
|
||||
inline void VectorMA(const vec_t *veca, float scale, const T *vecm, vec_t *out)
|
||||
{
|
||||
out[0] = scale * vecm[0] + veca[0];
|
||||
out[1] = scale * vecm[1] + veca[1];
|
||||
out[2] = scale * vecm[2] + veca[2];
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void VectorScale(const vec_t *in, float scale, vec_t *out)
|
||||
{
|
||||
out[0] = scale * in[0];
|
||||
out[1] = scale * in[1];
|
||||
out[2] = scale * in[2];
|
||||
}
|
||||
|
||||
inline float M_min(float a, float b) {
|
||||
return _mm_cvtss_f32(_mm_min_ss(_mm_load_ss(&a), _mm_load_ss(&b)));
|
||||
inline void VectorClear(vec_t *in)
|
||||
{
|
||||
in[0] = 0.0f;
|
||||
in[1] = 0.0f;
|
||||
in[2] = 0.0f;
|
||||
}
|
||||
|
||||
inline double M_min(double a, double b) {
|
||||
return _mm_cvtsd_f64(_mm_min_sd(_mm_load_sd(&a), _mm_load_sd(&b)));
|
||||
inline void VectorCopy(const vec_t *in, vec_t *out)
|
||||
{
|
||||
out[0] = in[0];
|
||||
out[1] = in[1];
|
||||
out[2] = in[2];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T M_min(T a, T b) {
|
||||
return min(a, b);
|
||||
inline void VectorNegate(const vec_t *in, vec_t *out)
|
||||
{
|
||||
out[0] = -in[0];
|
||||
out[1] = -in[1];
|
||||
out[2] = -in[2];
|
||||
}
|
||||
|
||||
inline float M_max(float a, float b) {
|
||||
return _mm_cvtss_f32(_mm_max_ss(_mm_load_ss(&a), _mm_load_ss(&b)));
|
||||
inline void VectorAverage(const vec_t *veca, const vec_t *vecb, vec_t *out)
|
||||
{
|
||||
out[0] = (veca[0] + vecb[0]) * 0.5f;
|
||||
out[1] = (veca[1] + vecb[1]) * 0.5f;
|
||||
out[2] = (veca[2] + vecb[2]) * 0.5f;
|
||||
}
|
||||
|
||||
inline double M_max(double a, double b) {
|
||||
return _mm_cvtsd_f64(_mm_max_sd(_mm_load_sd(&a), _mm_load_sd(&b)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T M_max(T a, T b) {
|
||||
return max(a, b);
|
||||
}
|
||||
|
||||
inline float M_clamp(float a, float min, float max) {
|
||||
return _mm_cvtss_f32(_mm_min_ss(_mm_max_ss(_mm_load_ss(&a), _mm_load_ss(&min)), _mm_load_ss(&max)));
|
||||
}
|
||||
|
||||
inline double M_clamp(double a, double min, double max) {
|
||||
return _mm_cvtsd_f64(_mm_min_sd(_mm_max_sd(_mm_load_sd(&a), _mm_load_sd(&min)), _mm_load_sd(&max)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T M_clamp(T a, T min, T max) {
|
||||
return clamp(a, min, max);
|
||||
inline bool VectorIsZero(const vec_t *in)
|
||||
{
|
||||
return (in[0] == 0.0f && in[1] == 0.0f && in[2] == 0.0f);
|
||||
}
|
||||
|
||||
float anglemod(float a);
|
||||
@ -116,14 +155,10 @@ void AngleMatrix(const vec_t *angles, float(*matrix)[4]);
|
||||
NOBODY void AngleIMatrix(const vec_t *angles, float *matrix);
|
||||
NOBODY void NormalizeAngles(float *angles);
|
||||
NOBODY void InterpolateAngles(float *start, float *end, float *output, float frac);
|
||||
void VectorTransform(const vec_t *in1, float *in2, vec_t *out);
|
||||
int VectorCompare(const vec_t *v1, const vec_t *v2);
|
||||
void VectorTransform(const vec_t *in1, float (*in2)[4], vec_t *out);
|
||||
qboolean VectorCompare(const vec_t *v1, const vec_t *v2);
|
||||
void VectorMA(const vec_t *veca, float scale, const vec_t *vecm, vec_t *out);
|
||||
#ifdef REHLDS_FIXES
|
||||
float _DotProduct(const vec_t *v1, const vec_t *v2); // with sse support
|
||||
#else // REHLDS_FIXES
|
||||
long double _DotProduct(const vec_t *v1, const vec_t *v2); // precise
|
||||
#endif // REHLDS_FIXES
|
||||
real_t _DotProduct(const vec_t *v1, const vec_t *v2);
|
||||
NOBODY void _VectorSubtract(vec_t *veca, vec_t *vecb, vec_t *out);
|
||||
void _VectorAdd(vec_t *veca, vec_t *vecb, vec_t *out);
|
||||
NOBODY void _VectorCopy(vec_t *in, vec_t *out);
|
||||
@ -132,7 +167,6 @@ float Length(const vec_t *v);
|
||||
float Length2D(const vec_t *v);
|
||||
float VectorNormalize(vec_t *v);
|
||||
NOBODY void VectorInverse(vec_t *v);
|
||||
void VectorScale(const vec_t *in, float scale, vec_t *out);
|
||||
NOBODY int Q_log2(int val);
|
||||
NOBODY void VectorMatrix(vec_t *forward, vec_t *right, vec_t *up);
|
||||
void VectorAngles(const vec_t *forward, vec_t *angles);
|
||||
|
375
rehlds/engine/mathlib_sse.cpp
Normal file
375
rehlds/engine/mathlib_sse.cpp
Normal file
@ -0,0 +1,375 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#if defined(REHLDS_SSE)
|
||||
|
||||
// Intrisics guide: https://software.intel.com/sites/landingpage/IntrinsicsGuide/
|
||||
// Shufps calculator: http://wurstcaptures.untergrund.net/assembler_tricks.html
|
||||
|
||||
// aligned vec4_t
|
||||
typedef ALIGN16 vec4_t avec4_t;
|
||||
typedef ALIGN16 unsigned int aivec4_t[4];
|
||||
|
||||
// conversion multiplier
|
||||
const avec4_t deg2rad =
|
||||
{
|
||||
(float)M_PI / 180.f,
|
||||
(float)M_PI / 180.f,
|
||||
(float)M_PI / 180.f,
|
||||
(float)M_PI / 180.f
|
||||
};
|
||||
|
||||
const aivec4_t negmask[4] =
|
||||
{
|
||||
0x80000000,
|
||||
0x80000000,
|
||||
0x80000000,
|
||||
0x80000000
|
||||
};
|
||||
|
||||
const aivec4_t negmask_1001 =
|
||||
{
|
||||
0x80000000,
|
||||
0,
|
||||
0,
|
||||
0x80000000
|
||||
};
|
||||
|
||||
const aivec4_t negmask_0010 =
|
||||
{
|
||||
0,
|
||||
0,
|
||||
0x80000000,
|
||||
0
|
||||
};
|
||||
|
||||
// save 4d xmm to 3d vector. we can't optimize many simple vector3 functions because saving back to 3d is slow.
|
||||
inline void xmm2vec(vec_t *v, const __m128 m)
|
||||
{
|
||||
_mm_storel_pi((__m64*)v, m);
|
||||
_mm_store_ss(v + 2, _mm_shuffle_ps(m, m, 0x02));
|
||||
}
|
||||
|
||||
FUNC_TARGET("sse4.1")
|
||||
inline __m128 dotProduct3D(__m128 v1, __m128 v2)
|
||||
{
|
||||
if (cpuinfo.sse4_1)
|
||||
return _mm_dp_ps(v1, v2, 0x71);
|
||||
__m128 v = _mm_mul_ps(v1, v2);
|
||||
return _mm_add_ps(_mm_movehl_ps(v, v), _mm_hadd_ps(v, v)); // SSE3
|
||||
}
|
||||
|
||||
inline __m128 crossProduct3D(__m128 a, __m128 b)
|
||||
{
|
||||
__m128 tmp1 = _mm_mul_ps(a, _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 0, 2, 1)));
|
||||
__m128 tmp2 = _mm_mul_ps(b, _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 2, 1)));
|
||||
__m128 m = _mm_sub_ps(tmp1, tmp2);
|
||||
|
||||
return _mm_shuffle_ps(m, m, _MM_SHUFFLE(3, 0, 2, 1));
|
||||
}
|
||||
|
||||
inline __m128 length3D(__m128 v)
|
||||
{
|
||||
return _mm_sqrt_ps(dotProduct3D(v, v));
|
||||
}
|
||||
|
||||
inline __m128 length2D(__m128 v)
|
||||
{
|
||||
v = _mm_mul_ps(v, v);
|
||||
return _mm_sqrt_ps(_mm_hadd_ps(v, v)); // hadd = SSE3
|
||||
}
|
||||
|
||||
int BoxOnPlaneSide(vec_t *emins, vec_t *emaxs, mplane_t *p)
|
||||
{
|
||||
double dist1, dist2;
|
||||
int sides = 0;
|
||||
|
||||
__m128 emin = _mm_loadu_ps(emins);
|
||||
__m128 emax = _mm_loadu_ps(emaxs);
|
||||
avec4_t d1, d2;
|
||||
|
||||
// general case
|
||||
switch (p->signbits)
|
||||
{
|
||||
case 0:
|
||||
_mm_store_ps(d1, emax);
|
||||
_mm_store_ps(d2, emin);
|
||||
break;
|
||||
case 1:
|
||||
_mm_store_ps(d1, emax);
|
||||
_mm_store_ps(d2, emin);
|
||||
d1[0] = emins[0];
|
||||
d2[0] = emaxs[0];
|
||||
break;
|
||||
case 2:
|
||||
_mm_store_ps(d1, emax);
|
||||
_mm_store_ps(d2, emin);
|
||||
d1[1] = emins[1];
|
||||
d2[1] = emaxs[1];
|
||||
break;
|
||||
case 3:
|
||||
_mm_store_ps(d1, emin);
|
||||
_mm_store_ps(d2, emax);
|
||||
d1[2] = emaxs[2];
|
||||
d2[2] = emins[2];
|
||||
break;
|
||||
case 4:
|
||||
_mm_store_ps(d1, emax);
|
||||
_mm_store_ps(d2, emin);
|
||||
d1[2] = emins[2];
|
||||
d2[2] = emaxs[2];
|
||||
break;
|
||||
case 5:
|
||||
_mm_store_ps(d1, emin);
|
||||
_mm_store_ps(d2, emax);
|
||||
d1[1] = emaxs[1];
|
||||
d2[1] = emins[1];
|
||||
break;
|
||||
case 6:
|
||||
_mm_store_ps(d1, emin);
|
||||
_mm_store_ps(d2, emax);
|
||||
d1[0] = emaxs[0];
|
||||
d2[0] = emins[0];
|
||||
break;
|
||||
case 7:
|
||||
_mm_store_ps(d1, emin);
|
||||
_mm_store_ps(d2, emax);
|
||||
break;
|
||||
default:
|
||||
BOPS_Error();
|
||||
dist1 = dist2 = 0.0;
|
||||
break;
|
||||
}
|
||||
|
||||
dist1 = _DotProduct(p->normal, d1);
|
||||
dist2 = _DotProduct(p->normal, d2);
|
||||
|
||||
if (dist1 >= p->dist)
|
||||
sides = 1;
|
||||
|
||||
if (dist2 < p->dist)
|
||||
sides |= 2;
|
||||
|
||||
return sides;
|
||||
}
|
||||
|
||||
qboolean VectorCompare(const vec_t *v1, const vec_t *v2)
|
||||
{
|
||||
__m128 cmp = _mm_cmpneq_ps(_mm_loadu_ps(v1), _mm_loadu_ps(v2));
|
||||
return !(_mm_movemask_ps(cmp) & (1|2|4));
|
||||
}
|
||||
|
||||
void AngleVectors(const vec_t *angles, vec_t *forward, vec_t *right, vec_t *up)
|
||||
{
|
||||
#ifndef SWDS
|
||||
g_engdstAddrs.pfnAngleVectors(&angles, &forward, &right, &up);
|
||||
#endif // SWDS
|
||||
|
||||
__m128 s, c;
|
||||
sincos_ps(_mm_mul_ps(_mm_loadu_ps(angles), _mm_load_ps(deg2rad)), &s, &c);
|
||||
|
||||
__m128 m1 = _mm_shuffle_ps(c, s, 0x90); // [cp][cp][sy][sr]
|
||||
__m128 m2 = _mm_shuffle_ps(c, c, 0x09); // [cy][cr][cp][cp]
|
||||
__m128 cp_mults = _mm_mul_ps(m1, m2); // [cp * cy][cp * cr][cp * sy][cp * sr];
|
||||
|
||||
m1 = _mm_shuffle_ps(c, s, 0x15); // [cy][cy][sy][sp]
|
||||
m2 = _mm_shuffle_ps(s, c, 0xA0); // [sp][sp][cr][cr]
|
||||
m1 = _mm_shuffle_ps(m1, m1, 0xC8); // [cy][sy][cy][sp]
|
||||
|
||||
__m128 m3 = _mm_shuffle_ps(s, s, 0x4A); // [sr][sr][sp][sy];
|
||||
m3 = _mm_mul_ps(m3, _mm_mul_ps(m1, m2)); // [sp*cy*sr][sp*sy*sr][cr*cy*sp][cr*sp*sy]
|
||||
|
||||
m2 = _mm_shuffle_ps(s, c, 0x65); // [sy][sy][cr][cy]
|
||||
m1 = _mm_shuffle_ps(c, s, 0xA6); // [cr][cy][sr][sr]
|
||||
m2 = _mm_shuffle_ps(m2, m2, 0xD8); // [sy][cr][sy][cy]
|
||||
m1 = _mm_xor_ps(m1, _mm_load_ps((float *)&negmask_1001)); // [-cr][cy][sr][-sr]
|
||||
m1 = _mm_mul_ps(m1, m2); // [-cr*sy][cy*cr][sr*sy][-sr*cy]
|
||||
|
||||
m3 = _mm_add_ps(m3, m1);
|
||||
|
||||
if (forward)
|
||||
{
|
||||
_mm_storel_pi((__m64 *)forward, _mm_shuffle_ps(cp_mults, cp_mults, 0x08));
|
||||
forward[2] = -_mm_cvtss_f32(s);
|
||||
}
|
||||
if (right)
|
||||
{
|
||||
__m128 r = _mm_shuffle_ps(m3, cp_mults, 0xF4); // [m3(0)][m3(1)][cp(3)][cp(3)]
|
||||
xmm2vec(right, _mm_xor_ps(r, _mm_load_ps((float *)&negmask)));
|
||||
}
|
||||
if (up)
|
||||
{
|
||||
_mm_storel_pi((__m64 *)up, _mm_shuffle_ps(m3, m3, 0x0E));
|
||||
up[2] = _mm_cvtss_f32(_mm_shuffle_ps(cp_mults, cp_mults, 0x01));
|
||||
}
|
||||
}
|
||||
|
||||
void AngleVectorsTranspose(const vec_t *angles, vec_t *forward, vec_t *right, vec_t *up)
|
||||
{
|
||||
__m128 s, c;
|
||||
sincos_ps(_mm_mul_ps(_mm_loadu_ps(angles), _mm_load_ps(deg2rad)), &s, &c);
|
||||
|
||||
__m128 m1 = _mm_shuffle_ps(c, s, 0x90); // [cp][cp][sy][sr]
|
||||
__m128 m2 = _mm_shuffle_ps(c, c, 0x09); // [cy][cr][cp][cp]
|
||||
__m128 cp_mults = _mm_mul_ps(m1, m2); // [cp * cy][cp * cr][cp * sy][cp * sr];
|
||||
|
||||
m1 = _mm_shuffle_ps(s, s, 0x50); // [sp][sp][sy][sy]
|
||||
m2 = _mm_shuffle_ps(c, s, 0x05); // [cy][cy][sp][sp]
|
||||
|
||||
__m128 m3 = _mm_shuffle_ps(s, c, 0xAA); // [sr][sr][cr][cr]
|
||||
m1 = _mm_mul_ps(m1, m2);
|
||||
m3 = _mm_shuffle_ps(m3, m3, 0xD8); // [sr][cr][sr][cr]
|
||||
m3 = _mm_mul_ps(m3, m1); // [sp*cy*sr][sp*cy*cr][sy*sp*sr][sy*sp*cr]
|
||||
|
||||
m2 = _mm_shuffle_ps(c, s, 0xA6); // [cr][cy][sr][sr]
|
||||
m1 = _mm_shuffle_ps(s, c, 0x65); // [sy][sy][cr][cy]
|
||||
m2 = _mm_shuffle_ps(m2, m2, 0xD8); // [cr][sr][cy][sr]
|
||||
m1 = _mm_xor_ps(m1, _mm_load_ps((float *)&negmask_1001)); // [-cr][cy][sr][-sr]
|
||||
m1 = _mm_mul_ps(m1, m2); // [-cr*sy][sr*sy][cy*cr][-sr*cy]
|
||||
|
||||
m3 = _mm_add_ps(m3, m1);
|
||||
|
||||
if (forward)
|
||||
{
|
||||
forward[0] = _mm_cvtss_f32(cp_mults);
|
||||
_mm_storel_pi((__m64*)(forward + 1), m3); // (sr*sp*cy + cr*-sy);
|
||||
}
|
||||
if (right)
|
||||
{
|
||||
right[0] = _mm_cvtss_f32(_mm_shuffle_ps(cp_mults, cp_mults, 0x02));
|
||||
_mm_storel_pi((__m64*)(right + 1), _mm_shuffle_ps(m3, m3, 0x0E));
|
||||
}
|
||||
if (up)
|
||||
{
|
||||
up[0] = -_mm_cvtss_f32(s);
|
||||
_mm_storel_pi((__m64 *)&up[1], _mm_shuffle_ps(cp_mults, cp_mults, 0x07));
|
||||
}
|
||||
}
|
||||
|
||||
void AngleMatrix(const vec_t *angles, float(*matrix)[4])
|
||||
{
|
||||
__m128 s, c;
|
||||
sincos_ps(_mm_mul_ps(_mm_loadu_ps(angles), _mm_load_ps(deg2rad)), &s, &c);
|
||||
|
||||
/*
|
||||
matrix[0][1] = sr * sp * cy - cr * sy;
|
||||
matrix[1][1] = sr * sp * sy + cr * cy;
|
||||
matrix[0][2] = cr * sp * cy + sr * sy;
|
||||
matrix[1][2] = cr * sp * sy - sr * cy;
|
||||
*/
|
||||
__m128 m1;
|
||||
__m128 m2 = _mm_shuffle_ps(s, c, 0x00); // [sp][sp][cp][cp]
|
||||
__m128 m3 = _mm_shuffle_ps(c, s, 0x55); // [cy][cy][sy][sy]
|
||||
|
||||
m1 = _mm_shuffle_ps(s, c, 0xAA); // [sr][sr][cr][cr]
|
||||
m2 = _mm_shuffle_ps(m2, m2, 0x00); // [sp][sp][sp][sp]
|
||||
m3 = _mm_shuffle_ps(m3, m3, 0xD8); // [cy][sy][cy][sy]
|
||||
|
||||
m2 = _mm_mul_ps(m2, _mm_mul_ps(m1, m3)); // m1*m2*m3
|
||||
|
||||
m1 = _mm_shuffle_ps(m1, m1, 0x1B); // [cr][cr][sr][sr]
|
||||
m3 = _mm_shuffle_ps(m3, m3, 0xB1); // [sy][cy][sy][cy]
|
||||
m3 = _mm_xor_ps(m3, _mm_load_ps((float *)&negmask_1001));
|
||||
m3 = _mm_mul_ps(m3, m1);
|
||||
|
||||
m2 = _mm_add_ps(m2, m3);
|
||||
|
||||
/*
|
||||
matrix[0][0] = cp * cy;
|
||||
matrix[1][0] = cp * sy;
|
||||
matrix[2][1] = sr * cp;
|
||||
matrix[2][2] = cr * cp;
|
||||
*/
|
||||
m1 = _mm_shuffle_ps(s, c, 0x29); // [sy][sr][cr][cp]
|
||||
c = _mm_shuffle_ps(c, c, 0x40); // [cp][cp][cp][cy]
|
||||
m1 = _mm_mul_ps(m1, c);
|
||||
|
||||
// matrix[0]
|
||||
m3 = _mm_shuffle_ps(m2, m2, 0xE1);
|
||||
_mm_storeu_ps(&matrix[0][0], m3);
|
||||
matrix[0][0] = _mm_cvtss_f32(_mm_shuffle_ps(m1, m1, 0x03));
|
||||
*(int *)&matrix[0][3] = 0;
|
||||
|
||||
// matrix[1]
|
||||
m2 = _mm_shuffle_ps(m2, m2, 0xB4);
|
||||
_mm_storeu_ps(&matrix[1][0], m2);
|
||||
matrix[1][0] = _mm_cvtss_f32(m1);
|
||||
*(int *)&matrix[1][3] = 0;
|
||||
|
||||
// matrix[2]
|
||||
_mm_storeu_ps(&matrix[2][0], m1);
|
||||
matrix[2][0] = -_mm_cvtss_f32(s);
|
||||
*(int *)&matrix[2][3] = 0;
|
||||
}
|
||||
|
||||
void VectorMA(const vec_t *veca, float scale, const vec_t *vecm, vec_t *out)
|
||||
{
|
||||
xmm2vec(out, _mm_add_ps(_mm_mul_ps(_mm_set_ps1(scale), _mm_loadu_ps(vecm)), _mm_loadu_ps(veca)));
|
||||
}
|
||||
|
||||
float _DotProduct(const vec_t *v1, const vec_t *v2)
|
||||
{
|
||||
// _mm_loadu_ps - load xmm from unaligned address
|
||||
// _mm_cvtss_f32 - return low float value of xmm
|
||||
// _mm_dp_ps - dot product
|
||||
// 0x71 = 0b01110001 - mask for multiplying operands and result
|
||||
// dpps isn't binary compatible with separate sse2 instructions (max difference is about 0.0002f, but usually < 0.00001f)
|
||||
|
||||
return _mm_cvtss_f32(dotProduct3D(_mm_loadu_ps(v1), _mm_loadu_ps(v2)));
|
||||
}
|
||||
|
||||
float Length(const vec_t *v)
|
||||
{
|
||||
return _mm_cvtss_f32(length3D(_mm_loadu_ps(v))); // rsqrt is very inaccurate :(
|
||||
}
|
||||
|
||||
float Length2D(const vec_t *v)
|
||||
{
|
||||
return _mm_cvtss_f32(length2D(_mm_loadu_ps(v)));
|
||||
}
|
||||
|
||||
void CrossProduct(const vec_t *v1, const vec_t *v2, vec_t *cross)
|
||||
{
|
||||
xmm2vec(cross, crossProduct3D(_mm_loadu_ps(v1), _mm_loadu_ps(v2)));
|
||||
}
|
||||
|
||||
void R_ConcatTransforms(float in1[3][4], float in2[3][4], float out[3][4])
|
||||
{
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
{
|
||||
__m128 a1 = _mm_mul_ps(_mm_set_ps1(in1[i][0]), _mm_loadu_ps(in2[0]));
|
||||
__m128 a2 = _mm_mul_ps(_mm_set_ps1(in1[i][1]), _mm_loadu_ps(in2[1]));
|
||||
__m128 a3 = _mm_mul_ps(_mm_set_ps1(in1[i][2]), _mm_loadu_ps(in2[2]));
|
||||
_mm_storeu_ps(out[i], _mm_add_ps(a1, _mm_add_ps(a2, a3)));
|
||||
out[i][3] += in1[i][3];
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #if defined(REHLDS_SSE)
|
74
rehlds/engine/mathlib_sse.h
Normal file
74
rehlds/engine/mathlib_sse.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(REHLDS_SSE)
|
||||
|
||||
inline float M_min(float a, float b)
|
||||
{
|
||||
return _mm_cvtss_f32(_mm_min_ss(_mm_load_ss(&a), _mm_load_ss(&b)));
|
||||
}
|
||||
|
||||
inline double M_min(double a, double b)
|
||||
{
|
||||
return _mm_cvtsd_f64(_mm_min_sd(_mm_load_sd(&a), _mm_load_sd(&b)));
|
||||
}
|
||||
|
||||
inline float M_max(float a, float b)
|
||||
{
|
||||
return _mm_cvtss_f32(_mm_max_ss(_mm_load_ss(&a), _mm_load_ss(&b)));
|
||||
}
|
||||
|
||||
inline double M_max(double a, double b)
|
||||
{
|
||||
return _mm_cvtsd_f64(_mm_max_sd(_mm_load_sd(&a), _mm_load_sd(&b)));
|
||||
}
|
||||
|
||||
inline float M_sqrt(float value)
|
||||
{
|
||||
return _mm_cvtss_f32(_mm_sqrt_ss(_mm_load_ss(&value)));
|
||||
}
|
||||
|
||||
inline double M_sqrt(double value)
|
||||
{
|
||||
auto v = _mm_load_sd(&value);
|
||||
return _mm_cvtsd_f64(_mm_sqrt_sd(v, v));
|
||||
}
|
||||
|
||||
inline float M_clamp(float a, float min, float max)
|
||||
{
|
||||
return _mm_cvtss_f32(_mm_min_ss(_mm_max_ss(_mm_load_ss(&a), _mm_load_ss(&min)), _mm_load_ss(&max)));
|
||||
}
|
||||
|
||||
inline double M_clamp(double a, double min, double max)
|
||||
{
|
||||
return _mm_cvtsd_f64(_mm_min_sd(_mm_max_sd(_mm_load_sd(&a), _mm_load_sd(&min)), _mm_load_sd(&max)));
|
||||
}
|
||||
|
||||
#endif // #if defined(REHLDS_SSE)
|
@ -54,6 +54,17 @@ const char S2C_CONNECTION = 'B';
|
||||
// HLMaster rejected a server's connection because the server needs to be updated
|
||||
const char M2S_REQUESTRESTART = 'O';
|
||||
|
||||
// Response details about each player on the server
|
||||
const char S2A_PLAYERS = 'D';
|
||||
|
||||
// Response as multi-packeted the rules the server is using
|
||||
const char S2A_RULES = 'E';
|
||||
|
||||
// info request
|
||||
const char S2A_INFO = 'C'; // deprecated goldsrc response
|
||||
|
||||
const char S2A_INFO_DETAILED = 'm'; // New Query protocol, returns dedicated or not, + other performance info.
|
||||
|
||||
// send a log event as key value
|
||||
const char S2A_LOGSTRING = 'R';
|
||||
|
||||
@ -78,6 +89,9 @@ const char A2A_PING = 'i'; // respond with an A2A_ACK
|
||||
// Generic Ack
|
||||
const char A2A_ACK = 'j'; // general acknowledgement without info
|
||||
|
||||
// Print to client console
|
||||
const char A2A_PRINT = 'l'; // print a message on client
|
||||
|
||||
// Challenge response from master
|
||||
const char M2A_CHALLENGE = 's'; // + challenge value
|
||||
|
||||
|
@ -29,7 +29,11 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
HANDLE hThread;
|
||||
DWORD ThreadId;
|
||||
CRITICAL_SECTION net_cs;
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
qboolean net_thread_initialized;
|
||||
@ -46,8 +50,7 @@ netadr_t net_from;
|
||||
sizebuf_t net_message;
|
||||
qboolean noip;
|
||||
qboolean noipx;
|
||||
|
||||
int use_thread;
|
||||
qboolean use_thread;
|
||||
|
||||
unsigned char net_message_buffer[NET_MAX_PAYLOAD];
|
||||
unsigned char in_message_buf[NET_MAX_PAYLOAD];
|
||||
@ -141,7 +144,7 @@ cvar_t net_graphpos;
|
||||
|
||||
#endif // HOOK_ENGINE
|
||||
|
||||
void NET_ThreadLock(void)
|
||||
void NET_ThreadLock()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (use_thread && net_thread_initialized)
|
||||
@ -151,7 +154,7 @@ void NET_ThreadLock(void)
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
void NET_ThreadUnlock(void)
|
||||
void NET_ThreadUnlock()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (use_thread && net_thread_initialized)
|
||||
@ -212,7 +215,7 @@ void SockadrToNetadr(const struct sockaddr *s, netadr_t *a)
|
||||
else if (s->sa_family == AF_IPX)
|
||||
{
|
||||
a->type = NA_IPX;
|
||||
Q_memcpy(a->ipx, s->sa_data, 10);
|
||||
Q_memcpy(a->ipx, s->sa_data, sizeof(a->ipx));
|
||||
a->port = *(unsigned short *)&s->sa_data[10];
|
||||
}
|
||||
#endif // _WIN32
|
||||
@ -727,7 +730,7 @@ void NET_AddToLagged(netsrc_t sock, packetlag_t *pList, packetlag_t *pPacket, ne
|
||||
Q_memcpy(&pPacket->net_from_, net_from_, sizeof(netadr_t));
|
||||
}
|
||||
|
||||
void NET_AdjustLag(void)
|
||||
void NET_AdjustLag()
|
||||
{
|
||||
static double lasttime = realtime;
|
||||
double dt;
|
||||
@ -814,9 +817,11 @@ qboolean NET_LagPacket(qboolean newdata, netsrc_t sock, netadr_t *from, sizebuf_
|
||||
Cvar_SetValue("fakeloss", 0.0);
|
||||
}
|
||||
}
|
||||
pNewPacketLag = (packetlag_t *)Mem_ZeroMalloc(0x28u);
|
||||
|
||||
pNewPacketLag = (packetlag_t *)Mem_ZeroMalloc(sizeof(packetlag_t));
|
||||
NET_AddToLagged(sock, &g_pLagData[sock], pNewPacketLag, from, *data, curtime);
|
||||
}
|
||||
|
||||
pPacket = g_pLagData[sock].pNext;
|
||||
|
||||
while (pPacket != &g_pLagData[sock])
|
||||
@ -826,6 +831,7 @@ qboolean NET_LagPacket(qboolean newdata, netsrc_t sock, netadr_t *from, sizebuf_
|
||||
|
||||
pPacket = pPacket->pNext;
|
||||
}
|
||||
|
||||
if (pPacket == &g_pLagData[sock])
|
||||
return FALSE;
|
||||
|
||||
@ -1055,7 +1061,7 @@ qboolean NET_QueuePacket(netsrc_t sock)
|
||||
return NET_GetLong(in_message.data, ret, &in_message.cursize);
|
||||
}
|
||||
|
||||
DLL_EXPORT int NET_Sleep_Timeout(void)
|
||||
DLL_EXPORT int NET_Sleep_Timeout()
|
||||
{
|
||||
static int32 lasttime;
|
||||
static int numFrames;
|
||||
@ -1123,7 +1129,7 @@ DLL_EXPORT int NET_Sleep_Timeout(void)
|
||||
return res;
|
||||
}
|
||||
|
||||
int NET_Sleep(void)
|
||||
int NET_Sleep()
|
||||
{
|
||||
fd_set fdset;
|
||||
struct timeval tv;
|
||||
@ -1161,45 +1167,92 @@ int NET_Sleep(void)
|
||||
return select((int)(number + 1), &fdset, NULL, NULL, net_sleepforever == 0 ? &tv : NULL);
|
||||
}
|
||||
|
||||
void NET_StartThread(void)
|
||||
#ifdef _WIN32
|
||||
|
||||
DWORD WINAPI NET_ThreadMain(LPVOID lpThreadParameter)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
while (NET_Sleep())
|
||||
{
|
||||
qboolean bret = FALSE;
|
||||
for (int sock = 0; sock < NS_MAX; sock++)
|
||||
{
|
||||
NET_ThreadLock();
|
||||
|
||||
bret = NET_QueuePacket((netsrc_t)sock);
|
||||
if (bret)
|
||||
{
|
||||
net_messages_t *pmsg = NET_AllocMsg(in_message.cursize);
|
||||
pmsg->next = nullptr;
|
||||
Q_memcpy(pmsg->buffer, in_message.data, in_message.cursize);
|
||||
Q_memcpy(&pmsg->from, &in_from, sizeof(pmsg->from));
|
||||
|
||||
// add to tail of the list
|
||||
net_messages_t *p = messages[sock];
|
||||
if (p)
|
||||
{
|
||||
while (p->next)
|
||||
p = p->next;
|
||||
|
||||
p->next = pmsg;
|
||||
}
|
||||
// add to head
|
||||
else
|
||||
{
|
||||
messages[sock] = pmsg;
|
||||
}
|
||||
}
|
||||
|
||||
NET_ThreadUnlock();
|
||||
}
|
||||
|
||||
if (!bret)
|
||||
break;
|
||||
}
|
||||
|
||||
Sys_Sleep(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
void NET_StartThread()
|
||||
{
|
||||
if (use_thread)
|
||||
{
|
||||
if (!net_thread_initialized)
|
||||
{
|
||||
net_thread_initialized = TRUE;
|
||||
Sys_Error("%s: -netthread is not reversed yet", __func__);
|
||||
|
||||
#ifdef _WIN32
|
||||
/*
|
||||
InitializeCriticalSection(&net_cs);
|
||||
hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)NET_ThreadMain, 0, 0, &ThreadId);
|
||||
hThread = CreateThread(0, 0, NET_ThreadMain, 0, 0, &ThreadId);
|
||||
if (!hThread)
|
||||
{
|
||||
DeleteCriticalSection(&net_cs);
|
||||
net_thread_initialized = 0;
|
||||
use_thread = 0;
|
||||
net_thread_initialized = FALSE;
|
||||
use_thread = FALSE;
|
||||
Sys_Error("%s: Couldn't initialize network thread, run without -netthread\n", __func__);
|
||||
}
|
||||
*/
|
||||
#endif // _WIN32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NET_StopThread(void)
|
||||
void NET_StopThread()
|
||||
{
|
||||
if (use_thread)
|
||||
{
|
||||
if (net_thread_initialized)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
/*
|
||||
TerminateThread(hThread, 0);
|
||||
DeleteCriticalSection(&net_cs);
|
||||
*/
|
||||
#endif // _WIN32
|
||||
net_thread_initialized = FALSE;
|
||||
Sys_Error("%s: -netthread is not reversed yet", __func__);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1214,9 +1267,9 @@ net_messages_t *NET_AllocMsg(int size)
|
||||
net_messages_t *pmsg;
|
||||
if (size <= MSG_QUEUE_SIZE && normalqueue)
|
||||
{
|
||||
pmsg = normalqueue->next;
|
||||
normalqueue->buffersize = size;
|
||||
normalqueue = pmsg;
|
||||
pmsg = normalqueue;
|
||||
pmsg->buffersize = size;
|
||||
normalqueue = pmsg->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1273,7 +1326,7 @@ qboolean NET_GetPacket(netsrc_t sock)
|
||||
{
|
||||
Q_memcpy(net_message.data, in_message.data, in_message.cursize);
|
||||
net_message.cursize = in_message.cursize;
|
||||
Q_memcpy(&net_from, &in_from, 0x14u);
|
||||
Q_memcpy(&net_from, &in_from, sizeof(netadr_t));
|
||||
NET_ThreadUnlock();
|
||||
return bret;
|
||||
}
|
||||
@ -1287,20 +1340,20 @@ qboolean NET_GetPacket(netsrc_t sock)
|
||||
net_from = pmsg->from;
|
||||
msg_readcount = 0;
|
||||
NET_FreeMsg(pmsg);
|
||||
bret = 1;
|
||||
bret = TRUE;
|
||||
}
|
||||
NET_ThreadUnlock();
|
||||
return bret;
|
||||
}
|
||||
|
||||
void NET_AllocateQueues(void)
|
||||
void NET_AllocateQueues()
|
||||
{
|
||||
net_messages_t *p;
|
||||
for (int i = 0; i < NUM_MSG_QUEUES; i++)
|
||||
{
|
||||
p = (net_messages_t *)Mem_ZeroMalloc(sizeof(net_messages_t));
|
||||
p->buffer = (unsigned char *)Mem_ZeroMalloc(MSG_QUEUE_SIZE);
|
||||
p->preallocated = 1;
|
||||
p->preallocated = TRUE;
|
||||
p->next = normalqueue;
|
||||
normalqueue = p;
|
||||
}
|
||||
@ -1308,8 +1361,10 @@ void NET_AllocateQueues(void)
|
||||
NET_StartThread();
|
||||
}
|
||||
|
||||
void NET_FlushQueues(void)
|
||||
void NET_FlushQueues()
|
||||
{
|
||||
NET_StopThread();
|
||||
|
||||
for (int i = 0; i < NS_MAX; i++)
|
||||
{
|
||||
net_messages_t *p = messages[i];
|
||||
@ -1612,7 +1667,7 @@ SOCKET NET_IPSocket(char *net_interface, int port, qboolean multicast)
|
||||
return newsocket;
|
||||
}
|
||||
|
||||
void NET_OpenIP(void)
|
||||
void NET_OpenIP()
|
||||
{
|
||||
//cvar_t *ip;//unused?
|
||||
int port;
|
||||
@ -1744,7 +1799,7 @@ SOCKET NET_IPXSocket(int hostshort)
|
||||
return newsocket;
|
||||
}
|
||||
|
||||
void NET_OpenIPX(void)
|
||||
void NET_OpenIPX()
|
||||
{
|
||||
int port;
|
||||
int dedicated;
|
||||
@ -1795,7 +1850,7 @@ void NET_OpenIPX(void)
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
void NET_GetLocalAddress(void)
|
||||
void NET_GetLocalAddress()
|
||||
{
|
||||
char buff[512];
|
||||
struct sockaddr_in address;
|
||||
@ -1888,7 +1943,7 @@ void NET_GetLocalAddress(void)
|
||||
#endif //_WIN32
|
||||
}
|
||||
|
||||
int NET_IsConfigured(void)
|
||||
int NET_IsConfigured()
|
||||
{
|
||||
return net_configured;
|
||||
}
|
||||
@ -1950,7 +2005,7 @@ void NET_Config(qboolean multiplayer)
|
||||
net_configured = multiplayer ? 1 : 0;
|
||||
}
|
||||
|
||||
void MaxPlayers_f(void)
|
||||
void MaxPlayers_f()
|
||||
{
|
||||
if (Cmd_Argc() != 2)
|
||||
{
|
||||
@ -1983,7 +2038,7 @@ void MaxPlayers_f(void)
|
||||
Cvar_Set("deathmatch", "1");
|
||||
}
|
||||
|
||||
void NET_Init(void)
|
||||
void NET_Init()
|
||||
{
|
||||
#ifdef HOOK_ENGINE
|
||||
Cmd_AddCommand("maxplayers", (xcommand_t)GetOriginalFuncAddrOrDefault("MaxPlayers_f", (void *)MaxPlayers_f));
|
||||
@ -2012,10 +2067,8 @@ void NET_Init(void)
|
||||
Cvar_RegisterVariable(&net_graphpos);
|
||||
|
||||
if (COM_CheckParm("-netthread"))
|
||||
{
|
||||
use_thread = 1;
|
||||
Sys_Error("%s: -netthread is not reversed yet", __func__);
|
||||
}
|
||||
use_thread = TRUE;
|
||||
|
||||
if (COM_CheckParm("-netsleep"))
|
||||
net_sleepforever = 0;
|
||||
|
||||
@ -2073,7 +2126,7 @@ void NET_ClearLagData(qboolean bClient, qboolean bServer)
|
||||
NET_ThreadUnlock();
|
||||
}
|
||||
|
||||
void NET_Shutdown(void)
|
||||
void NET_Shutdown()
|
||||
{
|
||||
NET_ThreadLock();
|
||||
|
||||
|
@ -187,7 +187,7 @@ extern qboolean noipx;
|
||||
#endif // _WIN32
|
||||
extern sizebuf_t net_message;
|
||||
extern cvar_t clockwindow;
|
||||
extern int use_thread;
|
||||
extern qboolean use_thread;
|
||||
extern cvar_t iphostport;
|
||||
extern cvar_t hostport;
|
||||
#ifdef _WIN32
|
||||
@ -214,8 +214,8 @@ extern net_messages_t *messages[3];
|
||||
extern net_messages_t *normalqueue;
|
||||
|
||||
|
||||
void NET_ThreadLock(void);
|
||||
void NET_ThreadUnlock(void);
|
||||
void NET_ThreadLock();
|
||||
void NET_ThreadUnlock();
|
||||
unsigned short Q_ntohs(unsigned short netshort);
|
||||
void NetadrToSockadr(const netadr_t *a, struct sockaddr *s);
|
||||
void SockadrToNetadr(const struct sockaddr *s, netadr_t *a);
|
||||
@ -237,33 +237,33 @@ void NET_RemoveFromPacketList(packetlag_t *pPacket);
|
||||
NOXREF int NET_CountLaggedList(packetlag_t *pList);
|
||||
void NET_ClearLaggedList(packetlag_t *pList);
|
||||
void NET_AddToLagged(netsrc_t sock, packetlag_t *pList, packetlag_t *pPacket, netadr_t *net_from_, sizebuf_t messagedata, float timestamp);
|
||||
void NET_AdjustLag(void);
|
||||
void NET_AdjustLag();
|
||||
qboolean NET_LagPacket(qboolean newdata, netsrc_t sock, netadr_t *from, sizebuf_t *data);
|
||||
void NET_FlushSocket(netsrc_t sock);
|
||||
qboolean NET_GetLong(unsigned char *pData, int size, int *outSize);
|
||||
qboolean NET_QueuePacket(netsrc_t sock);
|
||||
int NET_Sleep(void);
|
||||
void NET_StartThread(void);
|
||||
void NET_StopThread(void);
|
||||
int NET_Sleep();
|
||||
void NET_StartThread();
|
||||
void NET_StopThread();
|
||||
void *net_malloc(size_t size);
|
||||
net_messages_t *NET_AllocMsg(int size);
|
||||
void NET_FreeMsg(net_messages_t *pmsg);
|
||||
qboolean NET_GetPacket(netsrc_t sock);
|
||||
void NET_AllocateQueues(void);
|
||||
void NET_FlushQueues(void);
|
||||
void NET_AllocateQueues();
|
||||
void NET_FlushQueues();
|
||||
int NET_SendLong(netsrc_t sock, SOCKET s, const char *buf, int len, int flags, const struct sockaddr *to, int tolen);
|
||||
void NET_SendPacket_api(unsigned int length, void *data, const netadr_t &to);
|
||||
void NET_SendPacket(netsrc_t sock, int length, void *data, const netadr_t& to);
|
||||
SOCKET NET_IPSocket(char *net_interface, int port, qboolean multicast);
|
||||
void NET_OpenIP(void);
|
||||
void NET_OpenIP();
|
||||
SOCKET NET_IPXSocket(int hostshort);
|
||||
void NET_OpenIPX(void);
|
||||
void NET_GetLocalAddress(void);
|
||||
int NET_IsConfigured(void);
|
||||
void NET_OpenIPX();
|
||||
void NET_GetLocalAddress();
|
||||
int NET_IsConfigured();
|
||||
void NET_Config(qboolean multiplayer);
|
||||
void MaxPlayers_f(void);
|
||||
void NET_Init(void);
|
||||
void MaxPlayers_f();
|
||||
void NET_Init();
|
||||
void NET_ClearLagData(qboolean bClient, qboolean bServer);
|
||||
void NET_Shutdown(void);
|
||||
void NET_Shutdown();
|
||||
qboolean NET_JoinGroup(netsrc_t sock, netadr_t& addr);
|
||||
qboolean NET_LeaveGroup(netsrc_t sock, netadr_t& addr);
|
||||
|
@ -501,7 +501,7 @@ pmtrace_t _PM_PlayerTrace(vec_t *start, vec_t *end, int traceFlags, int numphyse
|
||||
closest = 0;
|
||||
for (int j = 0; j < pNumHulls; j++)
|
||||
{
|
||||
Q_memset(&testtrace, 0, 0x44u);
|
||||
Q_memset(&testtrace, 0, sizeof(testtrace));
|
||||
testtrace.endpos[0] = end[0];
|
||||
testtrace.endpos[1] = end[1];
|
||||
testtrace.endpos[2] = end[2];
|
||||
|
@ -339,7 +339,7 @@ void EXT_FUNC PF_traceline_Shared(const float *v1, const float *v2, int nomonste
|
||||
#ifdef REHLDS_OPT_PEDANTIC
|
||||
trace_t trace = SV_Move_Point(v1, v2, nomonsters, ent);
|
||||
#else // REHLDS_OPT_PEDANTIC
|
||||
trace_t trace = SV_Move(v1, vec3_origin, vec3_origin, v2, nomonsters, ent, 0);
|
||||
trace_t trace = SV_Move(v1, vec3_origin, vec3_origin, v2, nomonsters, ent, FALSE);
|
||||
#endif // REHLDS_OPT_PEDANTIC
|
||||
|
||||
gGlobalVariables.trace_flags = 0;
|
||||
@ -370,7 +370,8 @@ void EXT_FUNC TraceHull(const float *v1, const float *v2, int fNoMonsters, int h
|
||||
hullNumber = hullNumber;
|
||||
if (hullNumber < 0 || hullNumber > 3)
|
||||
hullNumber = 0;
|
||||
trace_t trace = SV_Move(v1, gHullMins[hullNumber], gHullMaxs[hullNumber], v2, fNoMonsters, pentToSkip, 0);
|
||||
|
||||
trace_t trace = SV_Move(v1, gHullMins[hullNumber], gHullMaxs[hullNumber], v2, fNoMonsters, pentToSkip, FALSE);
|
||||
|
||||
ptr->fAllSolid = trace.allsolid;
|
||||
ptr->fStartSolid = trace.startsolid;
|
||||
@ -608,7 +609,7 @@ void EXT_FUNC PF_TraceToss_DLL(edict_t *pent, edict_t *pentToIgnore, TraceResult
|
||||
|
||||
int EXT_FUNC TraceMonsterHull(edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr)
|
||||
{
|
||||
qboolean monsterClip = (pEdict->v.flags & FL_MONSTERCLIP) ? 1 : 0;
|
||||
qboolean monsterClip = (pEdict->v.flags & FL_MONSTERCLIP) ? TRUE : FALSE;
|
||||
trace_t trace = SV_Move(v1, pEdict->v.mins, pEdict->v.maxs, v2, fNoMonsters, pentToSkip, monsterClip);
|
||||
if (ptr)
|
||||
{
|
||||
@ -1676,12 +1677,12 @@ int EXT_FUNC PF_droptofloor_I(edict_t *ent)
|
||||
{
|
||||
vec3_t end;
|
||||
trace_t trace;
|
||||
qboolean monsterClip = (ent->v.flags & FL_MONSTERCLIP) ? 1 : 0;
|
||||
qboolean monsterClip = (ent->v.flags & FL_MONSTERCLIP) ? TRUE : FALSE;
|
||||
|
||||
end[0] = ent->v.origin[0];
|
||||
end[1] = ent->v.origin[1];
|
||||
end[2] = ent->v.origin[2] - 256.0;
|
||||
trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, 0, ent, monsterClip);
|
||||
trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent, monsterClip);
|
||||
if (trace.allsolid)
|
||||
return -1;
|
||||
|
||||
@ -1772,7 +1773,7 @@ void EXT_FUNC PF_aim_I(edict_t *ent, float speed, float *rgflReturn)
|
||||
start[1] += ent->v.view_ofs[1];
|
||||
start[2] += ent->v.view_ofs[2];
|
||||
VectorMA(start, 2048.0, dir, end);
|
||||
tr = SV_Move(start, vec3_origin, vec3_origin, end, 0, ent, 0);
|
||||
tr = SV_Move(start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent, FALSE);
|
||||
|
||||
if (tr.ent && tr.ent->v.takedamage == 2.0f && (ent->v.team <= 0 || ent->v.team != tr.ent->v.team))
|
||||
{
|
||||
@ -1811,7 +1812,7 @@ void EXT_FUNC PF_aim_I(edict_t *ent, float speed, float *rgflReturn)
|
||||
|
||||
if (dist >= bestdist)
|
||||
{
|
||||
tr = SV_Move(start, vec3_origin, vec3_origin, end, 0, ent, 0);
|
||||
tr = SV_Move(start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent, FALSE);
|
||||
if (tr.ent == check)
|
||||
{
|
||||
bestdist = dist;
|
||||
|
@ -950,7 +950,7 @@ void EXT_FUNC GetAttachment(const edict_t *pEdict, int iAttachment, float *rgflO
|
||||
);
|
||||
|
||||
if (rgflOrigin)
|
||||
VectorTransform(pattachment->org, (float *)bonetransform[pattachment->bone], rgflOrigin);
|
||||
VectorTransform(pattachment->org, bonetransform[pattachment->bone], rgflOrigin);
|
||||
}
|
||||
|
||||
int ModelFrameCount(model_t *model)
|
||||
|
@ -2832,7 +2832,7 @@ NOXREF void ReplyServerChallenge(netadr_t *adr)
|
||||
buf.flags = SIZEBUF_ALLOW_OVERFLOW;
|
||||
|
||||
MSG_WriteLong(&buf, 0xffffffff);
|
||||
MSG_WriteByte(&buf, 65);
|
||||
MSG_WriteByte(&buf, S2C_CHALLENGE);
|
||||
MSG_WriteLong(&buf, GetChallengeNr(adr));
|
||||
NET_SendPacket(NS_SERVER, buf.cursize, (char *)buf.data, *adr);
|
||||
}
|
||||
@ -3000,7 +3000,7 @@ NOXREF void SVC_Info(qboolean bDetailed)
|
||||
}
|
||||
|
||||
MSG_WriteLong(&buf, 0xffffffff);
|
||||
MSG_WriteByte(&buf, bDetailed ? 109 : 67);
|
||||
MSG_WriteByte(&buf, bDetailed ? S2A_INFO_DETAILED : S2A_INFO);
|
||||
|
||||
if (noip)
|
||||
{
|
||||
@ -3102,7 +3102,7 @@ NOXREF void SVC_PlayerInfo(void)
|
||||
buf.flags = SIZEBUF_ALLOW_OVERFLOW;
|
||||
|
||||
MSG_WriteLong(&buf, 0xffffffff);
|
||||
MSG_WriteByte(&buf, 68);
|
||||
MSG_WriteByte(&buf, S2A_PLAYERS);
|
||||
|
||||
for (i = 0; i < g_psvs.maxclients; i++)
|
||||
{
|
||||
@ -3154,7 +3154,7 @@ NOXREF void SVC_RuleInfo(void)
|
||||
return;
|
||||
|
||||
MSG_WriteLong(&buf, 0xffffffff);
|
||||
MSG_WriteByte(&buf, 69);
|
||||
MSG_WriteByte(&buf, S2A_RULES);
|
||||
MSG_WriteShort(&buf, nNumRules);
|
||||
|
||||
var = cvar_vars;
|
||||
@ -3216,7 +3216,7 @@ void SV_FlushRedirect(void)
|
||||
buf.flags = SIZEBUF_ALLOW_OVERFLOW;
|
||||
|
||||
MSG_WriteLong(&buf, -1);
|
||||
MSG_WriteByte(&buf, 0x6Cu);
|
||||
MSG_WriteByte(&buf, A2A_PRINT);
|
||||
MSG_WriteString(&buf, outputbuf);
|
||||
MSG_WriteByte(&buf, 0);
|
||||
NET_SendPacket(NS_SERVER, buf.cursize, buf.data, sv_redirectto);
|
||||
|
@ -28,21 +28,7 @@
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
/*
|
||||
* Local initialization
|
||||
*/
|
||||
#ifndef HOOK_ENGINE
|
||||
|
||||
static int c_yes = 0;
|
||||
static int c_no = 0;
|
||||
|
||||
#else // HOOK_ENGINE
|
||||
|
||||
int c_yes;
|
||||
int c_no;
|
||||
|
||||
#endif // HOOK_ENGINE
|
||||
|
||||
// Returns false if any part of the bottom of the entity is off an edge that is not a staircase.
|
||||
qboolean SV_CheckBottom(edict_t *ent)
|
||||
{
|
||||
vec3_t mins;
|
||||
@ -54,12 +40,17 @@ qboolean SV_CheckBottom(edict_t *ent)
|
||||
int y;
|
||||
float mid;
|
||||
float bottom;
|
||||
qboolean monsterClip = (ent->v.flags & FL_MONSTERCLIP) ? 1 : 0;
|
||||
|
||||
_VectorAdd(ent->v.origin, ent->v.mins, mins);
|
||||
_VectorAdd(ent->v.origin, ent->v.maxs, maxs);
|
||||
qboolean monsterClip = (ent->v.flags & FL_MONSTERCLIP) ? TRUE : FALSE;
|
||||
|
||||
VectorAdd(ent->v.origin, ent->v.mins, mins);
|
||||
VectorAdd(ent->v.origin, ent->v.maxs, maxs);
|
||||
|
||||
// if all of the points under the corners are solid world, don't bother
|
||||
// with the tougher checks
|
||||
// the corners must be within 16 of the midpoint
|
||||
start[2] = mins[2] - 1.0f;
|
||||
|
||||
start[2] = mins[2] - 1;
|
||||
for (x = 0; x <= 1; x++)
|
||||
{
|
||||
for (y = 0; y <= 1; y++)
|
||||
@ -73,23 +64,28 @@ qboolean SV_CheckBottom(edict_t *ent)
|
||||
goto realcheck;
|
||||
}
|
||||
}
|
||||
++c_yes;
|
||||
return 1;
|
||||
|
||||
// we got out easy
|
||||
return TRUE;
|
||||
|
||||
realcheck:
|
||||
++c_no;
|
||||
|
||||
// check it for real...
|
||||
start[2] = mins[2];
|
||||
|
||||
// the midpoint must be within 16 of the bottom
|
||||
start[0] = stop[0] = (mins[0] + maxs[0]) * 0.5f;
|
||||
start[1] = stop[1] = (mins[1] + maxs[1]) * 0.5f;
|
||||
stop[2] = start[2] - 2 * sv_stepsize.value;
|
||||
trace = SV_Move(start, vec3_origin, vec3_origin, stop, 1, ent, monsterClip);
|
||||
|
||||
stop[2] = start[2] - 2.0f * sv_stepsize.value;
|
||||
trace = SV_Move(start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, monsterClip);
|
||||
|
||||
if (trace.fraction == 1.0f)
|
||||
return 0;
|
||||
return FALSE;
|
||||
|
||||
mid = bottom = trace.endpos[2];
|
||||
|
||||
// the corners must be within 16 of the midpoint
|
||||
for (x = 0; x <= 1; x++)
|
||||
{
|
||||
for (y = 0; y <= 1; y++)
|
||||
@ -97,18 +93,23 @@ realcheck:
|
||||
start[0] = stop[0] = x ? maxs[0] : mins[0];
|
||||
start[1] = stop[1] = y ? maxs[1] : mins[1];
|
||||
|
||||
trace = SV_Move(start, vec3_origin, vec3_origin, stop, 1, ent, monsterClip);
|
||||
trace = SV_Move(start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, monsterClip);
|
||||
|
||||
if (trace.fraction != 1.0f && trace.endpos[2] > bottom)
|
||||
bottom = trace.endpos[2];
|
||||
|
||||
if (trace.fraction == 1.0f || mid - trace.endpos[2] > sv_stepsize.value)
|
||||
return 0;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Called by monster program code.
|
||||
// The move will be adjusted for slopes and stairs, but if the move isn't
|
||||
// possible, no move is done, false is returned, and
|
||||
// pr_global_struct->trace_normal is set to the normal of the blocking wall
|
||||
qboolean SV_movetest(edict_t *ent, vec_t *move, qboolean relink)
|
||||
{
|
||||
vec3_t oldorg;
|
||||
@ -116,223 +117,255 @@ qboolean SV_movetest(edict_t *ent, vec_t *move, qboolean relink)
|
||||
vec3_t end;
|
||||
trace_t trace;
|
||||
|
||||
oldorg[0] = ent->v.origin[0];
|
||||
oldorg[1] = ent->v.origin[1];
|
||||
oldorg[2] = ent->v.origin[2];
|
||||
|
||||
neworg[0] = ent->v.origin[0] + move[0];
|
||||
neworg[1] = ent->v.origin[1] + move[1];
|
||||
neworg[2] = ent->v.origin[2] + move[2];
|
||||
end[0] = neworg[0];
|
||||
end[1] = neworg[1];
|
||||
// try the move
|
||||
VectorCopy(ent->v.origin, oldorg);
|
||||
VectorAdd(ent->v.origin, move, neworg);
|
||||
|
||||
// push down from a step height above the wished position
|
||||
neworg[2] += sv_stepsize.value;
|
||||
end[2] = neworg[2] - (2 * sv_stepsize.value);
|
||||
trace = SV_MoveNoEnts(neworg, ent->v.mins, ent->v.maxs, end, 0, ent);
|
||||
VectorCopy(neworg, end);
|
||||
end[2] -= sv_stepsize.value * 2.0f;
|
||||
|
||||
trace = SV_MoveNoEnts(neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
|
||||
|
||||
if (trace.allsolid)
|
||||
return 0;
|
||||
return FALSE;
|
||||
|
||||
if (trace.startsolid)
|
||||
{
|
||||
neworg[2] -= sv_stepsize.value;
|
||||
trace = SV_MoveNoEnts(neworg, ent->v.mins, ent->v.maxs, end, 0, ent);
|
||||
trace = SV_MoveNoEnts(neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
|
||||
|
||||
if (trace.allsolid || trace.startsolid)
|
||||
return 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (trace.fraction == 1.0f)
|
||||
{
|
||||
// if monster had the ground pulled out, go ahead and fall
|
||||
if (ent->v.flags & FL_PARTIALGROUND)
|
||||
{
|
||||
ent->v.origin[0] = *move + ent->v.origin[0];
|
||||
ent->v.origin[1] = ent->v.origin[1] + move[1];
|
||||
ent->v.origin[2] = ent->v.origin[2] + move[2];
|
||||
VectorAdd(ent->v.origin, move, ent->v.origin);
|
||||
|
||||
if (relink)
|
||||
{
|
||||
SV_LinkEdict(ent, TRUE);
|
||||
}
|
||||
|
||||
// fall down
|
||||
ent->v.flags &= ~FL_ONGROUND;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ent->v.origin[0] = trace.endpos[0];
|
||||
ent->v.origin[1] = trace.endpos[1];
|
||||
ent->v.origin[2] = trace.endpos[2];
|
||||
if (SV_CheckBottom(ent) == 0)
|
||||
// walked off an edge
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// check point traces down for dangling corners
|
||||
VectorCopy(trace.endpos, ent->v.origin);
|
||||
|
||||
if (!SV_CheckBottom(ent))
|
||||
{
|
||||
if (!(ent->v.flags & FL_PARTIALGROUND))
|
||||
{
|
||||
ent->v.origin[0] = oldorg[0];
|
||||
ent->v.origin[1] = oldorg[1];
|
||||
ent->v.origin[2] = oldorg[2];
|
||||
return 0;
|
||||
VectorCopy(oldorg, ent->v.origin);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// entity had floor mostly pulled out from underneath it
|
||||
// and is trying to correct
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ent->v.flags & FL_PARTIALGROUND)
|
||||
{
|
||||
// back on ground
|
||||
ent->v.flags &= ~FL_PARTIALGROUND;
|
||||
}
|
||||
|
||||
ent->v.groundentity = trace.ent;
|
||||
}
|
||||
|
||||
// the move is ok
|
||||
if (relink)
|
||||
{
|
||||
SV_LinkEdict(ent, TRUE);
|
||||
}
|
||||
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Called by monster program code.
|
||||
// The move will be adjusted for slopes and stairs, but if the move isn't
|
||||
// possible, no move is done, false is returned, and
|
||||
// pr_global_struct->trace_normal is set to the normal of the blocking wall
|
||||
qboolean SV_movestep(edict_t *ent, vec_t *move, qboolean relink)
|
||||
{
|
||||
trace_t trace;
|
||||
vec3_t end;
|
||||
vec3_t oldorg;
|
||||
float dz;
|
||||
qboolean monsterClipBrush;
|
||||
vec3_t start;
|
||||
vec3_t neworg, oldorg, end;
|
||||
|
||||
oldorg[0] = ent->v.origin[0];
|
||||
oldorg[1] = ent->v.origin[1];
|
||||
oldorg[2] = ent->v.origin[2];
|
||||
// try the move
|
||||
VectorCopy(ent->v.origin, oldorg);
|
||||
VectorAdd(ent->v.origin, move, neworg);
|
||||
|
||||
start[0] = ent->v.origin[0] + move[0];
|
||||
start[1] = ent->v.origin[1] + move[1];
|
||||
start[2] = ent->v.origin[2] + move[2];
|
||||
monsterClipBrush = (ent->v.flags & FL_MONSTERCLIP) != 0;
|
||||
qboolean monsterClipBrush = (ent->v.flags & FL_MONSTERCLIP) ? TRUE : FALSE;
|
||||
|
||||
// flying monsters don't step up
|
||||
if (ent->v.flags & (FL_FLY | FL_SWIM))
|
||||
{
|
||||
int i = 0;
|
||||
while (i < 2)
|
||||
// try one move with vertical motion, then one without
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
start[0] = ent->v.origin[0] + move[0];
|
||||
start[1] = ent->v.origin[1] + move[1];
|
||||
start[2] = ent->v.origin[2] + move[2];
|
||||
edict_t* enemy = ent->v.enemy;
|
||||
|
||||
VectorAdd(ent->v.origin, move, neworg);
|
||||
|
||||
edict_t *enemy = ent->v.enemy;
|
||||
if (i == 0 && enemy)
|
||||
{
|
||||
dz = ent->v.origin[2] - enemy->v.origin[2];
|
||||
if (dz > 40.0)
|
||||
start[2] = start[2] - 8.0;
|
||||
if (dz < 30.0)
|
||||
start[2] = start[2] + 8.0;
|
||||
float dz = ent->v.origin[2] - enemy->v.origin[2];
|
||||
|
||||
if (dz > 40.0f)
|
||||
neworg[2] -= 8.0f;
|
||||
else if (dz < 30.0f)
|
||||
neworg[2] += 8.0f;
|
||||
}
|
||||
trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, start, 0, ent, monsterClipBrush);
|
||||
|
||||
trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, neworg, MOVE_NORMAL, ent, monsterClipBrush);
|
||||
|
||||
if (trace.fraction == 1.0f)
|
||||
break;
|
||||
{
|
||||
g_groupmask = ent->v.groupinfo;
|
||||
|
||||
if ((ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == CONTENTS_EMPTY)
|
||||
{
|
||||
// swim monster left water
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VectorCopy(trace.endpos, ent->v.origin);
|
||||
|
||||
if (relink)
|
||||
{
|
||||
SV_LinkEdict(ent, TRUE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!enemy)
|
||||
return 0;
|
||||
|
||||
if (i == 1)
|
||||
return 0;
|
||||
|
||||
i++;
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_groupmask = ent->v.groupinfo;
|
||||
if ((ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == -1)
|
||||
return 0;
|
||||
|
||||
ent->v.origin[0] = trace.endpos[0];
|
||||
ent->v.origin[1] = trace.endpos[1];
|
||||
ent->v.origin[2] = trace.endpos[2];
|
||||
if (relink)
|
||||
SV_LinkEdict(ent, TRUE);
|
||||
|
||||
return 1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
start[2] += sv_stepsize.value;
|
||||
end[0] = start[0];
|
||||
end[1] = start[1];
|
||||
end[2] = start[2] - (2 * sv_stepsize.value);
|
||||
trace = SV_Move(start, ent->v.mins, ent->v.maxs, end, 0, ent, (ent->v.flags & FL_MONSTERCLIP) != 0);
|
||||
// push down from a step height above the wished position
|
||||
neworg[2] += sv_stepsize.value;
|
||||
VectorCopy(neworg, end);
|
||||
end[2] -= sv_stepsize.value * 2.0f;
|
||||
|
||||
trace = SV_Move(neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent, monsterClipBrush);
|
||||
|
||||
if (trace.allsolid)
|
||||
return 0;
|
||||
return FALSE;
|
||||
|
||||
if (trace.startsolid)
|
||||
{
|
||||
start[2] = start[2] - sv_stepsize.value;
|
||||
trace = SV_Move(start, ent->v.mins, ent->v.maxs, end, 0, ent, monsterClipBrush);
|
||||
neworg[2] = neworg[2] - sv_stepsize.value;
|
||||
trace = SV_Move(neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent, monsterClipBrush);
|
||||
|
||||
if (trace.allsolid || trace.startsolid)
|
||||
return 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (trace.fraction != 1.0f)
|
||||
if (trace.fraction == 1.0f)
|
||||
{
|
||||
ent->v.origin[0] = trace.endpos[0];
|
||||
ent->v.origin[1] = trace.endpos[1];
|
||||
ent->v.origin[2] = trace.endpos[2];
|
||||
if (SV_CheckBottom(ent) == 0)
|
||||
// if monster had the ground pulled out, go ahead and fall
|
||||
if (ent->v.flags & FL_PARTIALGROUND)
|
||||
{
|
||||
VectorAdd(ent->v.origin, move, ent->v.origin);
|
||||
|
||||
if (relink)
|
||||
{
|
||||
SV_LinkEdict(ent, TRUE);
|
||||
}
|
||||
|
||||
// fall down
|
||||
ent->v.flags &= ~FL_ONGROUND;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// walked off an edge
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// check point traces down for dangling corners
|
||||
VectorCopy(trace.endpos, ent->v.origin);
|
||||
|
||||
if (!SV_CheckBottom(ent))
|
||||
{
|
||||
if (!(ent->v.flags & FL_PARTIALGROUND))
|
||||
{
|
||||
ent->v.origin[0] = oldorg[0];
|
||||
ent->v.origin[1] = oldorg[1];
|
||||
ent->v.origin[2] = oldorg[2];
|
||||
return 0;
|
||||
VectorCopy(oldorg, ent->v.origin);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// entity had floor mostly pulled out from underneath it
|
||||
// and is trying to correct
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ent->v.flags & FL_PARTIALGROUND)
|
||||
{
|
||||
// back on ground
|
||||
ent->v.flags &= ~FL_PARTIALGROUND;
|
||||
}
|
||||
|
||||
ent->v.groundentity = trace.ent;
|
||||
}
|
||||
|
||||
// the move is ok
|
||||
if (relink)
|
||||
{
|
||||
SV_LinkEdict(ent, TRUE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(ent->v.flags & FL_PARTIALGROUND))
|
||||
return 0;
|
||||
|
||||
ent->v.origin[0] += move[0];
|
||||
ent->v.origin[1] += move[1];
|
||||
ent->v.origin[2] += move[2];
|
||||
if (relink)
|
||||
SV_LinkEdict(ent, TRUE);
|
||||
|
||||
ent->v.flags &= ~FL_ONGROUND;
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Turns to the movement direction, and walks the current distance if facing it.
|
||||
qboolean SV_StepDirection(edict_t *ent, float yaw, float dist)
|
||||
{
|
||||
vec3_t move;
|
||||
|
||||
move[0] = cos(yaw * (2 * M_PI) / 360.0) * dist;
|
||||
move[1] = sin(yaw * (2 * M_PI) / 360.0) * dist;
|
||||
move[2] = 0;
|
||||
if (SV_movestep(ent, move, 0))
|
||||
yaw = yaw * (M_PI * 2.0f) / 360.0f;
|
||||
|
||||
move[0] = cos(yaw) * dist;
|
||||
move[1] = sin(yaw) * dist;
|
||||
move[2] = 0.0f;
|
||||
|
||||
if (SV_movestep(ent, move, FALSE))
|
||||
{
|
||||
SV_LinkEdict(ent, TRUE);
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
SV_LinkEdict(ent, TRUE);
|
||||
return 0;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
qboolean SV_FlyDirection(edict_t *ent, vec_t *direction)
|
||||
{
|
||||
if (SV_movestep(ent, direction, 0))
|
||||
if (SV_movestep(ent, direction, FALSE))
|
||||
{
|
||||
SV_LinkEdict(ent, TRUE);
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
SV_LinkEdict(ent, TRUE);
|
||||
return 0;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -341,51 +374,91 @@ void SV_FixCheckBottom(edict_t *ent)
|
||||
ent->v.flags |= FL_PARTIALGROUND;
|
||||
}
|
||||
|
||||
const int DI_NODIR = -1;
|
||||
|
||||
NOXREF void SV_NewChaseDir(edict_t *actor, edict_t *enemy, float dist)
|
||||
{
|
||||
NOXREFCHECK;
|
||||
float deltax;
|
||||
float deltay;
|
||||
float d[3];
|
||||
float tdir;
|
||||
float olddir;
|
||||
float turnaround;
|
||||
|
||||
olddir = anglemod(45.0 * (int)(actor->v.ideal_yaw / 45.0));
|
||||
turnaround = anglemod(olddir - 180.0);
|
||||
SV_NewChaseDir2(actor, enemy->v.origin, dist);
|
||||
}
|
||||
|
||||
deltax = enemy->v.origin[0] - actor->v.origin[0];
|
||||
deltay = enemy->v.origin[1] - actor->v.origin[1];
|
||||
NOXREF qboolean SV_CloseEnough(edict_t *ent, edict_t *goal, float dist)
|
||||
{
|
||||
NOXREFCHECK;
|
||||
|
||||
if (deltax > 10.0)
|
||||
d[1] = 0.0;
|
||||
else if (deltax <- 10.0)
|
||||
d[1]= 180.0;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (goal->v.absmin[i] > ent->v.absmax[i] + dist)
|
||||
return FALSE;
|
||||
|
||||
if (goal->v.absmax[i] < ent->v.absmin[i] - dist)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
NOXREF qboolean SV_ReachedGoal(edict_t *ent, vec_t *vecGoal, float flDist)
|
||||
{
|
||||
NOXREFCHECK;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (vecGoal[i] > ent->v.absmax[i] + flDist)
|
||||
return FALSE;
|
||||
|
||||
if (vecGoal[i] < ent->v.absmin[i] - flDist)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void SV_NewChaseDir2(edict_t *actor, vec_t *vecGoal, float dist)
|
||||
{
|
||||
vec3_t d;
|
||||
float deltax, deltay;
|
||||
float tempdir, olddir, turnaround;
|
||||
|
||||
olddir = anglemod(45.0f * (int)(actor->v.ideal_yaw / 45.0f));
|
||||
turnaround = anglemod(olddir - 180.0f);
|
||||
|
||||
deltax = vecGoal[0] - actor->v.origin[0];
|
||||
deltay = vecGoal[1] - actor->v.origin[1];
|
||||
|
||||
if (deltax > 10.0f)
|
||||
d[1] = 0.0f;
|
||||
else if (deltax < -10.0f)
|
||||
d[1] = 180.0f;
|
||||
else
|
||||
d[1]= DI_NODIR;
|
||||
if (deltay < -10.0)
|
||||
d[2] = 270.0;
|
||||
else if (deltay > 10.0)
|
||||
d[2] = 90.0;
|
||||
else
|
||||
d[2]= DI_NODIR;
|
||||
d[1] = DI_NODIR;
|
||||
|
||||
if (deltay < -10.0f)
|
||||
d[2] = 270.0f;
|
||||
else if (deltay > 10.0f)
|
||||
d[2] = 90.0f;
|
||||
else
|
||||
d[2] = DI_NODIR;
|
||||
|
||||
// try direct route
|
||||
if (d[1] != DI_NODIR && d[2] != DI_NODIR)
|
||||
{
|
||||
if (d[1] == 0.0)
|
||||
tdir = d[2] == 90.0 ? 45.0 : 315.0;
|
||||
if (d[1] == 0.0f)
|
||||
tempdir = d[2] == 90.0f ? 45.0f : 315.0f;
|
||||
else
|
||||
tdir = d[2] == 90.0 ? 135.0 : 215.0;
|
||||
tempdir = d[2] == 90.0f ? 135.0f : 215.0f;
|
||||
|
||||
if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
|
||||
if (tempdir != turnaround && SV_StepDirection(actor, tempdir, dist))
|
||||
return;
|
||||
}
|
||||
|
||||
// try other directions
|
||||
if (RandomLong(0, 1) || abs(deltay) > abs(deltax))
|
||||
{
|
||||
tdir = d[1];
|
||||
tempdir = d[1];
|
||||
d[1] = d[2];
|
||||
d[2] = tdir;
|
||||
d[2] = tempdir;
|
||||
}
|
||||
|
||||
if (d[1] != DI_NODIR && d[1] != turnaround && SV_StepDirection(actor, d[1], dist))
|
||||
@ -394,168 +467,68 @@ NOXREF void SV_NewChaseDir(edict_t *actor, edict_t *enemy, float dist)
|
||||
if (d[2] != DI_NODIR && d[2] != turnaround && SV_StepDirection(actor, d[2], dist))
|
||||
return;
|
||||
|
||||
// there is no direct path to the player, so pick another direction
|
||||
if (olddir != DI_NODIR && SV_StepDirection(actor, olddir, dist))
|
||||
return;
|
||||
|
||||
// randomly determine direction of search
|
||||
if (RandomLong(0, 1))
|
||||
{
|
||||
for (tdir = 0.0; tdir <= 315.0; tdir += 45.0)
|
||||
if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
|
||||
for (tempdir = 0.0f; tempdir <= 315.0f; tempdir += 45.0f)
|
||||
{
|
||||
if (tempdir != turnaround && SV_StepDirection(actor, tempdir, dist))
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (tdir = 315.0 ; tdir >= 0.0; tdir -= 45.0)
|
||||
if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
|
||||
for (tempdir = 315.0f; tempdir >= 0.0f; tempdir -= 45.0f)
|
||||
{
|
||||
if (tempdir != turnaround && SV_StepDirection(actor, tempdir, dist))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// we tried. run backwards. that ought to work...
|
||||
if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist))
|
||||
return;
|
||||
|
||||
// can't move, we're stuck somehow
|
||||
actor->v.ideal_yaw = olddir;
|
||||
|
||||
// if a bridge was pulled out from underneath a monster, it may not have
|
||||
// a valid standing position at all
|
||||
if (!SV_CheckBottom(actor))
|
||||
SV_FixCheckBottom(actor);
|
||||
}
|
||||
|
||||
NOXREF qboolean SV_CloseEnough(edict_t *ent, edict_t *goal, float dist)
|
||||
{
|
||||
NOXREFCHECK;
|
||||
int i;
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (goal->v.absmin[i] > ent->v.absmax[i] + dist)
|
||||
return FALSE;
|
||||
if (goal->v.absmax[i] < ent->v.absmin[i] - dist)
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
NOXREF qboolean SV_ReachedGoal(edict_t *ent, vec_t *vecGoal, float flDist)
|
||||
{
|
||||
NOXREFCHECK;
|
||||
int i;
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (vecGoal[i] > ent->v.absmax[i] + flDist)
|
||||
return FALSE;
|
||||
if (vecGoal[i] < ent->v.absmin[i] - flDist)
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void SV_NewChaseDir2(edict_t *actor, vec_t *vecGoal, float dist)
|
||||
{
|
||||
float deltax;
|
||||
float deltay;
|
||||
float d_1, d_2;
|
||||
float tdir;
|
||||
float olddir;
|
||||
float turnaround;
|
||||
|
||||
olddir = anglemod(45 * (int)(actor->v.ideal_yaw / 45.0));
|
||||
turnaround = anglemod(olddir - 180.0);
|
||||
deltax = vecGoal[0] - actor->v.origin[0];
|
||||
deltay = vecGoal[1] - actor->v.origin[1];
|
||||
|
||||
if (deltax > 10)
|
||||
d_1 = 0;
|
||||
else if (deltax < -10)
|
||||
d_1 = 180;
|
||||
else
|
||||
d_1 = DI_NODIR;
|
||||
|
||||
if (deltay < -10)
|
||||
d_2 = 270;
|
||||
else if (deltay > 10)
|
||||
d_2 = 90;
|
||||
else
|
||||
d_2 = DI_NODIR;
|
||||
|
||||
if (d_1 != DI_NODIR && d_2 != DI_NODIR)
|
||||
{
|
||||
if (d_1 == 0.0)
|
||||
tdir = d_2 == 90 ? 45 : 315;
|
||||
else
|
||||
tdir = d_2 == 90 ? 135 : 215;
|
||||
|
||||
if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
|
||||
return;
|
||||
}
|
||||
|
||||
if (RandomLong(0, 1) || abs(deltay) > abs(deltax))
|
||||
{
|
||||
tdir = d_1;
|
||||
d_1 = d_2;
|
||||
d_2 = tdir;
|
||||
}
|
||||
|
||||
if (d_1 != DI_NODIR && d_1 != turnaround
|
||||
&& SV_StepDirection(actor, d_1, dist))
|
||||
return;
|
||||
|
||||
if (d_2 != DI_NODIR && d_2 != turnaround
|
||||
&& SV_StepDirection(actor, d_2, dist))
|
||||
return;
|
||||
|
||||
if (olddir != DI_NODIR && SV_StepDirection(actor, olddir, dist))
|
||||
return;
|
||||
|
||||
if (RandomLong(0, 1))
|
||||
{
|
||||
for (tdir = 0; tdir <= 315; tdir += 45)
|
||||
{
|
||||
if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (tdir = 315; tdir >= 0; tdir -= 45)
|
||||
{
|
||||
if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (turnaround == DI_NODIR || !SV_StepDirection(actor, turnaround, dist))
|
||||
{
|
||||
actor->v.ideal_yaw = olddir;
|
||||
if (!SV_CheckBottom(actor))
|
||||
SV_FixCheckBottom(actor);
|
||||
}
|
||||
}
|
||||
|
||||
void EXT_FUNC SV_MoveToOrigin_I(edict_t *ent, const float *pflGoal, float dist, int iStrafe)
|
||||
void EXT_FUNC SV_MoveToOrigin_I(edict_t *ent, const float *pflGoal, float dist, int iMoveType)
|
||||
{
|
||||
vec3_t vecGoal;
|
||||
VectorCopy(pflGoal, vecGoal);
|
||||
|
||||
if (ent->v.flags & (FL_FLY | FL_SWIM | FL_ONGROUND))
|
||||
{
|
||||
if (iMoveType == MOVE_NORMAL)
|
||||
{
|
||||
if (!SV_StepDirection(ent, ent->v.ideal_yaw, dist))
|
||||
{
|
||||
SV_NewChaseDir2(ent, vecGoal, dist);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vec3_t vecDir;
|
||||
VectorSubtract(vecGoal, ent->v.origin, vecDir);
|
||||
|
||||
vecGoal[0] = pflGoal[0];
|
||||
vecGoal[1] = pflGoal[1];
|
||||
vecGoal[2] = pflGoal[2];
|
||||
|
||||
if (ent->v.flags & (FL_ONGROUND | FL_SWIM | FL_FLY))
|
||||
{
|
||||
if (iStrafe)
|
||||
{
|
||||
vecDir[0] = vecGoal[0] - ent->v.origin[0];
|
||||
vecDir[1] = vecGoal[1] - ent->v.origin[1];
|
||||
vecDir[2] = vecGoal[2] - ent->v.origin[2];
|
||||
if (!(ent->v.flags & (FL_SWIM | FL_FLY)))
|
||||
vecDir[2] = 0;
|
||||
vecDir[2] = 0.0f;
|
||||
|
||||
VectorNormalize(vecDir);
|
||||
VectorScale(vecDir, dist, vecDir);
|
||||
SV_FlyDirection(ent, vecDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!SV_StepDirection(ent, ent->v.ideal_yaw, dist))
|
||||
SV_NewChaseDir2(ent, vecGoal, dist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,18 +31,6 @@
|
||||
#include "maintypes.h"
|
||||
#include "server.h"
|
||||
|
||||
const int DI_NODIR = -1;
|
||||
|
||||
#ifdef HOOK_ENGINE
|
||||
|
||||
#define c_yes (*pc_yes)
|
||||
#define c_no (*pc_no)
|
||||
|
||||
extern int c_yes;
|
||||
extern int c_no;
|
||||
|
||||
#endif // HOOK_ENGINE
|
||||
|
||||
qboolean SV_CheckBottom(edict_t *ent);
|
||||
qboolean SV_movetest(edict_t *ent, vec_t *move, qboolean relink);
|
||||
qboolean SV_movestep(edict_t *ent, vec_t *move, qboolean relink);
|
||||
@ -53,4 +41,4 @@ NOXREF void SV_NewChaseDir(edict_t *actor, edict_t *enemy, float dist);
|
||||
NOXREF qboolean SV_CloseEnough(edict_t *ent, edict_t *goal, float dist);
|
||||
NOXREF qboolean SV_ReachedGoal(edict_t *ent, vec_t *vecGoal, float flDist);
|
||||
void SV_NewChaseDir2(edict_t *actor, vec_t *vecGoal, float dist);
|
||||
void SV_MoveToOrigin_I(edict_t *ent, const float *pflGoal, float dist, int iStrafe);
|
||||
void SV_MoveToOrigin_I(edict_t *ent, const float *pflGoal, float dist, int iMoveType);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -32,7 +32,6 @@
|
||||
#include "model.h"
|
||||
#include "cvar.h"
|
||||
|
||||
|
||||
#ifdef HOOK_ENGINE
|
||||
#define sv_maxvelocity (*psv_maxvelocity)
|
||||
#define sv_gravity (*psv_gravity)
|
||||
@ -54,8 +53,7 @@ extern cvar_t sv_stopspeed;
|
||||
extern vec3_t *g_moved_from;
|
||||
extern edict_t **g_moved_edict;
|
||||
|
||||
|
||||
NOXREF void SV_CheckAllEnts(void);
|
||||
NOXREF void SV_CheckAllEnts();
|
||||
void SV_CheckVelocity(edict_t *ent);
|
||||
qboolean SV_RunThink(edict_t *ent);
|
||||
void SV_Impact(edict_t *e1, edict_t *e2, trace_t *ptrace);
|
||||
@ -69,7 +67,7 @@ void SV_PushMove(edict_t *pusher, float movetime);
|
||||
int SV_PushRotate(edict_t *pusher, float movetime);
|
||||
void SV_Physics_Pusher(edict_t *ent);
|
||||
qboolean SV_CheckWater(edict_t *ent);
|
||||
float SV_RecursiveWaterLevel(vec_t *center, float out, float in, int count);
|
||||
float SV_RecursiveWaterLevel(const vec_t *origin, float mins, float maxs, int depth);
|
||||
float SV_Submerged(edict_t *ent);
|
||||
void SV_Physics_None(edict_t *ent);
|
||||
void SV_Physics_Follow(edict_t *ent);
|
||||
|
@ -396,8 +396,10 @@ void SV_CopyEdictToPhysent(physent_t *pe, int e, edict_t *check)
|
||||
|
||||
pe->origin[0] = check->v.origin[0];
|
||||
pe->origin[1] = check->v.origin[1];
|
||||
pe->info = e;
|
||||
pe->origin[2] = check->v.origin[2];
|
||||
|
||||
pe->info = e;
|
||||
|
||||
if (e < 1 || e > g_psvs.maxclients)
|
||||
{
|
||||
pe->player = 0;
|
||||
@ -411,30 +413,32 @@ void SV_CopyEdictToPhysent(physent_t *pe, int e, edict_t *check)
|
||||
pe->angles[0] = check->v.angles[0];
|
||||
pe->angles[1] = check->v.angles[1];
|
||||
pe->angles[2] = check->v.angles[2];
|
||||
pe->studiomodel = 0;
|
||||
|
||||
pe->studiomodel = nullptr;
|
||||
pe->rendermode = check->v.rendermode;
|
||||
|
||||
if (check->v.solid == SOLID_BSP)
|
||||
{
|
||||
pe->model = g_psv.models[check->v.modelindex];
|
||||
Q_strncpy(pe->name, pe->model->name, 0x20u);
|
||||
pe->name[31] = 0;
|
||||
Q_strncpy(pe->name, pe->model->name, sizeof(pe->name) - 1);
|
||||
pe->name[sizeof(pe->name) - 1] = 0;
|
||||
}
|
||||
else if (check->v.solid == SOLID_NOT)
|
||||
{
|
||||
if (check->v.modelindex)
|
||||
{
|
||||
pe->model = g_psv.models[check->v.modelindex];
|
||||
Q_strncpy(pe->name, pe->model->name, 0x20u);
|
||||
pe->name[31] = 0;
|
||||
Q_strncpy(pe->name, pe->model->name, sizeof(pe->name) - 1);
|
||||
pe->name[sizeof(pe->name) - 1] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pe->model = 0;
|
||||
pe->model = nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pe->model = NULL;
|
||||
pe->model = nullptr;
|
||||
if (check->v.solid != SOLID_BBOX)
|
||||
{
|
||||
pe->mins[0] = check->v.mins[0];
|
||||
@ -443,10 +447,11 @@ void SV_CopyEdictToPhysent(physent_t *pe, int e, edict_t *check)
|
||||
pe->mins[2] = check->v.mins[2];
|
||||
pe->maxs[1] = check->v.maxs[1];
|
||||
pe->maxs[2] = check->v.maxs[2];
|
||||
|
||||
if (check->v.classname)
|
||||
{
|
||||
Q_strncpy(pe->name, &pr_strings[check->v.classname], 0x20u);
|
||||
pe->name[31] = 0;
|
||||
Q_strncpy(pe->name, &pr_strings[check->v.classname], sizeof(pe->name) - 1);
|
||||
pe->name[sizeof(pe->name) - 1] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -460,13 +465,14 @@ void SV_CopyEdictToPhysent(physent_t *pe, int e, edict_t *check)
|
||||
pModel = g_psv.models[check->v.modelindex];
|
||||
if (pModel)
|
||||
{
|
||||
if (pModel->flags & 0x200)
|
||||
if (pModel->flags & STUDIO_TRACE_HITBOX)
|
||||
pe->studiomodel = pModel;
|
||||
|
||||
Q_strncpy(pe->name, pModel->name, 0x20u);
|
||||
pe->name[31] = 0;
|
||||
Q_strncpy(pe->name, pModel->name, sizeof(pe->name) - 1);
|
||||
pe->name[sizeof(pe->name) - 1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pe->mins[0] = check->v.mins[0];
|
||||
pe->mins[1] = check->v.mins[1];
|
||||
pe->mins[2] = check->v.mins[2];
|
||||
@ -475,13 +481,16 @@ void SV_CopyEdictToPhysent(physent_t *pe, int e, edict_t *check)
|
||||
pe->maxs[2] = check->v.maxs[2];
|
||||
}
|
||||
}
|
||||
|
||||
pe->skin = check->v.skin;
|
||||
pe->frame = check->v.frame;
|
||||
pe->solid = check->v.solid;
|
||||
pe->sequence = check->v.sequence;
|
||||
Q_memcpy(pe->controller, check->v.controller, 4);
|
||||
Q_memcpy(pe->blending, check->v.blending, 2);
|
||||
pe->movetype = check->v.movetype;
|
||||
|
||||
Q_memcpy(&pe->controller[0], &check->v.controller[0], 4 * sizeof(byte));
|
||||
Q_memcpy(&pe->blending[0], &check->v.blending[0], 2 * sizeof(byte));
|
||||
|
||||
pe->iuser1 = check->v.iuser1;
|
||||
pe->iuser2 = check->v.iuser2;
|
||||
pe->iuser3 = check->v.iuser3;
|
||||
@ -490,6 +499,7 @@ void SV_CopyEdictToPhysent(physent_t *pe, int e, edict_t *check)
|
||||
pe->fuser2 = check->v.fuser2;
|
||||
pe->fuser3 = check->v.fuser3;
|
||||
pe->fuser4 = check->v.fuser4;
|
||||
|
||||
pe->vuser1[0] = check->v.vuser1[0];
|
||||
pe->vuser1[1] = check->v.vuser1[1];
|
||||
pe->vuser1[2] = check->v.vuser1[2];
|
||||
@ -499,8 +509,10 @@ void SV_CopyEdictToPhysent(physent_t *pe, int e, edict_t *check)
|
||||
pe->vuser3[0] = check->v.vuser3[0];
|
||||
pe->vuser3[1] = check->v.vuser3[1];
|
||||
pe->vuser3[2] = check->v.vuser3[2];
|
||||
|
||||
pe->takedamage = 0;
|
||||
pe->blooddecal = 0;
|
||||
|
||||
pe->vuser4[0] = check->v.vuser4[0];
|
||||
pe->vuser4[1] = check->v.vuser4[1];
|
||||
pe->vuser4[2] = check->v.vuser4[2];
|
||||
@ -619,8 +631,8 @@ void SV_AddLinksToPM(areanode_t *node, vec_t *origin)
|
||||
pmove->physents[0].model = g_psv.worldmodel;
|
||||
if (g_psv.worldmodel != NULL)
|
||||
{
|
||||
Q_strncpy(pmove->physents[0].name, g_psv.worldmodel->name, 0x20u);
|
||||
pmove->physents[0].name[31] = 0;
|
||||
Q_strncpy(pmove->physents[0].name, g_psv.worldmodel->name, sizeof(pmove->physents[0].name) - 1);
|
||||
pmove->physents[0].name[sizeof(pmove->physents[0].name) - 1] = 0;
|
||||
}
|
||||
pmove->physents[0].origin[0] = vec3_origin[0];
|
||||
pmove->physents[0].origin[1] = vec3_origin[1];
|
||||
@ -813,50 +825,62 @@ void SV_RunCmd(usercmd_t *ucmd, int random_seed)
|
||||
sv_player->v.clbasevelocity[1] = sv_player->v.basevelocity[1];
|
||||
sv_player->v.clbasevelocity[2] = sv_player->v.basevelocity[2];
|
||||
}
|
||||
pmove->server = 1;
|
||||
pmove->multiplayer = (qboolean)(g_psvs.maxclients > 1);
|
||||
|
||||
pmove->server = TRUE;
|
||||
pmove->multiplayer = (g_psvs.maxclients > 1) ? TRUE : FALSE;
|
||||
pmove->time = float(1000.0 * host_client->svtimebase);
|
||||
pmove->usehull = (sv_player->v.flags & 0x4000) != 0;
|
||||
pmove->usehull = (sv_player->v.flags & FL_DUCKING) == FL_DUCKING;
|
||||
pmove->maxspeed = sv_maxspeed.value;
|
||||
pmove->clientmaxspeed = sv_player->v.maxspeed;
|
||||
pmove->flDuckTime = (float) sv_player->v.flDuckTime;
|
||||
pmove->flDuckTime = (float)sv_player->v.flDuckTime;
|
||||
pmove->bInDuck = sv_player->v.bInDuck;
|
||||
pmove->flTimeStepSound = sv_player->v.flTimeStepSound;
|
||||
pmove->iStepLeft = sv_player->v.iStepLeft;
|
||||
pmove->flFallVelocity = sv_player->v.flFallVelocity;
|
||||
pmove->flSwimTime = (float)sv_player->v.flSwimTime;
|
||||
pmove->oldbuttons = sv_player->v.oldbuttons;
|
||||
Q_strncpy(pmove->physinfo, host_client->physinfo, 0xFFu);
|
||||
pmove->physinfo[255] = 0;
|
||||
|
||||
Q_strncpy(pmove->physinfo, host_client->physinfo, sizeof(pmove->physinfo) - 1);
|
||||
pmove->physinfo[sizeof(pmove->physinfo) - 1] = 0;
|
||||
|
||||
pmove->velocity[0] = sv_player->v.velocity[0];
|
||||
pmove->velocity[1] = sv_player->v.velocity[1];
|
||||
pmove->velocity[2] = sv_player->v.velocity[2];
|
||||
|
||||
pmove->movedir[0] = sv_player->v.movedir[0];
|
||||
pmove->movedir[1] = sv_player->v.movedir[1];
|
||||
pmove->movedir[2] = sv_player->v.movedir[2];
|
||||
|
||||
pmove->angles[0] = sv_player->v.v_angle[0];
|
||||
pmove->angles[1] = sv_player->v.v_angle[1];
|
||||
pmove->angles[2] = sv_player->v.v_angle[2];
|
||||
|
||||
pmove->basevelocity[0] = sv_player->v.basevelocity[0];
|
||||
pmove->basevelocity[1] = sv_player->v.basevelocity[1];
|
||||
pmove->basevelocity[2] = sv_player->v.basevelocity[2];
|
||||
|
||||
pmove->view_ofs[0] = sv_player->v.view_ofs[0];
|
||||
pmove->view_ofs[1] = sv_player->v.view_ofs[1];
|
||||
pmove->view_ofs[2] = sv_player->v.view_ofs[2];
|
||||
|
||||
pmove->punchangle[0] = sv_player->v.punchangle[0];
|
||||
pmove->punchangle[1] = sv_player->v.punchangle[1];
|
||||
pmove->punchangle[2] = sv_player->v.punchangle[2];
|
||||
|
||||
pmove->deadflag = sv_player->v.deadflag;
|
||||
pmove->effects = sv_player->v.effects;
|
||||
pmove->gravity = sv_player->v.gravity;
|
||||
pmove->friction = sv_player->v.friction;
|
||||
pmove->spectator = 0;
|
||||
pmove->waterjumptime = sv_player->v.teleport_time;
|
||||
|
||||
Q_memcpy(&pmove->cmd, &cmd, sizeof(pmove->cmd));
|
||||
|
||||
pmove->dead = sv_player->v.health <= 0.0;
|
||||
pmove->movetype = sv_player->v.movetype;
|
||||
pmove->flags = sv_player->v.flags;
|
||||
pmove->player_index = NUM_FOR_EDICT(sv_player) - 1;
|
||||
|
||||
pmove->iuser1 = sv_player->v.iuser1;
|
||||
pmove->iuser2 = sv_player->v.iuser2;
|
||||
pmove->iuser3 = sv_player->v.iuser3;
|
||||
@ -865,28 +889,37 @@ void SV_RunCmd(usercmd_t *ucmd, int random_seed)
|
||||
pmove->fuser2 = sv_player->v.fuser2;
|
||||
pmove->fuser3 = sv_player->v.fuser3;
|
||||
pmove->fuser4 = sv_player->v.fuser4;
|
||||
|
||||
pmove->vuser1[0] = sv_player->v.vuser1[0];
|
||||
pmove->vuser1[1] = sv_player->v.vuser1[1];
|
||||
pmove->vuser1[2] = sv_player->v.vuser1[2];
|
||||
|
||||
pmove->vuser2[0] = sv_player->v.vuser2[0];
|
||||
pmove->vuser2[1] = sv_player->v.vuser2[1];
|
||||
pmove->vuser2[2] = sv_player->v.vuser2[2];
|
||||
|
||||
pmove->vuser3[0] = sv_player->v.vuser3[0];
|
||||
pmove->vuser3[1] = sv_player->v.vuser3[1];
|
||||
pmove->vuser3[2] = sv_player->v.vuser3[2];
|
||||
|
||||
pmove->vuser4[0] = sv_player->v.vuser4[0];
|
||||
pmove->vuser4[1] = sv_player->v.vuser4[1];
|
||||
pmove->vuser4[2] = sv_player->v.vuser4[2];
|
||||
|
||||
pmove->origin[0] = sv_player->v.origin[0];
|
||||
pmove->origin[1] = sv_player->v.origin[1];
|
||||
pmove->origin[2] = sv_player->v.origin[2];
|
||||
|
||||
SV_AddLinksToPM(sv_areanodes, pmove->origin);
|
||||
|
||||
pmove->frametime = frametime;
|
||||
pmove->runfuncs = 1;
|
||||
pmove->runfuncs = TRUE;
|
||||
pmove->PM_PlaySound = PM_SV_PlaySound;
|
||||
pmove->PM_TraceTexture = PM_SV_TraceTexture;
|
||||
pmove->PM_PlaybackEventFull = PM_SV_PlaybackEventFull;
|
||||
gEntityInterface.pfnPM_Move(pmove, 1);
|
||||
|
||||
gEntityInterface.pfnPM_Move(pmove, TRUE);
|
||||
|
||||
sv_player->v.deadflag = pmove->deadflag;
|
||||
sv_player->v.effects = pmove->effects;
|
||||
sv_player->v.teleport_time = pmove->waterjumptime;
|
||||
@ -897,15 +930,19 @@ void SV_RunCmd(usercmd_t *ucmd, int random_seed)
|
||||
sv_player->v.movetype = pmove->movetype;
|
||||
sv_player->v.maxspeed = pmove->clientmaxspeed;
|
||||
sv_player->v.iStepLeft = pmove->iStepLeft;
|
||||
|
||||
sv_player->v.view_ofs[0] = pmove->view_ofs[0];
|
||||
sv_player->v.view_ofs[1] = pmove->view_ofs[1];
|
||||
sv_player->v.view_ofs[2] = pmove->view_ofs[2];
|
||||
|
||||
sv_player->v.movedir[0] = pmove->movedir[0];
|
||||
sv_player->v.movedir[1] = pmove->movedir[1];
|
||||
sv_player->v.movedir[2] = pmove->movedir[2];
|
||||
|
||||
sv_player->v.punchangle[0] = pmove->punchangle[0];
|
||||
sv_player->v.punchangle[1] = pmove->punchangle[1];
|
||||
sv_player->v.punchangle[2] = pmove->punchangle[2];
|
||||
|
||||
if (pmove->onground == -1)
|
||||
{
|
||||
sv_player->v.flags &= ~FL_ONGROUND;
|
||||
@ -915,15 +952,19 @@ void SV_RunCmd(usercmd_t *ucmd, int random_seed)
|
||||
sv_player->v.flags |= FL_ONGROUND;
|
||||
sv_player->v.groundentity = EDICT_NUM(pmove->physents[pmove->onground].info);
|
||||
}
|
||||
|
||||
sv_player->v.origin[0] = pmove->origin[0];
|
||||
sv_player->v.origin[1] = pmove->origin[1];
|
||||
sv_player->v.origin[2] = pmove->origin[2];
|
||||
|
||||
sv_player->v.velocity[0] = pmove->velocity[0];
|
||||
sv_player->v.velocity[1] = pmove->velocity[1];
|
||||
sv_player->v.velocity[2] = pmove->velocity[2];
|
||||
|
||||
sv_player->v.basevelocity[0] = pmove->basevelocity[0];
|
||||
sv_player->v.basevelocity[1] = pmove->basevelocity[1];
|
||||
sv_player->v.basevelocity[2] = pmove->basevelocity[2];
|
||||
|
||||
if (!sv_player->v.fixangle)
|
||||
{
|
||||
sv_player->v.v_angle[0] = pmove->angles[0];
|
||||
@ -933,12 +974,14 @@ void SV_RunCmd(usercmd_t *ucmd, int random_seed)
|
||||
sv_player->v.angles[1] = pmove->angles[1];
|
||||
sv_player->v.angles[2] = pmove->angles[2];
|
||||
}
|
||||
|
||||
sv_player->v.bInDuck = pmove->bInDuck;
|
||||
sv_player->v.flDuckTime = (int)pmove->flDuckTime;
|
||||
sv_player->v.flTimeStepSound = pmove->flTimeStepSound;
|
||||
sv_player->v.flFallVelocity = pmove->flFallVelocity;
|
||||
sv_player->v.flSwimTime = (int)pmove->flSwimTime;
|
||||
sv_player->v.oldbuttons = pmove->cmd.buttons;
|
||||
|
||||
sv_player->v.iuser1 = pmove->iuser1;
|
||||
sv_player->v.iuser2 = pmove->iuser2;
|
||||
sv_player->v.iuser3 = pmove->iuser3;
|
||||
@ -947,18 +990,23 @@ void SV_RunCmd(usercmd_t *ucmd, int random_seed)
|
||||
sv_player->v.fuser2 = pmove->fuser2;
|
||||
sv_player->v.fuser3 = pmove->fuser3;
|
||||
sv_player->v.fuser4 = pmove->fuser4;
|
||||
|
||||
sv_player->v.vuser1[0] = pmove->vuser1[0];
|
||||
sv_player->v.vuser1[1] = pmove->vuser1[1];
|
||||
sv_player->v.vuser1[2] = pmove->vuser1[2];
|
||||
|
||||
sv_player->v.vuser2[0] = pmove->vuser2[0];
|
||||
sv_player->v.vuser2[1] = pmove->vuser2[1];
|
||||
sv_player->v.vuser2[2] = pmove->vuser2[2];
|
||||
|
||||
sv_player->v.vuser3[0] = pmove->vuser3[0];
|
||||
sv_player->v.vuser3[1] = pmove->vuser3[1];
|
||||
sv_player->v.vuser3[2] = pmove->vuser3[2];
|
||||
|
||||
sv_player->v.vuser4[0] = pmove->vuser4[0];
|
||||
sv_player->v.vuser4[1] = pmove->vuser4[1];
|
||||
sv_player->v.vuser4[2] = pmove->vuser4[2];
|
||||
|
||||
SetMinMaxSize(sv_player, player_mins[pmove->usehull], player_maxs[pmove->usehull], 0);
|
||||
if (host_client->edict->v.solid)
|
||||
{
|
||||
@ -982,6 +1030,7 @@ void SV_RunCmd(usercmd_t *ucmd, int random_seed)
|
||||
sv_player->v.velocity[1] = vel[1];
|
||||
sv_player->v.velocity[2] = vel[2];
|
||||
}
|
||||
|
||||
gGlobalVariables.time = (float)host_client->svtimebase;
|
||||
gGlobalVariables.frametime = frametime;
|
||||
gEntityInterface.pfnPlayerPostThink(sv_player);
|
||||
|
@ -428,13 +428,12 @@ NOBODY void MaskExceptions(void);
|
||||
|
||||
NOBODY void Sys_Init(void);
|
||||
|
||||
NOXREF void Sys_Sleep(int msec)
|
||||
void Sys_Sleep(int msec)
|
||||
{
|
||||
NOXREFCHECK;
|
||||
#ifdef _WIN32
|
||||
Sleep(msec);
|
||||
#else
|
||||
usleep(1000 *msec);
|
||||
usleep(1000 * msec);
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
|
@ -150,7 +150,7 @@ NOBODY void Sys_PushFPCW_SetHigh(void);
|
||||
NOBODY void Sys_PopFPCW(void);
|
||||
NOBODY void MaskExceptions(void);
|
||||
NOBODY void Sys_Init(void);
|
||||
NOXREF void Sys_Sleep(int msec);
|
||||
void Sys_Sleep(int msec);
|
||||
NOBODY void Sys_DebugOutStraight(const char *pStr);
|
||||
void NORETURN Sys_Error(const char *error, ...);
|
||||
NOXREF void Sys_Warning(const char *pszWarning, ...);
|
||||
|
@ -214,8 +214,8 @@ void TEX_AddAnimatingTextures(void)
|
||||
if (miptex[i][0] != '+' && miptex[i][0] != '-')
|
||||
continue;
|
||||
|
||||
Q_strncpy(name, miptex[i], 0x1Fu);
|
||||
name[31] = 0;
|
||||
Q_strncpy(name, miptex[i], sizeof(name) - 1);
|
||||
name[sizeof(name) - 1] = 0;
|
||||
|
||||
for (int j = 0; j < 20; j++)
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -40,6 +40,9 @@ typedef struct areanode_s
|
||||
link_t solid_edicts;
|
||||
} areanode_t;
|
||||
|
||||
const int AREA_DEPTH = 4;
|
||||
const int AREA_NODES = 32;
|
||||
|
||||
typedef struct moveclip_s // TODO: Move it to world.cpp someday
|
||||
{
|
||||
vec3_t boxmins;
|
||||
@ -57,6 +60,15 @@ typedef struct moveclip_s // TODO: Move it to world.cpp someday
|
||||
qboolean monsterClipBrush;
|
||||
} moveclip_t;
|
||||
|
||||
#define CONTENTS_NONE 0 // no custom contents specified
|
||||
|
||||
#define MOVE_NORMAL 0 // normal trace
|
||||
#define MOVE_NOMONSTERS 1 // ignore monsters (edicts with flags (FL_MONSTER|FL_FAKECLIENT|FL_CLIENT) set)
|
||||
#define MOVE_MISSILE 2 // extra size for monsters
|
||||
|
||||
#define FMOVE_IGNORE_GLASS 0x100
|
||||
#define FMOVE_SIMPLEBOX 0x200
|
||||
|
||||
typedef dclipnode_t box_clipnodes_t[6];
|
||||
typedef mplane_t box_planes_t[6];
|
||||
typedef mplane_t beam_planes_t[6];
|
||||
@ -78,7 +90,7 @@ extern hull_t beam_hull;
|
||||
extern box_clipnodes_t box_clipnodes;
|
||||
extern box_planes_t box_planes;
|
||||
extern beam_planes_t beam_planes;
|
||||
extern areanode_t sv_areanodes[32];
|
||||
extern areanode_t sv_areanodes[AREA_NODES];
|
||||
extern int sv_numareanodes;
|
||||
|
||||
extern cvar_t sv_force_ent_intersection;
|
||||
@ -87,13 +99,13 @@ void ClearLink(link_t *l);
|
||||
void RemoveLink(link_t *l);
|
||||
void InsertLinkBefore(link_t *l, link_t *before);
|
||||
NOXREF void InsertLinkAfter(link_t *l, link_t *after);
|
||||
void SV_InitBoxHull(void);
|
||||
void SV_InitBoxHull();
|
||||
hull_t *SV_HullForBox(const vec_t *mins, const vec_t *maxs);
|
||||
NOXREF hull_t *SV_HullForBeam(const vec_t *start, const vec_t *end, const vec_t *size);
|
||||
struct hull_s *SV_HullForBsp(edict_t *ent, const vec_t *mins, const vec_t *maxs, vec_t *offset);
|
||||
hull_t *SV_HullForBsp(edict_t *ent, const vec_t *mins, const vec_t *maxs, vec_t *offset);
|
||||
hull_t *SV_HullForEntity(edict_t *ent, const vec_t *mins, const vec_t *maxs, vec_t *offset);
|
||||
areanode_t *SV_CreateAreaNode(int depth, vec_t *mins, vec_t *maxs);
|
||||
void SV_ClearWorld(void);
|
||||
void SV_ClearWorld();
|
||||
void SV_UnlinkEdict(edict_t *ent);
|
||||
void SV_TouchLinks(edict_t *ent, areanode_t *node);
|
||||
void SV_FindTouchedLeafs(edict_t *ent, mnode_t *node, int *topnode);
|
||||
|
158
rehlds/filesystem/FileSystem_Stdio/build.gradle
Normal file
158
rehlds/filesystem/FileSystem_Stdio/build.gradle
Normal file
@ -0,0 +1,158 @@
|
||||
import org.doomedsociety.gradlecpp.cfg.ToolchainConfigUtils
|
||||
import org.doomedsociety.gradlecpp.msvc.MsvcToolchainConfig
|
||||
import org.doomedsociety.gradlecpp.toolchain.icc.Icc
|
||||
import org.doomedsociety.gradlecpp.toolchain.icc.IccCompilerPlugin
|
||||
import org.doomedsociety.gradlecpp.gcc.GccToolchainConfig
|
||||
import org.doomedsociety.gradlecpp.GradleCppUtils
|
||||
import org.gradle.nativeplatform.NativeBinarySpec
|
||||
import org.gradle.nativeplatform.NativeLibrarySpec
|
||||
import org.gradle.nativeplatform.toolchain.VisualCpp
|
||||
|
||||
apply plugin: 'cpp'
|
||||
apply plugin: IccCompilerPlugin
|
||||
apply plugin: GccCompilerPlugin
|
||||
|
||||
void setupToolchain(NativeBinarySpec b) {
|
||||
boolean useGcc = project.hasProperty("useGcc")
|
||||
def cfg = rootProject.createToolchainConfig(b);
|
||||
cfg.projectInclude(project, '/../..', '/src', '/../../common', '/../../public', '/../../public/rehlds');
|
||||
cfg.singleDefines 'USE_BREAKPAD_HANDLER'
|
||||
|
||||
if (cfg instanceof MsvcToolchainConfig) {
|
||||
cfg.compilerOptions.pchConfig = new MsvcToolchainConfig.PrecompiledHeadersConfig(
|
||||
enabled: true,
|
||||
pchHeader: 'precompiled.h',
|
||||
pchSourceSet: 'filesystem_pch'
|
||||
);
|
||||
|
||||
cfg.singleDefines('_CRT_SECURE_NO_WARNINGS')
|
||||
cfg.compilerOptions.args '/Ob2', '/Oi', '/GF'
|
||||
}
|
||||
else if (cfg instanceof GccToolchainConfig) {
|
||||
if (!useGcc) {
|
||||
cfg.compilerOptions.pchConfig = new GccToolchainConfig.PrecompilerHeaderOptions(
|
||||
enabled: true,
|
||||
pchSourceSet: 'filesystem_pch'
|
||||
);
|
||||
}
|
||||
|
||||
cfg.compilerOptions.languageStandard = 'c++11'
|
||||
cfg.defines([
|
||||
'_strdup': 'strdup',
|
||||
'_stricmp': 'strcasecmp',
|
||||
'_strnicmp': 'strncasecmp',
|
||||
'_vsnprintf': 'vsnprintf',
|
||||
'_snprintf': 'snprintf',
|
||||
'_unlink': 'unlink',
|
||||
]);
|
||||
|
||||
if (useGcc) {
|
||||
// Produce code optimized for the most common IA32/AMD64/EM64T processors.
|
||||
// As new processors are deployed in the marketplace, the behavior of this option will change.
|
||||
cfg.compilerOptions.args '-mtune=generic', '-Wno-write-strings', '-msse3', '-flto'
|
||||
} else {
|
||||
cfg.compilerOptions.args '-Qoption,cpp,--treat_func_as_string_literal_cpp'
|
||||
}
|
||||
|
||||
cfg.compilerOptions.args '-fno-exceptions'
|
||||
cfg.compilerOptions.interProceduralOptimizations = false;
|
||||
cfg.linkerOptions.interProceduralOptimizations = false;
|
||||
|
||||
def funcToWrap = [
|
||||
"freopen", "fopen", "fopen64", "open", "open64", "creat", "access",
|
||||
"stat", "lstat", "scandir", "opendir", "__xstat", "__lxstat", "__xstat64", "__lxstat64",
|
||||
"chmod", "chown", "lchown", "symlink", "link", "mknod", "mount", "unlink",
|
||||
"mkfifo", "rename", "utime", "utimes", "mkdir", "rmdir"
|
||||
];
|
||||
|
||||
funcToWrap.each {
|
||||
cfg.linkerOptions.args "-Wl,-wrap," + it
|
||||
}
|
||||
}
|
||||
|
||||
ToolchainConfigUtils.apply(project, cfg, b);
|
||||
}
|
||||
|
||||
model {
|
||||
buildTypes {
|
||||
release
|
||||
}
|
||||
|
||||
platforms {
|
||||
x86 {
|
||||
architecture "x86"
|
||||
}
|
||||
}
|
||||
|
||||
toolChains {
|
||||
visualCpp(VisualCpp) {
|
||||
}
|
||||
if (project.hasProperty("useGcc")) {
|
||||
gcc(Gcc)
|
||||
} else {
|
||||
icc(Icc)
|
||||
}
|
||||
}
|
||||
|
||||
components {
|
||||
filesystem(NativeLibrarySpec) {
|
||||
targetPlatform 'x86'
|
||||
baseName 'filesystem_stdio'
|
||||
|
||||
sources {
|
||||
filesystem_main(CppSourceSet) {
|
||||
source {
|
||||
srcDir "src"
|
||||
include "**/*.cpp"
|
||||
exclude "precompiled.cpp"
|
||||
}
|
||||
}
|
||||
|
||||
filesystem_pch(CppSourceSet) {
|
||||
source {
|
||||
srcDir "src"
|
||||
include "precompiled.cpp"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binaries.all {
|
||||
NativeBinarySpec b -> project.setupToolchain(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task buildFinalize << {
|
||||
if (GradleCppUtils.windows) {
|
||||
return;
|
||||
}
|
||||
|
||||
binaries.withType(SharedLibraryBinarySpec) {
|
||||
def sharedBinary = it.getSharedLibraryFile();
|
||||
if (sharedBinary.exists()) {
|
||||
sharedBinary.renameTo(new File(sharedBinary.getParent() + "/" + sharedBinary.getName().replaceFirst("^lib", "")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task buildFixes {
|
||||
dependsOn binaries.withType(SharedLibraryBinarySpec).matching { SharedLibraryBinarySpec blib ->
|
||||
blib.buildable && blib.buildType.name == 'release'
|
||||
}
|
||||
}
|
||||
|
||||
task buildRelease {
|
||||
dependsOn binaries.withType(SharedLibraryBinarySpec).matching { SharedLibraryBinarySpec blib ->
|
||||
blib.buildable && blib.buildType.name == 'release'
|
||||
}
|
||||
}
|
||||
|
||||
build.finalizedBy(buildFinalize);
|
||||
buildFixes.finalizedBy(buildFinalize);
|
||||
buildRelease.finalizedBy(buildFinalize);
|
||||
|
||||
// prevent static lib building
|
||||
binaries.withType(StaticLibraryBinarySpec) { binary ->
|
||||
buildable = false
|
||||
}
|
39
rehlds/filesystem/FileSystem_Stdio/msvc/PostBuild.bat
Normal file
39
rehlds/filesystem/FileSystem_Stdio/msvc/PostBuild.bat
Normal file
@ -0,0 +1,39 @@
|
||||
@echo OFF
|
||||
::
|
||||
:: Post-build auto-deploy script
|
||||
:: Create and fill PublishPath.txt file with path to deployment folder
|
||||
:: I.e. PublishPath.txt should contain one line with a folder path
|
||||
:: Call it so:
|
||||
:: IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)")
|
||||
::
|
||||
|
||||
SET targetDir=%~1
|
||||
SET targetName=%~2
|
||||
SET targetExt=%~3
|
||||
SET projectDir=%~4
|
||||
SET destination=
|
||||
|
||||
IF NOT EXIST "%projectDir%\PublishPath.txt" (
|
||||
ECHO No deployment path specified. Create PublishPath.txt near PostBuild.bat with paths on separate lines for auto deployment.
|
||||
exit /B 0
|
||||
)
|
||||
|
||||
FOR /f "tokens=* delims= usebackq" %%a IN ("%projectDir%\PublishPath.txt") DO (
|
||||
ECHO Deploying to: %%a
|
||||
IF NOT "%%a" == "" (
|
||||
copy /Y "%targetDir%%targetName%%targetExt%" "%%a"
|
||||
IF NOT ERRORLEVEL 1 (
|
||||
IF EXIST "%targetDir%%targetName%.pdb" (
|
||||
copy /Y "%targetDir%%targetName%.pdb" "%%a"
|
||||
)
|
||||
) ELSE (
|
||||
ECHO PostBuild.bat ^(27^) : warning : Can't copy '%targetName%%targetExt%' to deploy path '%%a'
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
IF "%%a" == "" (
|
||||
ECHO No deployment path specified.
|
||||
)
|
||||
|
||||
exit /B 0
|
22
rehlds/filesystem/FileSystem_Stdio/msvc/filesystem_stdio.sln
Normal file
22
rehlds/filesystem/FileSystem_Stdio/msvc/filesystem_stdio.sln
Normal file
@ -0,0 +1,22 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "filesystem_stdio", "filesystem_stdio.vcxproj", "{A428392F-52FB-489E-87D8-623528C7F4F9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{A428392F-52FB-489E-87D8-623528C7F4F9}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
174
rehlds/filesystem/FileSystem_Stdio/msvc/filesystem_stdio.vcxproj
Normal file
174
rehlds/filesystem/FileSystem_Stdio/msvc/filesystem_stdio.vcxproj
Normal file
@ -0,0 +1,174 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{A428392F-52FB-489E-87D8-623528C7F4F9}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>filesystem_stdio</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)' == '12.0'">v120_xp</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)' == '14.0'">v140_xp</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141_xp</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)' == '12.0'">v120_xp</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)' == '14.0'">v140_xp</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141_xp</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_WINDOWS;USE_BREAKPAD_HANDLER;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\src;$(ProjectDir)..\..\..\;$(ProjectDir)..\..\..\common;$(ProjectDir)..\..\..\public;$(ProjectDir)..\..\..\public\rehlds;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
<InlineFunctionExpansion>Default</InlineFunctionExpansion>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<FunctionLevelLinking>
|
||||
</FunctionLevelLinking>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>psapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)")</Command>
|
||||
<Message>Automatic deployment script</Message>
|
||||
</PostBuildEvent>
|
||||
<CustomBuildStep>
|
||||
<Command>echo Empty Action</Command>
|
||||
</CustomBuildStep>
|
||||
<CustomBuildStep>
|
||||
<Message>Force build to run Pre-Build event</Message>
|
||||
</CustomBuildStep>
|
||||
<CustomBuildStep>
|
||||
<Outputs>build.always.run</Outputs>
|
||||
</CustomBuildStep>
|
||||
<CustomBuildStep>
|
||||
<Inputs>build.always.run</Inputs>
|
||||
</CustomBuildStep>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;_WINDOWS;USE_BREAKPAD_HANDLER;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\src;$(ProjectDir)..\..\..\;$(ProjectDir)..\..\..\common;$(ProjectDir)..\..\..\public;$(ProjectDir)..\..\..\public\rehlds;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>psapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)")</Command>
|
||||
<Message>Automatic deployment script</Message>
|
||||
</PostBuildEvent>
|
||||
<CustomBuildStep>
|
||||
<Command>echo Empty Action</Command>
|
||||
</CustomBuildStep>
|
||||
<CustomBuildStep>
|
||||
<Message>Force build to run Pre-Build event</Message>
|
||||
</CustomBuildStep>
|
||||
<CustomBuildStep>
|
||||
<Outputs>build.always.run</Outputs>
|
||||
</CustomBuildStep>
|
||||
<CustomBuildStep>
|
||||
<Inputs>build.always.run</Inputs>
|
||||
</CustomBuildStep>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\hookers\filesystem\hooklist.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\hookers\filesystem\main.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\BaseFileSystem.cpp" />
|
||||
<ClCompile Include="..\src\filesystem_helpers.cpp" />
|
||||
<ClCompile Include="..\src\FileSystem_Stdio.cpp" />
|
||||
<ClCompile Include="..\src\linux_support.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\pathmatch.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\precompiled.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\public_amalgamation.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\hookers\filesystem\hooklist.h">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\BaseFileSystem.h" />
|
||||
<ClInclude Include="..\src\filesystem_helpers.h" />
|
||||
<ClInclude Include="..\src\FileSystem_Stdio.h" />
|
||||
<ClInclude Include="..\src\linux_support.h">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\precompiled.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="src">
|
||||
<UniqueIdentifier>{3f7611e3-cf43-4956-a8a1-b6efbcf1a63d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="hookers">
|
||||
<UniqueIdentifier>{cacc7b07-9ac2-42d5-bba3-14c061a19d11}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\src\BaseFileSystem.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\FileSystem_Stdio.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\linux_support.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\pathmatch.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\precompiled.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\public_amalgamation.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\filesystem_helpers.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\hookers\filesystem\hooklist.cpp">
|
||||
<Filter>hookers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\hookers\filesystem\main.cpp">
|
||||
<Filter>hookers</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\src\BaseFileSystem.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\linux_support.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\precompiled.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\filesystem_helpers.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\hookers\filesystem\hooklist.h">
|
||||
<Filter>hookers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\FileSystem_Stdio.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
1676
rehlds/filesystem/FileSystem_Stdio/src/BaseFileSystem.cpp
Normal file
1676
rehlds/filesystem/FileSystem_Stdio/src/BaseFileSystem.cpp
Normal file
File diff suppressed because it is too large
Load Diff
378
rehlds/filesystem/FileSystem_Stdio/src/BaseFileSystem.h
Normal file
378
rehlds/filesystem/FileSystem_Stdio/src/BaseFileSystem.h
Normal file
@ -0,0 +1,378 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <FileSystem.h>
|
||||
#include "filesystem_helpers.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h> // mkdir
|
||||
#else
|
||||
#include <unistd.h> // unlink
|
||||
#include "linux_support.h"
|
||||
|
||||
// undo the prepended "_" 's
|
||||
#define _chmod chmod
|
||||
#define _stat stat
|
||||
#define _alloca alloca
|
||||
#define _S_IFDIR S_IFDIR
|
||||
|
||||
#define HANDLE int
|
||||
#define INVALID_HANDLE_VALUE ((HANDLE)~0)
|
||||
#endif // _WIN32
|
||||
|
||||
#include "utlsymbol.h"
|
||||
|
||||
class CBaseFileSystem: public IFileSystem {
|
||||
public:
|
||||
CBaseFileSystem();
|
||||
virtual ~CBaseFileSystem() {};
|
||||
|
||||
// Mount and unmount the filesystem
|
||||
virtual void Mount();
|
||||
virtual void Unmount();
|
||||
|
||||
// opens a file
|
||||
// if pathID is NULL, all paths will be searched for the file
|
||||
virtual FileHandle_t Open(const char *pFileName, const char *pOptions, const char *pathID = 0L);
|
||||
|
||||
// open a file but force the data to come from the steam cache, NOT from disk
|
||||
virtual FileHandle_t OpenFromCacheForRead(const char *pFileName, const char *pOptions, const char *pathID = 0L);
|
||||
|
||||
virtual void Close(FileHandle_t file);
|
||||
|
||||
virtual void Seek(FileHandle_t file, int pos, FileSystemSeek_t seekType);
|
||||
virtual size_t Tell(FileHandle_t file);
|
||||
|
||||
virtual size_t Size(FileHandle_t file);
|
||||
virtual size_t Size(const char *pFileName);
|
||||
|
||||
virtual bool IsOk(FileHandle_t file);
|
||||
|
||||
virtual void Flush(FileHandle_t file);
|
||||
virtual bool EndOfFile(FileHandle_t file);
|
||||
|
||||
virtual int Read(void* pOutput, int size, FileHandle_t file);
|
||||
virtual int Write(void const* pInput, int size, FileHandle_t file);
|
||||
virtual char *ReadLine(char *pOutput, int maxChars, FileHandle_t file);
|
||||
virtual int FPrintf(FileHandle_t file, const char *fmt, ...);
|
||||
|
||||
// direct filesystem buffer access
|
||||
// returns a handle to a buffer containing the file data
|
||||
// this is the optimal way to access the complete data for a file,
|
||||
// since the file preloader has probably already got it in memory
|
||||
virtual void *GetReadBuffer(FileHandle_t file, int *outBufferSize, bool failIfNotInCache);
|
||||
virtual void ReleaseReadBuffer(FileHandle_t file, void *readBuffer);
|
||||
|
||||
// Gets the current working directory
|
||||
virtual bool GetCurrentDirectory(char* pDirectory, int maxlen);
|
||||
|
||||
// this isn't implementable on STEAM as is.
|
||||
virtual void CreateDirHierarchy(const char *path, const char *pathID);
|
||||
|
||||
// File I/O and info
|
||||
virtual bool IsDirectory(const char *pFileName);
|
||||
virtual const char *GetLocalPath(const char *pFileName, char *pLocalPath, int localPathBufferSize);
|
||||
|
||||
// Deletes a file
|
||||
virtual void RemoveFile(const char *pRelativePath, const char *pathID);
|
||||
|
||||
// Remove all search paths (including write path?)
|
||||
virtual void RemoveAllSearchPaths();
|
||||
|
||||
// Add paths in priority order (mod dir, game dir, ....)
|
||||
// If one or more .pak files are in the specified directory, then they are
|
||||
// added after the file system path
|
||||
// If the path is the relative path to a .bsp file, then any previous .bsp file
|
||||
// override is cleared and the current .bsp is searched for an embedded PAK file
|
||||
// and this file becomes the highest priority search path (i.e., it's looked at first
|
||||
// even before the mod's file system path).
|
||||
virtual void AddSearchPath(const char *pPath, const char *pathID);
|
||||
virtual bool RemoveSearchPath(const char *pPath);
|
||||
|
||||
virtual bool FileExists(const char *pFileName);
|
||||
|
||||
virtual long GetFileTime(const char *pFileName);
|
||||
virtual void FileTimeToString(char* pStrip, int maxCharsIncludingTerminator, long fileTime);
|
||||
|
||||
// FindFirst/FindNext
|
||||
virtual const char *FindFirst(const char *pWildCard, FileFindHandle_t *pHandle, const char *pathID = 0L);
|
||||
virtual const char *FindNext(FileFindHandle_t handle);
|
||||
virtual bool FindIsDirectory(FileFindHandle_t handle);
|
||||
virtual void FindClose(FileFindHandle_t handle);
|
||||
|
||||
// Note: This is sort of a secondary feature; but it's really useful to have it here
|
||||
virtual char *ParseFile(char* pFileBytes, char* pToken, bool* pWasQuoted);
|
||||
|
||||
// Returns true on success (based on current list of search paths, otherwise false if it can't be resolved)
|
||||
virtual bool FullPathToRelativePath(const char *pFullpath, char *pRelative);
|
||||
|
||||
// Dump to printf/OutputDebugString the list of files that have not been closed
|
||||
virtual void PrintOpenedFiles();
|
||||
|
||||
virtual void SetWarningFunc(WarningFunc_t pfnWarning);
|
||||
virtual void SetWarningLevel(FileWarningLevel_t level);
|
||||
|
||||
// interface for custom pack files > 4Gb
|
||||
virtual bool AddPackFile(const char *fullpath, const char *pathID);
|
||||
|
||||
FILE *Trace_FOpen(const char *filename, const char *options, bool bFromCache = false);
|
||||
void Trace_FClose(FILE *fp);
|
||||
void Trace_DumpUnclosedFiles();
|
||||
|
||||
// Purpose: Functions implementing basic file system behavior.
|
||||
virtual FILE *FS_fopen(const char *filename, const char *options, bool bFromCache = false) = 0;
|
||||
virtual void FS_fclose(FILE *fp) = 0;
|
||||
virtual void FS_fseek(FILE *fp, int64_t pos, FileSystemSeek_t seekType) = 0;
|
||||
virtual size_t FS_ftell(FILE *fp) = 0;
|
||||
virtual int FS_feof(FILE *fp) = 0;
|
||||
virtual size_t FS_fread(void *dest, size_t count, size_t size, FILE *fp) = 0;
|
||||
virtual size_t FS_fwrite(const void *src, size_t count, size_t size, FILE *fp) = 0;
|
||||
virtual size_t FS_vfprintf(FILE *fp, const char *fmt, va_list list) = 0;
|
||||
virtual int FS_ferror(FILE *fp) = 0;
|
||||
virtual int FS_fflush(FILE *fp) = 0;
|
||||
virtual char *FS_fgets(char *dest, int destSize, FILE *fp) = 0;
|
||||
virtual int FS_stat(const char *path, struct _stat *buf) = 0;
|
||||
virtual HANDLE FS_FindFirstFile(char *findname, WIN32_FIND_DATA *dat) = 0;
|
||||
virtual bool FS_FindNextFile(HANDLE handle, WIN32_FIND_DATA *dat) = 0;
|
||||
virtual bool FS_FindClose(HANDLE handle) = 0;
|
||||
virtual bool IsThreadSafe() = 0;
|
||||
virtual bool IsFileImmediatelyAvailable(const char *pFileName) = 0;
|
||||
|
||||
protected:
|
||||
// structures for building pack files
|
||||
#pragma pack(1)
|
||||
typedef struct
|
||||
{
|
||||
char name[56];
|
||||
int filepos;
|
||||
int filelen;
|
||||
} packfile_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char id[4];
|
||||
int dirofs;
|
||||
int dirlen;
|
||||
} packheader_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[112];
|
||||
int64_t filepos;
|
||||
int64_t filelen;
|
||||
} packfile64_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char id[4];
|
||||
int64_t dirofs;
|
||||
int64_t dirlen;
|
||||
} packheader64_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char id[8];
|
||||
int64_t packheaderpos;
|
||||
int64_t originalfilesize;
|
||||
} packappenededheader_t;
|
||||
#pragma pack()
|
||||
|
||||
// A Pack file directory entry:
|
||||
class CPackFileEntry
|
||||
{
|
||||
public:
|
||||
CUtlSymbol m_Name;
|
||||
int64_t m_nPosition;
|
||||
int64_t m_nLength;
|
||||
};
|
||||
|
||||
class CFileHandle
|
||||
{
|
||||
public:
|
||||
FILE* m_pFile;
|
||||
bool m_bPack;
|
||||
bool m_bErrorFlagged;
|
||||
int64_t m_nStartOffset;
|
||||
int64_t m_nLength;
|
||||
long m_nFileTime;
|
||||
};
|
||||
|
||||
enum { MAX_FILES_IN_PACK = 32768 };
|
||||
class CSearchPath
|
||||
{
|
||||
public:
|
||||
CSearchPath();
|
||||
~CSearchPath();
|
||||
|
||||
// Path ID ("game", "mod", "gamebin") accessors.
|
||||
void SetPathID(CUtlSymbol id);
|
||||
const CUtlSymbol &GetPathID() const;
|
||||
|
||||
// Search path (c:\hl\hl) accessors.
|
||||
void SetPath(CUtlSymbol id);
|
||||
const CUtlSymbol &GetPath() const;
|
||||
|
||||
void SetWritePath(bool st);
|
||||
|
||||
bool IsAllowWrite() const;
|
||||
bool IsPackFile() const;
|
||||
bool IsMapPath() const;
|
||||
|
||||
private:
|
||||
friend class CBaseFileSystem;
|
||||
|
||||
CUtlSymbol m_Path;
|
||||
CUtlSymbol m_PathID;
|
||||
|
||||
bool m_bIsMapPath;
|
||||
bool m_bIsPackFile;
|
||||
|
||||
long m_lPackFileTime;
|
||||
CFileHandle* m_hPackFile;
|
||||
int m_nNumPackFiles;
|
||||
size_t m_iCurSearchFile;
|
||||
bool m_bAllowWrite;
|
||||
|
||||
enum { MAX_ENTRY_PATH = 32 };
|
||||
|
||||
// Entries to the individual files stored inside the pack file.
|
||||
CUtlRBTree<CPackFileEntry, int> m_PackFiles;
|
||||
static bool PackFileLessFunc(CPackFileEntry const &src1, CPackFileEntry const &src2);
|
||||
};
|
||||
|
||||
// Purpose: For tracking unclosed files
|
||||
// NOTE: The symbol table could take up memory that we don't want to eat here.
|
||||
// In that case, we shouldn't store them in a table, or we should store them as locally allocates stings
|
||||
// so we can control the size
|
||||
class COpenedFile
|
||||
{
|
||||
public:
|
||||
COpenedFile();
|
||||
~COpenedFile();
|
||||
|
||||
COpenedFile(COpenedFile const &src);
|
||||
bool operator==(COpenedFile const &src) const;
|
||||
|
||||
void SetName(char const *name);
|
||||
const char *GetName();
|
||||
|
||||
FILE *m_pFile;
|
||||
char *m_pName;
|
||||
};
|
||||
|
||||
struct FindData_t
|
||||
{
|
||||
WIN32_FIND_DATA m_FindData;
|
||||
int m_CurrentSearchPathID;
|
||||
int m_LimitedPathID;
|
||||
CUtlVector<char> m_WildCardString;
|
||||
HANDLE m_FindHandle;
|
||||
};
|
||||
|
||||
virtual void AddSearchPathNoWrite(const char *pPath, const char *pathID);
|
||||
void AddSearchPathInternal(const char *pPath, const char *pathID, bool bAllowWrite);
|
||||
|
||||
void Warning(FileWarningLevel_t level, const char *fmt, ...);
|
||||
void FixSlashes(char *str);
|
||||
void FixPath(char *str);
|
||||
void StripFilename(char *path);
|
||||
CSearchPath *GetWritePath(const char *pathID);
|
||||
FileHandle_t FindFile(CSearchPath *path, const char *pFileName, const char *pOptions, bool bFromCache = false);
|
||||
int FastFindFileSize(CSearchPath *path, const char *pFileName);
|
||||
void RemoveAllMapSearchPaths();
|
||||
void AddPackFiles(const char *pPath);
|
||||
bool AddPackFileFromPath(const char *pPath, const char *pakfile, bool bCheckForAppendedPack, const char *pathID);
|
||||
bool PreparePackFile(CSearchPath &packfile, int64_t offsetofpackinmetafile);
|
||||
bool Prepare64BitPackFile(CSearchPath &packfile, int64_t offsetofpackinmetafile);
|
||||
const char *SearchPakFile(const char *pWildCard, int currentSearchPathID, bool first = true);
|
||||
bool FileInSearchPaths(const char *pSearchWildcard, const char *pFileName, int minSearchPathID, int maxSearchPathID);
|
||||
bool FindNextFileHelper(FindData_t *pFindData);
|
||||
const char *FindFirstHelper(const char *pWildCard, FileFindHandle_t *pHandle, int searchPath, FindData_t *pFindData);
|
||||
|
||||
public:
|
||||
static CBaseFileSystem *s_pFileSystem;
|
||||
|
||||
protected:
|
||||
CUtlVector<COpenedFile> m_OpenedFiles;
|
||||
static bool OpenedFileLessFunc(COpenedFile const &src1, COpenedFile const &src2);
|
||||
|
||||
CUtlVector<FILE *> m_PackFileHandles;
|
||||
CUtlVector<FindData_t> m_FindData;
|
||||
CUtlVector<CSearchPath> m_SearchPaths;
|
||||
|
||||
FileWarningLevel_t m_fwLevel;
|
||||
WarningFunc_t m_pfnWarning;
|
||||
|
||||
int m_nOpenCount;
|
||||
};
|
||||
|
||||
// singleton accessor
|
||||
CBaseFileSystem *BaseFileSystem();
|
||||
|
||||
// Inlines
|
||||
inline void CBaseFileSystem::CSearchPath::SetPathID(CUtlSymbol sym)
|
||||
{
|
||||
m_PathID = sym;
|
||||
}
|
||||
|
||||
inline const CUtlSymbol &CBaseFileSystem::CSearchPath::GetPathID() const
|
||||
{
|
||||
return m_PathID;
|
||||
}
|
||||
|
||||
inline void CBaseFileSystem::CSearchPath::SetPath(CUtlSymbol id)
|
||||
{
|
||||
m_Path = id;
|
||||
}
|
||||
|
||||
inline const CUtlSymbol &CBaseFileSystem::CSearchPath::GetPath() const
|
||||
{
|
||||
return m_Path;
|
||||
}
|
||||
|
||||
inline void CBaseFileSystem::CSearchPath::SetWritePath(bool st)
|
||||
{
|
||||
m_bAllowWrite = st;
|
||||
}
|
||||
|
||||
inline bool CBaseFileSystem::CSearchPath::IsAllowWrite() const
|
||||
{
|
||||
return m_bAllowWrite;
|
||||
}
|
||||
|
||||
inline bool CBaseFileSystem::CSearchPath::IsPackFile() const
|
||||
{
|
||||
return m_bIsPackFile;
|
||||
}
|
||||
|
||||
inline bool CBaseFileSystem::CSearchPath::IsMapPath() const
|
||||
{
|
||||
return m_bIsMapPath;
|
||||
}
|
232
rehlds/filesystem/FileSystem_Stdio/src/FileSystem_Stdio.cpp
Normal file
232
rehlds/filesystem/FileSystem_Stdio/src/FileSystem_Stdio.cpp
Normal file
@ -0,0 +1,232 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
CFileSystem_Stdio::CFileSystem_Stdio()
|
||||
{
|
||||
m_bMounted = false;
|
||||
}
|
||||
|
||||
CFileSystem_Stdio::~CFileSystem_Stdio()
|
||||
{
|
||||
RemoveAllSearchPaths();
|
||||
Trace_DumpUnclosedFiles();
|
||||
}
|
||||
|
||||
void CFileSystem_Stdio::Mount()
|
||||
{
|
||||
m_bMounted = true;
|
||||
CBaseFileSystem::Mount();
|
||||
}
|
||||
|
||||
void CFileSystem_Stdio::Unmount()
|
||||
{
|
||||
m_bMounted = false;
|
||||
CBaseFileSystem::Unmount();
|
||||
}
|
||||
|
||||
// low-level filesystem wrapper
|
||||
FILE *CFileSystem_Stdio::FS_fopen(const char *filename, const char *options, bool bFromCache)
|
||||
{
|
||||
FILE *tst = fopen(filename, options);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (!tst && !Q_strchr(options, 'w') && !Q_strchr(options, '+')) {
|
||||
const char *file = findFileInDirCaseInsensitive(filename);
|
||||
tst = fopen(filename, options);
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
return tst;
|
||||
}
|
||||
|
||||
void CFileSystem_Stdio::FS_fclose(FILE *fp)
|
||||
{
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void CFileSystem_Stdio::FS_fseek(FILE *fp, int64_t pos, FileSystemSeek_t seekType)
|
||||
{
|
||||
fseek(fp, pos, seekType);
|
||||
}
|
||||
|
||||
size_t CFileSystem_Stdio::FS_ftell(FILE *fp)
|
||||
{
|
||||
return ftell(fp);
|
||||
}
|
||||
|
||||
int CFileSystem_Stdio::FS_feof(FILE *fp)
|
||||
{
|
||||
return feof(fp);
|
||||
}
|
||||
|
||||
size_t CFileSystem_Stdio::FS_fread(void *dest, size_t count, size_t size, FILE *fp)
|
||||
{
|
||||
return fread(dest, count, size, fp);
|
||||
}
|
||||
|
||||
size_t CFileSystem_Stdio::FS_fwrite(const void *src, size_t count, size_t size, FILE *fp)
|
||||
{
|
||||
return fwrite(src, count, size, fp);
|
||||
}
|
||||
|
||||
size_t CFileSystem_Stdio::FS_vfprintf(FILE *fp, const char *fmt, va_list list)
|
||||
{
|
||||
return vfprintf(fp, fmt, list);
|
||||
}
|
||||
|
||||
int CFileSystem_Stdio::FS_ferror(FILE *fp)
|
||||
{
|
||||
return ferror(fp);
|
||||
}
|
||||
|
||||
int CFileSystem_Stdio::FS_fflush(FILE *fp)
|
||||
{
|
||||
return fflush(fp);
|
||||
}
|
||||
|
||||
char *CFileSystem_Stdio::FS_fgets(char *dest, int destSize, FILE *fp)
|
||||
{
|
||||
return fgets(dest, destSize, fp);
|
||||
}
|
||||
|
||||
int CFileSystem_Stdio::FS_stat(const char *path, struct _stat *buf)
|
||||
{
|
||||
int rt = _stat(path, buf);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (rt == -1)
|
||||
{
|
||||
const char *file = findFileInDirCaseInsensitive(path);
|
||||
if (file) {
|
||||
rt = _stat(file, buf);
|
||||
}
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
HANDLE CFileSystem_Stdio::FS_FindFirstFile(char *findname, WIN32_FIND_DATA *dat)
|
||||
{
|
||||
return ::FindFirstFile(findname, dat);
|
||||
}
|
||||
|
||||
bool CFileSystem_Stdio::FS_FindNextFile(HANDLE handle, WIN32_FIND_DATA *dat)
|
||||
{
|
||||
return (::FindNextFile(handle, dat) != 0);
|
||||
}
|
||||
|
||||
bool CFileSystem_Stdio::FS_FindClose(HANDLE handle)
|
||||
{
|
||||
return (::FindClose(handle) != 0);
|
||||
}
|
||||
|
||||
bool CFileSystem_Stdio::IsThreadSafe()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CFileSystem_Stdio::IsFileImmediatelyAvailable(const char *pFileName)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void CFileSystem_Stdio::GetLocalCopy(const char *pFileName)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void CFileSystem_Stdio::LogLevelLoadFinished(const char *name)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void CFileSystem_Stdio::LogLevelLoadStarted(const char *name)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
int CFileSystem_Stdio::HintResourceNeed(const char *hintlist, int forgetEverything)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CFileSystem_Stdio::PauseResourcePreloading()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CFileSystem_Stdio::ResumeResourcePreloading()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CFileSystem_Stdio::SetVBuf(FileHandle_t stream, char *buffer, int mode, long size)
|
||||
{
|
||||
CFileHandle *fh = reinterpret_cast<CFileHandle *>(stream);
|
||||
if (!fh) {
|
||||
Warning(FILESYSTEM_WARNING, "FS: Tried to SetVBuf NULL file handle!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return setvbuf(fh->m_pFile, buffer, mode, size);
|
||||
}
|
||||
|
||||
void CFileSystem_Stdio::GetInterfaceVersion(char *p, int maxlen)
|
||||
{
|
||||
Q_strncpy(p, "Stdio", maxlen);
|
||||
}
|
||||
|
||||
WaitForResourcesHandle_t CFileSystem_Stdio::WaitForResources(const char *resourcelist)
|
||||
{
|
||||
return (WaitForResourcesHandle_t)FILESYSTEM_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
bool CFileSystem_Stdio::GetWaitForResourcesProgress(WaitForResourcesHandle_t handle, float *progress, bool *complete)
|
||||
{
|
||||
if (progress) *progress = 0;
|
||||
if (complete) *complete = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CFileSystem_Stdio::CancelWaitForResources(WaitForResourcesHandle_t handle)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
bool CFileSystem_Stdio::IsAppReadyForOfflinePlay(int appID)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef HOOK_FILESYSTEM
|
||||
EXPOSE_SINGLE_INTERFACE(CFileSystem_Stdio, IFileSystem, FILESYSTEM_INTERFACE_VERSION);
|
||||
#endif // HOOK_FILESYSTEM
|
91
rehlds/filesystem/FileSystem_Stdio/src/FileSystem_Stdio.h
Normal file
91
rehlds/filesystem/FileSystem_Stdio/src/FileSystem_Stdio.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BaseFileSystem.h"
|
||||
#include "linux_support.h"
|
||||
|
||||
class CFileSystem_Stdio: public CBaseFileSystem
|
||||
{
|
||||
public:
|
||||
CFileSystem_Stdio();
|
||||
virtual ~CFileSystem_Stdio();
|
||||
|
||||
// Mount and unmount the filesystem
|
||||
virtual void Mount();
|
||||
virtual void Unmount();
|
||||
|
||||
virtual void GetLocalCopy(const char *pFileName);
|
||||
|
||||
virtual void LogLevelLoadStarted(const char *name);
|
||||
virtual void LogLevelLoadFinished(const char *name);
|
||||
virtual int HintResourceNeed(const char *hintlist, int forgetEverything);
|
||||
virtual int PauseResourcePreloading();
|
||||
virtual int ResumeResourcePreloading();
|
||||
virtual int SetVBuf(FileHandle_t stream, char *buffer, int mode, long size);
|
||||
virtual void GetInterfaceVersion(char *p, int maxlen);
|
||||
|
||||
// starts waiting for resources to be available
|
||||
// returns FILESYSTEM_INVALID_HANDLE if there is nothing to wait on
|
||||
virtual WaitForResourcesHandle_t WaitForResources(const char *resourcelist);
|
||||
|
||||
// get progress on waiting for resources; progress is a float [0, 1], complete is true on the waiting being done
|
||||
// returns false if no progress is available
|
||||
// any calls after complete is true or on an invalid handle will return false, 0.0f, true
|
||||
virtual bool GetWaitForResourcesProgress(WaitForResourcesHandle_t handle, float *progress /* out */ , bool *complete /* out */);
|
||||
|
||||
// cancels a progress call
|
||||
virtual void CancelWaitForResources(WaitForResourcesHandle_t handle);
|
||||
|
||||
// returns true if the appID has all its caches fully preloaded
|
||||
virtual bool IsAppReadyForOfflinePlay(int appID);
|
||||
|
||||
protected:
|
||||
// implementation of CBaseFileSystem virtual functions
|
||||
virtual FILE *FS_fopen(const char *filename, const char *options, bool bFromCache = false);
|
||||
virtual void FS_fclose(FILE *fp);
|
||||
virtual void FS_fseek(FILE *fp, int64_t pos, FileSystemSeek_t seekType);
|
||||
virtual size_t FS_ftell(FILE *fp);
|
||||
virtual int FS_feof(FILE *fp);
|
||||
virtual size_t FS_fread(void *dest, size_t count, size_t size, FILE *fp);
|
||||
virtual size_t FS_fwrite(const void *src, size_t count, size_t size, FILE *fp);
|
||||
virtual size_t FS_vfprintf(FILE *fp, const char *fmt, va_list list);
|
||||
virtual int FS_ferror(FILE *fp);
|
||||
virtual int FS_fflush(FILE *fp);
|
||||
virtual char *FS_fgets(char *dest, int destSize, FILE *fp);
|
||||
virtual int FS_stat(const char *path, struct _stat *buf);
|
||||
virtual HANDLE FS_FindFirstFile(char *findname, WIN32_FIND_DATA *dat);
|
||||
virtual bool FS_FindNextFile(HANDLE handle, WIN32_FIND_DATA *dat);
|
||||
virtual bool FS_FindClose(HANDLE handle);
|
||||
virtual bool IsThreadSafe();
|
||||
virtual bool IsFileImmediatelyAvailable(const char *pFileName);
|
||||
|
||||
private:
|
||||
bool m_bMounted;
|
||||
};
|
178
rehlds/filesystem/FileSystem_Stdio/src/filesystem_helpers.cpp
Normal file
178
rehlds/filesystem/FileSystem_Stdio/src/filesystem_helpers.cpp
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
// wordbreak parsing set
|
||||
characterset_t g_BreakSet, g_BreakSetIncludingColons;
|
||||
|
||||
void InitializeCharacterSets()
|
||||
{
|
||||
static bool s_CharacterSetInitialized = false;
|
||||
if (!s_CharacterSetInitialized)
|
||||
{
|
||||
CharacterSetBuild(&g_BreakSet, "{}()'");
|
||||
CharacterSetBuild(&g_BreakSetIncludingColons, "{}()':");
|
||||
s_CharacterSetInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
const char *ParseFile(const char *pFileBytes, char *pToken, bool *pWasQuoted, characterset_t *pCharSet)
|
||||
{
|
||||
if (pWasQuoted)
|
||||
*pWasQuoted = false;
|
||||
|
||||
if (!pFileBytes)
|
||||
return nullptr;
|
||||
|
||||
InitializeCharacterSets();
|
||||
|
||||
// YWB: Ignore colons as token separators in COM_Parse
|
||||
static const bool com_ignorecolons = false;
|
||||
characterset_t &breaks = pCharSet ? *pCharSet : (com_ignorecolons ? g_BreakSet : g_BreakSetIncludingColons);
|
||||
|
||||
int c;
|
||||
int len = 0;
|
||||
pToken[0] = '\0';
|
||||
|
||||
skipwhite:
|
||||
// skip whitespace
|
||||
while ((c = *pFileBytes) <= ' ')
|
||||
{
|
||||
if (c == 0)
|
||||
{
|
||||
// end of file;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
pFileBytes++;
|
||||
}
|
||||
|
||||
// skip // comments till the next line
|
||||
if (c == '/' && pFileBytes[1] == '/')
|
||||
{
|
||||
while (*pFileBytes && *pFileBytes != '\n')
|
||||
pFileBytes++;
|
||||
goto skipwhite; // start over new line
|
||||
}
|
||||
|
||||
// skip c-style comments
|
||||
if (c == '/' && pFileBytes[1] == '*')
|
||||
{
|
||||
// Skip "/*"
|
||||
pFileBytes += 2;
|
||||
|
||||
while (*pFileBytes)
|
||||
{
|
||||
if (*pFileBytes == '*' && pFileBytes[1] == '/')
|
||||
{
|
||||
pFileBytes += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
pFileBytes++;
|
||||
}
|
||||
|
||||
goto skipwhite;
|
||||
}
|
||||
|
||||
// handle quoted strings specially: copy till the end or another quote
|
||||
if (c == '\"')
|
||||
{
|
||||
if (pWasQuoted)
|
||||
*pWasQuoted = true;
|
||||
|
||||
pFileBytes++; // skip starting quote
|
||||
while (true)
|
||||
{
|
||||
c = *pFileBytes++; // get char and advance
|
||||
|
||||
if (!c) // EOL
|
||||
{
|
||||
pToken[len] = '\0';
|
||||
return pFileBytes - 1; // we are done with that, but return data to show that token is present
|
||||
}
|
||||
|
||||
if (c == '\"') // closing quote
|
||||
{
|
||||
pToken[len] = '\0';
|
||||
return pFileBytes;
|
||||
}
|
||||
|
||||
pToken[len++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
// parse single characters
|
||||
if (IN_CHARACTERSET(breaks, c))
|
||||
{
|
||||
pToken[len++] = c;
|
||||
pToken[len] = '\0';
|
||||
return pFileBytes + 1;
|
||||
}
|
||||
|
||||
// parse a regular word
|
||||
do
|
||||
{
|
||||
pToken[len++] = c;
|
||||
pFileBytes++;
|
||||
|
||||
c = *pFileBytes;
|
||||
if (IN_CHARACTERSET(breaks, c))
|
||||
break;
|
||||
}
|
||||
while (c > 32);
|
||||
|
||||
pToken[len] = '\0';
|
||||
return pFileBytes;
|
||||
}
|
||||
|
||||
char *ParseFile(char *pFileBytes, char *pToken, bool *pWasQuoted)
|
||||
{
|
||||
return const_cast<char *>(ParseFile(static_cast<const char *>(pFileBytes), pToken, pWasQuoted));
|
||||
}
|
||||
|
||||
void NORETURN FileSystem_SysError(const char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
static char string[8192];
|
||||
|
||||
va_start(argptr, fmt);
|
||||
vsnprintf(string, sizeof(string), fmt, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
printf("%s\n", string);
|
||||
|
||||
FILE* fl = fopen("filesystem_error.txt", "w");
|
||||
fprintf(fl, "%s\n", string);
|
||||
fclose(fl);
|
||||
|
||||
int *null = 0;
|
||||
*null = 0;
|
||||
exit(-1);
|
||||
}
|
36
rehlds/filesystem/FileSystem_Stdio/src/filesystem_helpers.h
Normal file
36
rehlds/filesystem/FileSystem_Stdio/src/filesystem_helpers.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tier0/characterset.h"
|
||||
|
||||
// Call until it returns nullptr. Each time you call it, it will parse out a token.
|
||||
struct characterset_t;
|
||||
|
||||
const char *ParseFile(const char *pFileBytes, char *pToken, bool *pWasQuoted, characterset_t *pCharSet = nullptr);
|
||||
char *ParseFile(char *pFileBytes, char *pToken, bool *pWasQuoted); // (same exact thing as the const version)
|
||||
void NORETURN FileSystem_SysError(const char *fmt, ...);
|
258
rehlds/filesystem/FileSystem_Stdio/src/linux_support.cpp
Normal file
258
rehlds/filesystem/FileSystem_Stdio/src/linux_support.cpp
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#if !defined(_WIN32)
|
||||
|
||||
char selectBuf[PATH_MAX];
|
||||
int FileSelect(const struct dirent *ent)
|
||||
{
|
||||
const char *mask = selectBuf;
|
||||
const char *name = ent->d_name;
|
||||
|
||||
//printf("Test:%s %s\n", mask, name);
|
||||
|
||||
if (!Q_strcmp(name, ".") || !Q_strcmp(name, ".."))
|
||||
return 0;
|
||||
|
||||
if (!Q_strcmp(selectBuf, "*.*"))
|
||||
return 1;
|
||||
|
||||
while (*mask && *name)
|
||||
{
|
||||
if (*mask == '*')
|
||||
{
|
||||
mask++; // move to the next char in the mask
|
||||
if (!*mask) // if this is the end of the mask its a match
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
while (*name && toupper(*name) != toupper(*mask))
|
||||
{
|
||||
// while the two don't meet up again
|
||||
name++;
|
||||
}
|
||||
if (!*name)
|
||||
{
|
||||
// end of the name
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (*mask != '?')
|
||||
{
|
||||
if (toupper(*mask) != toupper(*name))
|
||||
{
|
||||
// mismatched!
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask++;
|
||||
name++;
|
||||
if (!*mask && !*name)
|
||||
{
|
||||
// if its at the end of the buffer
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// mask is "?", we don't care
|
||||
else
|
||||
{
|
||||
mask++;
|
||||
name++;
|
||||
}
|
||||
}
|
||||
|
||||
// both of the strings are at the end
|
||||
return (!*mask && !*name);
|
||||
}
|
||||
|
||||
int FillDataStruct(FIND_DATA *dat)
|
||||
{
|
||||
char szFileName[MAX_PATH];
|
||||
struct stat fileStat;
|
||||
|
||||
if (dat->numMatches < 0)
|
||||
return -1;
|
||||
|
||||
Q_strlcpy(szFileName, dat->cDir);
|
||||
Q_strlcat(szFileName, "/");
|
||||
Q_strlcat(szFileName, dat->namelist[dat->numMatches]->d_name);
|
||||
Q_strlcpy(dat->cFileName, dat->namelist[dat->numMatches]->d_name);
|
||||
|
||||
if (!stat(szFileName, &fileStat))
|
||||
{
|
||||
dat->dwFileAttributes = fileStat.st_mode;
|
||||
}
|
||||
else
|
||||
{
|
||||
dat->dwFileAttributes = 0;
|
||||
}
|
||||
|
||||
// printf("%s\n", dat->namelist[dat->numMatches]->d_name);
|
||||
free(dat->namelist[dat->numMatches]);
|
||||
dat->numMatches--;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int FindFirstFile(char *fileName, FIND_DATA *dat)
|
||||
{
|
||||
char nameStore[PATH_MAX];
|
||||
char *dir = nullptr;
|
||||
int n, iret = -1;
|
||||
|
||||
Q_strlcpy(nameStore, fileName);
|
||||
|
||||
if (Q_strrchr(nameStore, '/'))
|
||||
{
|
||||
dir = nameStore;
|
||||
while (Q_strrchr(dir, '/'))
|
||||
{
|
||||
struct stat dirChk;
|
||||
|
||||
// zero this with the dir name
|
||||
dir = Q_strrchr(nameStore, '/');
|
||||
*dir = '\0';
|
||||
|
||||
dir = nameStore;
|
||||
stat(dir, &dirChk);
|
||||
|
||||
if (S_ISDIR(dirChk.st_mode))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// couldn't find a dir seperator...
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (Q_strlen(dir) > 0)
|
||||
{
|
||||
Q_strlcpy(selectBuf, fileName + Q_strlen(dir) + 1);
|
||||
Q_strlcpy(dat->cDir, dir);
|
||||
|
||||
n = scandir(dir, &dat->namelist, FileSelect, alphasort);
|
||||
if (n < 0)
|
||||
{
|
||||
// silently return, nothing interesting
|
||||
printf("scandir failed:%s\n", dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
// n is the number of matches
|
||||
dat->numMatches = n - 1;
|
||||
iret = FillDataStruct(dat);
|
||||
if (iret < 0)
|
||||
{
|
||||
free(dat->namelist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// printf("Returning: %i \n", iret);
|
||||
return iret;
|
||||
}
|
||||
|
||||
bool FindNextFile(int handle, FIND_DATA *dat)
|
||||
{
|
||||
if (dat->numMatches < 0)
|
||||
{
|
||||
free(dat->namelist);
|
||||
return false; // no matches left
|
||||
}
|
||||
|
||||
FillDataStruct(dat);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FindClose(int handle)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static char fileName[MAX_PATH];
|
||||
int CheckName(const struct dirent *dir)
|
||||
{
|
||||
return !Q_stricmp(dir->d_name, fileName);
|
||||
}
|
||||
|
||||
const char *findFileInDirCaseInsensitive(const char *file)
|
||||
{
|
||||
const char *dirSep = Q_strrchr(file, '/');
|
||||
if (!dirSep)
|
||||
{
|
||||
dirSep = Q_strrchr(file, '\\');
|
||||
if (!dirSep)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
char *dirName = static_cast<char *>(alloca(((dirSep - file) + 1) * sizeof(char)));
|
||||
if (!dirName) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Q_strncpy(dirName, file, dirSep - file);
|
||||
dirName[dirSep - file] = '\0';
|
||||
|
||||
struct dirent **namelist;
|
||||
int n;
|
||||
|
||||
Q_strlcpy(fileName, dirSep + 1);
|
||||
n = scandir(dirName, &namelist, CheckName, alphasort);
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
while (n > 1)
|
||||
{
|
||||
// free the malloc'd strings
|
||||
free(namelist[n]);
|
||||
n--;
|
||||
}
|
||||
|
||||
Q_snprintf(fileName, sizeof(fileName), "%s/%s", dirName, namelist[0]->d_name);
|
||||
free(namelist[0]);
|
||||
return fileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_strlcpy(fileName, file);
|
||||
Q_strlwr(fileName);
|
||||
return fileName;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #if !defined(_WIN32)
|
62
rehlds/filesystem/FileSystem_Stdio/src/linux_support.h
Normal file
62
rehlds/filesystem/FileSystem_Stdio/src/linux_support.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <ctype.h> // tolower()
|
||||
#include <limits.h> // PATH_MAX define
|
||||
#include <string.h> // strcmp, strcpy
|
||||
#include <sys/stat.h> // stat()
|
||||
#include <unistd.h>
|
||||
#include <dirent.h> // scandir()
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define FILE_ATTRIBUTE_DIRECTORY S_IFDIR
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// public data
|
||||
int dwFileAttributes;
|
||||
char cFileName[MAX_PATH]; // the file name returned from the call
|
||||
|
||||
int numMatches;
|
||||
struct dirent **namelist;
|
||||
char cDir[MAX_PATH];
|
||||
} FIND_DATA;
|
||||
|
||||
#define WIN32_FIND_DATA FIND_DATA
|
||||
|
||||
int FindFirstFile(char *findName, FIND_DATA *dat);
|
||||
bool FindNextFile(int handle, FIND_DATA *dat);
|
||||
bool FindClose(int handle);
|
||||
const char *findFileInDirCaseInsensitive(const char *file);
|
||||
|
||||
#endif // _WIN32
|
898
rehlds/filesystem/FileSystem_Stdio/src/pathmatch.cpp
Normal file
898
rehlds/filesystem/FileSystem_Stdio/src/pathmatch.cpp
Normal file
@ -0,0 +1,898 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
* ------------------------------------------------------------------------------------
|
||||
* This file implements the --wrap for ld on linux that lets file i/o api's
|
||||
* behave as if it were running on a case insensitive file system. Unfortunately,
|
||||
* this is needed by both steam2 and steam3. It was decided to check the source
|
||||
* into both locations, otherwise someone would find the .o and have no idea
|
||||
* where to go for the source if it was in the 'other' tree. Also, because this
|
||||
* needs to be linked into every elf binary, the .o is checked in for Steam3 so that it is
|
||||
* always available. In Steam2 it sits with the PosixWin32.cpp implementation and gets
|
||||
* compiled along side of it through the make system. If you are reading this in Steam3,
|
||||
* you will probably want to actually make your changes in steam2 and do a baseless merge
|
||||
* to the steam3 copy.
|
||||
*
|
||||
* HOWTO: Add a new function. Add the function with _WRAP to the makefiles as noted below.
|
||||
* Add the implementation to pathmatch.cpp - probably mimicking the existing functions.
|
||||
* Build steam2 and copy to matching steam3/client. Take the pathmatch.o from steam 2
|
||||
* and check it in to steam3 (in the location noted below). Full rebuild (re-link really)
|
||||
* of steam3. Test steam and check in.
|
||||
*
|
||||
* If you are looking at updating this file, please update the following as needed:
|
||||
*
|
||||
* STEAM2.../Projects/GazelleProto/Client/Engine/obj/RELEASE_NORMAL/libsteam_linux/Common/Misc/pathmatch.o
|
||||
* This is where steam2 builds the pathmatch.o out to.
|
||||
*
|
||||
* STEAM2.../Projects/GazelleProto/Makefile.shlib.base - contains _WRAP references
|
||||
* STEAM2.../Projects/Common/Misc/pathmatch.cpp - Where the source is checked in, keep in sync with:
|
||||
* STEAM3.../src/common/pathmatch.cpp - should be identical to previous file, but discoverable in steam3.
|
||||
* STEAM3.../src/lib/linux32/release/pathmatch.o - steam3 checked in version
|
||||
* STEAM3.../src/devtools/makefile_base_posix.mak - look for the _WRAP references
|
||||
* ------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <stdint.h>
|
||||
#include <strings.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/mount.h>
|
||||
#include <fcntl.h>
|
||||
#include <utime.h>
|
||||
|
||||
// Enable to do pathmatch caching. Beware: this code isn't threadsafe.
|
||||
// #define DO_PATHMATCH_CACHE
|
||||
|
||||
#ifdef DO_PATHMATCH_CACHE
|
||||
#include <map>
|
||||
#endif
|
||||
|
||||
#ifdef UTF8_PATHMATCH
|
||||
#define Q_stricmp utf8casecmp
|
||||
#endif
|
||||
|
||||
static bool s_bShowDiag;
|
||||
#define DEBUG_MSG(...) if (s_bShowDiag) fprintf(stderr, ##__VA_ARGS__)
|
||||
#define DEBUG_BREAK() __asm__ __volatile__ ("int $3")
|
||||
#define _COMPILE_TIME_ASSERT(pred) switch(0) {case 0:case pred:;}
|
||||
|
||||
#define WRAP(fn, ret, ...)\
|
||||
ret __real_##fn(__VA_ARGS__);\
|
||||
ret __wrap_##fn(__VA_ARGS__)
|
||||
|
||||
#define CALL(fn) __real_##fn
|
||||
|
||||
// Needed by pathmatch code
|
||||
extern "C" int __real_access(const char *pathname, int mode);
|
||||
extern "C" DIR *__real_opendir(const char *name);
|
||||
|
||||
// UTF-8 work from PhysicsFS: http://icculus.org/physfs/
|
||||
// Even if it wasn't under the zlib license, Ryan wrote all this code originally.
|
||||
|
||||
#define UNICODE_BOGUS_CHAR_VALUE 0xFFFFFFFF
|
||||
#define UNICODE_BOGUS_CHAR_CODEPOINT '?'
|
||||
|
||||
inline __attribute__((always_inline)) static uint32_t utf8codepoint(const char **_str)
|
||||
{
|
||||
const char *str = *_str;
|
||||
uint32_t retval = 0;
|
||||
uint32_t octet = (uint32_t)((uint8_t)*str);
|
||||
uint32_t octet2, octet3, octet4;
|
||||
|
||||
// null terminator, end of string.
|
||||
if (octet == 0)
|
||||
return 0;
|
||||
|
||||
// one octet char: 0 to 127
|
||||
else if (octet < 128)
|
||||
{
|
||||
(*_str)++; // skip to next possible start of codepoint.
|
||||
return octet;
|
||||
}
|
||||
else if ((octet > 127) && (octet < 192)) // bad (starts with 10xxxxxx).
|
||||
{
|
||||
// Apparently each of these is supposed to be flagged as a bogus
|
||||
// char, instead of just resyncing to the next valid codepoint.
|
||||
|
||||
(*_str)++; // skip to next possible start of codepoint.
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
}
|
||||
else if (octet < 224) // two octets
|
||||
{
|
||||
octet -= (128 + 64);
|
||||
octet2 = (uint32_t)((uint8_t)*(++str));
|
||||
if ((octet2 & (128 + 64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
*_str += 2; // skip to next possible start of codepoint.
|
||||
retval = ((octet << 6) | (octet2 - 128));
|
||||
if ((retval >= 0x80) && (retval <= 0x7FF))
|
||||
return retval;
|
||||
}
|
||||
else if (octet < 240) // three octets
|
||||
{
|
||||
octet -= (128 + 64 + 32);
|
||||
octet2 = (uint32_t)((uint8_t)*(++str));
|
||||
if ((octet2 & (128 + 64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet3 = (uint32_t)((uint8_t)*(++str));
|
||||
if ((octet3 & (128 + 64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
*_str += 3; // skip to next possible start of codepoint.
|
||||
retval = (((octet << 12)) | ((octet2 - 128) << 6) | ((octet3 - 128)));
|
||||
|
||||
// There are seven "UTF-16 surrogates" that are illegal in UTF-8.
|
||||
switch (retval)
|
||||
{
|
||||
case 0xD800:
|
||||
case 0xDB7F:
|
||||
case 0xDB80:
|
||||
case 0xDBFF:
|
||||
case 0xDC00:
|
||||
case 0xDF80:
|
||||
case 0xDFFF:
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
}
|
||||
|
||||
// 0xFFFE and 0xFFFF are illegal, too, so we check them at the edge.
|
||||
if ((retval >= 0x800) && (retval <= 0xFFFD))
|
||||
return retval;
|
||||
}
|
||||
else if (octet < 248) // four octets
|
||||
{
|
||||
octet -= (128 + 64 + 32 + 16);
|
||||
octet2 = (uint32_t)((uint8_t)*(++str));
|
||||
if ((octet2 & (128 + 64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet3 = (uint32_t)((uint8_t)*(++str));
|
||||
if ((octet3 & (128 + 64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet4 = (uint32_t)((uint8_t)*(++str));
|
||||
if ((octet4 & (128 + 64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
*_str += 4; // skip to next possible start of codepoint.
|
||||
retval = (((octet << 18)) | ((octet2 - 128) << 12) | ((octet3 - 128) << 6) | ((octet4 - 128)));
|
||||
if ((retval >= 0x10000) && (retval <= 0x10FFFF))
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Five and six octet sequences became illegal in rfc3629.
|
||||
// We throw the codepoint away, but parse them to make sure we move
|
||||
// ahead the right number of bytes and don't overflow the buffer.
|
||||
else if (octet < 252) // five octets
|
||||
{
|
||||
octet = (uint32_t)((uint8_t)*(++str));
|
||||
if ((octet & (128 + 64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet = (uint32_t)((uint8_t)*(++str));
|
||||
if ((octet & (128 + 64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet = (uint32_t)((uint8_t)*(++str));
|
||||
if ((octet & (128 + 64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet = (uint32_t)((uint8_t)*(++str));
|
||||
if ((octet & (128 + 64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
*_str += 5; // skip to next possible start of codepoint.
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
}
|
||||
else // six octets
|
||||
{
|
||||
octet = (uint32_t)((uint8_t)*(++str));
|
||||
if ((octet & (128 + 64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet = (uint32_t)((uint8_t)*(++str));
|
||||
if ((octet & (128 + 64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet = (uint32_t)((uint8_t)*(++str));
|
||||
if ((octet & (128 + 64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet = (uint32_t)((uint8_t)*(++str));
|
||||
if ((octet & (128 + 64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet = (uint32_t)((uint8_t)*(++str));
|
||||
if ((octet & (128 + 64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
*_str += 6; // skip to next possible start of codepoint.
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
}
|
||||
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
}
|
||||
|
||||
typedef struct CaseFoldMapping
|
||||
{
|
||||
uint32_t from;
|
||||
uint32_t to0;
|
||||
uint32_t to1;
|
||||
uint32_t to2;
|
||||
} CaseFoldMapping;
|
||||
|
||||
typedef struct CaseFoldHashBucket
|
||||
{
|
||||
const uint8_t count;
|
||||
const CaseFoldMapping *list;
|
||||
} CaseFoldHashBucket;
|
||||
|
||||
#include "pathmatch_casefolding.h"
|
||||
|
||||
inline static void locate_case_fold_mapping(const uint32_t from, uint32_t *to)
|
||||
{
|
||||
const uint8_t hashed = ((from ^ (from >> 8)) & 0xFF);
|
||||
const CaseFoldHashBucket *bucket = &case_fold_hash[hashed];
|
||||
const CaseFoldMapping *mapping = bucket->list;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < bucket->count; i++, mapping++)
|
||||
{
|
||||
if (mapping->from == from)
|
||||
{
|
||||
to[0] = mapping->to0;
|
||||
to[1] = mapping->to1;
|
||||
to[2] = mapping->to2;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Not found...there's no remapping for this codepoint.
|
||||
to[0] = from;
|
||||
to[1] = 0;
|
||||
to[2] = 0;
|
||||
}
|
||||
|
||||
inline static uint32_t *fold_utf8(const char *str)
|
||||
{
|
||||
uint32_t *retval = new uint32_t[(Q_strlen(str) * 3) + 1];
|
||||
uint32_t *dst = retval;
|
||||
while (*str)
|
||||
{
|
||||
const char ch = *str;
|
||||
if (ch & 0x80) // high bit set? UTF-8 sequence!
|
||||
{
|
||||
uint32_t fold[3];
|
||||
locate_case_fold_mapping(utf8codepoint(&str), fold);
|
||||
*(dst++) = fold[0];
|
||||
if (fold[1])
|
||||
{
|
||||
*(dst++) = fold[1];
|
||||
if (fold[2])
|
||||
*(dst++) = fold[2];
|
||||
}
|
||||
}
|
||||
// simple ASCII test.
|
||||
else
|
||||
{
|
||||
*(dst++) = (uint32_t) (((ch >= 'A') && (ch <= 'Z')) ? ch + 32 : ch);
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
*dst = 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
inline static int utf8casecmp_loop(const uint32_t *folded1, const uint32_t *folded2)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
const uint32_t ch1 = *(folded1++);
|
||||
const uint32_t ch2 = *(folded2++);
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
else if (ch1 == 0)
|
||||
{
|
||||
// complete match.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int utf8casecmp(const char *str1, const char *str2)
|
||||
{
|
||||
uint32_t *folded1 = fold_utf8(str1);
|
||||
uint32_t *folded2 = fold_utf8(str2);
|
||||
const int retval = utf8casecmp_loop(folded1, folded2);
|
||||
delete[] folded1;
|
||||
delete[] folded2;
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Simple object to help make sure a DIR* from opendir
|
||||
// gets closed when it goes out of scope.
|
||||
class CDirPtr
|
||||
{
|
||||
public:
|
||||
CDirPtr() { m_pDir = nullptr; }
|
||||
CDirPtr(DIR *pDir) : m_pDir(pDir) {}
|
||||
~CDirPtr() { Close(); }
|
||||
|
||||
void operator=(DIR *pDir) { Close(); m_pDir = pDir; }
|
||||
|
||||
operator DIR *() { return m_pDir; }
|
||||
operator bool() { return m_pDir != nullptr; }
|
||||
|
||||
private:
|
||||
void Close() { if (m_pDir) closedir(m_pDir); }
|
||||
|
||||
DIR *m_pDir;
|
||||
};
|
||||
|
||||
// Object used to temporarily slice a path into a smaller componentent
|
||||
// and then repair it when going out of scope. Typically used as an unnamed
|
||||
// temp object that is a parameter to a function.
|
||||
class CDirTrimmer
|
||||
{
|
||||
public:
|
||||
CDirTrimmer(char *pPath, size_t nTrimIdx)
|
||||
{
|
||||
m_pPath = pPath;
|
||||
m_idx = nTrimIdx;
|
||||
m_c = m_pPath[nTrimIdx];
|
||||
m_pPath[nTrimIdx] = '\0';
|
||||
}
|
||||
~CDirTrimmer() { m_pPath[m_idx] = m_c; }
|
||||
|
||||
operator const char *() { return m_pPath; }
|
||||
|
||||
private:
|
||||
size_t m_idx;
|
||||
char *m_pPath;
|
||||
char m_c;
|
||||
};
|
||||
|
||||
enum PathMod_t
|
||||
{
|
||||
kPathUnchanged,
|
||||
kPathLowered,
|
||||
kPathChanged,
|
||||
kPathFailed,
|
||||
};
|
||||
|
||||
static bool Descend(char *pPath, size_t nStartIdx, bool bAllowBasenameMismatch, size_t nLevel = 0)
|
||||
{
|
||||
DEBUG_MSG("(%zu) Descend: %s, (%s), %s\n", nLevel, pPath, pPath + nStartIdx, bAllowBasenameMismatch ? "true" : "false ");
|
||||
|
||||
// We assume up through nStartIdx is valid and matching
|
||||
size_t nNextSlash = nStartIdx + 1;
|
||||
|
||||
// path might be a dir
|
||||
if (pPath[nNextSlash] == '\0') {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bIsDir = false; // is the new component a directory for certain?
|
||||
while (pPath[nNextSlash] != '\0' && pPath[nNextSlash] != '/') {
|
||||
nNextSlash++;
|
||||
}
|
||||
|
||||
// Modify the pPath string
|
||||
if (pPath[nNextSlash] == '/') {
|
||||
bIsDir = true;
|
||||
}
|
||||
|
||||
// See if we have an immediate match
|
||||
if (__real_access(CDirTrimmer(pPath, nNextSlash), F_OK) == 0)
|
||||
{
|
||||
if (!bIsDir) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bRet = Descend(pPath, nNextSlash, bAllowBasenameMismatch, nLevel + 1);
|
||||
if (bRet) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Start enumerating dirents
|
||||
CDirPtr spDir;
|
||||
if (nStartIdx)
|
||||
{
|
||||
// we have a path
|
||||
spDir = __real_opendir(CDirTrimmer(pPath, nStartIdx));
|
||||
nStartIdx++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we either start at root or cwd
|
||||
const char *pRoot = ".";
|
||||
if (*pPath == '/')
|
||||
{
|
||||
pRoot = "/";
|
||||
nStartIdx++;
|
||||
}
|
||||
|
||||
spDir = __real_opendir(pRoot);
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
|
||||
struct dirent *pEntry = spDir ? readdir(spDir) : nullptr;
|
||||
char *pszComponent = pPath + nStartIdx;
|
||||
size_t cbComponent = nNextSlash - nStartIdx;
|
||||
while (pEntry)
|
||||
{
|
||||
DEBUG_MSG("\t(%zu) comparing %s with %s\n", nLevel, pEntry->d_name, (const char *)CDirTrimmer(pszComponent, cbComponent));
|
||||
|
||||
// the candidate must match the target, but not be a case-identical match (we would
|
||||
// have looked there in the short-circuit code above, so don't look again)
|
||||
bool bMatches = (Q_stricmp(CDirTrimmer(pszComponent, cbComponent), pEntry->d_name) == 0 &&
|
||||
Q_strcmp(CDirTrimmer(pszComponent, cbComponent), pEntry->d_name) != 0);
|
||||
|
||||
if (bMatches)
|
||||
{
|
||||
char *pSrc = pEntry->d_name;
|
||||
char *pDst = &pPath[nStartIdx];
|
||||
|
||||
// found a match; copy it in.
|
||||
while (*pSrc && (*pSrc != '/')) {
|
||||
*pDst++ = *pSrc++;
|
||||
}
|
||||
|
||||
if (!bIsDir)
|
||||
return true;
|
||||
|
||||
if (Descend(pPath, nNextSlash, bAllowBasenameMismatch, nLevel + 1))
|
||||
return true;
|
||||
|
||||
// If descend fails, try more directories
|
||||
}
|
||||
|
||||
pEntry = readdir(spDir);
|
||||
}
|
||||
|
||||
if (bIsDir) {
|
||||
DEBUG_MSG("(%zu) readdir failed to find '%s' in '%s'\n", nLevel, (const char *)CDirTrimmer(pszComponent, cbComponent), (const char *)CDirTrimmer(pPath, nStartIdx));
|
||||
}
|
||||
|
||||
// Sometimes it's ok for the filename portion to not match
|
||||
// since we might be opening for write. Note that if
|
||||
// the filename matches case insensitive, that will be
|
||||
// preferred over preserving the input name
|
||||
if (!bIsDir && bAllowBasenameMismatch) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
char *GetSteamContentPath()
|
||||
{
|
||||
char szContentLink[4096];
|
||||
Q_snprintf(szContentLink, sizeof(szContentLink), "%s/.steam/steam", getenv("HOME"));
|
||||
|
||||
char *pszContentPath = realpath(szContentLink, nullptr);
|
||||
if (pszContentPath) {
|
||||
Q_strcat(pszContentPath, "/");
|
||||
}
|
||||
else {
|
||||
pszContentPath = Q_strdup("/");
|
||||
}
|
||||
|
||||
return pszContentPath;
|
||||
}
|
||||
|
||||
#ifdef DO_PATHMATCH_CACHE
|
||||
typedef std::map<std::string, std::pair<std::string, time_t> > resultCache_t;
|
||||
typedef std::map<std::string, std::pair<std::string, time_t> >::iterator resultCacheItr_t;
|
||||
static resultCache_t resultCache;
|
||||
static const int k_cMaxCacheLifetimeSeconds = 2;
|
||||
#endif // DO_PATHMATCH_CACHE
|
||||
|
||||
PathMod_t pathmatch(const char *pszIn, char **ppszOut, bool bAllowBasenameMismatch, char *pszOutBuf, size_t OutBufLen)
|
||||
{
|
||||
static const char *s_pszDbgPathMatch = getenv("DBG_PATHMATCH");
|
||||
|
||||
s_bShowDiag = (s_pszDbgPathMatch != nullptr);
|
||||
|
||||
*ppszOut = nullptr;
|
||||
|
||||
if (__real_access(pszIn, F_OK) == 0)
|
||||
return kPathUnchanged;
|
||||
|
||||
#ifdef DO_PATHMATCH_CACHE
|
||||
resultCacheItr_t cachedResult = resultCache.find(pszIn);
|
||||
if (cachedResult != resultCache.end())
|
||||
{
|
||||
unsigned int age = time(nullptr) - cachedResult->second.second;
|
||||
const char *pszResult = cachedResult->second.first.c_str();
|
||||
if (pszResult[0] != '\0' || age <= k_cMaxCacheLifetimeSeconds)
|
||||
{
|
||||
if (pszResult[0] != '\0')
|
||||
{
|
||||
*ppszOut = Q_strdup(pszResult);
|
||||
DEBUG_MSG("Cached '%s' -> '%s'\n", pszIn, *ppszOut);
|
||||
return kPathChanged;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_MSG("Cached '%s' -> kPathFailed\n", pszIn);
|
||||
return kPathFailed;
|
||||
}
|
||||
}
|
||||
else if (age <= k_cMaxCacheLifetimeSeconds)
|
||||
{
|
||||
DEBUG_MSG("Rechecking '%s' - cache is %u seconds old\n", pszIn, age);
|
||||
}
|
||||
}
|
||||
#endif // DO_PATHMATCH_CACHE
|
||||
|
||||
char *pPath;
|
||||
if (Q_strlen(pszIn) >= OutBufLen)
|
||||
{
|
||||
pPath = Q_strdup(pszIn);
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_strncpy(pszOutBuf, pszIn, OutBufLen);
|
||||
pPath = pszOutBuf;
|
||||
}
|
||||
|
||||
if (pPath)
|
||||
{
|
||||
// optimization, if the path contained steam somewhere
|
||||
// assume the path up through the component with 'steam' in
|
||||
// is valid (because we almost certainly obtained it
|
||||
// progamatically
|
||||
size_t nStartIdx = 0;
|
||||
static char *pszSteamPath = nullptr;
|
||||
static size_t nSteamPathLen = 0;
|
||||
if (!pszSteamPath)
|
||||
{
|
||||
pszSteamPath = GetSteamContentPath();
|
||||
nSteamPathLen = Q_strlen(pszSteamPath);
|
||||
}
|
||||
|
||||
// optimization, if the path contained steam somewhere
|
||||
// assume the path up through the component with 'steam' in
|
||||
// is valid (because we almost certainly obtained it
|
||||
// progamatically
|
||||
if (strncasecmp(pPath, pszSteamPath, nSteamPathLen) == 0)
|
||||
{
|
||||
nStartIdx = nSteamPathLen - 1;
|
||||
Q_memcpy(pPath, pszSteamPath, nStartIdx);
|
||||
}
|
||||
|
||||
char *p = pPath;
|
||||
|
||||
// Try the lower casing of the remaining path
|
||||
char *pBasename = p + nStartIdx;
|
||||
while (*p)
|
||||
{
|
||||
if (*p == '/') {
|
||||
pBasename = p + 1;
|
||||
}
|
||||
|
||||
*p = tolower(*p);
|
||||
p++;
|
||||
}
|
||||
|
||||
if (__real_access(pPath, F_OK) == 0)
|
||||
{
|
||||
*ppszOut = pPath;
|
||||
DEBUG_MSG("Lowered '%s' -> '%s'\n", pszIn, pPath);
|
||||
return kPathLowered;
|
||||
}
|
||||
|
||||
// path didn't match lowered successfully, restore the basename
|
||||
// if bAllowBasenameMismatch was true
|
||||
if (bAllowBasenameMismatch && *pBasename)
|
||||
{
|
||||
const char *pSrc = pszIn + (pBasename - pPath);
|
||||
while (*pBasename)
|
||||
{
|
||||
*pBasename++ = *pSrc++;
|
||||
}
|
||||
}
|
||||
|
||||
if (s_pszDbgPathMatch && strcasestr(s_pszDbgPathMatch, pszIn))
|
||||
{
|
||||
DEBUG_MSG("Breaking '%s' in '%s'\n", pszIn, s_pszDbgPathMatch);
|
||||
DEBUG_BREAK();
|
||||
}
|
||||
|
||||
bool bSuccess = Descend(pPath, nStartIdx, bAllowBasenameMismatch);
|
||||
if (bSuccess)
|
||||
{
|
||||
*ppszOut = pPath;
|
||||
DEBUG_MSG("Matched '%s' -> '%s'\n", pszIn, pPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_MSG("Unmatched %s\n", pszIn);
|
||||
}
|
||||
|
||||
#ifndef DO_PATHMATCH_CACHE
|
||||
return bSuccess ? kPathChanged : kPathFailed;
|
||||
#else
|
||||
time_t now = time(nullptr);
|
||||
if (bSuccess)
|
||||
{
|
||||
resultCache[pszIn] = std::make_pair(*ppszOut, now);
|
||||
return kPathChanged;
|
||||
}
|
||||
else
|
||||
{
|
||||
resultCache[pszIn] = std::make_pair("", now);
|
||||
return kPathFailed;
|
||||
}
|
||||
#endif // DO_PATHMATCH_CACHE
|
||||
}
|
||||
|
||||
return kPathFailed;
|
||||
}
|
||||
|
||||
// Wrapper object that manages the 'typical' usage cases of pathmatch()
|
||||
class CWrap
|
||||
{
|
||||
public:
|
||||
CWrap(const char *pSuppliedPath, bool bAllowMismatchedBasename)
|
||||
: m_pSuppliedPath(pSuppliedPath), m_pBestMatch(nullptr)
|
||||
{
|
||||
m_eResult = pathmatch(m_pSuppliedPath, &m_pBestMatch, bAllowMismatchedBasename, m_BestMatchBuf, sizeof(m_BestMatchBuf));
|
||||
if (m_pBestMatch == nullptr)
|
||||
{
|
||||
m_pBestMatch = const_cast<char *>(m_pSuppliedPath);
|
||||
}
|
||||
}
|
||||
|
||||
~CWrap()
|
||||
{
|
||||
if ((m_pBestMatch != m_pSuppliedPath) && (m_pBestMatch != m_BestMatchBuf))
|
||||
free(m_pBestMatch);
|
||||
}
|
||||
|
||||
const char *GetBest() const { return m_pBestMatch; }
|
||||
const char *GetOriginal() const { return m_pSuppliedPath; }
|
||||
PathMod_t GetMatchResult() const { return m_eResult; }
|
||||
|
||||
operator const char*() { return GetBest(); }
|
||||
|
||||
private:
|
||||
const char *m_pSuppliedPath;
|
||||
char *m_pBestMatch;
|
||||
char m_BestMatchBuf[512];
|
||||
PathMod_t m_eResult;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
||||
char *SteamRealPath(char *szOrigPath, char *szFinalPath, uint uiFinalPathCapacity)
|
||||
{
|
||||
char *szMatchPath = nullptr;
|
||||
char szRealPath[MAX_PATH];
|
||||
char szPathMatchBuf[MAX_PATH];
|
||||
|
||||
if (uiFinalPathCapacity > sizeof(szRealPath) || !uiFinalPathCapacity || !szFinalPath)
|
||||
return nullptr;
|
||||
|
||||
PathMod_t pmStat = pathmatch(szOrigPath, &szMatchPath, true, szPathMatchBuf, sizeof(szPathMatchBuf));
|
||||
if (pmStat != kPathFailed)
|
||||
{
|
||||
if (realpath(szMatchPath ? szMatchPath : szOrigPath, szRealPath) == szRealPath)
|
||||
{
|
||||
Q_strncpy(szFinalPath, szRealPath, uiFinalPathCapacity);
|
||||
return szFinalPath;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WRAP(freopen, FILE *, const char *path, const char *mode, FILE *stream)
|
||||
{
|
||||
// if mode does not have w, a, or +, it's open for read.
|
||||
bool bAllowBasenameMismatch = strpbrk(mode, "wa+") != nullptr;
|
||||
CWrap mpath(path, bAllowBasenameMismatch);
|
||||
|
||||
return CALL(freopen)(mpath, mode, stream);
|
||||
}
|
||||
|
||||
WRAP(fopen, FILE *, const char *path, const char *mode)
|
||||
{
|
||||
// if mode does not have w, a, or +, it's open for read.
|
||||
bool bAllowBasenameMismatch = strpbrk(mode, "wa+") != nullptr;
|
||||
CWrap mpath(path, bAllowBasenameMismatch);
|
||||
|
||||
return CALL(fopen)(mpath, mode);
|
||||
}
|
||||
|
||||
WRAP(fopen64, FILE *, const char *path, const char *mode)
|
||||
{
|
||||
// if mode does not have w, a, or +, it's open for read.
|
||||
bool bAllowBasenameMismatch = strpbrk(mode, "wa+") != nullptr;
|
||||
CWrap mpath(path, bAllowBasenameMismatch);
|
||||
|
||||
return CALL(fopen64)(mpath, mode);
|
||||
}
|
||||
|
||||
WRAP(open, int, const char *pathname, int flags, mode_t mode)
|
||||
{
|
||||
bool bAllowBasenameMismatch = ((flags & (O_WRONLY | O_RDWR)) != 0);
|
||||
CWrap mpath(pathname, bAllowBasenameMismatch);
|
||||
return CALL(open)(mpath, flags, mode);
|
||||
}
|
||||
|
||||
WRAP(open64, int, const char *pathname, int flags, mode_t mode)
|
||||
{
|
||||
bool bAllowBasenameMismatch = ((flags & (O_WRONLY | O_RDWR)) != 0);
|
||||
CWrap mpath(pathname, bAllowBasenameMismatch);
|
||||
return CALL(open64)(mpath, flags, mode);
|
||||
}
|
||||
|
||||
int __wrap_creat(const char *pathname, mode_t mode)
|
||||
{
|
||||
return __wrap_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
|
||||
}
|
||||
|
||||
int __wrap_access(const char *pathname, int mode)
|
||||
{
|
||||
return __real_access(CWrap(pathname, false), mode);
|
||||
}
|
||||
|
||||
WRAP(stat, int, const char *path, struct stat *buf)
|
||||
{
|
||||
return CALL(stat)(CWrap(path, false), buf);
|
||||
}
|
||||
|
||||
WRAP(lstat, int, const char *path, struct stat *buf)
|
||||
{
|
||||
return CALL(lstat)(CWrap(path, false), buf);
|
||||
}
|
||||
|
||||
WRAP(scandir, int, const char *dirp, struct dirent ***namelist,
|
||||
int (*filter)(const struct dirent *),
|
||||
int (*compar)(const struct dirent **, const struct dirent **))
|
||||
{
|
||||
return CALL(scandir)(CWrap(dirp, false), namelist, filter, compar);
|
||||
}
|
||||
|
||||
WRAP(opendir, DIR *, const char *name)
|
||||
{
|
||||
return CALL(opendir)(CWrap(name, false));
|
||||
}
|
||||
|
||||
WRAP(__xstat, int, int __ver, __const char *__filename, struct stat *__stat_buf)
|
||||
{
|
||||
return CALL(__xstat)(__ver, CWrap(__filename, false), __stat_buf);
|
||||
}
|
||||
|
||||
WRAP(__lxstat, int, int __ver, __const char *__filename, struct stat *__stat_buf)
|
||||
{
|
||||
return CALL(__lxstat)(__ver, CWrap(__filename, false), __stat_buf);
|
||||
}
|
||||
|
||||
WRAP(__xstat64, int, int __ver, __const char *__filename, struct stat *__stat_buf)
|
||||
{
|
||||
return CALL(__xstat64)(__ver, CWrap(__filename, false), __stat_buf);
|
||||
}
|
||||
|
||||
WRAP(__lxstat64, int, int __ver, __const char *__filename, struct stat *__stat_buf)
|
||||
{
|
||||
return CALL(__lxstat64)(__ver, CWrap(__filename, false), __stat_buf);
|
||||
}
|
||||
|
||||
WRAP(chmod, int, const char *path, mode_t mode)
|
||||
{
|
||||
return CALL(chmod)(CWrap(path, false), mode);
|
||||
}
|
||||
|
||||
WRAP(chown, int, const char *path, uid_t owner, gid_t group)
|
||||
{
|
||||
return CALL(chown)(CWrap(path, false), owner, group);
|
||||
}
|
||||
|
||||
WRAP(lchown, int, const char *path, uid_t owner, gid_t group)
|
||||
{
|
||||
return CALL(lchown)(CWrap(path, false), owner, group);
|
||||
}
|
||||
|
||||
WRAP(symlink, int, const char *oldpath, const char *newpath)
|
||||
{
|
||||
return CALL(symlink)(CWrap(oldpath, false), CWrap(newpath, true));
|
||||
}
|
||||
|
||||
WRAP(link, int, const char *oldpath, const char *newpath)
|
||||
{
|
||||
return CALL(link)(CWrap(oldpath, false), CWrap(newpath, true));
|
||||
}
|
||||
|
||||
WRAP(mknod, int, const char *pathname, mode_t mode, dev_t dev)
|
||||
{
|
||||
return CALL(mknod)(CWrap(pathname, true), mode, dev);
|
||||
}
|
||||
|
||||
WRAP(mount, int, const char *source, const char *target,
|
||||
const char *filesystemtype, unsigned long mountflags,
|
||||
const void *data)
|
||||
{
|
||||
return CALL(mount)(CWrap(source, false), CWrap(target, false), filesystemtype, mountflags, data);
|
||||
}
|
||||
|
||||
WRAP(unlink, int, const char *pathname)
|
||||
{
|
||||
return CALL(unlink)(CWrap(pathname, false));
|
||||
}
|
||||
|
||||
WRAP(mkfifo, int, const char *pathname, mode_t mode)
|
||||
{
|
||||
return CALL(mkfifo)(CWrap(pathname, true), mode);
|
||||
}
|
||||
|
||||
WRAP(rename, int, const char *oldpath, const char *newpath)
|
||||
{
|
||||
return CALL(rename)(CWrap(oldpath, false), CWrap(newpath, true));
|
||||
}
|
||||
|
||||
WRAP(utime, int, const char *filename, const struct utimbuf *times)
|
||||
{
|
||||
return CALL(utime)(CWrap(filename, false), times);
|
||||
}
|
||||
|
||||
WRAP(utimes, int, const char *filename, const struct timeval times[2])
|
||||
{
|
||||
return CALL(utimes)(CWrap(filename, false), times);
|
||||
}
|
||||
|
||||
//WRAP(realpath, char *, const char *path, char *resolved_path)
|
||||
//{
|
||||
// return CALL(realpath)(CWrap(path, true), resolved_path);
|
||||
//}
|
||||
|
||||
WRAP(mkdir, int, const char *pathname, mode_t mode)
|
||||
{
|
||||
return CALL(mkdir)(CWrap(pathname, true), mode);
|
||||
}
|
||||
|
||||
WRAP(rmdir, char *, const char *pathname)
|
||||
{
|
||||
return CALL(rmdir)(CWrap(pathname, false));
|
||||
}
|
||||
|
||||
}; // extern "C"
|
||||
|
||||
#endif // _WIN32
|
2031
rehlds/filesystem/FileSystem_Stdio/src/pathmatch_casefolding.h
Normal file
2031
rehlds/filesystem/FileSystem_Stdio/src/pathmatch_casefolding.h
Normal file
File diff suppressed because it is too large
Load Diff
29
rehlds/filesystem/FileSystem_Stdio/src/precompiled.cpp
Normal file
29
rehlds/filesystem/FileSystem_Stdio/src/precompiled.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
40
rehlds/filesystem/FileSystem_Stdio/src/precompiled.h
Normal file
40
rehlds/filesystem/FileSystem_Stdio/src/precompiled.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "osconfig.h"
|
||||
#include "archtypes.h"
|
||||
#include "interface.h"
|
||||
#include "strtools.h"
|
||||
|
||||
// Hooks stuff
|
||||
#include "hookers/filesystem/hooklist.h"
|
||||
|
||||
// FileSystem stuff
|
||||
#include "FileSystem_Stdio.h"
|
@ -0,0 +1,7 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "interface.cpp"
|
||||
#include "utlsymbol.cpp"
|
||||
|
||||
#include "tier0/dbg.cpp"
|
||||
#include "tier0/characterset.cpp"
|
5
rehlds/filesystem/build.gradle
Normal file
5
rehlds/filesystem/build.gradle
Normal file
@ -0,0 +1,5 @@
|
||||
evaluationDependsOn(':rehlds/filesystem/FileSystem_Stdio');
|
||||
|
||||
task build {
|
||||
dependsOn project(':rehlds/filesystem/FileSystem_Stdio').tasks.build
|
||||
}
|
@ -1381,7 +1381,7 @@ FunctionHook g_FunctionHooks[] =
|
||||
HOOK_DEF(0x01D50460, Length),
|
||||
HOOK_DEF(0x01D504A0, VectorNormalize),
|
||||
//HOOK_DEF(0x, VectorInverse),
|
||||
HOOK_DEF(0x01D50550, VectorScale),
|
||||
//HOOK_DEF(0x01D50550, VectorScale),
|
||||
//HOOK_DEF(0x, Q_log2),
|
||||
//HOOK_DEF(0x, VectorMatrix),
|
||||
HOOK_DEF(0x01D50640, VectorAngles),
|
||||
@ -2371,8 +2371,8 @@ AddressRef g_DataRefs[] =
|
||||
GLOBALVAR_LINK(0x01E48EA0, "sv_stopspeed", psv_stopspeed),
|
||||
GLOBALVAR_LINK(0x021C2B48, "g_moved_from", pg_moved_from),
|
||||
GLOBALVAR_LINK(0x021C2B4C, "sv_numareanodes", pg_moved_edict),
|
||||
GLOBALVAR_LINK(0x021C2B50, "c_yes", pc_yes),
|
||||
GLOBALVAR_LINK(0x021C2B54, "c_no", pc_no),
|
||||
//GLOBALVAR_LINK(0x021C2B50, "c_yes", pc_yes),
|
||||
//GLOBALVAR_LINK(0x021C2B54, "c_no", pc_no),
|
||||
GLOBALVAR_LINK(0x020042AC, "net_thread_initialized", pnet_thread_initialized),
|
||||
GLOBALVAR_LINK(0x01E3E8DC, "net_address", pnet_address),
|
||||
GLOBALVAR_LINK(0x01E3E900, "ipname", pipname),
|
||||
|
182
rehlds/hookers/filesystem/hooklist.cpp
Normal file
182
rehlds/hookers/filesystem/hooklist.cpp
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
// Hooks stuff
|
||||
#include "hookers/memory.cpp"
|
||||
#include "hookers/hooker.cpp"
|
||||
|
||||
//#define Mem_region
|
||||
//#define BaseFileSystem_region
|
||||
//#define CUtlSymbol_Region
|
||||
//#define Function_References_region
|
||||
//#define Data_References_region
|
||||
|
||||
FunctionHook g_FunctionHooks[] =
|
||||
{
|
||||
// DO NOT DISABLE, other functions depends on memory allocation routines
|
||||
#ifndef Mem_region
|
||||
|
||||
#ifdef _WIN32
|
||||
HOOK_SYMBOLDEF(0x01D06F5E, "_malloca", malloc_wrapper),
|
||||
HOOK_SYMBOLDEF(0x01D067CA, "_free", free_wrapper),
|
||||
HOOK_SYMBOLDEF(0x01D07098, "realloc", realloc_wrapper),
|
||||
HOOK_SYMBOLDEF(0x01D06F70, "__nh_malloc", __nh_malloc_wrapper),
|
||||
#endif //_WIN32
|
||||
|
||||
#endif // Mem_region
|
||||
|
||||
#ifndef BaseFileSystem_region
|
||||
|
||||
HOOK_DEF(0x01D01080, MethodThunk<CFileSystem_Stdio>::Destructor),
|
||||
HOOK_DEF(0x01D01010, (MethodThunk<CFileSystem_Stdio>::Constructor)),
|
||||
|
||||
// virtual functions - CFileSystem_Stdio
|
||||
HOOK_VIRTUAL_DEF(0x01D05340, CFileSystem_Stdio::Mount),
|
||||
HOOK_VIRTUAL_DEF(0x01D011C0, CFileSystem_Stdio::Unmount),
|
||||
HOOK_VIRTUAL_DEF(0x01D05510, CFileSystem_Stdio::GetLocalCopy),
|
||||
HOOK_VIRTUAL_DEF(0x01D05520, CFileSystem_Stdio::LogLevelLoadStarted),
|
||||
HOOK_VIRTUAL_DEF(0x01D05530, CFileSystem_Stdio::LogLevelLoadFinished),
|
||||
HOOK_VIRTUAL_DEF(0x01D05540, CFileSystem_Stdio::HintResourceNeed),
|
||||
HOOK_VIRTUAL_DEF(0x01D05550, CFileSystem_Stdio::PauseResourcePreloading),
|
||||
HOOK_VIRTUAL_DEF(0x01D05560, CFileSystem_Stdio::ResumeResourcePreloading),
|
||||
HOOK_VIRTUAL_DEF(0x01D05570, CFileSystem_Stdio::SetVBuf),
|
||||
HOOK_VIRTUAL_DEF(0x01D055B0, CFileSystem_Stdio::GetInterfaceVersion),
|
||||
HOOK_VIRTUAL_DEF(0x01D055D0, CFileSystem_Stdio::WaitForResources),
|
||||
HOOK_VIRTUAL_DEF(0x01D055E0, CFileSystem_Stdio::GetWaitForResourcesProgress),
|
||||
HOOK_VIRTUAL_DEF(0x01D05600, CFileSystem_Stdio::CancelWaitForResources),
|
||||
HOOK_VIRTUAL_DEF(0x01D05610, CFileSystem_Stdio::IsAppReadyForOfflinePlay),
|
||||
|
||||
// virtual functions - BaseFileSystem
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D01AF0, CFileSystem_Stdio, Open),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D01CC0, CFileSystem_Stdio, OpenFromCacheForRead),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D01D50, CFileSystem_Stdio, Close),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D01DD0, CFileSystem_Stdio, Seek),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D01EA0, CFileSystem_Stdio, Tell),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D01EF0, CFileSystem_Stdio, Size, size_t (FileHandle_t)),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D01F30, CFileSystem_Stdio, Size, size_t (const char *)),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D02310, CFileSystem_Stdio, IsOk),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D02370, CFileSystem_Stdio, Flush),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D02150, CFileSystem_Stdio, EndOfFile),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D021E0, CFileSystem_Stdio, Read),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D02240, CFileSystem_Stdio, Write),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D023B0, CFileSystem_Stdio, ReadLine),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D02290, CFileSystem_Stdio, FPrintf),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D022F0, CFileSystem_Stdio, GetReadBuffer),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D02300, CFileSystem_Stdio, ReleaseReadBuffer),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D012B0, CFileSystem_Stdio, GetCurrentDirectory),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D012B0, CFileSystem_Stdio, GetCurrentDirectory),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D011D0, CFileSystem_Stdio, CreateDirHierarchy),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D01680, CFileSystem_Stdio, IsDirectory),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D024A0, CFileSystem_Stdio, GetLocalPath),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D02400, CFileSystem_Stdio, RemoveFile),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D042B0, CFileSystem_Stdio, RemoveAllSearchPaths),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D01320, CFileSystem_Stdio, AddSearchPath),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D014E0, CFileSystem_Stdio, RemoveSearchPath),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D01AA0, CFileSystem_Stdio, FileExists),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D04000, CFileSystem_Stdio, GetFileTime),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D04060, CFileSystem_Stdio, FileTimeToString),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D036B0, CFileSystem_Stdio, FindFirst),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D03DB0, CFileSystem_Stdio, FindNext),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D03DF0, CFileSystem_Stdio, FindIsDirectory),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D03E10, CFileSystem_Stdio, FindClose),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D03EF0, CFileSystem_Stdio, ParseFile),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D04130, CFileSystem_Stdio, FullPathToRelativePath),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D012A0, CFileSystem_Stdio, PrintOpenedFiles),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D04090, CFileSystem_Stdio, SetWarningFunc),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D040A0, CFileSystem_Stdio, SetWarningLevel),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D02A20, CFileSystem_Stdio, AddPackFile),
|
||||
HOOK_SYMBOL_VIRTUAL_EX(0x01D01300, CFileSystem_Stdio, AddSearchPathNoWrite),
|
||||
|
||||
// non-virtual functions - BaseFileSystem
|
||||
HOOK_DEF(0x01D02780, CBaseFileSystem::Trace_FOpen),
|
||||
HOOK_DEF(0x01D028A0, CBaseFileSystem::Trace_FClose),
|
||||
HOOK_DEF(0x01D029E0, CBaseFileSystem::Trace_DumpUnclosedFiles),
|
||||
HOOK_DEF(0x01D01340, CBaseFileSystem::AddSearchPathInternal),
|
||||
HOOK_DEF(0x01D040B0, CBaseFileSystem::Warning),
|
||||
HOOK_DEF(0x01D04350, CBaseFileSystem::FixSlashes),
|
||||
HOOK_DEF(0x01D04370, CBaseFileSystem::FixPath),
|
||||
//HOOK_DEF(0x01D04320, CBaseFileSystem::StripFilename), // NOXREF
|
||||
HOOK_DEF(0x01D01610, CBaseFileSystem::GetWritePath),
|
||||
HOOK_DEF(0x01D01790, CBaseFileSystem::FindFile),
|
||||
HOOK_DEF(0x01D01F70, CBaseFileSystem::FastFindFileSize),
|
||||
//HOOK_DEF(0x01D034B0, CBaseFileSystem::RemoveAllMapSearchPaths), // NOXREF
|
||||
HOOK_DEF(0x01D033A0, CBaseFileSystem::AddPackFiles),
|
||||
HOOK_DEF(0x01D02A40, CBaseFileSystem::AddPackFileFromPath),
|
||||
HOOK_DEF(0x01D02D20, CBaseFileSystem::PreparePackFile),
|
||||
HOOK_DEF(0x01D03070, CBaseFileSystem::Prepare64BitPackFile),
|
||||
HOOK_DEF(0x01D03510, CBaseFileSystem::SearchPakFile),
|
||||
//HOOK_DEF(0x01D039B0, CBaseFileSystem::FileInSearchPaths), // NOXREF
|
||||
HOOK_DEF(0x01D03B70, CBaseFileSystem::FindNextFileHelper),
|
||||
HOOK_DEF(0x01D03890, CBaseFileSystem::FindFirstHelper),
|
||||
|
||||
#endif // BaseFileSystem_region
|
||||
|
||||
#ifndef CUtlSymbol_Region
|
||||
|
||||
//HOOK_DEF(0x01D05AA0, MethodThunk<CUtlSymbolTable>::Destructor), // NOXREF
|
||||
HOOK_DEF(0x01D05A30, (MethodThunk<CUtlSymbolTable, int, int, bool>::Constructor), void(int, int, bool)),
|
||||
HOOK_DEF(0x01D05C50, CUtlSymbolTable::AddString),
|
||||
HOOK_DEF(0x01D05B10, CUtlSymbolTable::Find),
|
||||
HOOK_DEF(0x01D05DA0, CUtlSymbolTable::String),
|
||||
//HOOK_DEF(0x0, CUtlSymbolTable::RemoveAll), // NOXREF
|
||||
HOOK_DEF(0x01D05960, CUtlSymbolTable::SymLess),
|
||||
HOOK_DEF(0x01D059E0, CUtlSymbolTable::SymLessi),
|
||||
|
||||
HOOK_DEF(0x01D05890, (MethodThunk<CUtlSymbol, const char *>::Constructor), void(const char *)),
|
||||
HOOK_DEF(0x01D05830, CUtlSymbol::Initialize), // Don't touch it
|
||||
HOOK_DEF(0x01D05880, CUtlSymbol::CurrTable), // Don't touch it
|
||||
HOOK_DEF(0x01D058C0, CUtlSymbol::String),
|
||||
//HOOK_DEF(0x01D058E0, CUtlSymbol::operator==, bool (const char *) const), // NOXREF
|
||||
|
||||
#endif // CUtlSymbol_Region
|
||||
|
||||
{ NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
AddressRef g_FunctionRefs[] =
|
||||
{
|
||||
#ifndef Function_References_region
|
||||
|
||||
#endif // Function_References_region
|
||||
|
||||
{ NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
AddressRef g_DataRefs[] =
|
||||
{
|
||||
#ifndef Data_References_region
|
||||
|
||||
//GLOBALVAR_LINK(0x01D1B020, "CBaseFileSystem::s_pFileSystem", CBaseFileSystem::s_pFileSystem),
|
||||
GLOBALVAR_LINK(0x01D1B0B8, "g_LessCtx", pg_LessCtx),
|
||||
|
||||
#endif // Data_References_region
|
||||
|
||||
{ NULL, NULL, NULL },
|
||||
};
|
42
rehlds/hookers/filesystem/hooklist.h
Normal file
42
rehlds/hookers/filesystem/hooklist.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef HOOK_FILESYSTEM
|
||||
|
||||
#define rehlds_syserror FileSystem_SysError
|
||||
#define g_LessCtx (*pg_LessCtx)
|
||||
|
||||
#include "hookers/memory.h"
|
||||
#include "hookers/helper.h"
|
||||
#include "hookers/hooker.h"
|
||||
|
||||
extern struct LessCtx_t g_LessCtx;
|
||||
|
||||
#endif // HOOK_FILESYSTEM
|
86
rehlds/hookers/filesystem/main.cpp
Normal file
86
rehlds/hookers/filesystem/main.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#if defined(HOOK_FILESYSTEM)
|
||||
|
||||
const char *ORIGINAL_FILESYSTEM_DLL_NAME = "filesystem_stdio2.dll";
|
||||
|
||||
CSysModule *g_pOriginalFileSystemModule = nullptr;
|
||||
CreateInterfaceFn g_OriginalFileSystemFactory = nullptr;
|
||||
IFileSystem *g_pOriginalFileSystem = nullptr;
|
||||
|
||||
IBaseInterface *CreateFileSystemInterface()
|
||||
{
|
||||
if (g_pOriginalFileSystem) {
|
||||
return g_pOriginalFileSystem;
|
||||
}
|
||||
|
||||
if (g_pOriginalFileSystemModule)
|
||||
{
|
||||
g_OriginalFileSystemFactory = (CreateInterfaceFn)Sys_GetFactory(g_pOriginalFileSystemModule);
|
||||
|
||||
if (g_OriginalFileSystemFactory)
|
||||
{
|
||||
int returnCode = 0;
|
||||
g_pOriginalFileSystem = (IFileSystem *)g_OriginalFileSystemFactory(FILESYSTEM_INTERFACE_VERSION, &returnCode);
|
||||
return g_pOriginalFileSystem;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EXPOSE_INTERFACE_FN(CreateFileSystemInterface, IFileSystem, FILESYSTEM_INTERFACE_VERSION);
|
||||
|
||||
// DLL entry point
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
if (fdwReason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
g_pOriginalFileSystemModule = (CSysModule *)LoadLibrary(ORIGINAL_FILESYSTEM_DLL_NAME);
|
||||
size_t addr = (size_t)Sys_GetProcAddress(ORIGINAL_FILESYSTEM_DLL_NAME, CREATEINTERFACE_PROCNAME);
|
||||
HookModule("hlds.exe", addr);
|
||||
}
|
||||
else if (fdwReason == DLL_PROCESS_DETACH)
|
||||
{
|
||||
if (g_pOriginalFileSystemModule)
|
||||
{
|
||||
Sys_UnloadModule(g_pOriginalFileSystemModule);
|
||||
g_pOriginalFileSystemModule = nullptr;
|
||||
|
||||
g_OriginalFileSystemFactory = nullptr;
|
||||
g_pOriginalFileSystem = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif // #if defined(HOOK_FILESYSTEM)
|
@ -8,7 +8,7 @@
|
||||
#include <array>
|
||||
#include <utility>
|
||||
|
||||
#if defined(HOOK_ENGINE) || defined(HOOK_HLTV)
|
||||
#if defined(HOOK_ENGINE) || defined(HOOK_HLTV) || defined(HOOK_FILESYSTEM)
|
||||
|
||||
#define private public
|
||||
#define protected public
|
||||
@ -116,6 +116,9 @@ namespace MsvcMethod {
|
||||
return (vIndexGetter->*vIndexGetterFunction)();
|
||||
}
|
||||
|
||||
template <typename TMethod, typename T>
|
||||
TMethod &declmethod(TMethod T::*method);
|
||||
|
||||
template <typename TMethod, typename T>
|
||||
std::enable_if_t<Detail::is_function_v<TMethod>, std::uintptr_t>
|
||||
GetVirtualAddress(TMethod T::*method)
|
||||
@ -148,6 +151,7 @@ namespace MsvcMethod {
|
||||
#define GLOBALVAR_LINK(offset, symbol, var, ...) { offset, #symbol, (size_t)&##var, __VA_ARGS__ }
|
||||
#define HOOK_SYMBOLDEF(offset, symbol, func, ...) { offset, #symbol, MsvcMethod::GetAddress<__VA_ARGS__>(&func) }
|
||||
#define HOOK_SYMBOL_VIRTUAL_DEF(offset, symbol, func, ...) { offset, #symbol, MsvcMethod::GetVirtualAddress<__VA_ARGS__>(&func) }
|
||||
#define HOOK_SYMBOL_VIRTUAL_EX(offset, class, func, ...) { offset, #class#func, MsvcMethod::GetVirtualAddress<std::remove_reference<decltype(MsvcMethod::declmethod<__VA_ARGS__>(&class::func))>::type, class>(&class::func) }
|
||||
|
||||
#define HOOK_DEF(offset, func, ...) HOOK_SYMBOLDEF(offset, func, func, __VA_ARGS__)
|
||||
#define HOOK_VIRTUAL_DEF(offset, func, ...) HOOK_SYMBOL_VIRTUAL_DEF(offset, func, func, __VA_ARGS__)
|
||||
@ -156,4 +160,4 @@ namespace MsvcMethod {
|
||||
#error Hooking stuff is only available using MSVC compiler.
|
||||
#endif // _MSC_VER
|
||||
|
||||
#endif // #if defined(HOOK_ENGINE) || defined(HOOK_HLTV)
|
||||
#endif // #if defined(HOOK_ENGINE) || defined(HOOK_HLTV) || defined(HOOK_FILESYSTEM)
|
||||
|
@ -72,6 +72,7 @@
|
||||
<ClCompile Include="..\engine\ipratelimitWrapper.cpp" />
|
||||
<ClCompile Include="..\engine\l_studio.cpp" />
|
||||
<ClCompile Include="..\engine\mathlib.cpp" />
|
||||
<ClCompile Include="..\engine\mathlib_sse.cpp" />
|
||||
<ClCompile Include="..\engine\md5.cpp" />
|
||||
<ClCompile Include="..\engine\mem.cpp" />
|
||||
<ClCompile Include="..\engine\model.cpp" />
|
||||
@ -432,6 +433,7 @@
|
||||
<ClInclude Include="..\engine\keys.h" />
|
||||
<ClInclude Include="..\engine\l_studio.h" />
|
||||
<ClInclude Include="..\engine\mathlib_e.h" />
|
||||
<ClInclude Include="..\engine\mathlib_sse.h" />
|
||||
<ClInclude Include="..\engine\mem.h" />
|
||||
<ClInclude Include="..\engine\model_rehlds.h" />
|
||||
<ClInclude Include="..\engine\modinfo.h" />
|
||||
@ -805,7 +807,7 @@
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>REHLDS_API;REHLDS_FLIGHT_REC;REHLDS_OPT_PEDANTIC;REHLDS_FIXES;REHLDS_SELF;REHLDS_CHECKS;HAVE_OPT_STRTOOLS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>REHLDS_API;REHLDS_FLIGHT_REC;REHLDS_OPT_PEDANTIC;REHLDS_FIXES;REHLDS_SSE;REHLDS_SELF;REHLDS_CHECKS;HAVE_OPT_STRTOOLS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<FloatingPointModel>Precise</FloatingPointModel>
|
||||
<AdditionalOptions>/arch:IA32 %(AdditionalOptions)</AdditionalOptions>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
@ -1149,7 +1151,7 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>REHLDS_API;REHLDS_FLIGHT_REC;REHLDS_FIXES;REHLDS_OPT_PEDANTIC;REHLDS_SELF;REHLDS_CHECKS;HAVE_OPT_STRTOOLS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>REHLDS_API;REHLDS_FLIGHT_REC;REHLDS_FIXES;REHLDS_SSE;REHLDS_OPT_PEDANTIC;REHLDS_SELF;REHLDS_CHECKS;HAVE_OPT_STRTOOLS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<AdditionalOptions>/arch:IA32 %(AdditionalOptions)</AdditionalOptions>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
|
@ -353,6 +353,9 @@
|
||||
<ClCompile Include="..\engine\SystemWrapper.cpp">
|
||||
<Filter>engine\common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\engine\mathlib_sse.cpp">
|
||||
<Filter>engine</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\version\version.h">
|
||||
@ -1081,6 +1084,9 @@
|
||||
<ClInclude Include="..\public\strtools.h">
|
||||
<Filter>public</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\engine\mathlib_sse.h">
|
||||
<Filter>engine</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\linux\appversion.sh">
|
||||
|
@ -64,20 +64,22 @@ enum
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FILESYSTEM_WARNING = -1, // A problem!
|
||||
FILESYSTEM_WARNING_QUIET = 0, // Don't print anything
|
||||
FILESYSTEM_WARNING_REPORTUNCLOSED, // On shutdown, report names of files left unclosed
|
||||
FILESYSTEM_WARNING_REPORTUSAGE, // Report number of times a file was opened, closed
|
||||
FILESYSTEM_WARNING_REPORTALLACCESSES // Report all open/close events to console (!slow!)
|
||||
} FileWarningLevel_t;
|
||||
|
||||
#define FILESYSTEM_INVALID_HANDLE (FileHandle_t)0
|
||||
const FileHandle_t FILESYSTEM_INVALID_HANDLE = nullptr;
|
||||
|
||||
#endif // FILESYSTEM_INTERNAL_H
|
||||
|
||||
// turn off any windows defines
|
||||
#undef GetCurrentDirectory
|
||||
|
||||
// Purpose: Main file system interface
|
||||
class IFileSystem : public IBaseInterface
|
||||
class IFileSystem: public IBaseInterface
|
||||
{
|
||||
public:
|
||||
// Mount and unmount the filesystem
|
||||
@ -114,10 +116,10 @@ public:
|
||||
virtual void Close(FileHandle_t file) = 0;
|
||||
|
||||
virtual void Seek(FileHandle_t file, int pos, FileSystemSeek_t seekType) = 0;
|
||||
virtual unsigned int Tell(FileHandle_t file) = 0;
|
||||
virtual size_t Tell(FileHandle_t file) = 0;
|
||||
|
||||
virtual unsigned int Size(FileHandle_t file) = 0;
|
||||
virtual unsigned int Size(const char *pFileName) = 0;
|
||||
virtual size_t Size(FileHandle_t file) = 0;
|
||||
virtual size_t Size(const char *pFileName) = 0;
|
||||
|
||||
virtual long GetFileTime(const char *pFileName) = 0;
|
||||
virtual void FileTimeToString(char *pStrip, int maxCharsIncludingTerminator, long fileTime) = 0;
|
||||
@ -130,7 +132,7 @@ public:
|
||||
virtual int Read(void *pOutput, int size, FileHandle_t file) = 0;
|
||||
virtual int Write(void const *pInput, int size, FileHandle_t file) = 0;
|
||||
virtual char *ReadLine(char *pOutput, int maxChars, FileHandle_t file) = 0;
|
||||
virtual int FPrintf(FileHandle_t file, char *pFormat, ...) = 0;
|
||||
virtual int FPrintf(FileHandle_t file, const char *fmt, ...) = 0;
|
||||
|
||||
// direct filesystem buffer access
|
||||
// returns a handle to a buffer containing the file data
|
||||
|
@ -70,7 +70,7 @@ public:
|
||||
//
|
||||
// Use this if you want to write the factory function.
|
||||
#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName)\
|
||||
static InterfaceReg __g_Create##className##_reg(functionName, versionName);
|
||||
static InterfaceReg __g_Create##interfaceName##_reg(functionName, versionName);
|
||||
|
||||
#define EXPOSE_INTERFACE(className, interfaceName, versionName)\
|
||||
static IBaseInterface *__Create##className##_interface() {return (interfaceName *)new className;}\
|
||||
|
@ -115,6 +115,7 @@ uint32 crc32c_t_nosse(uint32 iCRC, const uint8 *buf, int len) {
|
||||
return crc;
|
||||
}
|
||||
|
||||
#ifdef REHLDS_SSE
|
||||
FUNC_TARGET("sse4.2")
|
||||
uint32 crc32c_t8_sse(uint32 iCRC, uint8 u8) {
|
||||
return _mm_crc32_u8(iCRC, u8);
|
||||
@ -140,6 +141,14 @@ uint32 crc32c_t(uint32 iCRC, const uint8 *buf, unsigned int len) {
|
||||
return cpuinfo.sse4_2 ? crc32c_t_sse(iCRC, buf, len) : crc32c_t_nosse(iCRC, buf, len);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
uint32 crc32c_t(uint32 iCRC, const uint8 *buf, unsigned int len) {
|
||||
return crc32c_t_nosse(iCRC, buf, len);
|
||||
}
|
||||
|
||||
#endif // REHLDS_SSE
|
||||
|
||||
uint32 crc32c(const uint8 *buf, int len) {
|
||||
return crc32c_t(0xffffffff, buf, len);
|
||||
}
|
||||
|
@ -11,7 +11,9 @@ GNU Lesser General Public License for more details.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "archtypes.h"
|
||||
|
||||
extern uint32 crc32c_t8_nosse(uint32 iCRC, uint8 u8);
|
||||
|
@ -60,7 +60,7 @@ struct event_state_s
|
||||
#include "edict.h"
|
||||
#endif
|
||||
|
||||
#define STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - (int)&(((t *)0)->m)))
|
||||
#define STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - offsetof(t, m)))
|
||||
#define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area)
|
||||
|
||||
//============================================================================
|
||||
|
@ -169,7 +169,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Iterator(CStaticMap* m) {
|
||||
m_Map = m;
|
||||
m_RootNodes = m_Map->m_RootNodes;
|
||||
@ -226,6 +225,7 @@ protected:
|
||||
virtual uint32 hash(const char* const &val) {
|
||||
uint32 cksum = 0;
|
||||
const char* pcc = val;
|
||||
#ifdef REHLDS_SSE
|
||||
if (cpuinfo.sse4_2) {
|
||||
while (*pcc) {
|
||||
char cc = *(pcc++);
|
||||
@ -234,7 +234,10 @@ protected:
|
||||
}
|
||||
cksum = crc32c_t8_sse(cksum, cc);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
#endif // REHLDS_SSE
|
||||
{
|
||||
while (*pcc) {
|
||||
char cc = *(pcc++);
|
||||
if (cc >= 'A' || cc <= 'Z') {
|
||||
|
50
rehlds/public/tier0/characterset.cpp
Normal file
50
rehlds/public/tier0/characterset.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "characterset.h"
|
||||
|
||||
// Builds a simple lookup table of a group of important characters
|
||||
// Input : *pParseGroup - pointer to the buffer for the group
|
||||
// *pGroupString - null terminated list of characters to flag
|
||||
void CharacterSetBuild(characterset_t *pSetBuffer, const char *pszSetString)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
// Test our pointers
|
||||
if (!pSetBuffer || !pszSetString)
|
||||
return;
|
||||
|
||||
memset(pSetBuffer->set, 0, sizeof(pSetBuffer->set));
|
||||
|
||||
while (pszSetString[i])
|
||||
{
|
||||
pSetBuffer->set[pszSetString[i]] = 1;
|
||||
i++;
|
||||
}
|
||||
}
|
46
rehlds/public/tier0/characterset.h
Normal file
46
rehlds/public/tier0/characterset.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct characterset_t
|
||||
{
|
||||
char set[256];
|
||||
};
|
||||
|
||||
// This is essentially a strpbrk() using a precalculated lookup table
|
||||
//
|
||||
// Builds a simple lookup table of a group of important characters
|
||||
// Input : *pSetBuffer - pointer to the buffer for the group
|
||||
// *pSetString - list of characters to flag
|
||||
extern void CharacterSetBuild(characterset_t *pSetBuffer, const char *pSetString);
|
||||
|
||||
// Input : *pSetBuffer - pre-build group buffer
|
||||
// character - character to lookup
|
||||
// Output : int - 1 if the character was in the set
|
||||
#define IN_CHARACTERSET(SetBuffer, character) ((SetBuffer).set[(character)])
|
@ -116,7 +116,7 @@ private:
|
||||
int m_nGrowSize;
|
||||
};
|
||||
|
||||
// constructor, destructor
|
||||
// Constructor, Destructor
|
||||
template <class T, class I>
|
||||
CUtlMemory<T, I>::CUtlMemory(int nGrowSize, int nInitSize) : m_pMemory(0),
|
||||
m_nAllocationCount(nInitSize), m_nGrowSize(nGrowSize)
|
||||
@ -170,7 +170,7 @@ void CUtlMemory<T, I>::SetExternalBuffer(T *pMemory, int numElements)
|
||||
m_nGrowSize = EXTERNAL_BUFFER_MARKER;
|
||||
}
|
||||
|
||||
// element access
|
||||
// Element access
|
||||
template <class T, class I>
|
||||
inline T& CUtlMemory<T, I>::operator[](I i)
|
||||
{
|
||||
@ -199,7 +199,7 @@ inline T const& CUtlMemory<T, I>::Element(I i) const
|
||||
return m_pMemory[i];
|
||||
}
|
||||
|
||||
// is the memory externally allocated?
|
||||
// Is the memory externally allocated?
|
||||
template <class T, class I>
|
||||
bool CUtlMemory<T, I>::IsExternallyAllocated() const
|
||||
{
|
||||
@ -329,6 +329,7 @@ void CUtlMemory<T, I>::Purge()
|
||||
free((void *)m_pMemory);
|
||||
m_pMemory = 0;
|
||||
}
|
||||
|
||||
m_nAllocationCount = 0;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
152
rehlds/public/utlsymbol.cpp
Normal file
152
rehlds/public/utlsymbol.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "utlsymbol.h"
|
||||
|
||||
LessCtx_t g_LessCtx;
|
||||
CUtlSymbolTable *CUtlSymbol::s_pSymbolTable = nullptr;
|
||||
|
||||
void CUtlSymbol::Initialize()
|
||||
{
|
||||
// necessary to allow us to create global symbols
|
||||
static bool symbolsInitialized = false;
|
||||
if (!symbolsInitialized)
|
||||
{
|
||||
s_pSymbolTable = new CUtlSymbolTable;
|
||||
symbolsInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
CUtlSymbolTable *CUtlSymbol::CurrTable()
|
||||
{
|
||||
Initialize();
|
||||
return s_pSymbolTable;
|
||||
}
|
||||
|
||||
CUtlSymbol::CUtlSymbol(const char *pStr)
|
||||
{
|
||||
m_Id = CurrTable()->AddString(pStr);
|
||||
}
|
||||
|
||||
const char *CUtlSymbol::String() const
|
||||
{
|
||||
return CurrTable()->String(m_Id);
|
||||
}
|
||||
|
||||
// Checks if the symbol matches a string
|
||||
bool CUtlSymbol::operator==(const char *pStr) const
|
||||
{
|
||||
if (m_Id == UTL_INVAL_SYMBOL)
|
||||
return false;
|
||||
|
||||
return Q_strcmp(String(), pStr) == 0;
|
||||
}
|
||||
|
||||
bool CUtlSymbolTable::SymLess(const unsigned int &i1, const unsigned int &i2)
|
||||
{
|
||||
const char *str1 = (i1 == INVALID_STRING_INDEX) ? g_LessCtx.m_pUserString : g_LessCtx.m_pTable->StringFromIndex(i1);
|
||||
const char *str2 = (i2 == INVALID_STRING_INDEX) ? g_LessCtx.m_pUserString : g_LessCtx.m_pTable->StringFromIndex(i2);
|
||||
|
||||
return Q_strcmp(str1, str2) < 0;
|
||||
}
|
||||
|
||||
bool CUtlSymbolTable::SymLessi(const unsigned int &i1, const unsigned int &i2)
|
||||
{
|
||||
const char *str1 = (i1 == INVALID_STRING_INDEX) ? g_LessCtx.m_pUserString : g_LessCtx.m_pTable->StringFromIndex(i1);
|
||||
const char *str2 = (i2 == INVALID_STRING_INDEX) ? g_LessCtx.m_pUserString : g_LessCtx.m_pTable->StringFromIndex(i2);
|
||||
|
||||
return Q_stricmp(str1, str2) < 0;
|
||||
}
|
||||
|
||||
// Constructor, Destructor
|
||||
CUtlSymbolTable::CUtlSymbolTable(int growSize, int initSize, bool caseInsensitive) :
|
||||
m_Lookup(growSize, initSize, caseInsensitive ? SymLess : SymLessi),
|
||||
m_StringPools(MAX_STRING_POOL_SIZE)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
CUtlSymbolTable::~CUtlSymbolTable()
|
||||
{
|
||||
// Release the stringpool string data
|
||||
RemoveAll();
|
||||
}
|
||||
|
||||
CUtlSymbol CUtlSymbolTable::Find(const char *pString)
|
||||
{
|
||||
if (!pString)
|
||||
return CUtlSymbol();
|
||||
|
||||
// Store a special context used to help with insertion
|
||||
g_LessCtx.m_pUserString = pString;
|
||||
g_LessCtx.m_pTable = this;
|
||||
|
||||
// Passing this special invalid symbol makes the comparison function
|
||||
// use the string passed in the context
|
||||
UtlSymId_t idx = m_Lookup.Find(INVALID_STRING_INDEX);
|
||||
return CUtlSymbol(idx);
|
||||
}
|
||||
|
||||
// Finds and/or creates a symbol based on the string
|
||||
CUtlSymbol CUtlSymbolTable::AddString(const char *pString)
|
||||
{
|
||||
if (!pString)
|
||||
return CUtlSymbol(UTL_INVAL_SYMBOL);
|
||||
|
||||
// Find a pool with space for this string, or allocate a new one
|
||||
CUtlSymbol id = Find(pString);
|
||||
|
||||
if (id.IsValid())
|
||||
return id;
|
||||
|
||||
// Add a new pool
|
||||
int len = Q_strlen(pString) + 1;
|
||||
int stridx = m_StringPools.AddMultipleToTail(len);
|
||||
Q_memcpy(&m_StringPools[stridx], pString, len);
|
||||
|
||||
// Didn't find, insert the string into the vector
|
||||
UtlSymId_t idx = m_Lookup.Insert(stridx);
|
||||
return CUtlSymbol(idx);
|
||||
}
|
||||
|
||||
// Look up the string associated with a particular symbol
|
||||
const char *CUtlSymbolTable::String(CUtlSymbol id) const
|
||||
{
|
||||
if (!id.IsValid())
|
||||
return "";
|
||||
|
||||
Assert(m_Lookup.IsValidIndex((UtlSymId_t)id));
|
||||
return StringFromIndex(m_Lookup[id]);
|
||||
}
|
||||
|
||||
// Remove all symbols in the table
|
||||
void CUtlSymbolTable::RemoveAll()
|
||||
{
|
||||
m_Lookup.RemoveAll();
|
||||
m_StringPools.RemoveAll();
|
||||
}
|
113
rehlds/public/utlsymbol.h
Normal file
113
rehlds/public/utlsymbol.h
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "utlrbtree.h"
|
||||
#include "utlvector.h"
|
||||
|
||||
class CUtlSymbolTable;
|
||||
|
||||
using UtlSymId_t = unsigned short;
|
||||
|
||||
const int MAX_STRING_POOL_SIZE = 256;
|
||||
const UtlSymId_t UTL_INVAL_SYMBOL = ((UtlSymId_t)~0);
|
||||
const unsigned int INVALID_STRING_INDEX = -1;
|
||||
|
||||
struct LessCtx_t
|
||||
{
|
||||
const char *m_pUserString;
|
||||
CUtlSymbolTable *m_pTable;
|
||||
|
||||
LessCtx_t() : m_pUserString(0), m_pTable(0) {}
|
||||
};
|
||||
|
||||
class CUtlSymbol
|
||||
{
|
||||
public:
|
||||
// constructor, destructor
|
||||
CUtlSymbol() : m_Id(UTL_INVAL_SYMBOL) {}
|
||||
CUtlSymbol(UtlSymId_t id) : m_Id(id) {}
|
||||
CUtlSymbol(const char *pStr);
|
||||
CUtlSymbol(CUtlSymbol const &sym) : m_Id(sym.m_Id) {}
|
||||
|
||||
// operator=
|
||||
CUtlSymbol &operator=(CUtlSymbol const &src)
|
||||
{
|
||||
m_Id = src.m_Id;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// operator==
|
||||
bool operator==(CUtlSymbol const &src) const { return m_Id == src.m_Id; }
|
||||
bool operator==(const char *pStr) const;
|
||||
|
||||
// Is valid?
|
||||
bool IsValid() const { return m_Id != UTL_INVAL_SYMBOL; }
|
||||
|
||||
operator UtlSymId_t() const { return m_Id; } // Gets at the symbol
|
||||
const char *String() const; // Gets the string associated with the symbol
|
||||
|
||||
protected:
|
||||
static void Initialize(); // Initializes the symbol table
|
||||
static CUtlSymbolTable *CurrTable(); // returns the current symbol table
|
||||
|
||||
UtlSymId_t m_Id;
|
||||
static CUtlSymbolTable *s_pSymbolTable;
|
||||
};
|
||||
|
||||
class CUtlSymbolTable
|
||||
{
|
||||
public:
|
||||
// constructor, destructor
|
||||
CUtlSymbolTable(int growSize = 0, int initSize = 32, bool caseInsensitive = false);
|
||||
~CUtlSymbolTable();
|
||||
|
||||
CUtlSymbol AddString(const char *pString); // Finds and/or creates a symbol based on the string
|
||||
CUtlSymbol Find(const char *pString); // Finds the symbol for pString
|
||||
|
||||
const char *String(CUtlSymbol id) const; // Look up the string associated with a particular symbol
|
||||
void RemoveAll(); // Remove all symbols in the table
|
||||
|
||||
public:
|
||||
static bool SymLess(const unsigned int &i1, const unsigned int &i2);
|
||||
static bool SymLessi(const unsigned int &i1, const unsigned int &i2);
|
||||
|
||||
private:
|
||||
const char *StringFromIndex(const UtlSymId_t &index) const;
|
||||
|
||||
protected:
|
||||
CUtlRBTree<unsigned int, UtlSymId_t> m_Lookup;
|
||||
CUtlVector<char> m_StringPools;
|
||||
};
|
||||
|
||||
inline const char *CUtlSymbolTable::StringFromIndex(const UtlSymId_t &index) const
|
||||
{
|
||||
Assert(index < m_StringPools.Count());
|
||||
return &m_StringPools[index];
|
||||
}
|
@ -1,24 +1,34 @@
|
||||
//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. ===========
|
||||
//
|
||||
// The copyright to the contents herein is the property of Valve, L.L.C.
|
||||
// The contents may be used and/or copied only with the written permission of
|
||||
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
|
||||
// the agreement/contract under which the contents have been supplied.
|
||||
//
|
||||
// $Header: $
|
||||
// $NoKeywords: $
|
||||
//
|
||||
// A growable memory class.
|
||||
//=============================================================================
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UTLVECTOR_H
|
||||
#define UTLVECTOR_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "utlmemory.h"
|
||||
#include "tier0/platform.h"
|
||||
|
||||
template<class T>
|
||||
class CUtlVector
|
||||
@ -27,22 +37,29 @@ public:
|
||||
typedef T ElemType_t;
|
||||
|
||||
// constructor, destructor
|
||||
CUtlVector( int growSize = 0, int initSize = 0 );
|
||||
CUtlVector( T* pMemory, int numElements );
|
||||
CUtlVector(int growSize = 0, int initSize = 0);
|
||||
CUtlVector(T *pMemory, int numElements);
|
||||
~CUtlVector();
|
||||
|
||||
// features C++11 ranged based for
|
||||
T *begin() { return &m_Memory[0]; }
|
||||
T *end() { return &m_Memory[m_Size - 1]; }
|
||||
|
||||
T const *begin() const { return &m_Memory[0]; }
|
||||
T const *end() const { return &m_Memory[m_Size - 1]; }
|
||||
|
||||
// Copy the array.
|
||||
CUtlVector<T>& operator=( const CUtlVector<T> &other );
|
||||
CUtlVector<T> &operator=(const CUtlVector<T> &other);
|
||||
|
||||
// element access
|
||||
T& operator[]( int i );
|
||||
T const& operator[]( int i ) const;
|
||||
T& Element( int i );
|
||||
T const& Element( int i ) const;
|
||||
T &operator[](int i);
|
||||
T const &operator[](int i) const;
|
||||
T &Element(int i);
|
||||
T const &Element(int i) const;
|
||||
|
||||
// Gets the base address (can change when adding elements!)
|
||||
T* Base();
|
||||
T const* Base() const;
|
||||
T *Base();
|
||||
T const *Base() const;
|
||||
|
||||
// Returns the number of elements in the vector
|
||||
// SIZE IS DEPRECATED!
|
||||
@ -50,53 +67,53 @@ public:
|
||||
int Size() const; // don't use me!
|
||||
|
||||
// Is element index valid?
|
||||
bool IsValidIndex( int i ) const;
|
||||
static int InvalidIndex( void );
|
||||
bool IsValidIndex(int i) const;
|
||||
static int InvalidIndex(void);
|
||||
|
||||
// Adds an element, uses default constructor
|
||||
int AddToHead();
|
||||
int AddToTail();
|
||||
int InsertBefore( int elem );
|
||||
int InsertAfter( int elem );
|
||||
int InsertBefore(int elem);
|
||||
int InsertAfter(int elem);
|
||||
|
||||
// Adds an element, uses copy constructor
|
||||
int AddToHead( T const& src );
|
||||
int AddToTail( T const& src );
|
||||
int InsertBefore( int elem, T const& src );
|
||||
int InsertAfter( int elem, T const& src );
|
||||
int AddToHead(T const &src);
|
||||
int AddToTail(T const &src);
|
||||
int InsertBefore(int elem, T const &src);
|
||||
int InsertAfter(int elem, T const &src);
|
||||
|
||||
// Adds multiple elements, uses default constructor
|
||||
int AddMultipleToHead( int num );
|
||||
int AddMultipleToTail( int num, const T *pToCopy=NULL );
|
||||
int InsertMultipleBefore( int elem, int num, const T *pToCopy=NULL ); // If pToCopy is set, then it's an array of length 'num' and
|
||||
int InsertMultipleAfter( int elem, int num );
|
||||
int AddMultipleToHead(int num);
|
||||
int AddMultipleToTail(int num, const T *pToCopy = nullptr);
|
||||
int InsertMultipleBefore(int elem, int num, const T *pToCopy = nullptr); // If pToCopy is set, then it's an array of length 'num' and
|
||||
int InsertMultipleAfter(int elem, int num);
|
||||
|
||||
// Calls RemoveAll() then AddMultipleToTail.
|
||||
void SetSize( int size );
|
||||
void SetCount( int count );
|
||||
void SetSize(int size);
|
||||
void SetCount(int count);
|
||||
|
||||
// Calls SetSize and copies each element.
|
||||
void CopyArray( T const *pArray, int size );
|
||||
void CopyArray(T const *pArray, int size);
|
||||
|
||||
// Add the specified array to the tail.
|
||||
int AddVectorToTail( CUtlVector<T> const &src );
|
||||
int AddVectorToTail(CUtlVector<T> const &src);
|
||||
|
||||
// Finds an element (element needs operator== defined)
|
||||
int Find( T const& src ) const;
|
||||
int Find(T const &src) const;
|
||||
|
||||
bool HasElement( T const& src );
|
||||
bool HasElement(T const &src);
|
||||
|
||||
// Makes sure we have enough memory allocated to store a requested # of elements
|
||||
void EnsureCapacity( int num );
|
||||
void EnsureCapacity(int num);
|
||||
|
||||
// Makes sure we have at least this many elements
|
||||
void EnsureCount( int num );
|
||||
void EnsureCount(int num);
|
||||
|
||||
// Element removal
|
||||
void FastRemove( int elem ); // doesn't preserve order
|
||||
void Remove( int elem ); // preserves order, shifts elements
|
||||
void FindAndRemove( T const& src ); // removes first occurrence of src, preserves order, shifts elements
|
||||
void RemoveMultiple( int elem, int num ); // preserves order, shifts elements
|
||||
void FastRemove(int elem); // doesn't preserve order
|
||||
void Remove(int elem); // preserves order, shifts elements
|
||||
void FindAndRemove(T const &src); // removes first occurrence of src, preserves order, shifts elements
|
||||
void RemoveMultiple(int elem, int num); // preserves order, shifts elements
|
||||
void RemoveAll(); // doesn't deallocate memory
|
||||
|
||||
// Memory deallocation
|
||||
@ -106,19 +123,18 @@ public:
|
||||
void PurgeAndDeleteElements();
|
||||
|
||||
// Set the size by which it grows when it needs to allocate more memory.
|
||||
void SetGrowSize( int size );
|
||||
void SetGrowSize(int size);
|
||||
|
||||
protected:
|
||||
// Can't copy this unless we explicitly do it!
|
||||
CUtlVector( CUtlVector const& vec ) { assert(0);
|
||||
}
|
||||
CUtlVector(CUtlVector const &vec) { Assert(0); }
|
||||
|
||||
// Grows the vector
|
||||
void GrowVector( int num = 1 );
|
||||
void GrowVector(int num = 1);
|
||||
|
||||
// Shifts elements....
|
||||
void ShiftElementsRight( int elem, int num = 1 );
|
||||
void ShiftElementsLeft( int elem, int num = 1 );
|
||||
void ShiftElementsRight(int elem, int num = 1);
|
||||
void ShiftElementsLeft(int elem, int num = 1);
|
||||
|
||||
// For easier access to the elements through the debugger
|
||||
void ResetDbgInfo();
|
||||
@ -131,444 +147,408 @@ protected:
|
||||
T *m_pElements;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// For easier access to the elements through the debugger
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
template <class T>
|
||||
inline void CUtlVector<T>::ResetDbgInfo()
|
||||
{
|
||||
m_pElements = m_Memory.Base();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// constructor, destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
inline CUtlVector<T>::CUtlVector( int growSize, int initSize ) :
|
||||
template <class T>
|
||||
inline CUtlVector<T>::CUtlVector(int growSize, int initSize) :
|
||||
m_Memory(growSize, initSize), m_Size(0)
|
||||
{
|
||||
ResetDbgInfo();
|
||||
}
|
||||
|
||||
template< class T >
|
||||
inline CUtlVector<T>::CUtlVector( T* pMemory, int numElements ) :
|
||||
template <class T>
|
||||
inline CUtlVector<T>::CUtlVector(T *pMemory, int numElements) :
|
||||
m_Memory(pMemory, numElements), m_Size(0)
|
||||
{
|
||||
ResetDbgInfo();
|
||||
}
|
||||
|
||||
template< class T >
|
||||
template <class T>
|
||||
inline CUtlVector<T>::~CUtlVector()
|
||||
{
|
||||
Purge();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline CUtlVector<T>& CUtlVector<T>::operator=( const CUtlVector<T> &other )
|
||||
template <class T>
|
||||
inline CUtlVector<T> &CUtlVector<T>::operator=(const CUtlVector<T> &other)
|
||||
{
|
||||
CopyArray( other.Base(), other.Count() );
|
||||
CopyArray(other.Base(), other.Count());
|
||||
return *this;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// element access
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
inline T& CUtlVector<T>::operator[]( int i )
|
||||
template <class T>
|
||||
inline T &CUtlVector<T>::operator[](int i)
|
||||
{
|
||||
assert( IsValidIndex(i) );
|
||||
Assert(IsValidIndex(i));
|
||||
return m_Memory[i];
|
||||
}
|
||||
|
||||
template< class T >
|
||||
inline T const& CUtlVector<T>::operator[]( int i ) const
|
||||
template <class T>
|
||||
inline T const &CUtlVector<T>::operator[](int i) const
|
||||
{
|
||||
assert( IsValidIndex(i) );
|
||||
Assert(IsValidIndex(i));
|
||||
return m_Memory[i];
|
||||
}
|
||||
|
||||
template< class T >
|
||||
inline T& CUtlVector<T>::Element( int i )
|
||||
template <class T>
|
||||
inline T &CUtlVector<T>::Element(int i)
|
||||
{
|
||||
assert( IsValidIndex(i) );
|
||||
Assert(IsValidIndex(i));
|
||||
return m_Memory[i];
|
||||
}
|
||||
|
||||
template< class T >
|
||||
inline T const& CUtlVector<T>::Element( int i ) const
|
||||
template <class T>
|
||||
inline T const &CUtlVector<T>::Element(int i) const
|
||||
{
|
||||
assert( IsValidIndex(i) );
|
||||
Assert(IsValidIndex(i));
|
||||
return m_Memory[i];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Gets the base address (can change when adding elements!)
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
inline T* CUtlVector<T>::Base()
|
||||
template <class T>
|
||||
inline T *CUtlVector<T>::Base()
|
||||
{
|
||||
return m_Memory.Base();
|
||||
}
|
||||
|
||||
template< class T >
|
||||
inline T const* CUtlVector<T>::Base() const
|
||||
template <class T>
|
||||
inline T const *CUtlVector<T>::Base() const
|
||||
{
|
||||
return m_Memory.Base();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Count
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
template <class T>
|
||||
inline int CUtlVector<T>::Size() const
|
||||
{
|
||||
return m_Size;
|
||||
}
|
||||
|
||||
template< class T >
|
||||
template <class T>
|
||||
inline int CUtlVector<T>::Count() const
|
||||
{
|
||||
return m_Size;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Is element index valid?
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
inline bool CUtlVector<T>::IsValidIndex( int i ) const
|
||||
template <class T>
|
||||
inline bool CUtlVector<T>::IsValidIndex(int i) const
|
||||
{
|
||||
return (i >= 0) && (i < m_Size);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns in invalid index
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
inline int CUtlVector<T>::InvalidIndex( void )
|
||||
template <class T>
|
||||
inline int CUtlVector<T>::InvalidIndex(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Grows the vector
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
void CUtlVector<T>::GrowVector( int num )
|
||||
template <class T>
|
||||
void CUtlVector<T>::GrowVector(int num)
|
||||
{
|
||||
if (m_Size + num - 1 >= m_Memory.NumAllocated())
|
||||
{
|
||||
m_Memory.Grow( m_Size + num - m_Memory.NumAllocated() );
|
||||
m_Memory.Grow(m_Size + num - m_Memory.NumAllocated());
|
||||
}
|
||||
|
||||
m_Size += num;
|
||||
ResetDbgInfo();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Makes sure we have enough memory allocated to store a requested # of elements
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
void CUtlVector<T>::EnsureCapacity( int num )
|
||||
template <class T>
|
||||
void CUtlVector<T>::EnsureCapacity(int num)
|
||||
{
|
||||
m_Memory.EnsureCapacity(num);
|
||||
ResetDbgInfo();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Makes sure we have at least this many elements
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
void CUtlVector<T>::EnsureCount( int num )
|
||||
template <class T>
|
||||
void CUtlVector<T>::EnsureCount(int num)
|
||||
{
|
||||
if (Count() < num)
|
||||
AddMultipleToTail( num - Count() );
|
||||
AddMultipleToTail(num - Count());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Shifts elements
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
void CUtlVector<T>::ShiftElementsRight( int elem, int num )
|
||||
template <class T>
|
||||
void CUtlVector<T>::ShiftElementsRight(int elem, int num)
|
||||
{
|
||||
assert( IsValidIndex(elem) || ( m_Size == 0 ) || ( num == 0 ));
|
||||
Assert(IsValidIndex(elem) || (m_Size == 0) || (num == 0));
|
||||
int numToMove = m_Size - elem - num;
|
||||
if ((numToMove > 0) && (num > 0))
|
||||
memmove( &Element(elem+num), &Element(elem), numToMove * sizeof(T) );
|
||||
memmove(&Element(elem+num), &Element(elem), numToMove * sizeof(T));
|
||||
}
|
||||
|
||||
template< class T >
|
||||
void CUtlVector<T>::ShiftElementsLeft( int elem, int num )
|
||||
template <class T>
|
||||
void CUtlVector<T>::ShiftElementsLeft(int elem, int num)
|
||||
{
|
||||
assert( IsValidIndex(elem) || ( m_Size == 0 ) || ( num == 0 ));
|
||||
Assert(IsValidIndex(elem) || (m_Size == 0) || (num == 0));
|
||||
int numToMove = m_Size - elem - num;
|
||||
if ((numToMove > 0) && (num > 0))
|
||||
{
|
||||
memmove( &Element(elem), &Element(elem+num), numToMove * sizeof(T) );
|
||||
memmove(&Element(elem), &Element(elem + num), numToMove * sizeof(T));
|
||||
|
||||
#ifdef _DEBUG
|
||||
memset( &Element(m_Size-num), 0xDD, num * sizeof(T) );
|
||||
memset(&Element(m_Size-num), 0xDD, num * sizeof(T));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Adds an element, uses default constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template< class T >
|
||||
template <class T>
|
||||
inline int CUtlVector<T>::AddToHead()
|
||||
{
|
||||
return InsertBefore(0);
|
||||
}
|
||||
|
||||
template< class T >
|
||||
template <class T>
|
||||
inline int CUtlVector<T>::AddToTail()
|
||||
{
|
||||
return InsertBefore( m_Size );
|
||||
return InsertBefore(m_Size);
|
||||
}
|
||||
|
||||
template< class T >
|
||||
inline int CUtlVector<T>::InsertAfter( int elem )
|
||||
template <class T>
|
||||
inline int CUtlVector<T>::InsertAfter(int elem)
|
||||
{
|
||||
return InsertBefore( elem + 1 );
|
||||
return InsertBefore(elem + 1);
|
||||
}
|
||||
|
||||
template< class T >
|
||||
int CUtlVector<T>::InsertBefore( int elem )
|
||||
template <class T>
|
||||
int CUtlVector<T>::InsertBefore(int elem)
|
||||
{
|
||||
// Can insert at the end
|
||||
assert( (elem == Count()) || IsValidIndex(elem) );
|
||||
Assert((elem == Count()) || IsValidIndex(elem));
|
||||
|
||||
GrowVector();
|
||||
ShiftElementsRight(elem);
|
||||
Construct( &Element(elem) );
|
||||
Construct(&Element(elem));
|
||||
return elem;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Adds an element, uses copy constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template< class T >
|
||||
inline int CUtlVector<T>::AddToHead( T const& src )
|
||||
template <class T>
|
||||
inline int CUtlVector<T>::AddToHead(T const &src)
|
||||
{
|
||||
return InsertBefore( 0, src );
|
||||
return InsertBefore(0, src);
|
||||
}
|
||||
|
||||
template< class T >
|
||||
inline int CUtlVector<T>::AddToTail( T const& src )
|
||||
inline int CUtlVector<T>::AddToTail(T const &src)
|
||||
{
|
||||
return InsertBefore( m_Size, src );
|
||||
return InsertBefore(m_Size, src);
|
||||
}
|
||||
|
||||
template< class T >
|
||||
inline int CUtlVector<T>::InsertAfter( int elem, T const& src )
|
||||
inline int CUtlVector<T>::InsertAfter(int elem, T const &src)
|
||||
{
|
||||
return InsertBefore( elem + 1, src );
|
||||
return InsertBefore(elem + 1, src);
|
||||
}
|
||||
|
||||
template< class T >
|
||||
int CUtlVector<T>::InsertBefore( int elem, T const& src )
|
||||
int CUtlVector<T>::InsertBefore(int elem, T const &src)
|
||||
{
|
||||
// Can insert at the end
|
||||
assert( (elem == Count()) || IsValidIndex(elem) );
|
||||
Assert((elem == Count()) || IsValidIndex(elem));
|
||||
|
||||
GrowVector();
|
||||
ShiftElementsRight(elem);
|
||||
CopyConstruct( &Element(elem), src );
|
||||
CopyConstruct(&Element(elem), src);
|
||||
return elem;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Adds multiple elements, uses default constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template< class T >
|
||||
inline int CUtlVector<T>::AddMultipleToHead( int num )
|
||||
template <class T>
|
||||
inline int CUtlVector<T>::AddMultipleToHead(int num)
|
||||
{
|
||||
return InsertMultipleBefore( 0, num );
|
||||
return InsertMultipleBefore(0, num);
|
||||
}
|
||||
|
||||
template< class T >
|
||||
inline int CUtlVector<T>::AddMultipleToTail( int num, const T *pToCopy )
|
||||
template <class T>
|
||||
inline int CUtlVector<T>::AddMultipleToTail(int num, const T *pToCopy)
|
||||
{
|
||||
return InsertMultipleBefore( m_Size, num, pToCopy );
|
||||
return InsertMultipleBefore(m_Size, num, pToCopy);
|
||||
}
|
||||
|
||||
template< class T >
|
||||
int CUtlVector<T>::InsertMultipleAfter( int elem, int num )
|
||||
template <class T>
|
||||
int CUtlVector<T>::InsertMultipleAfter(int elem, int num)
|
||||
{
|
||||
return InsertMultipleBefore( elem + 1, num );
|
||||
return InsertMultipleBefore(elem + 1, num);
|
||||
}
|
||||
|
||||
|
||||
template< class T >
|
||||
void CUtlVector<T>::SetCount( int count )
|
||||
template <class T>
|
||||
void CUtlVector<T>::SetCount(int count)
|
||||
{
|
||||
RemoveAll();
|
||||
AddMultipleToTail( count );
|
||||
AddMultipleToTail(count);
|
||||
}
|
||||
|
||||
template< class T >
|
||||
inline void CUtlVector<T>::SetSize( int size )
|
||||
template <class T>
|
||||
inline void CUtlVector<T>::SetSize(int size)
|
||||
{
|
||||
SetCount( size );
|
||||
SetCount(size);
|
||||
}
|
||||
|
||||
template< class T >
|
||||
void CUtlVector<T>::CopyArray( T const *pArray, int size )
|
||||
template <class T>
|
||||
void CUtlVector<T>::CopyArray(T const *pArray, int size)
|
||||
{
|
||||
SetSize( size );
|
||||
for( int i=0; i < size; i++ )
|
||||
SetSize(size);
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
(*this)[i] = pArray[i];
|
||||
}
|
||||
}
|
||||
|
||||
template< class T >
|
||||
int CUtlVector<T>::AddVectorToTail( CUtlVector const &src )
|
||||
template <class T>
|
||||
int CUtlVector<T>::AddVectorToTail(CUtlVector const &src)
|
||||
{
|
||||
int base = Count();
|
||||
|
||||
// Make space.
|
||||
AddMultipleToTail( src.Count() );
|
||||
AddMultipleToTail(src.Count());
|
||||
|
||||
// Copy the elements.
|
||||
for ( int i=0; i < src.Count(); i++ )
|
||||
for (int i = 0; i < src.Count(); i++)
|
||||
{
|
||||
(*this)[base + i] = src[i];
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
template< class T >
|
||||
inline int CUtlVector<T>::InsertMultipleBefore( int elem, int num, const T *pToInsert )
|
||||
template <class T>
|
||||
inline int CUtlVector<T>::InsertMultipleBefore(int elem, int num, const T *pToInsert)
|
||||
{
|
||||
if( num == 0 )
|
||||
if(num == 0)
|
||||
return elem;
|
||||
|
||||
// Can insert at the end
|
||||
assert( (elem == Count()) || IsValidIndex(elem) );
|
||||
Assert((elem == Count()) || IsValidIndex(elem));
|
||||
|
||||
GrowVector(num);
|
||||
ShiftElementsRight(elem, num);
|
||||
|
||||
// Invoke default constructors
|
||||
for (int i = 0; i < num; ++i)
|
||||
Construct( &Element(elem+i) );
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
Construct(&Element(elem+i));
|
||||
}
|
||||
|
||||
// Copy stuff in?
|
||||
if ( pToInsert )
|
||||
if (pToInsert)
|
||||
{
|
||||
for ( int i=0; i < num; i++ )
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
Element( elem+i ) = pToInsert[i];
|
||||
Element(elem+i) = pToInsert[i];
|
||||
}
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Finds an element (element needs operator== defined)
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
int CUtlVector<T>::Find( T const& src ) const
|
||||
template <class T>
|
||||
int CUtlVector<T>::Find(T const &src) const
|
||||
{
|
||||
for ( int i = 0; i < Count(); ++i )
|
||||
for (int i = 0; i < Count(); i++)
|
||||
{
|
||||
if (Element(i) == src)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
|
||||
return InvalidIndex();
|
||||
}
|
||||
|
||||
template< class T >
|
||||
bool CUtlVector<T>::HasElement( T const& src )
|
||||
template <class T>
|
||||
bool CUtlVector<T>::HasElement(T const &src)
|
||||
{
|
||||
return ( Find(src) >= 0 );
|
||||
return (Find(src) >= 0);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Element removal
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template< class T >
|
||||
void CUtlVector<T>::FastRemove( int elem )
|
||||
template <class T>
|
||||
void CUtlVector<T>::FastRemove(int elem)
|
||||
{
|
||||
assert( IsValidIndex(elem) );
|
||||
Assert(IsValidIndex(elem));
|
||||
|
||||
Destruct( &Element(elem) );
|
||||
Destruct(&Element(elem));
|
||||
if (m_Size > 0)
|
||||
{
|
||||
memcpy( &Element(elem), &Element(m_Size-1), sizeof(T) );
|
||||
--m_Size;
|
||||
memcpy(&Element(elem), &Element(m_Size - 1), sizeof(T));
|
||||
m_Size--;
|
||||
}
|
||||
}
|
||||
|
||||
template< class T >
|
||||
void CUtlVector<T>::Remove( int elem )
|
||||
template <class T>
|
||||
void CUtlVector<T>::Remove(int elem)
|
||||
{
|
||||
Destruct( &Element(elem) );
|
||||
Destruct(&Element(elem));
|
||||
ShiftElementsLeft(elem);
|
||||
--m_Size;
|
||||
m_Size--;
|
||||
}
|
||||
|
||||
template< class T >
|
||||
void CUtlVector<T>::FindAndRemove( T const& src )
|
||||
template <class T>
|
||||
void CUtlVector<T>::FindAndRemove(T const &src)
|
||||
{
|
||||
int elem = Find( src );
|
||||
if ( elem != -1 )
|
||||
int elem = Find(src);
|
||||
if (elem != InvalidIndex())
|
||||
{
|
||||
Remove( elem );
|
||||
Remove(elem);
|
||||
}
|
||||
}
|
||||
|
||||
template< class T >
|
||||
void CUtlVector<T>::RemoveMultiple( int elem, int num )
|
||||
template <class T>
|
||||
void CUtlVector<T>::RemoveMultiple(int elem, int num)
|
||||
{
|
||||
assert( IsValidIndex(elem) );
|
||||
assert( elem + num <= Count() );
|
||||
Assert(IsValidIndex(elem));
|
||||
Assert(elem + num <= Count());
|
||||
|
||||
for (int i = elem + num; --i >= elem; )
|
||||
for (int i = elem + num; --i >= elem;)
|
||||
Destruct(&Element(i));
|
||||
|
||||
ShiftElementsLeft(elem, num);
|
||||
m_Size -= num;
|
||||
}
|
||||
|
||||
template< class T >
|
||||
template <class T>
|
||||
void CUtlVector<T>::RemoveAll()
|
||||
{
|
||||
for (int i = m_Size; --i >= 0; )
|
||||
for (int i = m_Size; --i >= 0;)
|
||||
Destruct(&Element(i));
|
||||
|
||||
m_Size = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Memory deallocation
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template< class T >
|
||||
template <class T>
|
||||
void CUtlVector<T>::Purge()
|
||||
{
|
||||
RemoveAll();
|
||||
m_Memory.Purge( );
|
||||
m_Memory.Purge();
|
||||
ResetDbgInfo();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
template <class T>
|
||||
inline void CUtlVector<T>::PurgeAndDeleteElements()
|
||||
{
|
||||
for( int i=0; i < m_Size; i++ )
|
||||
for (int i = 0; i < m_Size; i++)
|
||||
delete Element(i);
|
||||
|
||||
Purge();
|
||||
}
|
||||
|
||||
template< class T >
|
||||
void CUtlVector<T>::SetGrowSize( int size )
|
||||
template <class T>
|
||||
void CUtlVector<T>::SetGrowSize(int size)
|
||||
{
|
||||
m_Memory.SetGrowSize( size );
|
||||
m_Memory.SetGrowSize(size);
|
||||
}
|
||||
|
||||
#endif // CCVECTOR_H
|
||||
|
@ -3,5 +3,6 @@ include 'dep/cppunitlite'
|
||||
include 'dep/bzip2'
|
||||
include 'rehlds'
|
||||
include 'rehlds/dedicated'
|
||||
include 'rehlds/filesystem/FileSystem_Stdio'
|
||||
include 'rehlds/HLTV', 'rehlds/HLTV/Core', 'rehlds/HLTV/Proxy', 'rehlds/HLTV/Console', 'rehlds/HLTV/Director', 'rehlds/HLTV/DemoPlayer'
|
||||
include 'flightrec/decoder_api', 'flightrec/decoder'
|
||||
|
@ -66,6 +66,6 @@ rootProject.ext.createGccConfig = { boolean release, BinaryKind binKind ->
|
||||
)
|
||||
}
|
||||
|
||||
cfg.singleDefines('LINUX')
|
||||
cfg.singleDefines('LINUX', '_LINUX')
|
||||
return cfg
|
||||
}
|
||||
|
@ -66,6 +66,6 @@ rootProject.ext.createIccConfig = { boolean release, BinaryKind binKind ->
|
||||
)
|
||||
}
|
||||
|
||||
cfg.singleDefines('LINUX')
|
||||
cfg.singleDefines('LINUX', '_LINUX')
|
||||
return cfg
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user