Przeglądaj źródła

Labyrinth run logger.

Iñigo Valentin 5 lat temu
rodzic
commit
a3ea1748d0

+ 2 - 1
application/API/v2/bin/MAPPING.py

@@ -150,6 +150,7 @@ def parseRun(db, data_request, data_response):
         crystal = mana = data_response["reward"]["crystal"]
     else:
         crystal = 0
+    guild_points = 0
     helper = 0
 
     # Get the new ID and insert
@@ -160,7 +161,7 @@ def parseRun(db, data_request, data_response):
 
     score = None
     rank = None
-    insert(db, "run", (uid, id, dtime, area_type, area, stage, difficulty, win, time, mana, energy, crystal, helper, score, rank))
+    insert(db, "run", (uid, id, dtime, area_type, area, stage, difficulty, win, time, mana, energy, crystal, guild_points, helper, score, rank))
 
     # Parse various types of reward
     crate = data_response["reward"]["crate"]

+ 4 - 3
application/API/v2/bin/upload_run_dungeon.py

@@ -143,15 +143,16 @@ def parseRun(db, data_request, data_response):
     else:
         mana = 0
     if ("energy" in data_response["reward"]):
-        energy = mana = data_response["reward"]["energy"]
+        energy = data_response["reward"]["energy"]
     else:
         energy = 0
     if ("crystal" in data_response["reward"]):
-        crystal = mana = data_response["reward"]["crystal"]
+        crystal = data_response["reward"]["crystal"]
     else:
         crystal = 0
     # TODO Read helper. Do a test with SWBD-debug
     helper = 0
+    guild_points = 0
 
     # GEt the new ID and insert
     cursor.execute("SELECT max(id) + 1 AS id FROM run;")
@@ -161,7 +162,7 @@ def parseRun(db, data_request, data_response):
 
     score = None
     rank = None
-    insert(db, "run", (uid, id, dtime, area_type, area, stage, difficulty, win, time, mana, energy, crystal, helper, score, rank))
+    insert(db, "run", (uid, id, dtime, area_type, area, stage, difficulty, win, time, mana, energy, crystal, guild_points, helper, score, rank))
 
     # Parse various types of reward
     crate = data_response["reward"]["crate"]

+ 273 - 0
application/API/v2/bin/upload_run_lab.py

