make larger trackers linked tables
This commit is contained in:
		
							parent
							
								
									d2e3c457be
								
							
						
					
					
						commit
						521d3b0584
					
				| 
						 | 
				
			
			@ -436,26 +436,23 @@ class CollectionState(object):
 | 
			
		|||
            queue.extend(start.exits)
 | 
			
		||||
 | 
			
		||||
        # run BFS on all connections, and keep track of those blocked by missing items
 | 
			
		||||
        while True:
 | 
			
		||||
            try:
 | 
			
		||||
                connection = queue.popleft()
 | 
			
		||||
                new_region = connection.connected_region
 | 
			
		||||
                if new_region in rrp:
 | 
			
		||||
                    bc.remove(connection)
 | 
			
		||||
                elif connection.can_reach(self):
 | 
			
		||||
                    rrp.add(new_region)
 | 
			
		||||
                    bc.remove(connection)
 | 
			
		||||
                    bc.update(new_region.exits)
 | 
			
		||||
                    queue.extend(new_region.exits)
 | 
			
		||||
                    self.path[new_region] = (new_region.name, self.path.get(connection, None))
 | 
			
		||||
        while queue:
 | 
			
		||||
            connection = queue.popleft()
 | 
			
		||||
            new_region = connection.connected_region
 | 
			
		||||
            if new_region in rrp:
 | 
			
		||||
                bc.remove(connection)
 | 
			
		||||
            elif connection.can_reach(self):
 | 
			
		||||
                rrp.add(new_region)
 | 
			
		||||
                bc.remove(connection)
 | 
			
		||||
                bc.update(new_region.exits)
 | 
			
		||||
                queue.extend(new_region.exits)
 | 
			
		||||
                self.path[new_region] = (new_region.name, self.path.get(connection, None))
 | 
			
		||||
 | 
			
		||||
                    # Retry connections if the new region can unblock them
 | 
			
		||||
                    if new_region.name in indirect_connections:
 | 
			
		||||
                        new_entrance = self.world.get_entrance(indirect_connections[new_region.name], player)
 | 
			
		||||
                        if new_entrance in bc and new_entrance not in queue:
 | 
			
		||||
                            queue.append(new_entrance)
 | 
			
		||||
            except IndexError:
 | 
			
		||||
                break
 | 
			
		||||
                # Retry connections if the new region can unblock them
 | 
			
		||||
                if new_region.name in indirect_connections:
 | 
			
		||||
                    new_entrance = self.world.get_entrance(indirect_connections[new_region.name], player)
 | 
			
		||||
                    if new_entrance in bc and new_entrance not in queue:
 | 
			
		||||
                        queue.append(new_entrance)
 | 
			
		||||
 | 
			
		||||
    def copy(self) -> CollectionState:
 | 
			
		||||
        ret = CollectionState(self.world)
 | 
			
		||||
| 
						 | 
				
			
			@ -468,7 +465,7 @@ class CollectionState(object):
 | 
			
		|||
        ret.locations_checked = copy.copy(self.locations_checked)
 | 
			
		||||
        return ret
 | 
			
		||||
 | 
			
		||||
    def can_reach(self, spot, resolution_hint=None, player=None):
 | 
			
		||||
    def can_reach(self, spot, resolution_hint=None, player=None) -> bool:
 | 
			
		||||
        if not hasattr(spot, "spot_type"):
 | 
			
		||||
            # try to resolve a name
 | 
			
		||||
            if resolution_hint == 'Location':
 | 
			
		||||
| 
						 | 
				
			
			@ -480,7 +477,7 @@ class CollectionState(object):
 | 
			
		|||
                spot = self.world.get_region(spot, player)
 | 
			
		||||
        return spot.can_reach(self)
 | 
			
		||||
 | 
			
		||||
    def sweep_for_events(self, key_only=False, locations=None):
 | 
			
		||||
    def sweep_for_events(self, key_only: bool = False, locations=None):
 | 
			
		||||
        # this may need improvement
 | 
			
		||||
        if locations is None:
 | 
			
		||||
            locations = self.world.get_filled_locations()
 | 
			
		||||
