changeset 1789:513c467f3a87

Implement basic search functionality. Has bugs and limitations to be rid of.
author Matti Hamalainen <ccr@tnsp.org>
date Sun, 29 Oct 2017 17:13:04 +0200
parents 6539555f00b0
children 24e23feca10a
files mapsearch.c
diffstat 1 files changed, 146 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/mapsearch.c	Sun Oct 29 05:18:21 2017 +0200
+++ b/mapsearch.c	Sun Oct 29 17:13:04 2017 +0200
@@ -62,6 +62,15 @@
 } MAPInfoCtx;
 
 
+typedef struct
+{
+    char *map;
+    int mx, my, wx, wy;
+    double accuracy;
+    BOOL centered;
+} MAPMatch;
+
+
 /* Options
  */
 MAPInfoCtx optMaps[SET_MAX_MAPS];
@@ -613,6 +622,117 @@
 }
 
 
+void mapPerformSearch(struct lws *wsi, const unsigned char *data, const size_t len, char **verr)
+{
+    int width, height, centerX, centerY;
+    MapBlock *pattern = NULL;
+    MAPMatch matches[SET_MAX_MATCHES];
+    int nmatches = 0, maxMatches = SET_MAX_MATCHES;
+    BOOL centerFound;
+
+    // Parse pattern block dimensions
+    mapBlockGetDimensions(data, len - 10, &width, &height);
+    if (width <= 0 || height <= 0)
+    {
+        *verr = "Could not parse map block dimensions.";
+        goto out;
+    }
+
+    if (width * height < 3)
+    {
+        *verr = "Search block pattern too small.";
+        goto out;
+    }
+
+    if ((pattern = mapBlockAlloc(width, height)) == NULL)
+        goto out;
+
+    if (!mapBlockParse(data, len, pattern))
+    {
+        *verr = "Error parsing map block data.";
+        goto out;
+    }
+
+    // Entropy check
+    int entropy = mapBlockGetEntropy(pattern, optCleanChars, strlen(optCleanChars));
+
+    if ((entropy < 2 && width < 10 && height < 10) ||
+        (entropy < 3 && width * height < 6))
+    {
+        *verr = "Search block entropy insufficient.";
+        goto out;
+    }
+
+    // Find pattern center marker, if any
+    centerFound = mapBlockFindCenter(pattern, "*@", &centerX, &centerY, 20);
+
+    // Clean the pattern from characters we do not want to match
+    mapBlockClean(pattern, optCleanChars);
+
+    // Search maps ..
+    for (int nmap = 0; nmap < optNMaps; nmap++)
+    {
+        MAPInfoCtx *info = &optMaps[nmap];
+
+        for (int oy = 0; oy < info->map->height - height - 1; oy++)
+        for (int ox = 0; ox < info->map->width - width - 1; ox++)
+        {
+            double accuracy = mapMatchBlock(info->map, pattern, ox, oy, 0, TRUE);
+            if (accuracy > 99.5f)
+            {
+                MAPMatch *match = &matches[nmatches++];
+
+                match->map = info->locFile.continent;
+                match->mx = ox + centerX;
+                match->my = oy + centerY;
+                match->wx = optWorldXC + info->locFile.x + ox + centerX;
+                match->wy = optWorldYC + info->locFile.y + oy + centerY;
+                match->accuracy = accuracy;
+                match->centered = centerFound;
+
+                if (nmatches >= SET_MAX_MATCHES || nmatches >= maxMatches)
+                    goto out;
+            }
+        }
+    }
+
+out:
+    mapBlockFree(pattern);
+
+    if (*verr != NULL)
+        return;
+
+    if (nmatches > 0)
+    {
+        char *buf = NULL;
+        size_t bufLen = 0, bufSize = 0;
+
+        th_strbuf_puts(&buf, &bufSize, &bufLen, "RESULT:[");
+
+        for (int n = 0; n < nmatches; n++)
+        {
+            MAPMatch *match = &matches[n];
+            char *vstr = th_strdup_printf(
+                "[%1.2f,%d,\"%s\",%d,%d,%d,%d]%s",
+                match->accuracy,
+                match->centered,
+                match->map,
+                match->mx, match->my,
+                match->wx, match->wy,
+                (n < nmatches - 1) ? "," : "");
+
+            th_strbuf_puts(&buf, &bufSize, &bufLen, vstr);
+            th_free(vstr);
+        }
+
+        th_strbuf_puts(&buf, &bufSize, &bufLen, "]");
+        lws_write(wsi, (unsigned char *) buf, bufLen, LWS_WRITE_TEXT);
+    }
+    else
+        *verr = "No matches found.";
+}
+
+
 int mapLWSCallback(struct lws *wsi,
     enum lws_callback_reasons reason,
     void *user, void *in, size_t len)
@@ -627,6 +747,32 @@
 
         case LWS_CALLBACK_RECEIVE:
             {
+            char *data = (char *) in;
+            unsigned char *udata = (unsigned char *) in;
+            char *verr = NULL;
+
+            if (len >= 10 && strncmp(data, "MAPSEARCH\n", 10) == 0)
+            {
+                if (len <= 10 + 1)
+                    verr = "Search pattern data too small.";
+                else
+                    mapPerformSearch(wsi, udata + 10, len - 10, &verr);
+            }
+            else
+            {
+                verr = "Invalid command/search query, not enough data.";
+            }
+
+            if (verr != NULL)
+            {
+                THERR("%s\n", verr);
+                char *vstr = th_strdup_printf("ERROR:%s", verr);
+                lws_write(wsi, (unsigned char *) vstr, strlen(vstr), LWS_WRITE_TEXT);
+                th_free(vstr);
+            }
+
+            verr = "END";
+            lws_write(wsi, (unsigned char *) verr, strlen(verr), LWS_WRITE_TEXT);
             lws_close_reason(wsi, LWS_CLOSE_STATUS_NOSTATUS, NULL, 0);
             }
             break;