NET_HANDLE(ENT_CLIENT_INIT, bool isnew)
{
- make_pure(this);
-
nb_pb_period = ReadByte() / 32; //Accuracy of 1/32th
hook_shotorigin[0] = decompressShotOrigin(ReadInt24_t());
REGISTRY(Buffs, BITS(4))
#define Buffs_from(i) _Buffs_from(i, BUFF_Null)
REGISTER_REGISTRY(RegisterBuffs)
+REGISTRY_CHECK(Buffs)
#define REGISTER_BUFF(id) \
REGISTER(RegisterBuffs, BUFF, Buffs, id, m_id, NEW(Buff)); \
const int RACE_NET_SERVER_STATUS = 12;
const int RANKINGS_CNT = 15;
+REGISTER_NET_LINKED(_ENT_CLIENT_INIT)
+#ifdef CSQC
+NET_HANDLE(_ENT_CLIENT_INIT, bool isnew) { return true; }
+#endif
+/** Sent as a temp entity from a persistent linked entity */
+REGISTER_NET_TEMP(ENT_CLIENT_INIT)
+
REGISTER_NET_LINKED(ENT_CLIENT_ENTCS)
REGISTER_NET_LINKED(ENT_CLIENT_SCORES_INFO)
REGISTER_NET_LINKED(ENT_CLIENT_SCORES)
REGISTER_NET_LINKED(ENT_CLIENT_NAGGER) // flags [votecalledvote]
REGISTER_NET_LINKED(ENT_CLIENT_RADARLINK) // flags [startorigin] [endorigin] [startcolor+16*endcolor]
REGISTER_NET_LINKED(ENT_CLIENT_PROJECTILE)
-REGISTER_NET_LINKED(ENT_CLIENT_INIT)
REGISTER_NET_LINKED(ENT_CLIENT_MAPVOTE)
REGISTER_NET_LINKED(ENT_CLIENT_CLIENTDATA)
REGISTER_NET_LINKED(ENT_CLIENT_RANDOMSEED)
REGISTRY(Deathtypes, BITS(8))
#define Deathtypes_from(i) _Deathtypes_from(i, NULL)
REGISTER_REGISTRY(RegisterDeathtypes)
+REGISTRY_CHECK(Deathtypes)
.entity death_msgself;
.entity death_msgmurder;
REGISTRY(Effects, BITS(8))
#define Effects_from(i) _Effects_from(i, EFFECT_Null)
REGISTER_REGISTRY(RegisterEffects)
+REGISTRY_CHECK(Effects)
#define EFFECT(istrail, name, realname) \
REGISTER(RegisterEffects, EFFECT, Effects, name, m_id, Create_Effect_Entity(realname, istrail));
#define REGISTER_ITEM(id, class) REGISTER(RegisterItems, ITEM, Items, id, m_id, NEW(class))
REGISTRY_SORT(Items, 0)
+REGISTRY_CHECK(Items)
STATIC_INIT(Items) { FOREACH(Items, true, LAMBDA(it.m_id = i)); }
void Dump_Items();
REGISTRY(Gametypes, BITS(4))
#define Gametypes_from(i) _Gametypes_from(i, NULL)
REGISTER_REGISTRY(RegisterGametypes)
+REGISTRY_CHECK(Gametypes)
int MAPINFO_TYPE_ALL;
#define REGISTER_GAMETYPE(hname, sname, g_name, NAME, gteamplay, mutators, defaults, gdescription) \
int MAPINFO_TYPE_##NAME; \
REGISTRY(Minigames, BITS(3))
#define Minigames_from(i) _Minigames_from(i, NULL)
REGISTER_REGISTRY(RegisterMinigames)
+REGISTRY_CHECK(Minigames)
#define REGISTER_MINIGAME(name,nicename) \
REGISTER(RegisterMinigames, MINIGAME, Minigames, name, m_id, new(minigame_descriptor)); \
void name##_hud_board(vector, vector); \
REGISTRY(Minigames, BITS(3))
#define Minigames_from(i) _Minigames_from(i, NULL)
REGISTER_REGISTRY(RegisterMinigames)
+REGISTRY_CHECK(Minigames)
#define REGISTER_MINIGAME(name,nicename) \
REGISTER(RegisterMinigames, MINIGAME, Minigames, name, m_id, new(minigame_descriptor)); \
int name##_server_event(entity, string, ...); \
#define Monsters_from(i) _Monsters_from(i, MON_Null)
#define get_monsterinfo(i) Monsters_from(i)
REGISTER_REGISTRY(RegisterMonsters)
+REGISTRY_CHECK(Monsters)
const int MON_FIRST = 1;
#define MON_LAST (Monsters_COUNT - 1)
/** If you register a new monster, make sure to add it to all.inc */
REGISTRY(Waypoints, BITS(6))
#define Waypoints_from(i) _Waypoints_from(i, WP_Null)
REGISTER_REGISTRY(RegisterWaypoints)
+REGISTRY_CHECK(Waypoints)
+
/** If you register a new waypoint, make sure to add it to all.inc */
#define REGISTER_WAYPOINT_(id, init) REGISTER(RegisterWaypoints, WP, Waypoints, id, m_id, init)
REGISTRY(RadarIcons, BITS(7))
#define RadarIcons_from(i) _RadarIcons_from(i, RADARICON_NONE)
REGISTER_REGISTRY(RegisterRadarIcons)
+REGISTRY_CHECK(RadarIcons)
+
.int m_radaricon;
#define REGISTER_RADARICON(id, num) REGISTER(RegisterRadarIcons, RADARICON, RadarIcons, id, m_id, new(RadarIcon)) { make_pure(this); this.m_radaricon = num; this.netname = #id; }
REGISTRY(Nades, BITS(4))
#define Nades_from(i) _Nades_from(i, NADE_TYPE_Null)
REGISTER_REGISTRY(RegisterNades)
+REGISTRY_CHECK(Nades)
+
#define REGISTER_NADE(id) REGISTER(RegisterNades, NADE_TYPE, Nades, id, m_id, NEW(Nade))
CLASS(Nade, Object)
#define Turrets_from(i) _Turrets_from(i, TUR_Null)
#define get_turretinfo(i) Turrets_from(i)
REGISTER_REGISTRY(RegisterTurrets)
+REGISTRY_CHECK(Turrets)
GENERIC_COMMAND(dumpturrets, "Dump all turrets into turrets_dump.txt")
#define Vehicles_from(i) _Vehicles_from(i, VEH_Null)
#define get_vehicleinfo(i) Vehicles_from(i)
REGISTER_REGISTRY(RegisterVehicles)
+REGISTRY_CHECK(Vehicles)
+
const int VEH_FIRST = 1;
#define VEH_LAST (Vehicles_COUNT - 1)
#define WEP_IMPULSE_END bound(WEP_IMPULSE_BEGIN, WEP_IMPULSE_BEGIN + (Weapons_COUNT - 1) - 1, 253)
REGISTRY_SORT(Weapons, WEP_HARDCODED_IMPULSES + 1)
+REGISTRY_CHECK(Weapons)
STATIC_INIT(register_weapons_done)
{
#include "progname.qh"
#include "random.qc"
#include "registry.qh"
+#include "registry_net.qh"
#include "replicate.qh"
#include "self.qh"
#include "sortlist.qc"
#define LinkedEntities_from(i) _LinkedEntities_from(i, NULL)
REGISTER_REGISTRY(RegisterLinkedEntities)
REGISTRY_SORT(LinkedEntities, 0)
+REGISTRY_CHECK(LinkedEntities)
STATIC_INIT(RegisterLinkedEntities_renumber)
{
for (int i = 0; i < LinkedEntities_COUNT; ++i)
#define TempEntities_from(i) _TempEntities_from(i, NULL)
REGISTER_REGISTRY(RegisterTempEntities)
REGISTRY_SORT(TempEntities, 0)
+REGISTRY_CHECK(TempEntities)
STATIC_INIT(RegisterTempEntities_renumber)
{
for (int i = 0; i < TempEntities_COUNT; ++i)
STATIC_INIT(Registry_sort_##id) \
{ \
heapsort(id##_COUNT - (skip), _REGISTRY_SWAP_##id, _REGISTRY_CMP_##id, NULL); \
- } \
- REGISTRY_CHECK(id)
+ }
+
+#define REGISTRY_HASH(id) Registry_hash_##id
+
+[[accumulate]] void Registry_check(string r, string server) { }
+[[accumulate]] void Registry_send_all() { }
+
+#ifdef SVQC
+void Registry_send(string id, string hash);
+#else
+#define Registry_send(id, hash)
+#endif
#define REGISTRY_CHECK(id) \
+ string REGISTRY_HASH(id); \
STATIC_INIT(Registry_check_##id) \
{ \
string algo = "SHA256"; \
string s = ""; \
FOREACH(id, true, LAMBDA(s = strcat(s, join, it.registered_id))); \
s = substring(s, strlen(join), -1); \
- LOG_TRACEF(#id ": %s\n[%s]\n", digest_hex(algo, s), s); \
- }
+ string h = REGISTRY_HASH(id) = strzone(digest_hex(algo, s)); \
+ LOG_TRACEF(#id ": %s\n[%s]\n", h, s); \
+ } \
+ [[accumulate]] void Registry_check(string r, string sv) \
+ { \
+ if (r == #id) \
+ { \
+ string cl = REGISTRY_HASH(id); \
+ if (cl != sv) \
+ { \
+ LOG_FATALF("client/server mismatch (%s).\nCL: %s\nSV: %s\n", r, cl, sv); \
+ } \
+ } \
+ } \
+ [[accumulate]] void Registry_send_all() { Registry_send(#id, REGISTRY_HASH(id)); } \
#endif
--- /dev/null
+#ifndef REGISTRY_NET_H
+#define REGISTRY_NET_H
+
+#include "net.qh"
+
+REGISTER_NET_TEMP(registry)
+
+#ifdef CSQC
+NET_HANDLE(registry, bool isnew)
+{
+ string k = ReadString();
+ string v = ReadString();
+ Registry_check(k, v);
+ return true;
+}
+#endif
+
+#ifdef SVQC
+void Registry_send(string id, string hash)
+{
+ int channel = MSG_ONE;
+ WriteHeader(channel, registry);
+ WriteString(channel, id);
+ WriteString(channel, hash);
+}
+#endif
+
+#endif
// changes and just have a console command to update this?
bool ClientInit_SendEntity(entity this, entity to, int sf)
{
- WriteHeader(MSG_ENTITY, ENT_CLIENT_INIT);
- WriteByte(MSG_ENTITY, g_nexball_meter_period * 32);
- WriteInt24_t(MSG_ENTITY, compressShotOrigin(hook_shotorigin[0]));
- WriteInt24_t(MSG_ENTITY, compressShotOrigin(hook_shotorigin[1]));
- WriteInt24_t(MSG_ENTITY, compressShotOrigin(hook_shotorigin[2]));
- WriteInt24_t(MSG_ENTITY, compressShotOrigin(hook_shotorigin[3]));
- WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[0]));
- WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[1]));
- WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[2]));
- WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[3]));
+ WriteHeader(MSG_ENTITY, _ENT_CLIENT_INIT);
+ return = true;
+ msg_entity = to;
+ Registry_send_all();
+ int channel = MSG_ONE;
+ WriteHeader(channel, ENT_CLIENT_INIT);
+ WriteByte(channel, g_nexball_meter_period * 32);
+ WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[0]));
+ WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[1]));
+ WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[2]));
+ WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[3]));
+ WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[0]));
+ WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[1]));
+ WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[2]));
+ WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[3]));
if(sv_foginterval && world.fog != "")
- WriteString(MSG_ENTITY, world.fog);
+ WriteString(channel, world.fog);
else
- WriteString(MSG_ENTITY, "");
- WriteByte(MSG_ENTITY, self.count * 255.0); // g_balance_armor_blockpercent
- WriteCoord(MSG_ENTITY, self.bouncefactor); // g_balance_mortar_bouncefactor // WEAPONTODO
- WriteCoord(MSG_ENTITY, self.bouncestop); // g_balance_mortar_bouncestop
- WriteCoord(MSG_ENTITY, self.ebouncefactor); // g_balance_mortar_bouncefactor
- WriteCoord(MSG_ENTITY, self.ebouncestop); // g_balance_mortar_bouncestop
- WriteByte(MSG_ENTITY, WEP_CVAR(vortex, secondary)); // client has to know if it should zoom or not // WEAPONTODO
- WriteByte(MSG_ENTITY, WEP_CVAR(rifle, secondary)); // client has to know if it should zoom or not // WEAPONTODO
- WriteByte(MSG_ENTITY, serverflags); // client has to know if it should zoom or not
- WriteByte(MSG_ENTITY, WEP_CVAR(minelayer, limit)); // minelayer max mines // WEAPONTODO
- WriteByte(MSG_ENTITY, WEP_CVAR_SEC(hagar, load_max)); // hagar max loadable rockets // WEAPONTODO
- WriteCoord(MSG_ENTITY, autocvar_g_trueaim_minrange);
- WriteByte(MSG_ENTITY, WEP_CVAR(porto, secondary)); // WEAPONTODO
+ WriteString(channel, "");
+ WriteByte(channel, self.count * 255.0); // g_balance_armor_blockpercent
+ WriteCoord(channel, self.bouncefactor); // g_balance_mortar_bouncefactor // WEAPONTODO
+ WriteCoord(channel, self.bouncestop); // g_balance_mortar_bouncestop
+ WriteCoord(channel, self.ebouncefactor); // g_balance_mortar_bouncefactor
+ WriteCoord(channel, self.ebouncestop); // g_balance_mortar_bouncestop
+ WriteByte(channel, WEP_CVAR(vortex, secondary)); // client has to know if it should zoom or not // WEAPONTODO
+ WriteByte(channel, WEP_CVAR(rifle, secondary)); // client has to know if it should zoom or not // WEAPONTODO
+ WriteByte(channel, serverflags); // client has to know if it should zoom or not
+ WriteByte(channel, WEP_CVAR(minelayer, limit)); // minelayer max mines // WEAPONTODO
+ WriteByte(channel, WEP_CVAR_SEC(hagar, load_max)); // hagar max loadable rockets // WEAPONTODO
+ WriteCoord(channel, autocvar_g_trueaim_minrange);
+ WriteByte(channel, WEP_CVAR(porto, secondary)); // WEAPONTODO
MUTATOR_CALLHOOK(Ent_Init);
- return true;
}
void ClientInit_CheckUpdate()