]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
C2S protocol
authorTimePath <andrew.hardaker1995@gmail.com>
Sun, 20 Dec 2015 10:45:41 +0000 (21:45 +1100)
committerTimePath <andrew.hardaker1995@gmail.com>
Sun, 20 Dec 2015 11:07:55 +0000 (22:07 +1100)
qcsrc/client/view.qc
qcsrc/lib/iter.qh
qcsrc/lib/net.qh
qcsrc/lib/yenc.qh
qcsrc/server/command/cmd.qc

index a5425cb3c9b13ab5d1cfb0b51648272f4f2ee3e3..55610620a82b786f18e46f05f7dd53436f3e09e4 100644 (file)
@@ -2197,6 +2197,7 @@ void CSQC_UpdateView(float w, float h)
                HUD_Radar_Mouse();
 
        cl_notice_run();
+       Net_Flush();
 
        // let's reset the view back to normal for the end
        setproperty(VF_MIN, '0 0 0');
index 7a21dab760c0640c14e106b1b498ab1c71008888..790c3929d197f58faf5a42d31fcacad9de09f4e9 100644 (file)
 
 #define STRING_ITERATOR(this, s, i) \
        string this##_s = s; \
-       int this##_i = i; \
-       MACRO_BEGIN MACRO_END
+       int this##_i = i
+
+#define STRING_ITERATOR_SET(this, s, i) \
+       MACRO_BEGIN { \
+               this##_s = s; \
+               this##_i = i; \
+       } MACRO_END
 
 #define STRING_ITERATOR_GET(this) str2chr(this##_s, this##_i++)
 
index af914fc6482a2d0af6094b24e3f5e67313a7e3d6..f73fcf97aa037fb9ce5dc0b099ad710e57b827e2 100644 (file)
@@ -1,7 +1,102 @@
 #ifndef NET_H
 #define NET_H
 
+#include "registry.qh"
+#include "sort.qh"
+#include "yenc.qh"
+
+.string netname;
+.int m_id;
+.bool(entity this, bool isNew) m_read;
+#define NET_HANDLE(id, param) bool Net_Handle_##id(entity this, param)
+
+
+#ifdef CSQC
+       #define REGISTER_NET_TEMP(id) \
+               NET_HANDLE(id, bool); \
+               REGISTER(TempEntities, NET, id, m_id, new_pure(net_temp_packet)) \
+               { \
+                       this.netname = #id; \
+                       this.m_read = Net_Handle_##id; \
+               }
+#else
+       #define REGISTER_NET_TEMP(id) \
+               const bool NET_##id##_istemp = true; \
+               REGISTER(TempEntities, NET, id, m_id, new_pure(net_temp_packet)) \
+               { \
+                       this.netname = #id; \
+               }
+#endif
+#define REGISTER_NET_S2C(id) REGISTER_NET_TEMP(id)
+
+REGISTRY(TempEntities, BITS(8) - 80)
+#define TempEntities_from(i) _TempEntities_from(i, NULL)
+REGISTER_REGISTRY(TempEntities)
+REGISTRY_SORT(TempEntities)
+REGISTRY_CHECK(TempEntities)
+STATIC_INIT(RegisterTempEntities_renumber) { FOREACH(TempEntities, true, it.m_id = 80 + i); }
+
+
+
+#ifdef CSQC
+       #define REGISTER_NET_LINKED(id) \
+               [[accumulate]] NET_HANDLE(id, bool isnew) \
+               { \
+                       this = self; \
+                       this.sourceLocFile = __FILE__; \
+                       this.sourceLocLine = __LINE__; \
+                       if (!this) isnew = true; \
+               } \
+               REGISTER(LinkedEntities, NET, id, m_id, new_pure(net_linked_packet)) \
+               { \
+                       this.netname = #id; \
+                       this.m_read = Net_Handle_##id; \
+               }
+#else
+       #define REGISTER_NET_LINKED(id) \
+               const bool NET_##id##_istemp = false; \
+               REGISTER(LinkedEntities, NET, id, m_id, new_pure(net_linked_packet)) \
+               { \
+                       this.netname = #id; \
+               }
+#endif
+
+REGISTRY(LinkedEntities, BITS(8) - 1)
+#define LinkedEntities_from(i) _LinkedEntities_from(i, NULL)
+REGISTER_REGISTRY(LinkedEntities)
+REGISTRY_SORT(LinkedEntities)
+REGISTRY_CHECK(LinkedEntities)
+STATIC_INIT(RegisterLinkedEntities_renumber) { FOREACH(LinkedEntities, true, it.m_id = 1 + i); }
+
+
+
 #ifdef SVQC
