Compare commits
53 Commits
9ddaa099cb
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b43439eab0 | ||
|
|
f1430cd49b | ||
|
|
96a1b49693 | ||
|
|
de35cfdc13 | ||
|
|
d386c771f0 | ||
|
|
30515c4328 | ||
|
|
af2ef29585 | ||
|
|
cc35dec294 | ||
|
|
92065a7fa7 | ||
|
|
1d55095691 | ||
|
|
f1d98376d4 | ||
|
|
4886f78357 | ||
|
|
39301255a8 | ||
|
|
f966ee4abc | ||
|
|
8fe6fa4884 | ||
|
|
4eb1009afe | ||
|
|
364d155f9d | ||
|
|
dd0490ee13 | ||
|
|
40dd6ea865 | ||
|
|
785504ab6c | ||
|
|
5f3cad8884 | ||
|
|
940fed4bdf | ||
|
|
b90858b5cb | ||
|
|
f05503b871 | ||
|
|
ee708e9127 | ||
|
|
0f23259e04 | ||
|
|
a4a776d2fb | ||
|
|
ab931a5717 | ||
|
|
7824ca8c33 | ||
|
|
125ecfd437 | ||
|
|
457d20bd44 | ||
|
|
43a2a40207 | ||
|
|
db3d21a1fe | ||
|
|
21416bdc66 | ||
|
|
e1aa97aa71 | ||
|
|
3ae36aa759 | ||
|
|
3c852bcbd5 | ||
|
|
defb39b5cc | ||
|
|
5a6d0cd052 | ||
|
|
866833df65 | ||
|
|
05c472a3de | ||
|
|
fc233deb7e | ||
|
|
d94c1f4e3d | ||
|
|
cf0a2aa3b4 | ||
|
|
91111b220b | ||
|
|
add16e6c89 | ||
|
|
405e92bb5f | ||
|
|
b736a0b65c | ||
|
|
b015543cc5 | ||
|
|
b5cee96d7a | ||
|
|
408fec350b | ||
|
|
edb8d352d4 | ||
|
|
34e8a46888 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -121,3 +121,6 @@ venv.bak/
|
|||||||
pip-selfcheck.json
|
pip-selfcheck.json
|
||||||
|
|
||||||
# End of https://www.gitignore.io/api/python,virtualenv
|
# End of https://www.gitignore.io/api/python,virtualenv
|
||||||
|
|
||||||
|
tehmodel.json
|
||||||
|
backups
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"bar": "foo", "foo": 3, "test": 4, "kso72uuzubg22om7": {}}
|
|
||||||
44
index.html
44
index.html
@@ -4,38 +4,24 @@
|
|||||||
<head>
|
<head>
|
||||||
<title>leafblade Minecraft Server</title>
|
<title>leafblade Minecraft Server</title>
|
||||||
|
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8"/>
|
||||||
|
|
||||||
<style type="text/css">
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
#map {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
@media (max-width:768px) {
|
|
||||||
#overlay { width: 100% }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="container"></div>
|
this is the base site
|
||||||
this is the base site
|
|
||||||
</div>
|
<br>
|
||||||
|
|
||||||
|
<input id="username" type="text" placeholder="Joe"/>
|
||||||
|
<button id="btn_register">idk</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById("btn_register").onclick = function (e) {
|
||||||
|
let username = document.getElementById("username");
|
||||||
|
|
||||||
|
window.location.replace(`register/${encodeURIComponent(username.value || username.placeholder)}`)
|
||||||
|
};
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
53
main.py
53
main.py
@@ -1,6 +1,10 @@
|
|||||||
import aiohttp.web
|
import aiohttp.web
|
||||||
|
import traceback
|
||||||
|
import urllib.parse
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
|
||||||
from .model import Model
|
from model import Model
|
||||||
|
|
||||||
routes = aiohttp.web.RouteTableDef()
|
routes = aiohttp.web.RouteTableDef()
|
||||||
|
|
||||||
@@ -15,7 +19,12 @@ def get_client(request: aiohttp.web.Request):
|
|||||||
client = request.match_info.get("client", None)
|
client = request.match_info.get("client", None)
|
||||||
model = request.app['model']
|
model = request.app['model']
|
||||||
|
|
||||||
if not client or not model.exists_client(client):
|
if not client:
|
||||||
|
print('[get_client] client is not set, wtf')
|
||||||
|
raise aiohttp.web.HTTPBadRequest()
|
||||||
|
|
||||||
|
if not model.exists_client(client):
|
||||||
|
print(f'[get_client] model does not know {client=}')
|
||||||
raise aiohttp.web.HTTPBadRequest()
|
raise aiohttp.web.HTTPBadRequest()
|
||||||
|
|
||||||
return client
|
return client
|
||||||
@@ -25,7 +34,7 @@ def get_client(request: aiohttp.web.Request):
|
|||||||
async def handler(request: aiohttp.web.Request):
|
async def handler(request: aiohttp.web.Request):
|
||||||
# this handler prevents people missing trailing slashes
|
# this handler prevents people missing trailing slashes
|
||||||
client = get_client(request)
|
client = get_client(request)
|
||||||
raise aiohttp.web.HTTPFound(f"/{client}/")
|
raise aiohttp.web.HTTPFound(f"{client}/")
|
||||||
|
|
||||||
|
|
||||||
@routes.get(CLIENT_REGEX + '/')
|
@routes.get(CLIENT_REGEX + '/')
|
||||||
@@ -35,22 +44,26 @@ async def handler(request: aiohttp.web.Request):
|
|||||||
return aiohttp.web.FileResponse('ui.html')
|
return aiohttp.web.FileResponse('ui.html')
|
||||||
|
|
||||||
|
|
||||||
@routes.post(CLIENT_REGEX + '/api')
|
@routes.post(CLIENT_REGEX + '/api/{method}')
|
||||||
async def handler(request: aiohttp.web.Request):
|
async def handler(request: aiohttp.web.Request):
|
||||||
client = get_client(request)
|
client = get_client(request)
|
||||||
|
method = request.match_info.get('method', None)
|
||||||
model = request.app['model']
|
model = request.app['model']
|
||||||
|
|
||||||
data = await request.json()
|
data = await request.json()
|
||||||
|
|
||||||
print(f'{client=} {data=}')
|
print(f'{method=} {client=} {data=}')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
assert await model.handle_post(data, client)
|
assert method in model.ApiMethod.dict
|
||||||
|
await model.ApiMethod.dict[method](model, client, **data)
|
||||||
return aiohttp.web.Response(status=200)
|
return aiohttp.web.Response(status=200)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
del e # unused?
|
||||||
|
traceback.print_exc()
|
||||||
return aiohttp.web.Response(status=400)
|
return aiohttp.web.Response(status=400)
|
||||||
|
finally:
|
||||||
|
await model.send_state(client)
|
||||||
|
|
||||||
@routes.get(CLIENT_REGEX + '/ws')
|
@routes.get(CLIENT_REGEX + '/ws')
|
||||||
async def _(request: aiohttp.web.Request):
|
async def _(request: aiohttp.web.Request):
|
||||||
@@ -61,7 +74,7 @@ async def _(request: aiohttp.web.Request):
|
|||||||
await ws.prepare(request)
|
await ws.prepare(request)
|
||||||
|
|
||||||
print(f'[WS] client {client} connected, {ws=}')
|
print(f'[WS] client {client} connected, {ws=}')
|
||||||
model.subscribe(client, ws)
|
await model.subscribe(client, ws)
|
||||||
|
|
||||||
async for msg in ws:
|
async for msg in ws:
|
||||||
print(f'[WS] incoming message from client {client}, {ws=}, {msg=}')
|
print(f'[WS] incoming message from client {client}, {ws=}, {msg=}')
|
||||||
@@ -76,7 +89,7 @@ async def _(request: aiohttp.web.Request):
|
|||||||
async def handler(request: aiohttp.web.Request):
|
async def handler(request: aiohttp.web.Request):
|
||||||
model = request.app['model']
|
model = request.app['model']
|
||||||
|
|
||||||
return aiohttp.web.json_response(model.sessions)
|
return aiohttp.web.json_response(model.model)
|
||||||
|
|
||||||
|
|
||||||
@routes.get('/')
|
@routes.get('/')
|
||||||
@@ -86,11 +99,27 @@ async def handler(request):
|
|||||||
return aiohttp.web.FileResponse('index.html')
|
return aiohttp.web.FileResponse('index.html')
|
||||||
|
|
||||||
|
|
||||||
|
@routes.get('/register/{username:.+}')
|
||||||
|
async def handler(request):
|
||||||
|
model = request.app['model']
|
||||||
|
username = request.match_info.get('username', 'Joe')
|
||||||
|
username = urllib.parse.unquote(username)
|
||||||
|
|
||||||
|
client = model.create_client(username)
|
||||||
|
raise aiohttp.web.HTTPFound(f"/{client}/")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app = aiohttp.web.Application()
|
app = aiohttp.web.Application()
|
||||||
app.add_routes(routes)
|
app.add_routes(routes)
|
||||||
|
|
||||||
app['model'] = Model()
|
data = {}
|
||||||
|
filename = "tehsession.json"
|
||||||
|
if os.path.isfile(filename):
|
||||||
|
with open(filename) as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
app['model'] = Model(model = data)
|
||||||
|
|
||||||
aiohttp.web.run_app(app, port=42042)
|
aiohttp.web.run_app(app, port=42042)
|
||||||
print("should save state")
|
app['model'].save()
|
||||||
|
|||||||
387
model.py
387
model.py
@@ -5,63 +5,350 @@ import os
|
|||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
class Model:
|
def generate_random_id(_s=set()):
|
||||||
def __init__(self, filename = "tehmodel.json"):
|
while (new_id := base64.b32encode(bytearray(random.randint(0, 0xFF) for _ in range(10)))[:16].decode().lower()) in _s:
|
||||||
self.sockets = {}
|
pass
|
||||||
self.filename = filename
|
_s.add(new_id)
|
||||||
self.sessions = None
|
return new_id
|
||||||
if os.path.isfile(filename):
|
|
||||||
with open(filename) as f:
|
|
||||||
try:
|
class Model(object):
|
||||||
self.sessions = json.load(f)
|
class ApiMethod:
|
||||||
except:
|
dict = dict()
|
||||||
self.sessions = {}
|
|
||||||
|
def __init__(self, fun):
|
||||||
|
self.dict[fun.__name__] = fun
|
||||||
|
|
||||||
|
def __contains__(self, item):
|
||||||
|
return item in self.dict
|
||||||
|
|
||||||
|
def __init__(self, model = {}):
|
||||||
|
if "sessions" not in model:
|
||||||
|
model["sessions"] = []
|
||||||
|
if "clients" not in model:
|
||||||
|
model["clients"] = []
|
||||||
|
if "items" not in model:
|
||||||
|
model["items"] = []
|
||||||
|
self.sockets = {} # mapping: clientid -> sockets
|
||||||
|
self.sessions = { session: Session(model = model["sessions"][session]) for session in model["sessions"] }
|
||||||
|
self.clients = { client: Client(model = model["clients"][client]) for client in model["clients"] }
|
||||||
|
self.items = { item: Item(model = model["items"][item]) for item in model["items"] }
|
||||||
|
self.filename = "tehsession.json"
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
model = {
|
||||||
|
"sessions": {session: self.sessions[session].to_json() for session in self.sessions },
|
||||||
|
"clients": {client: self.clients[client].to_json() for client in self.clients },
|
||||||
|
"items": {item: self.items[item].to_json() for item in self.items },
|
||||||
|
}
|
||||||
|
return model
|
||||||
|
|
||||||
|
@ApiMethod
|
||||||
|
async def test_api(self, clientid):
|
||||||
|
print(f'test_api {clientid=}')
|
||||||
|
|
||||||
|
@ApiMethod
|
||||||
|
async def test_yeet(self, clientid):
|
||||||
|
raise Exception('yeet')
|
||||||
|
|
||||||
|
@ApiMethod
|
||||||
|
async def change_username(self, clientid, username) -> str:
|
||||||
|
self.clients[clientid].name = username
|
||||||
|
|
||||||
|
@ApiMethod
|
||||||
|
async def create_session(self, clientid, sessionname) -> str:
|
||||||
|
if not sessionname:
|
||||||
|
raise Exception(f"Sessionname cant be empty!")
|
||||||
|
session = Session(name = sessionname, owner = clientid)
|
||||||
|
self.sessions[session.id] = session
|
||||||
|
print("create_session was called")
|
||||||
|
|
||||||
|
@ApiMethod
|
||||||
|
async def change_sessionname(self, clientid, sessionid, sessionname) -> str:
|
||||||
|
if not sessionname:
|
||||||
|
raise Exception("Cant be empty!")
|
||||||
|
session = self.sessions[sessionid]
|
||||||
|
if not (session.owner == clientid):
|
||||||
|
raise Exception("Ownly owner can change sessionname")
|
||||||
|
session.name = sessionname
|
||||||
|
|
||||||
|
@ApiMethod
|
||||||
|
async def create_item(self, clientid, name, description, image):
|
||||||
|
client = self.clients[clientid]
|
||||||
|
if not client.session:
|
||||||
|
raise Exception("create_item requires the client to be host. But client is in no session")
|
||||||
|
session = self.sessions[client.session]
|
||||||
|
if (session.owner != client.id):
|
||||||
|
raise Exception("create_item requires the client to be host. But client is not the owner")
|
||||||
|
if not name:
|
||||||
|
raise Exception("create_item requires an item name")
|
||||||
|
item = Item(name = name, description = description, image = image)
|
||||||
|
self.items[item.id] = item
|
||||||
|
|
||||||
|
|
||||||
|
@ApiMethod
|
||||||
|
async def leave_session(self, clientid):
|
||||||
|
client = self.clients[clientid]
|
||||||
|
sessionid = client.session
|
||||||
|
if sessionid:
|
||||||
|
session = self.sessions[sessionid]
|
||||||
|
session.clients.remove(clientid)
|
||||||
|
self.clients[clientid].session = ""
|
||||||
|
|
||||||
|
@ApiMethod
|
||||||
|
async def join_session(self, clientid, sessionid):
|
||||||
|
client = self.clients[clientid]
|
||||||
|
old_sessionid = client.session
|
||||||
|
# leave old session
|
||||||
|
if old_sessionid:
|
||||||
|
old_session = self.sessions[old_sessionid]
|
||||||
|
old_session.clients.remove(clientid)
|
||||||
|
session = self.sessions[sessionid]
|
||||||
|
client.session = sessionid
|
||||||
|
session.clients.append(client.id)
|
||||||
|
|
||||||
|
|
||||||
|
@ApiMethod
|
||||||
|
async def move_item(self, clientid, fromplayer, toplayer, itemid, toslot, fromslot):
|
||||||
|
client = self.clients[clientid]
|
||||||
|
fromclient = next((client for client in self.clients.values() if client.name == fromplayer), None)
|
||||||
|
toclient = next((client for client in self.clients.values() if client.name == toplayer), None)
|
||||||
|
if fromplayer == "master":
|
||||||
|
# create item
|
||||||
|
if not toclient:
|
||||||
|
raise Exception("to-client is illegal")
|
||||||
|
session = self.sessions[client.session]
|
||||||
|
if not session:
|
||||||
|
raise Exception("move item must be used in session")
|
||||||
|
if client.id != session.owner:
|
||||||
|
raise Exception("Only owner can move items")
|
||||||
|
toslot -= 1
|
||||||
|
if toslot > len(session.inventories[toclient.id]):
|
||||||
|
raise Exception("Index out of toplayers range")
|
||||||
|
session.inventories[toclient.id].insert(toslot, itemid)
|
||||||
|
elif toplayer == "master":
|
||||||
|
if not fromclient:
|
||||||
|
raise Exception("from-client is illegal")
|
||||||
|
session = self.sessions[client.session]
|
||||||
|
if not session:
|
||||||
|
raise Exception("move item must be used in session")
|
||||||
|
if client.id != session.owner:
|
||||||
|
raise Exception("Only owner can move items")
|
||||||
|
if itemid not in session.inventories[fromclient.id]:
|
||||||
|
raise Exception("he does not have that item")
|
||||||
|
fromslot -= 1
|
||||||
|
if fromslot > len(session.inventories[fromclient.id]):
|
||||||
|
raise Exception("Index out of fromplayer range")
|
||||||
|
session.inventories[fromclient.id].pop(fromslot)
|
||||||
else:
|
else:
|
||||||
self.sessions = {}
|
if not fromclient and not toclient:
|
||||||
|
raise Exception("from- or to-client are illegal")
|
||||||
def handle_post(self, data):
|
session = self.sessions[client.session]
|
||||||
print("I have received P O S T data: " + str(data))
|
if not session:
|
||||||
print("let me tell everyone")
|
raise Exception("move item must be used in session")
|
||||||
for k, v in self.sockets.items():
|
if client.id != session.owner:
|
||||||
v.send_json({"message": "nudes"})
|
raise Exception("Only owner can move items")
|
||||||
|
if itemid not in session.inventories[fromclient.id]:
|
||||||
|
raise Exception("he does not have that item")
|
||||||
|
toslot -= 1
|
||||||
|
if toslot > len(session.inventories[toclient.id]):
|
||||||
|
raise Exception("Index out of toplayers range")
|
||||||
|
fromslot -= 1
|
||||||
|
if fromslot > len(session.inventories[fromclient.id]):
|
||||||
|
raise Exception("Index out of fromplayer range")
|
||||||
|
session.inventories[fromclient.id].pop(fromslot)
|
||||||
|
session.inventories[toclient.id].insert(toslot, itemid)
|
||||||
|
|
||||||
# handle post request data
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __exit__(self, exception_type, exception_value, traceback):
|
@ApiMethod
|
||||||
if not (exception_type or exception_value or traceback):
|
async def draw(self, clientid):
|
||||||
with open(self.filename, "w") as f:
|
await self.send_state(clientid)
|
||||||
json.dump(self.sessions, f)
|
|
||||||
if not os.path.isdir("backups"):
|
async def send_lobby_view(self, clientid):
|
||||||
try:
|
data = {}
|
||||||
os.mkdir("backups")
|
client = self.clients[clientid]
|
||||||
except FileExistsError:
|
|
||||||
print("backups is a file, no directory. Please delete yourself")
|
data["view"] = "lobby"
|
||||||
datestring = datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%d-%H%M%S")
|
data["username"] = client.name
|
||||||
with open(f"backups/{datestring}_{self.filename}", "w") as f:
|
data["sessions"] = {
|
||||||
json.dump(self.sessions, f)
|
session.id: {
|
||||||
|
"id": session.id,
|
||||||
|
"name": session.name,
|
||||||
|
"owned": session.owner == client.id,
|
||||||
|
} for session in self.sessions.values()
|
||||||
|
}
|
||||||
|
for socket in self.sockets[clientid]:
|
||||||
|
await socket.send_json(data)
|
||||||
|
|
||||||
|
async def send_master_view(self, clientid):
|
||||||
|
data = {}
|
||||||
|
client = self.clients[clientid]
|
||||||
|
session = self.sessions[client.session]
|
||||||
|
|
||||||
|
data["view"] = "master"
|
||||||
|
data["username"] = client.name
|
||||||
|
data["session"] = session.to_json()
|
||||||
|
data["items"] = self.to_json()["items"]
|
||||||
|
data["inventories"] = {}
|
||||||
|
for _client in session.inventories:
|
||||||
|
_client = self.clients[_client]
|
||||||
|
inventory = session.get_items(_client.id)
|
||||||
|
inventory = list(map(lambda itemid: self.to_json()["items"][itemid], inventory))
|
||||||
|
data["inventories"][_client.name] = inventory
|
||||||
|
|
||||||
|
for socket in self.sockets[clientid]:
|
||||||
|
await socket.send_json(data)
|
||||||
|
|
||||||
|
|
||||||
|
async def send_session_view(self, clientid):
|
||||||
|
data = {}
|
||||||
|
client = self.clients[clientid]
|
||||||
|
session = self.sessions[client.session]
|
||||||
|
|
||||||
|
data["view"] = "session"
|
||||||
|
data["username"] = client.name
|
||||||
|
data["session"] = session.name
|
||||||
|
data["inventories"] = {}
|
||||||
|
for _client in session.inventories:
|
||||||
|
_client = self.clients[_client]
|
||||||
|
inventory = session.get_items(_client.id)
|
||||||
|
inventory = list(map(lambda itemid: self.to_json()["items"][itemid], inventory))
|
||||||
|
data["inventories"][_client.name] = inventory
|
||||||
|
|
||||||
|
for socket in self.sockets[clientid]:
|
||||||
|
await socket.send_json(data)
|
||||||
|
|
||||||
|
async def send_state(self, clientid):
|
||||||
|
# TODO: compute state, send to client
|
||||||
|
data = {}
|
||||||
|
client = self.clients[clientid]
|
||||||
|
session = self.sessions[client.session] if client.session else None
|
||||||
|
if session:
|
||||||
|
if session.owner == client.id:
|
||||||
|
await self.send_master_view(clientid)
|
||||||
|
else:
|
||||||
|
await self.send_session_view(clientid)
|
||||||
|
else:
|
||||||
|
await self.send_lobby_view(clientid)
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
with open(self.filename, "w") as f:
|
||||||
|
json.dump(self.to_json(), f)
|
||||||
|
|
||||||
def exists_client(self, clientid: str) -> bool:
|
def exists_client(self, clientid: str) -> bool:
|
||||||
return clientid in self.sockets
|
return clientid in self.clients
|
||||||
|
|
||||||
def create_client(self, sessionid: str) -> str:
|
def create_client(self, name="Joe") -> str:
|
||||||
clientname = base64.b32encode(bytearray(random.randint(0, 0xFF) for _ in range(10)))[:16].decode().lower()
|
if not name:
|
||||||
self.sessions[sessionname]["players"].append(clientname)
|
raise Exception("Username cannot be empty!")
|
||||||
return sessionname
|
client = Client()
|
||||||
|
client.name = name
|
||||||
|
self.clients[client.id] = client
|
||||||
|
return client.id
|
||||||
|
|
||||||
def create_session(self) -> str:
|
async def subscribe(self, clientid, socket):
|
||||||
sessionname = base64.b32encode(bytearray(random.randint(0, 0xFF) for _ in range(10)))[:16].decode().lower()
|
if not clientid in self.sockets:
|
||||||
self.sessions[sessionname] = {"players": []}
|
self.sockets[clientid] = []
|
||||||
return sessionname
|
self.sockets[clientid].append(socket)
|
||||||
|
await self.send_state(clientid)
|
||||||
|
|
||||||
def subscribe(self, clientid, socket):
|
|
||||||
self.sockets[clientid] = socket
|
|
||||||
# todo subscribe socket, match with id
|
|
||||||
|
|
||||||
|
|
||||||
def unsubscribe(self, socket):
|
def unsubscribe(self, socket):
|
||||||
for k,v in self.sockets.items():
|
for client in self.sockets:
|
||||||
if v == socket:
|
if socket in self.sockets[client]:
|
||||||
self.sockets.pop(k)
|
self.sockets[client].remove(socket)
|
||||||
|
|
||||||
|
class Session:
|
||||||
|
|
||||||
|
def __init__(self, model = None, owner = None, name = None):
|
||||||
|
if model:
|
||||||
|
self.id = model["id"]
|
||||||
|
self.name = model["name"]
|
||||||
|
self.clients = model["clients"]
|
||||||
|
self.owner = model["owner"]
|
||||||
|
if "inventories" in model:
|
||||||
|
self.inventories = model["inventories"]
|
||||||
|
else:
|
||||||
|
self.inventories = {}
|
||||||
|
elif owner and name:
|
||||||
|
self.id = generate_random_id()
|
||||||
|
self.clients = []
|
||||||
|
self.owner = owner
|
||||||
|
self.name = name
|
||||||
|
self.inventories = {}
|
||||||
|
else:
|
||||||
|
raise Exception("Illegal session constructor")
|
||||||
|
|
||||||
|
def get_items(self, playerid):
|
||||||
|
if playerid in self.inventories:
|
||||||
|
return self.inventories[playerid]
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
def give_item(self, playerid, itemid):
|
||||||
|
if not playerid in self.inventories:
|
||||||
|
self.inventories[playerid] = []
|
||||||
|
self.inventories[playerid].append(itemid)
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
model = {
|
||||||
|
"id": self.id,
|
||||||
|
"name": self.name,
|
||||||
|
"clients": self.clients,
|
||||||
|
"owner": self.owner,
|
||||||
|
"inventories": self.inventories
|
||||||
|
}
|
||||||
|
return model
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Client:
|
||||||
|
|
||||||
|
def __init__(self, model = None):
|
||||||
|
if model:
|
||||||
|
self.id = model["id"]
|
||||||
|
self.name = model["name"]
|
||||||
|
self.session = model["session"]
|
||||||
|
else:
|
||||||
|
self.id = generate_random_id()
|
||||||
|
self.name = "Default Client Name"
|
||||||
|
self.session = ""
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
model = {
|
||||||
|
"id": self.id,
|
||||||
|
"name": self.name,
|
||||||
|
"session": self.session,
|
||||||
|
}
|
||||||
|
return model
|
||||||
|
|
||||||
|
class Item:
|
||||||
|
|
||||||
|
def __init__(self, model = None, name = None, description = "", image = "", tags = {}):
|
||||||
|
if model:
|
||||||
|
self.id = model["id"]
|
||||||
|
self.name = model["name"]
|
||||||
|
self.description = model["description"]
|
||||||
|
self.image = model["image"]
|
||||||
|
if "tags" in model:
|
||||||
|
self.tags = model["tags"]
|
||||||
|
else:
|
||||||
|
self.tags = {}
|
||||||
|
elif name:
|
||||||
|
self.id = generate_random_id()
|
||||||
|
self.name = name
|
||||||
|
self.description = description
|
||||||
|
self.image = image
|
||||||
|
self.tags = tags
|
||||||
|
else:
|
||||||
|
raise Exception("Illegal Item Constructor")
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
model = {
|
||||||
|
"id": self.id,
|
||||||
|
"name": self.name,
|
||||||
|
"description": self.description,
|
||||||
|
"image": self.image,
|
||||||
|
"tags": self.tags,
|
||||||
|
}
|
||||||
|
return model
|
||||||
|
|||||||
@@ -2,8 +2,33 @@ const ws_url = new URL('ws', window.location.href);
|
|||||||
ws_url.protocol = ws_url.protocol.replace('http', 'ws');
|
ws_url.protocol = ws_url.protocol.replace('http', 'ws');
|
||||||
const ws = new WebSocket(ws_url.href);
|
const ws = new WebSocket(ws_url.href);
|
||||||
|
|
||||||
ws.onmessage = function(event) {
|
ws.onmessage = async function(event) {
|
||||||
const msg = JSON.parse(event.data);
|
const msg = JSON.parse(event.data);
|
||||||
|
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
};
|
|
||||||
|
if (msg.hasOwnProperty('view')) {
|
||||||
|
view = msg.view;
|
||||||
|
console.log(view)
|
||||||
|
|
||||||
|
contentdiv = document.getElementById("content")
|
||||||
|
|
||||||
|
response = await fetch('../static/views/' + view + '/template.html')
|
||||||
|
contentdiv.innerHTML = await response.text();
|
||||||
|
console.log('../static/views/' + view + '/template.html'+":")
|
||||||
|
console.log(contentdiv.innerHTML)
|
||||||
|
|
||||||
|
var tehscript = document.createElement('script');
|
||||||
|
tehscript.type = 'text/javascript';
|
||||||
|
tehscript.src = '../static/views/' + view + '/script.js';
|
||||||
|
|
||||||
|
var tehmsg = document.createElement('text');
|
||||||
|
tehmsg.style.display = "none"
|
||||||
|
tehmsg.id = "msg"
|
||||||
|
tehmsg.innerText = JSON.stringify(msg);
|
||||||
|
|
||||||
|
contentdiv.appendChild(tehmsg);
|
||||||
|
contentdiv.appendChild(tehscript);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|||||||
143
static/views/lobby/script.js
Normal file
143
static/views/lobby/script.js
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
var text = document.getElementById("msg").innerText
|
||||||
|
msg = JSON.parse(text)
|
||||||
|
|
||||||
|
if (msg.hasOwnProperty('username')) {
|
||||||
|
document.getElementById('label-username').innerText = msg.username;
|
||||||
|
}
|
||||||
|
|
||||||
|
// username management
|
||||||
|
document.getElementById("btn-edit-username").onclick = async function (e) {
|
||||||
|
document.getElementById("btn-confirm-username").style.display = "inline-block";
|
||||||
|
document.getElementById("btn-discard-username").style.display = "inline-block";
|
||||||
|
document.getElementById("btn-edit-username").style.display = "none";
|
||||||
|
document.getElementById("label-username").style.display = "none";
|
||||||
|
document.getElementById("input-set-username").style.display = "inline-block";
|
||||||
|
document.getElementById("input-set-username").value = document.getElementById("label-username").innerText;
|
||||||
|
}
|
||||||
|
document.getElementById("btn-discard-username").onclick = async function (e) {
|
||||||
|
document.getElementById("btn-confirm-username").style.display = "none";
|
||||||
|
document.getElementById("btn-discard-username").style.display = "none";
|
||||||
|
document.getElementById("btn-edit-username").style.display = "inline-block";
|
||||||
|
document.getElementById("label-username").style.display = "inline-block";
|
||||||
|
document.getElementById("input-set-username").style.display = "none";
|
||||||
|
}
|
||||||
|
document.getElementById("btn-confirm-username").onclick = async function (e) {
|
||||||
|
var text = document.getElementById("input-set-username").value;
|
||||||
|
if (Boolean(text)) {
|
||||||
|
let data = {"username": text};
|
||||||
|
|
||||||
|
await fetch('api/change_username', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
})
|
||||||
|
document.getElementById("btn-confirm-username").style.display = "none";
|
||||||
|
document.getElementById("btn-discard-username").style.display = "none";
|
||||||
|
document.getElementById("btn-edit-username").style.display = "inline-block";
|
||||||
|
document.getElementById("label-username").style.display = "inline-block";
|
||||||
|
document.getElementById("input-set-username").style.display = "none";
|
||||||
|
} else {
|
||||||
|
console.log("cant be empty");
|
||||||
|
document.getElementById("btn-confirm-username").style.display = "none";
|
||||||
|
document.getElementById("btn-discard-username").style.display = "none";
|
||||||
|
document.getElementById("btn-edit-username").style.display = "inline-block";
|
||||||
|
document.getElementById("label-username").style.display = "inline-block";
|
||||||
|
document.getElementById("input-set-username").style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById("btn-create-session").onclick = async function (e) {
|
||||||
|
var text = document.getElementById("input-create-session").value;
|
||||||
|
if (Boolean(text)) {
|
||||||
|
let data = {"sessionname": text};
|
||||||
|
|
||||||
|
await fetch('api/create_session', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (msg.hasOwnProperty('sessions')) {
|
||||||
|
const sessions = document.getElementById('sessions');
|
||||||
|
|
||||||
|
while (sessions.children.length) sessions.lastChild.remove();
|
||||||
|
|
||||||
|
Object.keys(msg.sessions).forEach( session => {
|
||||||
|
session = msg.sessions[session];
|
||||||
|
var sessionid = session["id"];
|
||||||
|
var sessionname = session["name"];
|
||||||
|
var owned = session["owned"];
|
||||||
|
|
||||||
|
const tehsession = document.createElement('div');
|
||||||
|
const labelname = document.createElement('span');
|
||||||
|
labelname.innerText = sessionname;
|
||||||
|
|
||||||
|
tehsession.appendChild(labelname);
|
||||||
|
|
||||||
|
if (owned) {
|
||||||
|
const inputname = document.createElement('input');
|
||||||
|
inputname.style.display = "none";
|
||||||
|
const btnedit = document.createElement('button');
|
||||||
|
btnedit.innerText = '🖉'
|
||||||
|
const btnconfirm = document.createElement('button');
|
||||||
|
btnconfirm.innerText = '✔'
|
||||||
|
btnconfirm.style.display = "none"
|
||||||
|
const btndiscard = document.createElement('button');
|
||||||
|
btndiscard.innerText = '✘'
|
||||||
|
btndiscard.style.display = "none"
|
||||||
|
|
||||||
|
btnedit.onclick = async function (e) {
|
||||||
|
inputname.style.display = "inline-block";
|
||||||
|
inputname.value = sessionname;
|
||||||
|
btnedit.style.display = "none";
|
||||||
|
btnconfirm.style.display = "inline-block";
|
||||||
|
btndiscard.style.display = "inline-block";
|
||||||
|
labelname.style.display = "none";
|
||||||
|
}
|
||||||
|
btndiscard.onclick = async function (e) {
|
||||||
|
inputname.style.display = "none";
|
||||||
|
btnedit.style.display = "inline-block";
|
||||||
|
btnconfirm.style.display = "none";
|
||||||
|
btndiscard.style.display = "none";
|
||||||
|
labelname.style.display = "inline-block";
|
||||||
|
}
|
||||||
|
btnconfirm.onclick = async function (e) {
|
||||||
|
text = inputname.value;
|
||||||
|
if (Boolean(text)) {
|
||||||
|
let data = {"sessionid": sessionid, "sessionname": text};
|
||||||
|
await fetch('api/change_sessionname', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
});
|
||||||
|
inputname.style.display = "none";
|
||||||
|
btnedit.style.display = "inline-block";
|
||||||
|
btnconfirm.style.display = "none";
|
||||||
|
btndiscard.style.display = "none";
|
||||||
|
labelname.style.display = "inline-block";
|
||||||
|
} else {
|
||||||
|
console.log("cant be empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tehsession.appendChild(inputname);
|
||||||
|
tehsession.appendChild(btnedit);
|
||||||
|
tehsession.appendChild(btnconfirm);
|
||||||
|
tehsession.appendChild(btndiscard);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((! msg.hasOwnProperty('session')) || msg.session["id"] != sessionid) {
|
||||||
|
const btnjoin = document.createElement('button');
|
||||||
|
btnjoin.innerText = "Join";
|
||||||
|
btnjoin.onclick = async (e) => await fetch('api/join_session', {
|
||||||
|
method: 'POST', body: JSON.stringify({"sessionid": sessionid})
|
||||||
|
});
|
||||||
|
|
||||||
|
tehsession.appendChild(btnjoin);
|
||||||
|
}
|
||||||
|
|
||||||
|
sessions.appendChild(tehsession);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
21
static/views/lobby/template.html
Normal file
21
static/views/lobby/template.html
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<span id="greeting"></span><br>
|
||||||
|
<div id="username-area">
|
||||||
|
<span id="greeting">Hello, </span>
|
||||||
|
<span id="label-username">_</span>
|
||||||
|
<input id="input-set-username" style="display: none;">
|
||||||
|
<button id="btn-edit-username">🖉</button>
|
||||||
|
<button id="btn-discard-username" style="display: none;">✘</button>
|
||||||
|
<button id="btn-confirm-username" style="display: none;">✔</button>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
|
||||||
|
<span>Available sessions</span><br>
|
||||||
|
<div id="sessions"></div><br>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<span>Create Session</span><br>
|
||||||
|
<input id="input-create-session">
|
||||||
|
<button id="btn-create-session">+</button>
|
||||||
|
<br>
|
||||||
135
static/views/master/script.js
Normal file
135
static/views/master/script.js
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
var text = document.getElementById("msg").innerText
|
||||||
|
msg = JSON.parse(text)
|
||||||
|
|
||||||
|
function onDrag (evt) {
|
||||||
|
var item = evt.item; // dragged HTMLElement
|
||||||
|
fromplayer = evt.from.getAttribute("inventory")
|
||||||
|
toplayer = evt.to.getAttribute("inventory")
|
||||||
|
itemid = item.getAttribute("itemid")
|
||||||
|
toslot = evt.newIndex
|
||||||
|
fromslot = evt.oldIndex
|
||||||
|
data = {
|
||||||
|
"fromplayer": fromplayer,
|
||||||
|
"toplayer": toplayer,
|
||||||
|
"itemid": itemid,
|
||||||
|
"fromslot": fromslot,
|
||||||
|
"toslot": toslot,
|
||||||
|
}
|
||||||
|
fetch('api/move_item', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function draw_item(item) {
|
||||||
|
const itemdiv = document.createElement('itemdiv');
|
||||||
|
var name = item["name"]
|
||||||
|
var description = item["description"]
|
||||||
|
var image = item["image"] || "../static/empty.jpg"
|
||||||
|
|
||||||
|
namespan = document.createElement('b');
|
||||||
|
namespan.innerText = name;
|
||||||
|
namespan.style.display = "block"
|
||||||
|
namespan.style.textAlign = "center"
|
||||||
|
|
||||||
|
descriptionspan = document.createElement('span');
|
||||||
|
descriptionspan.innerText = description;
|
||||||
|
descriptionspan.style.display = "block"
|
||||||
|
descriptionspan.style.width = "8rem";
|
||||||
|
|
||||||
|
imageimg = document.createElement('img');
|
||||||
|
imageimg.src = image;
|
||||||
|
imageimg.style.width = "8rem";
|
||||||
|
imageimg.style.display = "block"
|
||||||
|
|
||||||
|
itemdiv.appendChild(namespan);
|
||||||
|
itemdiv.appendChild(imageimg);
|
||||||
|
itemdiv.appendChild(descriptionspan);
|
||||||
|
itemdiv.style.display = "inline-block"
|
||||||
|
itemdiv.style.background = "lightcoral"
|
||||||
|
itemdiv.setAttribute("itemid", item["id"]);
|
||||||
|
return itemdiv
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("btn-leave-session").onclick = async (e) => await fetch('api/leave_session', {
|
||||||
|
method: 'POST', body: JSON.stringify({})
|
||||||
|
});
|
||||||
|
var session = msg.session;
|
||||||
|
document.getElementById("session").innerText = session["name"];
|
||||||
|
document.getElementById('label-username').innerText = msg.username;
|
||||||
|
|
||||||
|
document.getElementById("btn-gen-item").onclick = async (e) => {
|
||||||
|
name = document.getElementById("input-gen-item-name").value;
|
||||||
|
description = document.getElementById("input-gen-item-description").value;
|
||||||
|
image = document.getElementById("input-gen-item-image").value;
|
||||||
|
if (Boolean(name)) {
|
||||||
|
await fetch('api/create_item', { method: 'POST', body: JSON.stringify(
|
||||||
|
{'name': name, 'description': description, 'image': image}
|
||||||
|
)});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var wrapper = document.getElementById("items");
|
||||||
|
var items = msg.items;
|
||||||
|
var itemsdiv = document.createElement('div');
|
||||||
|
var itemsheading = document.createElement('h3');
|
||||||
|
itemsheading.innerText = "All Items";
|
||||||
|
wrapper.style.background = "lightblue";
|
||||||
|
wrapper.style.display = "table";
|
||||||
|
|
||||||
|
while (wrapper.children.length) wrapper.lastChild.remove();
|
||||||
|
|
||||||
|
Object.keys(items).forEach( item => {
|
||||||
|
|
||||||
|
var item = items[item];
|
||||||
|
itemdiv = draw_item(item);
|
||||||
|
itemsdiv.appendChild(itemdiv);
|
||||||
|
|
||||||
|
});
|
||||||
|
Sortable.create(itemsdiv,
|
||||||
|
{
|
||||||
|
"group": "items",
|
||||||
|
"sort": "false",
|
||||||
|
"draggable": "itemdiv",
|
||||||
|
"onEnd": onDrag,
|
||||||
|
|
||||||
|
});
|
||||||
|
itemsdiv.setAttribute("inventory", "master");
|
||||||
|
wrapper.appendChild(itemsheading);
|
||||||
|
wrapper.appendChild(itemsdiv);
|
||||||
|
|
||||||
|
|
||||||
|
var inventories = document.getElementById("inventories");
|
||||||
|
while (inventories.children.length) inventories.lastChild.remove();
|
||||||
|
|
||||||
|
Object.keys(msg.inventories).forEach( name => {
|
||||||
|
inventory = msg.inventories[name];
|
||||||
|
inventorydiv = document.createElement('div');
|
||||||
|
inventorydiv.style.display = "block";
|
||||||
|
titlespan = document.createElement('h4');
|
||||||
|
titlespan.innerText = name;
|
||||||
|
titlespan.style.textAlign = "center";
|
||||||
|
inventorydiv.appendChild(titlespan);
|
||||||
|
|
||||||
|
Object.keys(inventory).forEach( item => {
|
||||||
|
item = inventory[item];
|
||||||
|
var thediv = draw_item(item);
|
||||||
|
//thediv.style.display = "block";
|
||||||
|
inventorydiv.appendChild(thediv);
|
||||||
|
inventorydiv.style.display = "inline-block";
|
||||||
|
});
|
||||||
|
|
||||||
|
inventorydiv.style.background = "lightgreen";
|
||||||
|
|
||||||
|
Sortable.create(inventorydiv,
|
||||||
|
{
|
||||||
|
"group": "items",
|
||||||
|
"sort": "false",
|
||||||
|
"draggable": "itemdiv",
|
||||||
|
"onEnd": onDrag,
|
||||||
|
});
|
||||||
|
inventorydiv.setAttribute("inventory", name);
|
||||||
|
|
||||||
|
inventories.appendChild(inventorydiv);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
inventories.style.display = "inline-block";
|
||||||
14
static/views/master/template.html
Normal file
14
static/views/master/template.html
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
Welcome to <b id="session"></b>, lobbymaster <span id="label-username"></span>
|
||||||
|
<br><br>
|
||||||
|
<button id="btn-leave-session">Leave Session</button>
|
||||||
|
|
||||||
|
<div id="div-gen-item">
|
||||||
|
Name: <input id="input-gen-item-name" /> <br>
|
||||||
|
Description: <input id="input-gen-item-description" /> <br>
|
||||||
|
Image: <input id="input-gen-item-image" /> <br>
|
||||||
|
<button id="btn-gen-item">Create item</button>
|
||||||
|
</div>
|
||||||
|
<div id="items">
|
||||||
|
</div>
|
||||||
|
<div id="inventories">
|
||||||
|
</div>
|
||||||
80
static/views/session/script.js
Normal file
80
static/views/session/script.js
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
function draw_item(item) {
|
||||||
|
const itemdiv = document.createElement('itemdiv');
|
||||||
|
var name = item["name"]
|
||||||
|
var description = item["description"]
|
||||||
|
var image = item["image"] || "../static/empty.jpg"
|
||||||
|
|
||||||
|
namespan = document.createElement('b');
|
||||||
|
namespan.innerText = name;
|
||||||
|
namespan.style.display = "block"
|
||||||
|
namespan.style.textAlign = "center"
|
||||||
|
|
||||||
|
descriptionspan = document.createElement('span');
|
||||||
|
descriptionspan.innerText = description;
|
||||||
|
descriptionspan.style.display = "block"
|
||||||
|
descriptionspan.style.width = "8rem";
|
||||||
|
|
||||||
|
imageimg = document.createElement('img');
|
||||||
|
imageimg.src = image;
|
||||||
|
imageimg.style.width = "8rem";
|
||||||
|
imageimg.style.display = "block"
|
||||||
|
|
||||||
|
itemdiv.appendChild(namespan);
|
||||||
|
itemdiv.appendChild(imageimg);
|
||||||
|
itemdiv.appendChild(descriptionspan);
|
||||||
|
itemdiv.style.display = "inline-block"
|
||||||
|
itemdiv.style.background = "lightcoral"
|
||||||
|
itemdiv.setAttribute("itemid", item["id"]);
|
||||||
|
return itemdiv
|
||||||
|
}
|
||||||
|
|
||||||
|
var text = document.getElementById("msg").innerText
|
||||||
|
msg = JSON.parse(text)
|
||||||
|
|
||||||
|
document.getElementById("btn-leave-session").onclick = async (e) => await fetch('api/leave_session', {
|
||||||
|
method: 'POST', body: JSON.stringify({})
|
||||||
|
});
|
||||||
|
document.getElementById("session").innerText = msg.session;
|
||||||
|
document.getElementById('label-username').innerText = msg.username;
|
||||||
|
//fill inventory and inventories
|
||||||
|
inventorydiv = document.getElementById("inventory");
|
||||||
|
inventoriesdiv = document.getElementById("inventories");
|
||||||
|
|
||||||
|
while (inventorydiv.children.length) inventorydiv.lastChild.remove();
|
||||||
|
while (inventoriesdiv.children.length) inventoriesdiv.lastChild.remove();
|
||||||
|
|
||||||
|
username = msg.username;
|
||||||
|
inventories = msg.inventories;
|
||||||
|
|
||||||
|
if (username in inventories) {
|
||||||
|
inventory = inventories[username]
|
||||||
|
|
||||||
|
Object.keys(inventory).forEach( item => {
|
||||||
|
|
||||||
|
var item = inventory[item];
|
||||||
|
itemdiv = draw_item(item);
|
||||||
|
inventorydiv.appendChild(itemdiv);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Object.keys(inventories).forEach( inventory => {
|
||||||
|
if (!(inventory in inventories))
|
||||||
|
return;
|
||||||
|
if (inventory == username)
|
||||||
|
return;
|
||||||
|
var wrapper = document.createElement('div')
|
||||||
|
var usernamespan = document.createElement('span')
|
||||||
|
usernamespan.innerText = inventory;
|
||||||
|
var inventorydiv = document.createElement('div')
|
||||||
|
Object.keys(inventories[inventory]).forEach( item => {
|
||||||
|
var item = inventories[inventory][item];
|
||||||
|
itemdiv = draw_item(item);
|
||||||
|
inventorydiv.appendChild(itemdiv);
|
||||||
|
});
|
||||||
|
//inventorydiv.appendChild(itemdiv);
|
||||||
|
wrapper.appendChild(usernamespan)
|
||||||
|
wrapper.appendChild(inventorydiv)
|
||||||
|
inventoriesdiv.appendChild(wrapper);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
13
static/views/session/template.html
Normal file
13
static/views/session/template.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<div>
|
||||||
|
Hello <span id="label-username"></span>
|
||||||
|
<br><br>
|
||||||
|
Welkome to <b id="session"></b>! <br>
|
||||||
|
<button id="btn-leave-session">Leave Session</button>
|
||||||
|
<br><br>
|
||||||
|
</div>
|
||||||
|
<h3>Your items</h3>
|
||||||
|
<div id="inventory">
|
||||||
|
</div>
|
||||||
|
<h3>Other players' inventories</h3>
|
||||||
|
<div id="inventories">
|
||||||
|
</div>
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"bar": "foo", "foo": 3, "test": 4, "kso72uuzubg22om7": {}}
|
|
||||||
1
tehsession.json
Normal file
1
tehsession.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"sessions": {"2b7jrklcn6eulwbw": {"id": "2b7jrklcn6eulwbw", "name": "Die coole session von Player 1", "clients": ["hmrcjnvo2ngs7265", "bkrqopf5j6q3tpta", "cho2o2ntflm4mq3u"], "owner": "bkrqopf5j6q3tpta", "inventories": {"cho2o2ntflm4mq3u": ["hr3gqfed4zelzdcz"], "bkrqopf5j6q3tpta": ["tuqjjll2cltlw6i6"]}}}, "clients": {"bkrqopf5j6q3tpta": {"id": "bkrqopf5j6q3tpta", "name": "Player 1", "session": "2b7jrklcn6eulwbw"}, "cho2o2ntflm4mq3u": {"id": "cho2o2ntflm4mq3u", "name": "Player 2", "session": "2b7jrklcn6eulwbw"}, "hmrcjnvo2ngs7265": {"id": "hmrcjnvo2ngs7265", "name": "Joe", "session": "2b7jrklcn6eulwbw"}}, "items": {"hr3gqfed4zelzdcz": {"id": "hr3gqfed4zelzdcz", "name": "Revive", "description": "Revives a KO pokemon and brings it to 50% health", "image": "https://1.bp.blogspot.com/-Hz8sIf0g7cY/VsyVIWiLsnI/AAAAAAAAnII/DjW20xLr0R4/s1600/max_revive_by_peetzaahhh2010-d8oki1o.png", "tags": {}}, "7htnswtslkla6rqh": {"id": "7htnswtslkla6rqh", "name": "Potion", "description": "Heals your Pokey-Man by 20 hp", "image": "https://cdn.bulbagarden.net/upload/thumb/4/45/PotionBaseSet94.jpg/200px-PotionBaseSet94.jpg", "tags": {}}, "tuqjjll2cltlw6i6": {"id": "tuqjjll2cltlw6i6", "name": "Revive\u2122", "description": "When mom tells you that there is Max-Revive at home", "image": "https://www.pokewiki.de/images/5/58/Vitalkraut_Traumwelt.png", "tags": {}}}}
|
||||||
39
ui.html
39
ui.html
@@ -1,27 +1,30 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>leafblade Minecraft Server</title>
|
<title>leafblade Minecraft Server</title>
|
||||||
<meta charset="UTF-8"/>
|
<script src="https://raw.githack.com/SortableJS/Sortable/master/Sortable.js"></script>
|
||||||
</head>
|
<meta charset="UTF-8"/>
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
/* border: 1px solid; */
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
this is the UI
|
<div id="content">
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
<button id="test_api">Test API</button>
|
<script src="../static/renderer.js"></script>
|
||||||
|
|
||||||
<script src="/static/renderer.js"></script>
|
<script>
|
||||||
<script>
|
fetch('api/draw', {
|
||||||
document.getElementById("test_api").onclick = async function (e) {
|
|
||||||
let data = {foo: 'bar'};
|
|
||||||
|
|
||||||
await fetch('api', {
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify({}),
|
||||||
})
|
});
|
||||||
};
|
</script>
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user