@@ -0,0 +1,273 @@
+#!/usr/bin/python3
+
+import sqlite3
+import json
+import sys
+import os
+
+import MAPPING
+
+"""
+Reads the API KEY, that must be passed as first command line argument.
+
+:returns: Recovered API KEY.
+:raises Exception: Th KEY couldn't be red.
+"""
+def readKey():
+    try:
+        key = sys.argv[1]
+        return key
+    except Exception as e:
+        print("Error parsing API KEY: " + str(e))
+        raise
+
+"""
+Reads the JSON data, that must be passed as second command line argument.
+
+:param: index 2 for start data, 3 for result data
+:returns: Recovered data, in JSON format.
+:raises Exception: The data couldn't be red or converted to JSON.
+"""
+def readData(index):
+    try:
+        data = json.loads(sys.argv[index])
+        return data
+    except Exception as e:
+        print("Error parsing data: " + str(e))
+        raise
+
+"""
+Verifies that the API key matches the player data and that it exists in th DB.
+
+:param db: Connection to the database.
+:returns: Connection to the database.
+:param data: Data in json format.
+:param key: API KEY.
+:returns: True if key and player match, False otherwise.
+:raises IntegrityError: The queryes couldn't bre executed.
+"""
+def verifyKey(db, data, key):
+    print('Verifying KEY...')
+    status = False
+    try:
+        uid = data["wizard_info"]["wizard_id"]
+        cursor = db.cursor()
+        cursor.execute('SELECT count(uid) AS c FROM player WHERE uid = ? AND api_key = ?;', (uid, key))
+        if cursor.fetchone()[0] == 1:
+            status = True
+        cursor.close()
+    except sqlite3.IntegrityError as e:
+        print("Error executing statement: " + str(e))
+        raise
+    return status
+
+"""
+Opens the database file and deletes from the user tables
+
+:param name: The path to the sqlite database.
+:returns: Connection to the database.
+:raises IntegrityError: The queryes couldn't bre executed.
+:raises IOError: The sqlite file couldn't be created.
+"""
+def openDatabase():
+    kdb = os.path.dirname(os.path.realpath(sys.argv[0])) + '/../../../sw.sqlite'
+    udb = os.path.dirname(os.path.realpath(sys.argv[0])) + '/../../../../data/sw.sqlite'
+    print('Configuring database...')
+    try:
+        db = sqlite3.connect(kdb)
+        cursor = db.cursor()
+        cursor.execute('attach "' + udb + '" as data;')
+        cursor.close()
+        return db
+    except sqlite3.IntegrityError as e:
+        print("Error executing statement: " + str(e))
+        raise
+    except IOError as e:
+        print("I/O Error creating database " + name + ": " + str(e))
+        raise
+
+"""
+Inserts a row into the database.
+
+:param db: Connection to the database.
+:param table: Name of the table to insert into.
+:param values: List of values to insert.
+:raises IntegrityError: The insert query was unsuccesfull.
+"""
+def insert(db, table, values):
+    cursor = db.cursor()
+    placeholders = ''
+    for x in range(0, len(values)):
+        placeholders = placeholders + '?, '
+    placeholders = placeholders[:len(placeholders) - 2]
+    query = 'INSERT INTO ' + table + ' VALUES (' + placeholders + ')'
+    try:
+        cursor.execute(query, values)
+    except sqlite3.IntegrityError as e:
+        print('Error Inserting into ' + table + ' with values (' + str(values) + '): ' + str(e))
+        raise
+    cursor.close;
+
+"""
+Parses run data (tables run, run_party, run_drop_rune, run_drop_runecraft,
+run_drop_item, run_drop_unit, run_drop_sd, run_drop_unit_pieces,
+run_drop_shapeshifting).
+
+:param db: Sqlite database connection.
+:param data_start: JSON data of the run start.
+:param data_result: JSON data of the run result.
+"""
+def parseRun(db, data_request, data_response):
+    print("Parsing run...")
+    cursor = db.cursor()
+
+    # Read basic data
+    uid = data_request["wizard_id"]
+    dtime = data_response["tvaluelocal"]
+
+    # Check if run has already been inserted.
+    cursor.execute("SELECT count(id) AS c FROM run WHERE uid = ? AND dtime = ?;", (uid, dtime))
+    if (cursor.fetchone()[0] > 0):
+        print("    Run already in database. Stopping....")
+        return 409;
+
+    # We are inserting, get aditional info
+    area_type = 9 # Tartarus Labyrinth
+    area = 9 # Tartarus Labyrinth
+    stage = 0 # Battle type
+    difficulty = data_request["difficulty"]
+    win = data_response["win_lose"]
+    helper = 0
+
+    tile_id = data_request["tile_id"]
+    # We now have the tile id from the request.
+    # Now we must loop all tiles in the response to get the info
+    for tile in data_response["guildmaze_tiles"]:
+        # TODO: Get correct types
+        if tile["tile_id"] == tile_id:
+            if tile["battle_type"] == 0: # Tartarus
+                stage = 1
+            elif tile["battle_type"] == 302: # Kottos (Fire guardian)
+                stage = 2
+            elif tile["battle_type"] == 0: # Leos (Water guardian)
+                stage = 3
+            elif tile["battle_type"] == 0: # Guilles (Wind guardian)
+                stage = 4
+            elif tile["battle_type"] == 0: # Normal stage
+                stage = 5
+            elif tile["battle_type"] == 0: # Rescue stage
+                stage = 6
+            elif tile["battle_type"] == 0: # Explode stage
+                stage = 7
+            elif tile["battle_type"] == 0: # Cooltime stage
+                stage = 8
+            elif tile["battle_type"] == 201: # Speed limit stage
+                stage = 9
+            elif tile["battle_type"] == 202: # Time limit stage
+                stage = 10
+            break
+    score = 0 # TODO
+    rank = ''
+    time = data_request["clear_time"]
+    if ("mana" in data_response["reward"]):
+        mana = data_response["reward"]["mana"]
+    else:
+        mana = 0
+    if ("energy" in data_response["reward"]):
+        energy = data_response["reward"]["energy"]
+    else:
+        energy = 0
+    if ("crystal" in data_response["reward"]):
+        crystal = data_response["reward"]["crystal"]
+    else:
+        crystal = 0
+    if ("guild-point" in data_response["reward"]):
+        guild_points = data_response["reward"]["guild-point"]
+    else:
+        guild_points = 0
+
+    # Get the new ID and insert
+    cursor.execute("SELECT max(id) + 1 AS id FROM run;")
+    id = cursor.fetchone()[0]
+    if id == None:
+        id = 1
+
+    insert(db, "run", (uid, id, dtime, area_type, area, stage, difficulty, win, time, mana, energy, crystal, guild_points, helper, score, rank))
+
+    # Parse various types of reward
+    crate = data_response["reward"]["crate"]
+
+    # Parse rune reward
+    if "rune" in crate:
+        rune = crate["rune"]
+        rune_id = rune["rune_id"]
+        rune_type = rune["set_id"]
+        slot = rune["slot_no"]
+        stars = rune["class"]
+        ancient = 0
+        quality = rune["rank"]
+        value = rune["sell_value"]
+        efficiency, max_efficiency = MAPPING.calculate_efficiency(rune)
+        main_stat = rune["pri_eff"][0]
+        main_stat_value = rune["pri_eff"][1]
+        if "prefix_eff" in rune:
+            innate_stat = rune["prefix_eff"][0]
+            innate_stat_value = rune["prefix_eff"][1]
+        else:
+            innate_stat = 0
+            innate_stat_value = 0
+        substat_1 = 0
+        substat_1_value = 0
+        substat_2 = 0
+        substat_2_value = 0
+        substat_3 = 0
+        substat_3_value = 0
+        substat_4 = 0
+        substat_4_value = 0
+        if "0" in rune["sec_eff"]:
+            substat_1 = rune["sec_eff"]["0"]["0"]
+            substat_1_value = rune["sec_eff"]["0"]["1"]
+        if "1" in rune["sec_eff"]:
+            substat_1 = rune["sec_eff"]["1"]["0"]
+            substat_1_value = rune["sec_eff"]["1"]["1"]
+        if "2" in rune["sec_eff"]:
+            substat_1 = rune["sec_eff"]["2"]["0"]
+            substat_1_value = rune["sec_eff"]["2"]["1"]
+        if "3" in rune["sec_eff"]:
+            substat_1 = rune["sec_eff"]["3"]["0"]
+            substat_1_value = rune["sec_eff"]["3"]["1"]
+        insert(db, "run_drop_rune", (id, rune_id, rune_type, slot, stars, ancient, quality, value, efficiency, max_efficiency, main_stat, main_stat_value, innate_stat, innate_stat_value, substat_1, substat_1_value, substat_2, substat_2_value, substat_3, substat_3_value, substat_4, substat_4_value))
+
+
+    # TODO: Parse grindstones/gems
+
+    # Parse units
+    first = True
+    for unit in data_response["unit_list"]:
+        unit_id = unit["unit_id"]
+        unit_master_id = unit["unit_master_id"]
+        if (first):
+            leader = 1
+            first = False
+        else:
+            leader = 0
+        front = 0
+        insert(db, "run_party", (id, unit_id, unit_master_id, leader, front))
+    db.commit()
+
+
+"""
+Begin script
+"""
+data_request = readData(2)
+data_response = readData(3)
+key = readKey()
+db = openDatabase()
+if verifyKey(db, data_response, key) == False:
+    print("Invalid API KEY...")
+    sys.exit(401)
+else:
+    parseRun(db, data_request, data_response)
+sys.exit(201)
+
+

