vector autocvar_cl_eventchase_maxs = '12 12 8';
vector autocvar_cl_eventchase_mins = '-12 -12 -8';
vector autocvar_cl_eventchase_viewoffset = '0 0 20';
-float autocvar_cl_lerpexcess; // TODO: int?
string autocvar__togglezoom;
int autocvar_cl_damageeffect;
float autocvar_cl_damageeffect_ticrate;
maxclients = i;
}
- // needs to be done so early because of the constants they create
- static_init();
- static_init_late();
- static_init_precache();
-
binddb = db_create();
tempdb = db_create();
ClientProgsDB = db_load("client.db");
#ifdef CSQC
#include "cl_main.qc"
#endif
+#ifdef SVQC
+ #include "sv_main.qc"
+#endif
#if !XONOTIC
entity me;
+ /** 6 bits provides up to 64 remembered states */
+ const int SNAP_BITS = 13;
+ .int snap;
+ .float times[1 << SNAP_BITS];
+
void CSQC_Init()
{
entity it = me = spawn();
it.com_phys_gravity = 800;
}
+ void CSQC_Ent_Update(bool isnew)
+ {
+ SELFPARAM();
+ int id = ReadByte();
+ entity recv = LinkedEntities_from(id);
+ if (isnew) this.classname = recv.netname;
+ if (recv) recv.m_read(this, NULL, isnew);
+ }
+
+ void rec()
+ {
+ me.ARRAY_INDEX(float, times, me.snap) = time;
+ // me.times[me.snap] = time;
+ me.snap = (me.snap + 1) & BITS(SNAP_BITS);
+ }
+
+ NET_HANDLE(ENT_OBJECT, bool isnew)
+ {
+ if (isnew)
+ {
+ this.com_phys = true;
+ precache_model("models/player/erebus.iqm");
+ _setmodel(this, "models/player/erebus.iqm");
+ this.drawmask = MASK_NORMAL;
+ }
+ this.com_phys_pos_prev = this.com_phys_pos;
+ this.com_phys_ang_prev = this.com_phys_ang;
+ serialize(ENT_OBJECT, 0, this);
+ this.com_phys_pos = this.origin;
+ this.com_phys_ang = this.angles;
+ return true;
+ }
+
void CSQC_UpdateView(float w, float h)
{
entity it = me;
void com_phys_interpolate(entity it, float a)
{
if (!autocvar_xon_com_phys_interpolate) a = 1;
+ // TODO: network time
+ // a = bound(0, (time - this.com_phys_time) / a, 1 /* + autocvar_cl_lerpexcess /* extrapolation frame limit */ */);
it.origin = it.com_phys_pos * a + it.com_phys_pos_prev * (1 - a);
- // TODO: orientation (slerp it)
+ it.angles = it.com_phys_ang * a + it.com_phys_ang_prev * (1 - a); // TODO: slerp, not lerp
}
#pragma once
+// TODO: store more frames for interpolation
COMPONENT(phys);
-.vector com_phys_pos;
-.vector com_phys_pos_prev;
+.vector com_phys_pos; .vector com_phys_pos_prev;
+.vector com_phys_ang; .vector com_phys_ang_prev;
.vector com_phys_vel;
.vector com_phys_acc;
#pragma once
+REGISTER_NET_LINKED(ENT_OBJECT);
+
+#define serialize_ENT_OBJECT(stream, this) \
+ MACRO_BEGIN \
+ serialize_vector(stream, this.origin); \
+ serialize_vector(stream, this.angles); \
+ MACRO_END
+
void systems_update();
void ClientKill() { if (_ClientKill) _ClientKill(); }
#define ClientKill _ClientKill
- void _PlayerPreThink();
- void PlayerPreThink() { if (_PlayerPreThink) _PlayerPreThink(); }
+ void _PlayerPreThink(entity this);
+ void PlayerPreThink() { SELFPARAM(); if (_PlayerPreThink) _PlayerPreThink(this); }
#define PlayerPreThink _PlayerPreThink
void _PlayerPostThink();
#ifdef CSQC
void _CSQC_Init();
- void CSQC_Init() { if (_CSQC_Init) _CSQC_Init(); }
+ void CSQC_Init() {
+ static_init();
+ static_init_late();
+ static_init_precache();
+ if (_CSQC_Init) _CSQC_Init();
+ }
#define CSQC_Init _CSQC_Init
void _CSQC_Shutdown();
}
}
+float autocvar_cl_lerpexcess;
+
/** set origin based on iorigin1 (old pos), iorigin2 (desired pos), and time */
void InterpolateOrigin_Do(entity this)
{
#endif
REGISTRY(LinkedEntities, BITS(8) - 1)
-#define LinkedEntities_from(i) _LinkedEntities_from(i, NULL)
+#define LinkedEntities_from(i) _LinkedEntities_from((i) - 1, NULL)
REGISTER_REGISTRY(LinkedEntities)
REGISTRY_SORT(LinkedEntities)
REGISTRY_CHECK(LinkedEntities)
} MACRO_END
#endif
+// serialization: new
+
+USING(Stream, int);
+#if defined(SVQC)
+ #define stream_reading(stream) false
+ #define stream_writing(stream) true
+#elif defined(CSQC)
+ #define stream_reading(stream) true
+ #define stream_writing(stream) false
+#endif
+
+#define serialize(T, stream, ...) serialize_##T(stream, __VA_ARGS__)
+
+#if defined(SVQC)
+ #define serialize_byte(stream, this) \
+ MACRO_BEGIN \
+ WriteByte(stream, this); \
+ MACRO_END
+#elif defined(CSQC)
+ #define serialize_byte(stream, this) \
+ MACRO_BEGIN \
+ this = ReadByte(); \
+ MACRO_END
+#endif
+
+#if defined(SVQC)
+ #define serialize_float(stream, this) \
+ MACRO_BEGIN \
+ WriteCoord(stream, this); \
+ MACRO_END
+#elif defined(CSQC)
+ #define serialize_float(stream, this) \
+ MACRO_BEGIN \
+ this = ReadCoord(); \
+ MACRO_END
+#endif
+
+#if defined(SVQC)
+ #define serialize_vector(stream, this) \
+ MACRO_BEGIN \
+ serialize_float(stream, this.x); \
+ serialize_float(stream, this.y); \
+ serialize_float(stream, this.z); \
+ MACRO_END
+#elif defined(CSQC)
+ #define serialize_vector(stream, this) \
+ MACRO_BEGIN \
+ vector _v; \
+ serialize_float(stream, _v.x); \
+ serialize_float(stream, _v.y); \
+ serialize_float(stream, _v.z); \
+ this = _v; \
+ MACRO_END
+#endif
+
+// serialization: old
+
#define ReadRegistered(r) r##_from(Read_byte())
#define WriteRegistered(r, to, it) Write_byte(to, it.m_id)
#define ReadVector() vec3(ReadFloat(), ReadFloat(), ReadFloat())
#define ReadVector2D() vec3(ReadFloat(), ReadFloat(), 0)
- float servertime;
+ float servertime;
float ReadApproxPastTime()
{
#pragma once
#define reinterpret_cast(T, it) _unsafe_cast_##T(0, it)
-#define X(T) T _unsafe_cast_##T(int dummy, ...) { return ...(0, T); }
+#define X(T) \
+ T _unsafe_cast_##T(int dummy, ...) { return ...(0, T); } \
+ USING(T##_fld, .T); T##_fld _unsafe_cast_##T##_fld(int dummy, ...) { return ...(0, T##_fld); }
X(bool)
X(int)
X(float)
+X(vector)
X(entity)
X(string)
USING(rawfunc, float(...));
{
INTEGER_ONE = reinterpret_cast(int, _unsafe_fld2) - reinterpret_cast(int, _unsafe_fld1);
}
+
+#define ARRAY_INDEX(T, arr, idx) (reinterpret_cast(T##_fld, reinterpret_cast(int, arr[0]) + FTOI(idx)))
void() nexball_setstatus;
.float last_vehiclecheck;
.int items_added;
-void PlayerPreThink ()
+void PlayerPreThink (entity this)
{
- SELFPARAM();
WarpZone_PlayerPhysics_FixVAngle(this);
STAT(GAMESTARTTIME, this) = game_starttime;