| 
						 | 
				
			
			@ -488,7 +485,9 @@ class CollectionState(object):
 | 
			
		|||
        checked_locations = 0
 | 
			
		||||
        while new_locations:
 | 
			
		||||
            reachable_events = [location for location in locations if location.event and
 | 
			
		||||
                                (not key_only or (not self.world.keyshuffle[location.item.player] and location.item.smallkey) or (not self.world.bigkeyshuffle[location.item.player] and location.item.bigkey))
 | 
			
		||||
                                (not key_only or (not self.world.keyshuffle[
 | 
			
		||||
                                    location.item.player] and location.item.smallkey) or (not self.world.bigkeyshuffle[
 | 
			
		||||
                                    location.item.player] and location.item.bigkey))
 | 
			
		||||
                                and location.can_reach(self)]
 | 
			
		||||
            for event in reachable_events:
 | 
			
		||||
                if (event.name, event.player) not in self.events:
 | 
			
		||||
| 
						 | 
				
			
			@ -497,12 +496,12 @@ class CollectionState(object):
 | 
			
		|||
            new_locations = len(reachable_events) > checked_locations
 | 
			
		||||
            checked_locations = len(reachable_events)
 | 
			
		||||
 | 
			
		||||
    def has(self, item, player, count=1):
 | 
			
		||||
    def has(self, item, player: int, count: int = 1):
 | 
			
		||||
        if count == 1:
 | 
			
		||||
            return (item, player) in self.prog_items
 | 
			
		||||
        return self.prog_items[item, player] >= count
 | 
			
		||||
 | 
			
		||||
    def has_key(self, item, player, count=1):
 | 
			
		||||
    def has_key(self, item, player, count: int = 1):
 | 
			
		||||
        if self.world.retro[player]:
 | 
			
		||||
            return self.can_buy_unlimited('Small Key (Universal)', player)
 | 
			
		||||
        if count == 1:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,7 @@ from pony.flask import Pony
 | 
			
		|||
from flask import Flask, request, redirect, url_for, render_template, Response, session, abort
 | 
			
		||||
from flask_caching import Cache
 | 
			
		||||
from flaskext.autoversion import Autoversion
 | 
			
		||||
from flask_compress import Compress
 | 
			
		||||
 | 
			
		||||
from .models import *
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -41,6 +42,7 @@ app.config["CACHE_TYPE"] = "simple"
 | 
			
		|||
app.autoversion = True
 | 
			
		||||
av = Autoversion(app)
 | 
			
		||||
cache = Cache(app)
 | 
			
		||||
Compress(app)
 | 
			
		||||
 | 
			
		||||
# this local cache is risky business if app hosting is done with subprocesses as it will not sync. Waitress is fine though
 | 
			
		||||
multiworlds = {}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,3 +3,4 @@ pony>=0.7.13
 | 
			
		|||
waitress>=1.4.4
 | 
			
		||||
flask-caching>=1.9.0
 | 
			
		||||
Flask-Autoversion>=0.1.0
 | 
			
		||||
Flask-Compress>=1.5.0
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,114 @@
 | 
			
		|||