+       #define REGISTER_NET_C2S(id) \
+               NET_HANDLE(id, bool); \
+               REGISTER(C2S_Protocol, NET, id, m_id, new_pure(net_c2s_packet)) \
+               { \
+                       this.netname = #id; \
+                       this.m_read = Net_Handle_##id; \
+               }
+#else
+       #define REGISTER_NET_C2S(id) \
+               const bool NET_##id##_istemp = true; \
+               REGISTER(C2S_Protocol, NET, id, m_id, new_pure(net_c2s_packet)) \
+               { \
+                       this.netname = #id; \
+               }
+#endif
+
+REGISTRY(C2S_Protocol, BITS(8) - 1)
+#define C2S_Protocol_from(i) _C2S_Protocol_from(i, NULL)
+REGISTER_REGISTRY(C2S_Protocol)
+REGISTRY_SORT(C2S_Protocol)
+REGISTRY_CHECK(C2S_Protocol)
+STATIC_INIT(C2S_Protocol_renumber) { FOREACH(C2S_Protocol, true, it.m_id = i); }
+
+#ifdef SVQC
+       const int MSG_ENTITY = 5;
+
        .int Version;  // deprecated, use SendFlags
        .int SendFlags;
        .bool(entity to, int sendflags) SendEntity;
                        WITH(entity, self, e, e.uncustomizeentityforclient());
        }
 
-#endif
+       STRING_ITERATOR(g_buf, string_null, 0);
 
-#include "registry.qh"
-#include "sort.qh"
+       int ReadByte();
 
-.string netname;
-.int m_id;
-.bool(entity this, bool isNew) m_read;
+       void Net_ClientCommand(string command)
+       {
+               // command matches `c2s "(.+)"`
+               string buf = substring(command, argv_start_index(1) + 1, -2);
+               if (buf == "") return;
+               STRING_ITERATOR_SET(g_buf, buf, 0);
+               for (int C2S; (C2S = ReadByte()) >= 0; )
+               {
+                       entity reader = C2S_Protocol_from(C2S);
+                       if (reader && reader.m_read && reader.m_read(NULL, true)) continue;
+                       LOG_SEVEREF("Net_ClientCommand() with malformed C2S=%d\n", C2S);
+                       return;
+               }
+               g_buf_i--;
+               int expected = strlen(buf);
+               if (g_buf_i > expected) LOG_WARNINGF("Underflow: %d", g_buf_i - expected);
+               if (g_buf_i < expected) LOG_WARNINGF("Overrflow: %d", expected - g_buf_i);
+       }
+
+#endif
 
 #ifdef CSQC
+       const int MSG_C2S = 0;
+
        #define Net_Accept(classname) \
