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)
|
queue.extend(start.exits)
|
||||||
|
|
||||||
# run BFS on all connections, and keep track of those blocked by missing items
|
# run BFS on all connections, and keep track of those blocked by missing items
|
||||||
while True:
|
while queue:
|
||||||
try:
|
connection = queue.popleft()
|
||||||
connection = queue.popleft()
|
new_region = connection.connected_region
|
||||||
new_region = connection.connected_region
|
if new_region in rrp:
|
||||||
if new_region in rrp:
|
bc.remove(connection)
|
||||||
bc.remove(connection)
|
elif connection.can_reach(self):
|
||||||
elif connection.can_reach(self):
|
rrp.add(new_region)
|
||||||
rrp.add(new_region)
|
bc.remove(connection)
|
||||||
bc.remove(connection)
|
bc.update(new_region.exits)
|
||||||
bc.update(new_region.exits)
|
queue.extend(new_region.exits)
|
||||||
queue.extend(new_region.exits)
|
self.path[new_region] = (new_region.name, self.path.get(connection, None))
|
||||||
self.path[new_region] = (new_region.name, self.path.get(connection, None))
|
|
||||||
|
|
||||||
# Retry connections if the new region can unblock them
|
# Retry connections if the new region can unblock them
|
||||||
if new_region.name in indirect_connections:
|
if new_region.name in indirect_connections:
|
||||||
new_entrance = self.world.get_entrance(indirect_connections[new_region.name], player)
|
new_entrance = self.world.get_entrance(indirect_connections[new_region.name], player)
|
||||||
if new_entrance in bc and new_entrance not in queue:
|
if new_entrance in bc and new_entrance not in queue:
|
||||||
queue.append(new_entrance)
|
queue.append(new_entrance)
|
||||||
except IndexError:
|
|
||||||
break
|
|
||||||
|
|
||||||
def copy(self) -> CollectionState:
|
def copy(self) -> CollectionState:
|
||||||
ret = CollectionState(self.world)
|
ret = CollectionState(self.world)
|
||||||
|
@ -468,7 +465,7 @@ class CollectionState(object):
|
||||||
ret.locations_checked = copy.copy(self.locations_checked)
|
ret.locations_checked = copy.copy(self.locations_checked)
|
||||||
return ret
|
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"):
|
if not hasattr(spot, "spot_type"):
|
||||||
# try to resolve a name
|
# try to resolve a name
|
||||||
if resolution_hint == 'Location':
|
if resolution_hint == 'Location':
|
||||||
|
@ -480,7 +477,7 @@ class CollectionState(object):
|
||||||
spot = self.world.get_region(spot, player)
|
spot = self.world.get_region(spot, player)
|
||||||
return spot.can_reach(self)
|
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
|
# this may need improvement
|
||||||
if locations is None:
|
if locations is None:
|
||||||
locations = self.world.get_filled_locations()
|
locations = self.world.get_filled_locations()
|
||||||
|
@ -488,7 +485,9 @@ class CollectionState(object):
|
||||||
checked_locations = 0
|
checked_locations = 0
|
||||||
while new_locations:
|
while new_locations:
|
||||||
reachable_events = [location for location in locations if location.event and
|
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)]
|
and location.can_reach(self)]
|
||||||
for event in reachable_events:
|
for event in reachable_events:
|
||||||
if (event.name, event.player) not in self.events:
|
if (event.name, event.player) not in self.events:
|
||||||
|
@ -497,12 +496,12 @@ class CollectionState(object):
|
||||||
new_locations = len(reachable_events) > checked_locations
|
new_locations = len(reachable_events) > checked_locations
|
||||||
checked_locations = len(reachable_events)
|
checked_locations = len(reachable_events)
|
||||||
|
|
||||||
def has(self, item, player, count=1):
|
def has(self, item, player: int, count: int = 1):
|
||||||
if count == 1:
|
if count == 1:
|
||||||
return (item, player) in self.prog_items
|
return (item, player) in self.prog_items
|
||||||
return self.prog_items[item, player] >= count
|
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]:
|
if self.world.retro[player]:
|
||||||
return self.can_buy_unlimited('Small Key (Universal)', player)
|
return self.can_buy_unlimited('Small Key (Universal)', player)
|
||||||
if count == 1:
|
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 import Flask, request, redirect, url_for, render_template, Response, session, abort
|
||||||
from flask_caching import Cache
|
from flask_caching import Cache
|
||||||
from flaskext.autoversion import Autoversion
|
from flaskext.autoversion import Autoversion
|
||||||
|
from flask_compress import Compress
|
||||||
|
|
||||||
from .models import *
|
from .models import *
|
||||||
|
|
||||||
|
@ -41,6 +42,7 @@ app.config["CACHE_TYPE"] = "simple"
|
||||||
app.autoversion = True
|
app.autoversion = True
|
||||||
av = Autoversion(app)
|
av = Autoversion(app)
|
||||||
cache = Cache(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
|
# this local cache is risky business if app hosting is done with subprocesses as it will not sync. Waitress is fine though
|
||||||
multiworlds = {}
|
multiworlds = {}
|
||||||
|
|
|
@ -3,3 +3,4 @@ pony>=0.7.13
|
||||||
waitress>=1.4.4
|
waitress>=1.4.4
|
||||||
flask-caching>=1.9.0
|
flask-caching>=1.9.0
|
||||||
Flask-Autoversion>=0.1.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' %}
|
{% extends 'layout.html' %}
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<title>Multiworld Tracker for Room {{ room.id }}</title>
|
<title>Multiworld Tracker for Room {{ room.id }}</title>
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css"
|
<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"/>
|
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"
|
<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>
|
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>
|
<script>
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
var tables = $(".table").DataTable({
|
var tables = $(".table").DataTable({
|
||||||
"paging": false,
|
"paging": false,
|
||||||
"ordering": true,
|
"ordering": true,
|
||||||
"info": false,
|
"info": false,
|
||||||
"fixedHeader": true,
|
"dom": "t",
|
||||||
"dom": "t"
|
"scrollY": "39vh",
|
||||||
|
"scrollCollapse": true,
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#searchbox').keyup(function () {
|
$('#searchbox').keyup(function () {
|
||||||
|
@ -26,8 +32,12 @@
|
||||||
target.find(".table").each(function (i, new_table) {
|
target.find(".table").each(function (i, new_table) {
|
||||||
var new_trs = $(new_table).find("tbody>tr");
|
var new_trs = $(new_table).find("tbody>tr");
|
||||||
var old_table = tables.eq(i);
|
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.clear();
|
||||||
old_table.rows.add(new_trs).draw();
|
old_table.rows.add(new_trs).draw();
|
||||||
|
$(old_table.settings()[0].nScrollBody).scrollTop(topscroll);
|
||||||
|
$(old_table.settings()[0].nScrollBody).scrollLeft(leftscroll);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log("Failed to connect to Server, in order to update Table Data.");
|
console.log("Failed to connect to Server, in order to update Table Data.");
|
||||||
|
@ -37,15 +47,28 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
setInterval(update, 30000);
|
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>
|
</script>
|
||||||
<link rel="stylesheet" type="text/css" href="{{ static_autoversion("static.css") }}"/>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<input id="searchbox" class="form-control" type="text" placeholder="Search">
|
<input id="searchbox" class="form-control" type="text" placeholder="Search">
|
||||||
{% for team, players in inventory.items() %}
|
<div>
|
||||||
<table class="table table-striped table-bordered table-hover table-sm">
|
{% for team, players in inventory.items() %}
|
||||||
<thead class="thead-dark">
|
<table class="table table-striped table-bordered table-hover table-sm">
|
||||||
|
<thead class="thead-dark">
|
||||||
<tr>
|
<tr>
|
||||||
<th>#</th>
|
<th>#</th>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
|
@ -86,8 +109,6 @@
|
||||||
</table>
|
</table>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% for team, players in checks_done.items() %}
|
{% for team, players in checks_done.items() %}
|
||||||
<table class="table table-striped table-bordered table-hover table-sm">
|
<table class="table table-striped table-bordered table-hover table-sm">
|
||||||
<thead class="thead-dark">
|
<thead class="thead-dark">
|
||||||
|
@ -147,4 +168,5 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
Loading…
Reference in New Issue