+ 2 - 1
application/API/v2/bin/upload_run_rift.py

@@ -181,7 +181,8 @@ def parseRun(db, data_request, data_response, data_start_request, data_start_res
     energy = 0
     crystal = 0
     helper = 0
-    insert(db, "run", (uid, id, dtime, area_type, area, stage, difficulty, win, time, mana, energy, crystal, helper, score, rank))
+    guild_points = 0
+    insert(db, "run", (uid, id, dtime, area_type, area, stage, difficulty, win, time, mana, energy, crystal, guild_points, helper, score, rank))
 
 
     for item in data_response["item_list"]:

+ 2 - 1
application/API/v2/bin/upload_run_scenario.py

@@ -143,6 +143,7 @@ def parseRun(db, data):
         crystal = mana = data["reward"]["crystal"]
     else:
         crystal = 0
+    guild_points = 0
     helper = data["helper"]
     cursor.execute("SELECT max(id) + 1 AS id FROM run;")
     id = cursor.fetchone()[0]
@@ -150,7 +151,7 @@ def parseRun(db, data):
         id = 1
     score = None
     rank = None
-    insert(db, "run", (uid, id, dtime, area_type, area, stage, difficulty, win, time, mana, energy, crystal, helper, score, rank))
+    insert(db, "run", (uid, id, dtime, area_type, area, stage, difficulty, win, time, mana, energy, crystal, guild_points, helper, score, rank))
     if data["shapeshifting"] > 0:
         insert(db, "run_drop_shapeshifting", (id, data["shapeshifting"]))
     if data["sd"] > 0:

+ 2 - 1
application/API/v2/bin/upload_run_toa.py

@@ -149,6 +149,7 @@ def parseRun(db, data_request, data_response):
     mana = 0
     energy = 0
     crystal = 0
+    guild_points = 0
     if stage == 10:
         energy = 50
     elif stage == 20:
@@ -185,7 +186,7 @@ def parseRun(db, data_request, data_response):
     # Insert
     score = None
     rank = None
-    insert(db, "run", (uid, id, dtime, area_type, area, stage, difficulty, win, time, mana, energy, crystal, helper, score, rank))
+    insert(db, "run", (uid, id, dtime, area_type, area, stage, difficulty, win, time, mana, energy, crystal, guild_points, helper, score, rank))
 
     # Parse units
     i = 0

+ 84 - 0
application/API/v2/upload_run_lab.php

@@ -0,0 +1,84 @@
+<?php
+    /**
+     * Tartarus Labyrinth run logger script.
+     *
+     * Exposes an API to save a run to the database.
+     * Reads post data and calls the upload_run_lab.py script.
+     * Mandatory POST parameters are:
+     *  - request: Intercepted game request.
+     *  - response: Intercepted game response.
+     *  - key: User API key.
+     *
+     * @category API
+     */
+
+    global $db;
+
+    try{
+        // Check data
+        $data_request = filter_input(INPUT_POST, 'request');
+        $data_response = filter_input(INPUT_POST, 'response');
+        if ($data_request == null || $data_request == false || $data_response == null || $data_response == false){
+            http_response_code(400);
+            return 400;
+        }
+
+        // Check API key.
+        $key = filter_input(INPUT_POST, 'key');
+        if ($key == null || $key == false){
+            http_response_code(401);
+            return 401;
+        }
+
+        // Check data format.
+        $json_request = json_decode($data_request);
+        $json_response = json_decode($data_response);
+        if ($json_response === null | $json_request === null){
+            http_response_code(400);
+            return 400;
+        }
+
+        // Authenticate
+        $uid = $json->{"wizard_id"};
+        $uname = $json->{"wizard_info"}->{"wizard_name"};
+        $s = "SELECT COUNT(uid) AS c FROM player WHERE uid = $uid AND api_key = '$key';";
+        if (1 != $db->query($s)->fetchArray(SQLITE3_ASSOC)["c"]){
+            http_response_code(401);
+            return 401;
+        }
+
+        // Run scenario run parser script
+        $cmd = __DIR__ . "/bin/upload_run_lab.py " . $key . " " . escapeshellarg($data);;
+        $out = [];
+        $ret = 0;
+        try{
+            exec($cmd, $out, $ret);
+        }
+        catch(Exception $e) {
+            error_log("Error Labyrinth scenario run script '$cmd': " . $e->getMessage());
+            http_response_code(500);
+            return 500;
+        }
+
+        if ($ret != 200){
+            try{
+                http_response_code($ret);
+                return $ret;
+            }
+            catch(Exception $e) {
+                error_log("Labyrinth run script '$cmd' returned an unexpected value $ret: " . $e->getMessage());
+                http_response_code(500);
+                return 500;
+            }
+        }
+
+        // At this point, status code should be 200
+        http_response_code($ret);
+        return $ret;
+    }
+    catch(Exception $e) {
+        error_log("Unknown error parsing Labyrinth run: " . $e->getMessage());
+        http_response_code(500);
+        return 500;
+    }
+?>

+ 4 - 0
application/entity/K_Area.php

@@ -98,6 +98,10 @@
             ){
                 return APPLICATION::img("AREA", $this->id);
             }