-               MACRO_BEGIN \
-               { \
+               MACRO_BEGIN { \
                        if (!this)    this = new(classname); \
                } MACRO_END
        #define Net_Reject() \
-               MACRO_BEGIN \
-               { \
+               MACRO_BEGIN { \
                        if (this)     remove(this); \
                } MACRO_END
-       #define NET_HANDLE(id, param) \
-               bool Net_Handle_##id(entity this, param)
-#else
+
+       string g_buf;
+
+       void Net_Flush()
+       {
+               if (g_buf == "") return;
+               localcmd("\ncmd c2s \"", strreplace("$", "$$", g_buf), "\"\n");
+               strunzone(g_buf);
+               g_buf = string_null;
+       }
+#endif
+
+#if defined(CSQC)
        #define WriteHeader(to, id) \
-               MACRO_BEGIN \
-               { \
+               MACRO_BEGIN { \
+                       WriteByte(to, NET_##id.m_id); \
+               } MACRO_END
+#elif defined(SVQC)
+       #define WriteHeader(to, id) \
+               MACRO_BEGIN { \
                        if (NET_##id##_istemp) WriteByte(to, SVC_TEMPENTITY); \
                        WriteByte(to, NET_##id.m_id); \
                } MACRO_END
 #endif
 
-#ifdef CSQC
-       #define REGISTER_NET_LINKED(id) \
-               [[accumulate]] NET_HANDLE(id, bool isnew) \
-               { \
-                       this = self; \
-                       this.sourceLocFile = __FILE__; \
-                       this.sourceLocLine = __LINE__; \
-                       if (!this) isnew = true; \
-               } \
-               REGISTER(LinkedEntities, NET, id, m_id, new(net_linked_packet)) \
-               { \
-                       make_pure(this); \
-                       this.netname = #id; \
-                       this.m_read = Net_Handle_##id; \
-               }
-#else
-       #define REGISTER_NET_LINKED(id) \
-               const bool NET_##id##_istemp = false; \
-               REGISTER(LinkedEntities, NET, id, m_id, new(net_linked_packet)) \
-               { \
-                       make_pure(this); \
-                       this.netname = #id; \
-               }
-#endif
+#define ReadRegistry(r) r##_from(Read_byte())
+#define WriteRegistry(r, to, it) Write_byte(to, it.m_id)
 
-REGISTRY(LinkedEntities, BITS(8) - 1)
-#define LinkedEntities_from(i) _LinkedEntities_from(i, NULL)
-REGISTER_REGISTRY(LinkedEntities)
-REGISTRY_SORT(LinkedEntities)
-REGISTRY_CHECK(LinkedEntities)
-STATIC_INIT(RegisterLinkedEntities_renumber)
-{
-       for (int i = 0; i < LinkedEntities_COUNT; ++i)
-               LinkedEntities_from(i).m_id = 1 + i;
-}
+#define Read_byte() ReadByte()
+#define Write_byte(to, f) WriteByte(to, f)
 
-#ifdef CSQC
-       #define REGISTER_NET_TEMP(id) \
-               NET_HANDLE(id, bool); \
-               REGISTER(TempEntities, NET, id, m_id, new(net_temp_packet)) \
-               { \
-                       make_pure(this); \
-                       this.netname = #id; \
-                       this.m_read = Net_Handle_##id; \
-               }
-#else
-       #define REGISTER_NET_TEMP(id) \
-               const bool NET_##id##_istemp = true; \
-               REGISTER(TempEntities, NET, id, m_id, new(net_temp_packet)) \
-               { \
-                       make_pure(this); \
-                       this.netname = #id; \
-               }
+#if defined(CSQC)
+       int ReadByte();
+       void WriteByte(int to, int b)
+       {
+               assert(to == MSG_C2S);
+               string s;
+               yenc_single(b, s);
+               string tmp = strcat(g_buf, s);
+               if (g_buf) strunzone(g_buf);
+               g_buf = strzone(tmp);
+       }
+#elif defined(SVQC)
+       int ReadByte()
+       {
+               ydec_single(g_buf, return);
+       }
+       void WriteByte(int to, int b);
 #endif
 
-REGISTRY(TempEntities, BITS(8) - 80)
-#define TempEntities_from(i) _TempEntities_from(i, NULL)
-REGISTER_REGISTRY(TempEntities)
-REGISTRY_SORT(TempEntities)
-REGISTRY_CHECK(TempEntities)
-STATIC_INIT(RegisterTempEntities_renumber)
-{
-       for (int i = 0; i < TempEntities_COUNT; ++i)
-               TempEntities_from(i).m_id = 80 + i;
-}
+#define Read_int() ReadInt24_t()
+#define Write_int(to, f) WriteInt24_t(to, f)
+
+#define Read_float() ReadFloat()
+#define Write_float(to, f) WriteFloat(to, f)
+
+#define Read_string() ReadString()
+#define Write_string(to, f) WriteString(to, f)
 
 #ifndef MENUQC
        const float APPROXPASTTIME_ACCURACY_REQUIREMENT = 0.05;
        #define APPROXPASTTIME_MAX (16384 * APPROXPASTTIME_ACCURACY_REQUIREMENT)
        #define APPROXPASTTIME_RANGE (64 * APPROXPASTTIME_ACCURACY_REQUIREMENT)
 
-       #if defined(CSQC)
-               #define Read_float() ReadFloat()
-               #define Read_int() ReadInt24_t()
-               #define Read_string() ReadString()
-       #elif defined(SVQC)
-               #define Write_float(to, f) WriteFloat(to, f)
-               #define Write_int(to, f) WriteInt24_t(to, f)
-               #define Write_string(to, f) WriteString(to, f)
-       #endif
-
        #ifdef CSQC
-       #define ReadRegistry(r) r##_from(ReadByte())
-
                entity ReadCSQCEntity()
                {
                        int f = ReadShort();
-                       if (f == 0) return world;
-                       return findfloat(world, entnum, f);
+                       if (f == 0) return NULL;
+                       return findfloat(NULL, entnum, f);
                }
                int ReadInt24_t()
                {
@@ -217,10 +298,6 @@ STATIC_INIT(RegisterTempEntities_renumber)
                }
 
        #else
-               const int MSG_ENTITY = 5;
-
-               #define WriteRegistry(r, to, it) WriteByte(to, it.m_id)
-
                void WriteInt24_t(float dst, float val)
                {
                        float v;
index 32a1648c328bb529f4559063759e3242885b4179..3e57d7f5d5401e563bc6f1f10caacba993fde558 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef YENC_H
 #define YENC_H
 
+#include "test.qh"
+
 #define yenc_single(c, ret) \
        MACRO_BEGIN { \
                int conv = c; \
@@ -14,7 +16,7 @@
                                ret = yenc_it; \
                                break; \
                        } \
-                       case '\0': \
+                       case 0: \
                        case '\n': \
                        case '\r': \
                        case '=': \
 #define ydec_single(stringiter, ret) \
        MACRO_BEGIN { \
                int conv = STRING_ITERATOR_GET(stringiter); \
-               bool esc = false; \
-               if (conv == '=') \
-               { \
-                       esc = true; \
-                       conv = STRING_ITERATOR_GET(stringiter); \
-                       conv -= 64; \
+               if (conv <= 0) { \
+                       ret = -1; \
+               } else { \
+                       bool esc = false; \
+                       if (conv == '=') { \
+                               esc = true; \
+                               conv = STRING_ITERATOR_GET(stringiter); \
+                               conv -= 64; \
+                       } \
+                       if (conv < 42) conv += 256; \
+                       conv -= 42; \
+                       ret = conv; \
                } \
-               if (conv < 42) conv += 256; \
-               conv -= 42; \
-               ret = conv; \
        } MACRO_END
 
 TEST(yEncDec)
 {
-       for (int i = 0; i < 255; ++i)
+       for (int i = 0; i <= 255; ++i)
        {
                int expect = i;
 
index 573b9417f99f887859b34243b515c8c5ced79224..a454ff947dc4f7ca49b5bd5ef2aca8d59f097d18 100644 (file)
@@ -752,6 +752,7 @@ void SV_ParseClientCommand(string command)
                case "prespawn": break;                            // handled by engine in host_cmd.c
                case "sentcvar": break;                            // handled by server in this file
                case "spawn": break;                               // handled by engine in host_cmd.c
+               case "c2s": Net_ClientCommand(command); return;    // handled by net.qh
 
                default:
                        if (SV_ParseClientCommand_floodcheck()) break; // "true": continue, as we're not flooding yet