(function (global, factory) {
 | 
			
		||||
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('jquery')) :
 | 
			
		||||
      typeof define === 'function' && define.amd ? define(['exports', 'jquery'], factory) :
 | 
			
		||||
          (factory((global.$ = global.$ || {}, global.$.fn = global.$.fn || {}), global.$));
 | 
			
		||||
}(this, (function (exports, $) {
 | 
			
		||||
  'use strict';
 | 
			
		||||
 | 
			
		||||
  $ = $ && $.hasOwnProperty('default') ? $['default'] : $;
 | 
			
		||||
 | 
			
		||||
// 参考了(reference):
 | 
			
		||||
// debouncing function from John Hann
 | 
			
		||||
// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
 | 
			
		||||
  function debounce(func, threshold) {
 | 
			
		||||
    var timeout;
 | 
			
		||||
    return function debounced() {
 | 
			
		||||
      var obj = this, args = arguments;
 | 
			
		||||
 | 
			
		||||
      function delayed() {
 | 
			
		||||
        // 让调用smartresize的对象执行
 | 
			
		||||
        func.apply(obj, args);
 | 
			
		||||
        /*
 | 
			
		||||
        timeout = null;:这个语句只是单纯将timeout指向null,
 | 
			
		||||
        而timeout指向的定时器还存在,
 | 
			
		||||
        要想清除定时器(让setTimeout调用的函数不执行)要用clearTimeout(timeout)。
 | 
			
		||||
        eg:
 | 
			
		||||
        var timeout = setTimeout(function(){
 | 
			
		||||
          alert('timeout = null');// 执行
 | 
			
		||||
        },1000);
 | 
			
		||||
        timeout = null;
 | 
			
		||||
        var timeout = setTimeout(function(){
 | 
			
		||||
          alert('clearTimeout(timeout)');// 不执行
 | 
			
		||||
        },1000);
 | 
			
		||||
        clearTimeout(timeout);
 | 
			
		||||
        var timeout = setTimeout(function(){
 | 
			
		||||
          clearTimeout(timeout);
 | 
			
		||||
          alert('clearTimeout(timeout)');// 执行(已经开始执行匿名函数了)
 | 
			
		||||
        },1000);
 | 
			
		||||
        */
 | 
			
		||||
        timeout = null;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // 如果有timeout正在倒计时,则清除当前timeout
 | 
			
		||||
      timeout && clearTimeout(timeout);
 | 
			
		||||
      timeout = setTimeout(delayed, threshold || 100);
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function smartscroll(fn, threshold) {
 | 
			
		||||
    return fn ? this.bind('scroll', debounce(fn, threshold)) : this.trigger('smartscroll');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
//jquery-smartscroll
 | 
			
		||||
  $.fn.smartscroll = smartscroll;
 | 
			
		||||
 | 
			
		||||
  function scrollsync(options) {
 | 
			
		||||
    var defaluts = {
 | 
			
		||||
      x_sync: true,
 | 
			
		||||
      y_sync: true,
 | 
			
		||||
      use_smartscroll: false,
 | 
			
		||||
      smartscroll_delay: 10,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // 使用jQuery.extend 覆盖插件默认参数
 | 
			
		||||
    var options = $.extend({}, defaluts, options);
 | 
			
		||||
    console.log(options);
 | 
			
		||||
 | 
			
		||||
    var scroll_type = options.use_smartscroll ? 'smartscroll' : 'scroll';
 | 
			
		||||
    var $containers = this;
 | 
			
		||||
 | 
			
		||||
    // 滚动后设置scrolling的值,调用set同步滚动条
 | 
			
		||||
    var scrolling = {};
 | 
			
		||||
    Object.defineProperty(scrolling, 'top', {
 | 
			
		||||
      set: function (val) {
 | 
			
		||||
        $containers.each(function () {
 | 
			
		||||
          $(this).scrollTop(val);
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    Object.defineProperty(scrolling, 'left', {
 | 
			
		||||
      set: function (val) {
 | 
			
		||||
        $containers.each(function () {
 | 
			
		||||
          $(this).scrollLeft(val);
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $containers.on({
 | 
			
		||||
      mouseover: function () {
 | 
			
		||||
        if (scroll_type == 'smartscroll') {
 | 
			
		||||
          $(this).smartscroll(function () {
 | 
			
		||||
            options.x_sync && (scrolling.top = $(this).scrollTop());
 | 
			
		||||
            options.y_sync && (scrolling.left = $(this).scrollLeft());
 | 
			
		||||
          }, options.smartscroll_delay);
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        $(this).bind('scroll', function () {
 | 
			
		||||
          options.x_sync && (scrolling.top = $(this).scrollTop());
 | 
			
		||||
          options.y_sync && (scrolling.left = $(this).scrollLeft());
 | 
			
		||||
        });
 | 
			
		||||
      },
 | 
			
		||||
      mouseout: function () {
 | 
			
		||||
        $(this).unbind('scroll');
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  exports.scrollsync = scrollsync;
 | 
			
		||||
 | 
			
		||||
  Object.defineProperty(exports, '__esModule', {value: true});
 | 
			
		||||
 | 
			
		||||
})));
 | 
			
		||||
| 
						 | 
				
			
			@ -1,18 +1,24 @@
 | 
			
		|||
{% extends 'layout.html' %}
 | 
			
		||||
{% block head %}
 | 
			
		||||
    <title>Multiworld Tracker for Room {{ room.id }}</title>
 | 
			
		||||
 | 
			
		||||
    <link rel="stylesheet" type="text/css"
 | 
			
		||||
          href="https://cdn.datatables.net/v/bs4/jq-3.3.1/dt-1.10.21/fh-3.1.7/datatables.min.css"/>
 | 
			
		||||
    <link rel="stylesheet" type="text/css" href="{{ static_autoversion("static.css") }}"/>
 | 
			
		||||
    <script type="text/javascript"
 | 
			
		||||
            src="https://cdn.datatables.net/v/bs4/jq-3.3.1/dt-1.10.21/fh-3.1.7/datatables.min.js"></script>
 | 
			
		||||
    <script src="{{ static_autoversion("jquery.scrollsync.js") }}"></script>
 | 
			
		||||
 | 
			
		||||
    <script>
 | 
			
		||||
 | 
			
		||||
        $(document).ready(function () {
 | 
			
		||||
            var tables = $(".table").DataTable({
 | 
			
		||||
                "paging": false,
 | 
			
		||||
                "ordering": true,
 | 
			
		||||
                "info": false,
 | 
			
		||||
                "fixedHeader": true,
 | 
			
		||||
                "dom": "t"
 | 
			
		||||
                "dom": "t",
 | 
			
		||||
                "scrollY": "39vh",
 | 
			
		||||
                "scrollCollapse": true,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            $('#searchbox').keyup(function () {
 | 
			
		||||
| 
						 | 
				
			
			@ -26,8 +32,12 @@
 | 
			
		|||
                        target.find(".table").each(function (i, new_table) {
 | 
			
		||||
                            var new_trs = $(new_table).find("tbody>tr");
 | 
			
		||||
                            var old_table = tables.eq(i);
 | 
			
		||||
                            var topscroll = $(old_table.settings()[0].nScrollBody).scrollTop();
 | 
			
		||||
                            var leftscroll = $(old_table.settings()[0].nScrollBody).scrollLeft();
 | 
			
		||||
                            old_table.clear();
 | 
			
		||||
                            old_table.rows.add(new_trs).draw();
 | 
			
		||||
                            $(old_table.settings()[0].nScrollBody).scrollTop(topscroll);
 | 
			
		||||
                            $(old_table.settings()[0].nScrollBody).scrollLeft(leftscroll);
 | 
			
		||||
                        });
 | 
			
		||||
                    } else {
 | 
			
		||||
                        console.log("Failed to connect to Server, in order to update Table Data.");
 | 
			
		||||
| 
						 | 
				
			
			@ -37,15 +47,28 @@
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
            setInterval(update, 30000);
 | 
			
		||||
 | 
			
		||||
            $(".dataTables_scrollBody").scrollsync({
 | 
			
		||||
                y_sync: true,
 | 
			
		||||
                x_sync: true
 | 
			
		||||
            })
 | 
			
		||||
            $(window).resize(function () {
 | 
			
		||||
                tables.draw();
 | 
			
		||||
            });
 | 
			
		||||
            setTimeout(
 | 
			
		||||
                tables.draw, {# this fixes the top header misalignment, for some reason #}
 | 
			
		||||
                500
 | 
			
		||||
            );
 | 
			
		||||
        })
 | 
			
		||||
    </script>
 | 
			
		||||
    <link rel="stylesheet" type="text/css" href="{{ static_autoversion("static.css") }}"/>
 | 
			
		||||
 | 
			
		||||
{% endblock %}
 | 
			
		||||
{% block body %}
 | 
			
		||||
    <input id="searchbox" class="form-control" type="text" placeholder="Search">
 | 
			
		||||
    {% for team, players in inventory.items() %}
 | 
			
		||||
        <table class="table table-striped table-bordered table-hover table-sm">
 | 
			
		||||
            <thead class="thead-dark">
 | 
			
		||||
    <div>
 | 
			
		||||
        {% for team, players in inventory.items() %}
 | 
			
		||||
            <table class="table table-striped table-bordered table-hover table-sm">
 | 
			
		||||
                <thead class="thead-dark">
 | 
			
		||||
            <tr>
 | 
			
		||||
                <th>#</th>
 | 
			
		||||
                <th>Name</th>
 | 
			
		||||
| 
						 | 
				
			
			@ -86,8 +109,6 @@
 | 
			
		|||
        </table>
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    {% for team, players in checks_done.items() %}
 | 
			
		||||
        <table class="table table-striped table-bordered table-hover table-sm">
 | 
			
		||||
            <thead class="thead-dark">
 | 
			
		||||
| 
						 | 
				
			
			@ -147,4 +168,5 @@
 | 
			
		|||
            </tbody>
 | 
			
		||||
        </table>
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
    </div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
		Loading…
	
		Reference in New Issue