DarkPlaces
Game engine based on the Quake 1 engine by id Software, developed by LadyHavoc
 
phys.c
Go to the documentation of this file.
1// for physics functions shared by the client and server
2
3#include "phys.h"
4
5#include "quakedef.h"
6#include "cl_collision.h"
7
8
9// TODO handle this in a nicer way...
10static inline trace_t PHYS_TraceBox(prvm_prog_t *prog, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend, qbool hitnetworkbrushmodels, qbool hitnetworkplayers, int *hitnetworkentity, qbool hitcsqcentities)
11{
12 return (prog == SVVM_prog)
13 ? SV_TraceBox(start, mins, maxs, end, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend)
14 : CL_TraceBox(start, mins, maxs, end, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities);
15}
16
17/*
18============
19PHYS_TestEntityPosition
20
21returns true if the entity is in solid currently
22============
23*/
25{
26 int hitsupercontentsmask = SV_GenericHitSuperContentsMask(ent);
27 int skipsupercontentsmask = 0;
28 int skipmaterialflagsmask = 0;
29 vec3_t org, entorigin, entmins, entmaxs;
30 trace_t trace;
31
36 trace = PHYS_TraceBox(prog, org, entmins, entmaxs, entorigin, ((PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), ent, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, collision_extendmovelength.value, true, false, NULL, false);
37 if (trace.startsupercontents & hitsupercontentsmask)
38 return true;
39 else
40 {
41 if (sv.worldmodel->brushq1.numclipnodes && !VectorCompare(PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs)))
42 {
43 // q1bsp/hlbsp use hulls and if the entity does not exactly match
44 // a hull size it is incorrectly tested, so this code tries to
45 // 'fix' it slightly...
46 // FIXME: this breaks entities larger than the hull size
47 int i;
48 vec3_t v, m1, m2, s;
49 VectorAdd(org, entmins, m1);
50 VectorAdd(org, entmaxs, m2);
51 VectorSubtract(m2, m1, s);
52#define EPSILON (1.0f / 32.0f)
53 if (s[0] >= EPSILON*2) {m1[0] += EPSILON;m2[0] -= EPSILON;}
54 if (s[1] >= EPSILON*2) {m1[1] += EPSILON;m2[1] -= EPSILON;}
55 if (s[2] >= EPSILON*2) {m1[2] += EPSILON;m2[2] -= EPSILON;}
56 for (i = 0;i < 8;i++)
57 {
58 v[0] = (i & 1) ? m2[0] : m1[0];
59 v[1] = (i & 2) ? m2[1] : m1[1];
60 v[2] = (i & 4) ? m2[2] : m1[2];
61 if (SV_PointSuperContents(v) & hitsupercontentsmask)
62 return true;
63 }
64 }
65 }
66 // if the trace found a better position for the entity, move it there
67 if (VectorDistance2(trace.endpos, PRVM_serveredictvector(ent, origin)) >= 0.0001)
68 {
69#if 0
70 // please switch back to this code when trace.endpos sometimes being in solid bug is fixed
72#else
73 // verify if the endpos is REALLY outside solid
74 VectorCopy(trace.endpos, org);
75 trace = PHYS_TraceBox(prog, org, entmins, entmaxs, org, MOVE_NOMONSTERS, ent, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, collision_extendmovelength.value, true, false, NULL, false);
76 if(trace.startsolid)
77 Con_Printf("PHYS_TestEntityPosition: trace.endpos detected to be in solid. NOT using it.\n");
78 else
80#endif
81 }
82 return false;
83}
84
85static float unstickoffsets[] =
86{
87 // poutting -/+z changes first as they are least weird
88 0, 0, -1,
89 0, 0, 1,
90 // x or y changes
91 -1, 0, 0,
92 1, 0, 0,
93 0, -1, 0,
94 0, 1, 0,
95 // x and y changes
96 -1, -1, 0,
97 1, -1, 0,
98 -1, 1, 0,
99 1, 1, 0,
100};
101
103{
104 int i, maxunstick;
105
106 // if not stuck in a bmodel, just return
107 if (!PHYS_TestEntityPosition(prog, ent, vec3_origin))
108 return UNSTICK_GOOD;
109
110 for (i = 0;i < (int)(sizeof(unstickoffsets) / sizeof(unstickoffsets[0]));i += 3)
111 {
112 if (!PHYS_TestEntityPosition(prog, ent, unstickoffsets + i))
113 {
115 return UNSTICK_UNSTUCK;
116 }
117 }
118
119 maxunstick = (int) ((PRVM_serveredictvector(ent, maxs)[2] - PRVM_serveredictvector(ent, mins)[2]) * 0.36);
120 // magic number 0.36 allows unsticking by up to 17 units with the largest supported bbox
121
122 for(i = 2; i <= maxunstick; ++i)
123 {
125 offset[2] = -i;
126 if (!PHYS_TestEntityPosition(prog, ent, offset))
127 return UNSTICK_UNSTUCK;
128 offset[2] = i;
129 if (!PHYS_TestEntityPosition(prog, ent, offset))
130 return UNSTICK_UNSTUCK;
131 }
132
133 return UNSTICK_STUCK;
134}
135
137{
138 int bump, pass;
139 trace_t stucktrace;
140 vec3_t testorigin, targetorigin;
141 vec3_t stuckmins, stuckmaxs;
142 vec_t separation;
143 model_t *worldmodel;
144
145 if (prog == SVVM_prog)
146 {
147 worldmodel = sv.worldmodel;
149 }
150 else if (prog == CLVM_prog)
151 {
152 worldmodel = cl.worldmodel;
154 }
155 else
156 Sys_Error("PHYS_NudgeOutOfSolid: cannot be called from %s VM\n", prog->name);
157
158 VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins);
159 VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs);
160 if (worldmodel && worldmodel->TraceBox != Mod_CollisionBIH_TraceBox)
161 {
162 separation = 0.0f; // when using hulls, it can not be enlarged
163
164 // FIXME: Mod_Q1BSP_TraceBox() doesn't support startdepth and startdepthnormal
165 return PHYS_UnstickEntityReturnOffset(prog, ent, testorigin); // fallback
166 }
167 else
168 {
169 stuckmins[0] -= separation;
170 stuckmins[1] -= separation;
171 stuckmins[2] -= separation;
172 stuckmaxs[0] += separation;
173 stuckmaxs[1] += separation;
174 stuckmaxs[2] += separation;
175 }
176
177 // first pass we try to get it out of brush entities
178 // second pass we try to get it out of world only (can't win them all)
179 for (pass = 0;pass < 2;pass++)
180 {
181 VectorCopy(PRVM_serveredictvector(ent, origin), testorigin);
182 for (bump = 0;bump < 10;bump++)
183 {
184 stucktrace = PHYS_TraceBox(prog, testorigin, stuckmins, stuckmaxs, testorigin, pass ? MOVE_WORLDONLY : MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, pass ? false : true, false, NULL, false);
185
186 // Separation compared here to ensure a good location will be recognised reliably.
187 if (-stucktrace.startdepth <= separation
188 || (!stucktrace.bmodelstartsolid && !stucktrace.worldstartsolid)
189 || (pass && !stucktrace.worldstartsolid))
190 {
191 // found a good location, use it
192 VectorCopy(testorigin, PRVM_serveredictvector(ent, origin));
193 return bump || pass ? UNSTICK_UNSTUCK : UNSTICK_GOOD;
194 }
195
196 VectorMA(testorigin, -stucktrace.startdepth, stucktrace.startdepthnormal, targetorigin);
197 // Trace to targetorigin so we don't set it out of the world in complex cases.
198 stucktrace = PHYS_TraceBox(prog, testorigin, stuckmins, stuckmaxs, targetorigin, pass ? MOVE_WORLDONLY : MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, pass ? false : true, false, NULL, false);
199 if (stucktrace.fraction)
200 VectorCopy(stucktrace.endpos, testorigin);
201 else
202 break; // Can't move it so no point doing more iterations on this pass.
203 }
204 }
205 return UNSTICK_STUCK;
206}
trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend, qbool hitnetworkbrushmodels, qbool hitnetworkplayers, int *hitnetworkentity, qbool hitcsqcentities)
cvar_t cl_gameplayfix_nudgeoutofsolid_separation
Definition cl_main.c:113
client_state_t cl
Definition cl_main.c:117
cvar_t collision_extendmovelength
Definition collision.c:14
void Con_Printf(const char *fmt,...)
Prints to all appropriate console targets.
Definition console.c:1514
float movetype
vector mins
vector maxs
vector origin
static int(ZEXPORT *qz_inflate)(z_stream *strm
const GLdouble * v
Definition glquake.h:762
GLuint GLuint GLintptr offset
Definition glquake.h:632
GLenum type
Definition glquake.h:656
vec3_t vec3_origin
Definition mathlib.c:26
#define VectorClear(a)
Definition mathlib.h:97
#define VectorDistance2(a, b)
Definition mathlib.h:107
#define VectorSubtract(a, b, out)
Definition mathlib.h:99
#define VectorCompare(a, b)
Definition mathlib.h:113
#define VectorCopy(in, out)
Definition mathlib.h:101
#define VectorAdd(a, b, out)
Definition mathlib.h:100
#define VectorMA(a, scale, b, out)
Definition mathlib.h:114
void Mod_CollisionBIH_TraceBox(model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
#define EPSILON
static trace_t PHYS_TraceBox(prvm_prog_t *prog, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend, qbool hitnetworkbrushmodels, qbool hitnetworkplayers, int *hitnetworkentity, qbool hitcsqcentities)
Definition phys.c:10
static float unstickoffsets[]
Definition phys.c:85
unstickresult_t PHYS_UnstickEntityReturnOffset(prvm_prog_t *prog, prvm_edict_t *ent, vec3_t offset)
Definition phys.c:102
unstickresult_t PHYS_NudgeOutOfSolid(prvm_prog_t *prog, prvm_edict_t *ent)
Definition phys.c:136
qbool PHYS_TestEntityPosition(prvm_prog_t *prog, prvm_edict_t *ent, vec3_t offset)
Definition phys.c:24
unstickresult_t
Definition phys.h:10
@ UNSTICK_GOOD
didn't need to be unstuck
Definition phys.h:13
@ UNSTICK_STUCK
Definition phys.h:12
@ UNSTICK_UNSTUCK
Definition phys.h:14
#define CLVM_prog
Definition progsvm.h:767
#define PRVM_serveredictvector(ed, fieldname)
Definition progsvm.h:173
#define PRVM_serveredictfloat(ed, fieldname)
Definition progsvm.h:172
#define SVVM_prog
Definition progsvm.h:766
int i
#define NULL
Definition qtypes.h:12
float vec_t
Definition qtypes.h:68
vec_t vec3_t[3]
Definition qtypes.h:71
bool qbool
Definition qtypes.h:9
server_t sv
local server
Definition sv_main.c:223
cvar_t sv_gameplayfix_nudgeoutofsolid_separation
Definition sv_main.c:118
int SV_GenericHitSuperContentsMask(const prvm_edict_t *edict)
calculates hitsupercontentsmask for a generic qc entity
Definition sv_phys.c:73
#define MOVETYPE_FLY_WORLDONLY
like MOVETYPE_FLY, but uses MOVE_WORLDONLY for all its traces; objects of this movetype better be SOL...
Definition server.h:327
int SV_PointSuperContents(const vec3_t point)
Definition sv_phys.c:611
trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend)
traces a box move against worldmodel and all entities in the specified area
Definition sv_phys.c:414
struct model_s * worldmodel
Definition client.h:934
float value
Definition cvar.h:74
void(* TraceBox)(struct model_s *model, const struct frameblend_s *frameblend, const struct skeleton_s *skeleton, struct trace_s *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
const char * name
name of the prog, e.g. "Server", "Client" or "Menu" (used for text output)
Definition progsvm.h:700
struct model_s * worldmodel
Definition server.h:112
qbool bmodelstartsolid
Definition collision.h:30
double startdepthnormal[3]
Definition collision.h:69
double fraction
Definition collision.h:40
qbool worldstartsolid
Definition collision.h:28
double endpos[3]
Definition collision.h:42
int startsupercontents
Definition collision.h:56
qbool startsolid
Definition collision.h:26
double startdepth
Definition collision.h:68
void Sys_Error(const char *error,...) DP_FUNC_PRINTF(1) DP_FUNC_NORETURN
Causes the entire program to exit ASAP.
Definition sys_shared.c:724
#define MOVE_WORLDONLY
Definition world.h:31
#define MOVE_NOMONSTERS
Definition world.h:29