From d4eac81821176675d429d314fd83f5b3a55a44c5 Mon Sep 17 00:00:00 2001 From: TimePath Date: Wed, 23 Mar 2016 10:55:00 +1100 Subject: [PATCH] OO: transmute --- qcsrc/Doxyfile | 4 ++-- qcsrc/dpdefs/doc.md | 2 ++ qcsrc/lib/oo.qh | 26 ++++++++++++++++++-------- qcsrc/server/_all.qh | 1 - qcsrc/server/cl_client.qc | 2 +- qcsrc/server/cl_client.qh | 28 ++++++++++++++++++++++++++++ 6 files changed, 51 insertions(+), 12 deletions(-) diff --git a/qcsrc/Doxyfile b/qcsrc/Doxyfile index d0379e41f..cb9ca2a88 100644 --- a/qcsrc/Doxyfile +++ b/qcsrc/Doxyfile @@ -1999,6 +1999,7 @@ INCLUDE_FILE_PATTERNS = PREDEFINED = \ "USING(name, T)=using name = T" \ "CLASS(name, base)=class name : public base { public:" \ + "INIT(class)=class::class()" \ "CONSTRUCTOR(class)=class::class(" \ "DESTRUCTOR(class)=class::~class()" \ "ATTRIB(class, name, T, val)=T name = val;" \ @@ -2019,8 +2020,7 @@ PREDEFINED = \ EXPAND_AS_DEFINED = \ USING \ CLASS \ - CONSTRUCTOR \ - DESTRUCTOR \ + INIT CONSTRUCTOR DESTRUCTOR \ ATTRIB ATTRIB_STRZONE \ STATIC_ATTRIB STATIC_ATTRIB_STRZONE \ METHOD \ diff --git a/qcsrc/dpdefs/doc.md b/qcsrc/dpdefs/doc.md index 302c5d806..fa2560440 100644 --- a/qcsrc/dpdefs/doc.md +++ b/qcsrc/dpdefs/doc.md @@ -86,12 +86,14 @@ void ClientKill(); // self void RestoreGame(); +// Called when a client connects to the server // input: // time // self // parm1..n void ClientConnect(); +// Called when a client spawns in the server // input: // time // self diff --git a/qcsrc/lib/oo.qh b/qcsrc/lib/oo.qh index 45fbb2627..d0c770ae3 100644 --- a/qcsrc/lib/oo.qh +++ b/qcsrc/lib/oo.qh @@ -105,16 +105,25 @@ void clearentity(entity e) // Classes have a `spawn##cname(entity)` constructor // The parameter is used across [[accumulate]] functions +.bool transmute; + // Macros to hide this implementation detail: #ifdef __STDC__ #define NEW(cname, ...) \ OVERLOAD_(spawn##cname, new_pure(cname) P99_IF_EMPTY(__VA_ARGS__)()(, __VA_ARGS__)) + + #define TRANSMUTE(cname, this, ...) \ + OVERLOAD_(spawn##cname, (this.transmute = true, this.classname = #cname, this) P99_IF_EMPTY(__VA_ARGS__)()(, __VA_ARGS__)) + #define CONSTRUCT(cname, ...) \ OVERLOAD_(spawn##cname, this P99_IF_EMPTY(__VA_ARGS__)()(, __VA_ARGS__)) #else #define NEW(cname, ...) \ OVERLOAD(spawn##cname, new_pure(cname),##__VA_ARGS__) + #define TRANSMUTE(cname, this, ...) \ + OVERLOAD(spawn##cname, (this.transmute = true, this.classname = #cname, this),##__VA_ARGS__) + #define CONSTRUCT(cname, ...) \ OVERLOAD(spawn##cname, this,##__VA_ARGS__) #endif @@ -154,25 +163,26 @@ STATIC_INIT(RegisterClasses) #define CLASS(cname, base) \ entityclass(cname, base); \ - class(cname).bool instanceOf##cname; \ + class(cname).bool instanceOf##cname; \ bool is_##cname(entity e) { return e.instanceOf##cname; } \ VTBL(cname, base) \ - _INIT_STATIC(cname) \ - { \ - if (cname##_vtbl) \ - { \ + _INIT_STATIC(cname) \ + { \ + if (cname##_vtbl && !this.transmute)\ + { \ copyentity(cname##_vtbl, this); \ return; \ } \ spawn##base##_static(this); \ this.instanceOf##cname = true; \ } \ - INIT(cname) \ - { \ + INIT(cname) \ + { \ /* Only statically initialize the current class, it contains everything it inherits */ \ if (cname##_vtbl.vtblname == this.classname) \ - { \ + { \ spawn##cname##_static(this); \ + this.transmute = false; \ this.classname = #cname; \ this.vtblname = string_null; \ this.vtblbase = cname##_vtbl; \ diff --git a/qcsrc/server/_all.qh b/qcsrc/server/_all.qh index 686b47d86..c43605435 100644 --- a/qcsrc/server/_all.qh +++ b/qcsrc/server/_all.qh @@ -11,7 +11,6 @@ const string STR_OBSERVER = "observer"; #define IS_OBSERVER(v) ((v).classname == STR_OBSERVER) #define IS_CLIENT(v) (v.flags & FL_CLIENT) -#define is_Client IS_CLIENT #define IS_BOT_CLIENT(v) (clienttype(v) == CLIENTTYPE_BOT) #define IS_REAL_CLIENT(v) (clienttype(v) == CLIENTTYPE_REAL) #define IS_NOT_A_CLIENT(v) (clienttype(v) == CLIENTTYPE_NOTACLIENT) diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index d3b0e098d..b4fd0f900 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -989,8 +989,8 @@ void ClientConnect() if (Ban_MaybeEnforceBanOnce(this)) return; assert(!IS_CLIENT(this), return); assert(player_count >= 0, player_count = 0); + TRANSMUTE(Client, this); this.classname = "player_joining"; - this.flags = FL_CLIENT; #ifdef WATERMARK Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_WATERMARK, WATERMARK); diff --git a/qcsrc/server/cl_client.qh b/qcsrc/server/cl_client.qh index 651e0cc60..55ef7114c 100644 --- a/qcsrc/server/cl_client.qh +++ b/qcsrc/server/cl_client.qh @@ -1,5 +1,33 @@ #pragma once +CLASS(Client, Object) + /** Client name */ + ATTRIB(Client, netname, string, this.netname) + ATTRIB(Client, colormap, int, this.colormap) + ATTRIB(Client, team, int, this.team) + ATTRIB(Client, clientcolors, int, this.clientcolors) + /** Client IP */ + ATTRIB(Client, netaddress, string, this.netaddress) + ATTRIB(Client, playermodel, string, this.playermodel) + ATTRIB(Client, playerskin, int, this.playerskin) + + /** fingerprint of CA key the player used to authenticate */ + ATTRIB(Client, crypto_keyfp, string, this.crypto_keyfp) + /** fingerprint of CA key the server used to authenticate to the player */ + ATTRIB(Client, crypto_mykeyfp, string, this.crypto_mykeyfp) + /** fingerprint of ID used by the player entity, or string_null if not identified */ + ATTRIB(Client, crypto_idfp, string, this.crypto_idfp) + /** set if the player's ID has been signed */ + ATTRIB(Client, crypto_idfp_signed, bool, this.crypto_idfp_signed) + /** the string "AES128" if encrypting, and string_null if plaintext */ + ATTRIB(Client, crypto_encryptmethod, string, this.crypto_encryptmethod) + /** the string "HMAC-SHA256" if signing, and string_null if plaintext */ + ATTRIB(Client, crypto_signmethod, string, this.crypto_signmethod) + INIT(Client) { + this.flags = FL_CLIENT; + } +ENDCLASS(Client) + float c1, c2, c3, c4; void play_countdown(float finished, Sound samp); -- 2.39.2