minecart layer stub
This commit is contained in:
parent
36e3a53e6a
commit
1b18e08cef
@ -50,3 +50,7 @@
|
|||||||
* advtrains_wagon_wood_inv.png
|
* advtrains_wagon_wood_inv.png
|
||||||
** License: CC BY-SA 3.0
|
** License: CC BY-SA 3.0
|
||||||
** Source [advtrains](http://advtrains.bleipb.de/)
|
** Source [advtrains](http://advtrains.bleipb.de/)
|
||||||
|
|
||||||
|
* minecart_logo.png
|
||||||
|
** License: CC0
|
||||||
|
** Source [minecart](https://github.com/joe7575/minecart)
|
||||||
|
@ -1,116 +0,0 @@
|
|||||||
-- mapserver http bridge
|
|
||||||
local has_advtrains = minetest.get_modpath("advtrains")
|
|
||||||
|
|
||||||
local function explode(sep, input)
|
|
||||||
local t={}
|
|
||||||
local i=0
|
|
||||||
for k in string.gmatch(input,"([^"..sep.."]+)") do
|
|
||||||
t[i]=k
|
|
||||||
i=i+1
|
|
||||||
end
|
|
||||||
return t
|
|
||||||
end
|
|
||||||
local function get_max_lag()
|
|
||||||
local arrayoutput = explode(", ",minetest.get_server_status())
|
|
||||||
arrayoutput = explode("=",arrayoutput[4])
|
|
||||||
return arrayoutput[1]
|
|
||||||
end
|
|
||||||
|
|
||||||
local http, url, key
|
|
||||||
|
|
||||||
function send_stats()
|
|
||||||
local t0 = minetest.get_us_time()
|
|
||||||
|
|
||||||
local data = {
|
|
||||||
time = minetest.get_timeofday() * 24000,
|
|
||||||
uptime = minetest.get_server_uptime(),
|
|
||||||
max_lag = tonumber(get_max_lag()),
|
|
||||||
players = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if has_advtrains then
|
|
||||||
-- send trains if 'advtrains' mod installed
|
|
||||||
|
|
||||||
data.trains = {}
|
|
||||||
for _, train in pairs(advtrains.trains) do
|
|
||||||
--print(dump(train))--XXX
|
|
||||||
|
|
||||||
local t = {
|
|
||||||
text_outside = train.text_outside,
|
|
||||||
text_inside = train.text_inside,
|
|
||||||
line = train.line,
|
|
||||||
pos = train.last_pos,
|
|
||||||
velocity = train.velocity,
|
|
||||||
off_track = train.off_track,
|
|
||||||
id = train.id,
|
|
||||||
wagons = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, part in pairs(train.trainparts) do
|
|
||||||
local wagon = advtrains.wagons[part]
|
|
||||||
if wagon ~= nil then
|
|
||||||
table.insert(t.wagons, {
|
|
||||||
id = wagon.id,
|
|
||||||
type = wagon.type,
|
|
||||||
pos_in_train = wagon.pos_in_train,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
table.insert(data.trains, t)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, player in ipairs(minetest.get_connected_players()) do
|
|
||||||
|
|
||||||
local is_hidden = minetest.check_player_privs(player:get_player_name(), {mapserver_hide_player = true})
|
|
||||||
|
|
||||||
local info = {
|
|
||||||
name = player:get_player_name(),
|
|
||||||
pos = player:get_pos(),
|
|
||||||
hp = player:get_hp(),
|
|
||||||
breath = player:get_breath(),
|
|
||||||
velocity = player:get_player_velocity()
|
|
||||||
}
|
|
||||||
|
|
||||||
if not is_hidden then
|
|
||||||
table.insert(data.players, info)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local json = minetest.write_json(data)
|
|
||||||
--print(json)--XXX
|
|
||||||
|
|
||||||
local t1 = minetest.get_us_time()
|
|
||||||
local process_time = t1 - t0
|
|
||||||
if process_time > 10000 then
|
|
||||||
minetest.log("warning", "[mapserver-bridge] processing took " .. process_time .. " us")
|
|
||||||
end
|
|
||||||
|
|
||||||
http.fetch({
|
|
||||||
url = url .. "/api/minetest",
|
|
||||||
extra_headers = { "Content-Type: application/json", "Authorization: " .. key },
|
|
||||||
timeout = 1,
|
|
||||||
post_data = json
|
|
||||||
}, function(res)
|
|
||||||
|
|
||||||
local t2 = minetest.get_us_time()
|
|
||||||
local post_time = t2 - t1
|
|
||||||
if post_time > 1000000 then -- warn if over a second
|
|
||||||
minetest.log("warning", "[mapserver-bridge] post took " .. post_time .. " us")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- TODO: error-handling
|
|
||||||
minetest.after(2, send_stats)
|
|
||||||
end)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function mapserver.bridge_init(_http, _url, _key)
|
|
||||||
http = _http
|
|
||||||
url = _url
|
|
||||||
key = _key
|
|
||||||
|
|
||||||
minetest.after(2, send_stats)
|
|
||||||
end
|
|
31
mapserver_mod/mapserver/bridge/advtrains.lua
Normal file
31
mapserver_mod/mapserver/bridge/advtrains.lua
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
mapserver.bridge.add_advtrains = function(data)
|
||||||
|
data.trains = {}
|
||||||
|
for _, train in pairs(advtrains.trains) do
|
||||||
|
|
||||||
|
local t = {
|
||||||
|
text_outside = train.text_outside,
|
||||||
|
text_inside = train.text_inside,
|
||||||
|
line = train.line,
|
||||||
|
pos = train.last_pos,
|
||||||
|
velocity = train.velocity,
|
||||||
|
off_track = train.off_track,
|
||||||
|
id = train.id,
|
||||||
|
wagons = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, part in pairs(train.trainparts) do
|
||||||
|
local wagon = advtrains.wagons[part]
|
||||||
|
if wagon ~= nil then
|
||||||
|
table.insert(t.wagons, {
|
||||||
|
id = wagon.id,
|
||||||
|
type = wagon.type,
|
||||||
|
pos_in_train = wagon.pos_in_train,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(data.trains, t)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
24
mapserver_mod/mapserver/bridge/defaults.lua
Normal file
24
mapserver_mod/mapserver/bridge/defaults.lua
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
local function explode(sep, input)
|
||||||
|
local t={}
|
||||||
|
local i=0
|
||||||
|
for k in string.gmatch(input,"([^"..sep.."]+)") do
|
||||||
|
t[i]=k
|
||||||
|
i=i+1
|
||||||
|
end
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
local function get_max_lag()
|
||||||
|
local arrayoutput = explode(", ",minetest.get_server_status())
|
||||||
|
arrayoutput = explode("=",arrayoutput[4])
|
||||||
|
return arrayoutput[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
mapserver.bridge.add_defaults = function(data)
|
||||||
|
data.time = minetest.get_timeofday() * 24000
|
||||||
|
data.uptime = minetest.get_server_uptime()
|
||||||
|
data.max_lag = tonumber(get_max_lag())
|
||||||
|
|
||||||
|
end
|
69
mapserver_mod/mapserver/bridge/init.lua
Normal file
69
mapserver_mod/mapserver/bridge/init.lua
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
local MP = minetest.get_modpath("mapserver")
|
||||||
|
dofile(MP .. "/bridge/defaults.lua")
|
||||||
|
dofile(MP .. "/bridge/players.lua")
|
||||||
|
dofile(MP .. "/bridge/advtrains.lua")
|
||||||
|
dofile(MP .. "/bridge/minecart.lua")
|
||||||
|
|
||||||
|
|
||||||
|
-- mapserver http bridge
|
||||||
|
local has_advtrains = minetest.get_modpath("advtrains")
|
||||||
|
local has_minecart = minetest.get_modpath("minecart")
|
||||||
|
|
||||||
|
|
||||||
|
local http, url, key
|
||||||
|
|
||||||
|
function send_stats()
|
||||||
|
local t0 = minetest.get_us_time()
|
||||||
|
|
||||||
|
-- data to send to mapserver
|
||||||
|
local data = {}
|
||||||
|
|
||||||
|
mapserver.bridge.add_players(data)
|
||||||
|
mapserver.bridge.add_defaults(data)
|
||||||
|
|
||||||
|
if has_minecart then
|
||||||
|
-- send minecarts positions if mod is installed
|
||||||
|
mapserver.bridge.add_minecart(data)
|
||||||
|
end
|
||||||
|
|
||||||
|
if has_advtrains then
|
||||||
|
-- send trains if 'advtrains' mod installed
|
||||||
|
mapserver.bridge.add_advtrains(data)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local json = minetest.write_json(data)
|
||||||
|
--print(json)--XXX
|
||||||
|
|
||||||
|
local t1 = minetest.get_us_time()
|
||||||
|
local process_time = t1 - t0
|
||||||
|
if process_time > 10000 then
|
||||||
|
minetest.log("warning", "[mapserver-bridge] processing took " .. process_time .. " us")
|
||||||
|
end
|
||||||
|
|
||||||
|
http.fetch({
|
||||||
|
url = url .. "/api/minetest",
|
||||||
|
extra_headers = { "Content-Type: application/json", "Authorization: " .. key },
|
||||||
|
timeout = 1,
|
||||||
|
post_data = json
|
||||||
|
}, function(res)
|
||||||
|
|
||||||
|
local t2 = minetest.get_us_time()
|
||||||
|
local post_time = t2 - t1
|
||||||
|
if post_time > 1000000 then -- warn if over a second
|
||||||
|
minetest.log("warning", "[mapserver-bridge] post took " .. post_time .. " us")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO: error-handling
|
||||||
|
minetest.after(2, send_stats)
|
||||||
|
end)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function mapserver.bridge_init(_http, _url, _key)
|
||||||
|
http = _http
|
||||||
|
url = _url
|
||||||
|
key = _key
|
||||||
|
|
||||||
|
minetest.after(2, send_stats)
|
||||||
|
end
|
4
mapserver_mod/mapserver/bridge/minecart.lua
Normal file
4
mapserver_mod/mapserver/bridge/minecart.lua
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
mapserver.bridge.add_minecart = function(data)
|
||||||
|
data.minecarts = minecart.get_cart_list()
|
||||||
|
end
|
23
mapserver_mod/mapserver/bridge/players.lua
Normal file
23
mapserver_mod/mapserver/bridge/players.lua
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
mapserver.bridge.add_players = function(data)
|
||||||
|
|
||||||
|
data.players = {}
|
||||||
|
|
||||||
|
for _, player in ipairs(minetest.get_connected_players()) do
|
||||||
|
|
||||||
|
local is_hidden = minetest.check_player_privs(player:get_player_name(), {mapserver_hide_player = true})
|
||||||
|
|
||||||
|
local info = {
|
||||||
|
name = player:get_player_name(),
|
||||||
|
pos = player:get_pos(),
|
||||||
|
hp = player:get_hp(),
|
||||||
|
breath = player:get_breath(),
|
||||||
|
velocity = player:get_player_velocity()
|
||||||
|
}
|
||||||
|
|
||||||
|
if not is_hidden then
|
||||||
|
table.insert(data.players, info)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
@ -1 +1,3 @@
|
|||||||
default
|
default
|
||||||
|
advtrains?
|
||||||
|
minecart?
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
mapserver = {
|
mapserver = {
|
||||||
enable_crafting = minetest.settings:get("mapserver.enable_crafting")
|
enable_crafting = minetest.settings:get("mapserver.enable_crafting")
|
||||||
|
|
||||||
|
bridge = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
local MP = minetest.get_modpath("mapserver")
|
local MP = minetest.get_modpath("mapserver")
|
||||||
@ -14,13 +16,6 @@ dofile(MP.."/privs.lua")
|
|||||||
|
|
||||||
|
|
||||||
-- optional mapserver-bridge stuff below
|
-- optional mapserver-bridge stuff below
|
||||||
|
|
||||||
--[[ minetest.conf
|
|
||||||
secure.http_mods = mapserver
|
|
||||||
mapserver.url = http://127.0.0.1:8080
|
|
||||||
mapserver.key = myserverkey
|
|
||||||
--]]
|
|
||||||
|
|
||||||
local http = minetest.request_http_api()
|
local http = minetest.request_http_api()
|
||||||
|
|
||||||
if http then
|
if http then
|
||||||
@ -31,7 +26,8 @@ if http then
|
|||||||
if not mapserver_key then error("mapserver.key is not defined") end
|
if not mapserver_key then error("mapserver.key is not defined") end
|
||||||
|
|
||||||
print("[Mapserver] starting mapserver-bridge with endpoint: " .. mapserver_url)
|
print("[Mapserver] starting mapserver-bridge with endpoint: " .. mapserver_url)
|
||||||
dofile(MP .. "/bridge.lua")
|
dofile(MP .. "/bridge/init.lua")
|
||||||
|
|
||||||
mapserver.bridge_init(http, mapserver_url, mapserver_key)
|
mapserver.bridge_init(http, mapserver_url, mapserver_key)
|
||||||
|
|
||||||
else
|
else
|
||||||
|
12
mapserver_mod/mapserver/readme.md
Normal file
12
mapserver_mod/mapserver/readme.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
# mapserver mod
|
||||||
|
|
||||||
|
|
||||||
|
## active mode configuration
|
||||||
|
|
||||||
|
minetest.conf
|
||||||
|
```
|
||||||
|
secure.http_mods = mapserver
|
||||||
|
mapserver.url = http://127.0.0.1:8080
|
||||||
|
mapserver.key = myserverkey
|
||||||
|
```
|
@ -60,6 +60,7 @@ type MapObjectConfig struct {
|
|||||||
Fancyvend bool `json:"fancyvend"`
|
Fancyvend bool `json:"fancyvend"`
|
||||||
ATM bool `json:"atm"`
|
ATM bool `json:"atm"`
|
||||||
Train bool `json:"train"`
|
Train bool `json:"train"`
|
||||||
|
Minecart bool `json:"minecart"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebApiConfig struct {
|
type WebApiConfig struct {
|
||||||
@ -146,6 +147,7 @@ func ParseConfig(filename string) (*Config, error) {
|
|||||||
Fancyvend: true,
|
Fancyvend: true,
|
||||||
ATM: true,
|
ATM: true,
|
||||||
Train: true,
|
Train: true,
|
||||||
|
Minecart: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
mapblockaccessor := MapBlockAccessorConfig{
|
mapblockaccessor := MapBlockAccessorConfig{
|
||||||
|
@ -135,4 +135,11 @@ function Overlaysetup(cfg, map, overlays, wsChannel, layerMgr){
|
|||||||
map.addLayer(overlays.Trains);
|
map.addLayer(overlays.Trains);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cfg.mapobjects.minecart) {
|
||||||
|
overlays.Minecart = new MinecartOverlay(wsChannel, layerMgr);
|
||||||
|
if (cfg.defaultoverlays.indexOf("minecart") >= 0) {
|
||||||
|
map.addLayer(overlays.Minecart);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
124
server/static/js/overlays/MinecartOverlay.js
Normal file
124
server/static/js/overlays/MinecartOverlay.js
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
/* exported MinecartOverlay */
|
||||||
|
/* globals AbstractIconOverlay: true */
|
||||||
|
/* jshint unused: false */
|
||||||
|
|
||||||
|
var MinecartOverlay = L.LayerGroup.extend({
|
||||||
|
initialize: function(wsChannel, layerMgr) {
|
||||||
|
L.LayerGroup.prototype.initialize.call(this);
|
||||||
|
|
||||||
|
this.layerMgr = layerMgr;
|
||||||
|
this.wsChannel = wsChannel;
|
||||||
|
|
||||||
|
this.currentObjects = {}; // name => marker
|
||||||
|
this.trains = [];
|
||||||
|
|
||||||
|
this.reDraw = this.reDraw.bind(this);
|
||||||
|
this.onMinetestUpdate = this.onMinetestUpdate.bind(this);
|
||||||
|
|
||||||
|
//update players all the time
|
||||||
|
this.wsChannel.addListener("minetest-info", function(info){
|
||||||
|
this.minecarts = info.minecarts || [];
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
createMarker: function(cart){
|
||||||
|
|
||||||
|
var Icon = L.icon({
|
||||||
|
iconUrl: "pics/minecart_logo.png",
|
||||||
|
|
||||||
|
iconSize: [32, 32],
|
||||||
|
iconAnchor: [16, 16],
|
||||||
|
popupAnchor: [0, -32]
|
||||||
|
});
|
||||||
|
|
||||||
|
var marker = L.marker([cart.pos.z, cart.pos.x], {icon: Icon});
|
||||||
|
var html = "<b>Minecart</b><hr>";
|
||||||
|
|
||||||
|
marker.bindPopup(html);
|
||||||
|
|
||||||
|
return marker;
|
||||||
|
},
|
||||||
|
|
||||||
|
isCartInCurrentLayer: function(cart){
|
||||||
|
var mapLayer = this.layerMgr.getCurrentLayer();
|
||||||
|
|
||||||
|
return (cart.pos.y >= (mapLayer.from*16) && cart.pos.y <= (mapLayer.to*16));
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
onMinetestUpdate: function(info){
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.minecarts.forEach(function(cart){
|
||||||
|
var isInLayer = self.isCartInCurrentLayer(cart);
|
||||||
|
|
||||||
|
if (!isInLayer){
|
||||||
|
if (self.currentObjects[train.id]){
|
||||||
|
//train is displayed and not on the layer anymore
|
||||||
|
//Remove the marker and reference
|
||||||
|
self.currentObjects[train.id].remove();
|
||||||
|
delete self.currentObjects[train.id];
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.currentObjects[train.id]){
|
||||||
|
//marker exists
|
||||||
|
self.currentObjects[train.id].setLatLng([train.pos.z, train.pos.x]);
|
||||||
|
//setPopupContent
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//marker does not exist
|
||||||
|
var marker = self.createMarker(train);
|
||||||
|
marker.addTo(self);
|
||||||
|
|
||||||
|
self.currentObjects[train.id] = marker;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.keys(self.currentObjects).forEach(function(existingId){
|
||||||
|
var trainIsActive = self.trains.find(function(t){
|
||||||
|
return t.id == existingId;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!trainIsActive){
|
||||||
|
//train
|
||||||
|
self.currentObjects[existingId].remove();
|
||||||
|
delete self.currentObjects[existingId];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
reDraw: function(){
|
||||||
|
var self = this;
|
||||||
|
this.currentObjects = {};
|
||||||
|
this.clearLayers();
|
||||||
|
|
||||||
|
var mapLayer = this.layerMgr.getCurrentLayer();
|
||||||
|
|
||||||
|
this.trains.forEach(function(train){
|
||||||
|
if (!self.isTrainInCurrentLayer(train)){
|
||||||
|
//not in current layer
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var marker = self.createMarker(train);
|
||||||
|
marker.addTo(self);
|
||||||
|
self.currentObjects[train.id] = marker;
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
onAdd: function(map) {
|
||||||
|
this.layerMgr.addListener(this.reDraw);
|
||||||
|
this.wsChannel.addListener("minetest-info", this.onMinetestUpdate);
|
||||||
|
this.reDraw();
|
||||||
|
},
|
||||||
|
|
||||||
|
onRemove: function(map) {
|
||||||
|
this.clearLayers();
|
||||||
|
this.layerMgr.removeListener(this.reDraw);
|
||||||
|
this.wsChannel.removeListener("minetest-info", this.onMinetestUpdate);
|
||||||
|
}
|
||||||
|
});
|
@ -25,6 +25,7 @@
|
|||||||
"/js/overlays/LabelOverlay.js",
|
"/js/overlays/LabelOverlay.js",
|
||||||
"/js/overlays/PlayerOverlay.js",
|
"/js/overlays/PlayerOverlay.js",
|
||||||
"/js/overlays/TrainOverlay.js",
|
"/js/overlays/TrainOverlay.js",
|
||||||
|
"/js/overlays/MinecartOverlay.js",
|
||||||
"/js/overlays/TrainlineOverlay.js",
|
"/js/overlays/TrainlineOverlay.js",
|
||||||
"/js/overlays/BorderOverlay.js",
|
"/js/overlays/BorderOverlay.js",
|
||||||
"/js/overlays/ProtectorOverlay.js",
|
"/js/overlays/ProtectorOverlay.js",
|
||||||
|
BIN
server/static/pics/minecart_logo.png
Normal file
BIN
server/static/pics/minecart_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 263 B |
@ -31,6 +31,11 @@ type Train struct {
|
|||||||
TextInside string `json:"text_inside"`
|
TextInside string `json:"text_inside"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Minecart struct {
|
||||||
|
Pos GenericPos `json:"pos"`
|
||||||
|
Speed GenericPos `json:"speed"`
|
||||||
|
}
|
||||||
|
|
||||||
type Player struct {
|
type Player struct {
|
||||||
Pos GenericPos `json:"pos"`
|
Pos GenericPos `json:"pos"`
|
||||||
Velocity GenericPos `json:"velocity"`
|
Velocity GenericPos `json:"velocity"`
|
||||||
@ -44,6 +49,7 @@ type MinetestInfo struct {
|
|||||||
MaxLag float64 `json:"max_lag"`
|
MaxLag float64 `json:"max_lag"`
|
||||||
Players []*Player `json:"players"`
|
Players []*Player `json:"players"`
|
||||||
Trains []*Train `json:"trains"`
|
Trains []*Train `json:"trains"`
|
||||||
|
Minecarts []*Minecart `json:"minecarts"`
|
||||||
Time float64 `json:"time"`
|
Time float64 `json:"time"`
|
||||||
Uptime float64 `json:"uptime"`
|
Uptime float64 `json:"uptime"`
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user