+            elseif ($this->type == AREA_TYPE_ID::TRIAL_OF_ASCENSION){
+                // Special case
+                return APPLICATION::img("AREA", "TRIAL_OF_ASCENSION");
+            }
             elseif ($this->type == AREA_TYPE_ID::CAIROS_DUNGEON && APPLICATION::valid_id("DUNGEON_ID", $this->id)){
                 switch ($this->id){
                     case DUNGEON_ID::GIANTS_KEEP:

+ 10 - 23
application/entity/Run.php

@@ -83,6 +83,12 @@
          */
         public $crystal;
 
+        /**
+         * @var int Reward guild points.
+         */
+        public $guild_points;
+
+
         /**
          * @var bool Indicates if a frind/mentor helped.
          */
@@ -166,6 +172,7 @@
                   id,
                   uid,
                   dtime,
+                  area_type,
                   area,
                   stage,
                   difficulty,
@@ -174,6 +181,7 @@
                   mana,
                   energy,
                   crystal,
+                  guild_points,
                   helper,
                   score,
                   rank
@@ -185,29 +193,7 @@
             $this->id = $r["id"];
             $this->uid = $r["uid"];
             $this->dtime = $r["dtime"];
-            $type = 0;
-            if (APPLICATION::valid_id("RAID_RIFT_DUNGEON_ID", $r["area"]) && $r["stage"] < 1){
-                $type = AREA_TYPE_ID::RIFT_RAID_DUNGEON;
-            }
-            elseif (APPLICATION::valid_id("SCENARIO_ID", $r["area"])){
-                $type = AREA_TYPE_ID::SCENARIO;
-            }
-            elseif (APPLICATION::valid_id("ELEMENTAL_RIFT_DUNGEON_ID", $r["area"]) && $r["stage"] < 1){
-                $type = AREA_TYPE_ID::RIFT_DUNGEON;
-            }
-            elseif (APPLICATION::valid_id("CAIROS_DUNGEON_ID", $r["area"])){
-                $type = AREA_TYPE_ID::CAIROS_DUNGEON;
-            }
-            elseif (APPLICATION::valid_id("DIMENSION_DUNGEON_ID", $r["area"])){
-                if ($this->id == 1486){
-                    error_log("VALID AREA ID: " . $r["area"] . ", " . AREA_TYPE_ID::DIMENSIONAL_HOLE);
-                }
-                $type = AREA_TYPE_ID::DIMENSIONAL_HOLE;
-            }
-            if ($this->id == 1486){
-                error_log("INSTANCING DH AREA: " . $r["area"] . ", " . $type);
-            }
-            $this->area = new K_Area($r["area"], $type);
+            $this->area = new K_Area($r["area"], $r["area_type"]);
             $this->stage = $r["stage"];
             $this->difficulty = $r["difficulty"];
             $this->win = $r["win"];
@@ -215,6 +201,7 @@
             $this->mana = $r["mana"];
             $this->energy = $r["energy"];
             $this->crystal = $r["crystal"];
+            $this->guild_points = $r["guild_points"];
             $this->helper = $r["helper"];
             $this->score = $r["score"];
             $this->rank = $r["rank"];

+ 1 - 0
application/page/Runs_Page.php

@@ -37,6 +37,7 @@
             $this->view = PATH::VIEW . "runs.php";
             $this->parse_filters();
             $s = $this->build_query();
+error_log($s);
             $q = $db->query($s);
             while ($r = $q->fetchArray(SQLITE3_ASSOC)){
                 array_push($this->runs, new Run($r["id"]));

BIN
application/sw.sqlite


+ 9 - 1
application/view/runs.php

@@ -225,7 +225,7 @@
                                     $enable_save = false;
 ?>
                                     <div class='monster_panel helper'>
-                                        <img class='monster' title='Friend/Menstor' src='<?=URL::IMG["CURRENCY"]?>socialpoint.png'/>
+                                        <img class='monster' title='Friend/Mentor' src='<?=URL::IMG["CURRENCY"]?>socialpoint.png'/>
                                     </div>
 <?php
                                 }
@@ -327,6 +327,14 @@
                                         <img class='item' title='Crystal' src='<?=URL::IMG["CURRENCY"]?>crystal.png'/>
                                         <span class='item'><?=$run->crystal?></span>
                                     </div>
+<?php
+                                }
+                                if ($run->guild_points > 0){
+?>
+                                    <div class='item'>
+                                        <img class='item' title='Guild Points' src='<?=URL::IMG["CURRENCY"]?>guildpoint.png'/>
+                                        <span class='item'><?=$run->guild_points?></span>
+                                    </div>
 <?php
                                 }
                                 foreach ($run->unit as $unit){

+ 3 - 0
install_data/install_base.sql

@@ -126,6 +126,8 @@ INSERT INTO k_area VALUES(6001,2,'Necropolis');
 INSERT INTO k_area VALUES(7001,2,'Hall of Light');
 INSERT INTO k_area VALUES(8001,2,'Giant''s Keep');
 INSERT INTO k_area VALUES(9001,2,'Dragon''s Lair');
+INSERT INTO k_area VALUES(9502,2,"Punisher's Crypt");
+INSERT INTO k_area VALUES(9602,2,'Steel Fortress'); -- TODO: Check?
 INSERT INTO k_area VALUES(1001,3,'Rift Dungeon - Ice Beast');
 INSERT INTO k_area VALUES(2001,3,'Rift Dungeon - Fire Beast');
 INSERT INTO k_area VALUES(3001,3,'Rift Dungeon - Wind Beast');
@@ -137,6 +139,7 @@ INSERT INTO k_area VALUES(3,4,'Rift of Worlds - level 3');
 INSERT INTO k_area VALUES(4,4,'Rift of Worlds - level 4');
 INSERT INTO k_area VALUES(5,4,'Rift of Worlds - level 5');
 INSERT INTO k_area VALUES(9,9,'Tartarus Labyrinth');
+INSERT INTO k_area VALUES (10, 10, 'Trial of Ascension');
 CREATE TABLE k_decoration(
     id INT NOT NULL PRIMARY KEY,
     area REFERENCES k_area_type(id),

+ 1 - 0
install_data/install_data.sql

@@ -247,6 +247,7 @@ CREATE TABLE run(
     mana INT NOT NULL CHECK(mana >= 0),
     energy INT NOT NULL CHECK(energy >= 0),
     crystal INT NOT NULL CHECK(crystal >= 0),
+    guild_points NOT NULL CHECK(guild_points >= 0),
     helper INT NOT NULL CHECK(helper IN (0, 1)),
     score INT,
     rank TEXT

+ 4 - 3
public/css/runs.css

@@ -34,12 +34,13 @@ table#runs td.area div.area span.stage{
 }
 
 table#runs td.area div.area span.difficulty{
-    position: absolute;
-    top: 0em;
     left: 0;
-    width: 1.8em;
     text-align: right;
     pointer-events: none;
+    position: relative;
+    top: -3.5em;
+    width: 1.1em;
+    display: inline-block;
 }
 table#runs td.area div.area span.difficulty img.difficulty{
     height: 0.6em;

+ 4 - 0
swex-plugin/swdb.js

@@ -123,6 +123,10 @@ module.exports = {
                 success = "Rift Dungeon run logged sucesfully!"
                 start = true;
                 break;
+            case 'battleGuildMazeResult':
+                apiCommand = "upload_run_lab";
+                success = "Tartarus Labyrinth run logged succesfully!"
+                break;
         }
         if (apiCommand != ""){
             this.command(apiCommand, req, res, start, success);