Implement egg-timer for legacy and vanilla clients

This commit is contained in:
Ben 2019-09-09 22:26:11 +01:00
parent 2ecd9f1850
commit 1c03374bd8
7 changed files with 68 additions and 5 deletions

View File

@ -500,6 +500,8 @@ CREATE TABLE penguin (
timer_active BOOLEAN NOT NULL DEFAULT FALSE, timer_active BOOLEAN NOT NULL DEFAULT FALSE,
timer_start TIME NOT NULL DEFAULT '00:00:00', timer_start TIME NOT NULL DEFAULT '00:00:00',
timer_end TIME NOT NULL DEFAULT '23:59:59', timer_end TIME NOT NULL DEFAULT '23:59:59',
timer_total INTERVAL NOT NULL DEFAULT '01:00:00',
grounded BOOLEAN NOT NULL DEFAULT FALSE,
approval_en BOOLEAN NOT NULL DEFAULT FALSE, approval_en BOOLEAN NOT NULL DEFAULT FALSE,
approval_pt BOOLEAN NOT NULL DEFAULT FALSE, approval_pt BOOLEAN NOT NULL DEFAULT FALSE,
approval_fr BOOLEAN NOT NULL DEFAULT FALSE, approval_fr BOOLEAN NOT NULL DEFAULT FALSE,
@ -587,6 +589,8 @@ COMMENT ON COLUMN penguin.status_field IS 'New player status field';
COMMENT ON COLUMN penguin.timer_active IS 'Is egg-timer active?'; COMMENT ON COLUMN penguin.timer_active IS 'Is egg-timer active?';
COMMENT ON COLUMN penguin.timer_start IS 'Egg-timer start time'; COMMENT ON COLUMN penguin.timer_start IS 'Egg-timer start time';
COMMENT ON COLUMN penguin.timer_end IS 'Egg-timer end time'; COMMENT ON COLUMN penguin.timer_end IS 'Egg-timer end time';
COMMENT ON COLUMN penguin.timer_total IS 'Egg-timer total play time';
COMMENT ON COLUMN penguin.grounded IS 'Is player grounded?';
COMMENT ON COLUMN penguin.approval_en IS 'English username approval'; COMMENT ON COLUMN penguin.approval_en IS 'English username approval';
COMMENT ON COLUMN penguin.approval_pt IS 'Portuguese username approval'; COMMENT ON COLUMN penguin.approval_pt IS 'Portuguese username approval';
COMMENT ON COLUMN penguin.approval_fr IS 'French username approval'; COMMENT ON COLUMN penguin.approval_fr IS 'French username approval';

View File

@ -1,4 +1,4 @@
from datetime import datetime from datetime import datetime, date
from houdini.data import db from houdini.data import db
@ -72,6 +72,7 @@ class Penguin(db.Model):
timer_active = db.Column(db.Boolean, nullable=False, server_default=db.text("false")) timer_active = db.Column(db.Boolean, nullable=False, server_default=db.text("false"))
timer_start = db.Column(db.Time, nullable=False, server_default=db.text("'00:00:00'::time without time zone")) timer_start = db.Column(db.Time, nullable=False, server_default=db.text("'00:00:00'::time without time zone"))
timer_end = db.Column(db.Time, nullable=False, server_default=db.text("'23:59:59'::time without time zone")) timer_end = db.Column(db.Time, nullable=False, server_default=db.text("'23:59:59'::time without time zone"))
timer_total = db.Column(db.Interval, nullable=False, server_default=db.text("'01:00:00'::interval"))
grounded = db.Column(db.Boolean, nullable=False, server_default=db.text("false")) grounded = db.Column(db.Boolean, nullable=False, server_default=db.text("false"))
approval_en = db.Column(db.Boolean, nullable=False, server_default=db.text("false")) approval_en = db.Column(db.Boolean, nullable=False, server_default=db.text("false"))
approval_pt = db.Column(db.Boolean, nullable=False, server_default=db.text("false")) approval_pt = db.Column(db.Boolean, nullable=False, server_default=db.text("false"))

View File

@ -11,7 +11,7 @@ import asyncio
import bcrypt import bcrypt
import os import os
from datetime import datetime from datetime import datetime, timedelta
@handlers.handler(XMLPacket('login')) @handlers.handler(XMLPacket('login'))
@ -73,6 +73,14 @@ async def handle_login(p, credentials: Credentials):
if data.grounded: if data.grounded:
return await p.send_error_and_disconnect(913) return await p.send_error_and_disconnect(913)
if data.timer_active:
if not data.timer_start < datetime.now().time() < data.timer_end:
return await p.send_error_and_disconnect(911, data.timer_start, data.timer_end)
if await data.minutes_played_today >= data.timer_total.total_seconds() // 60:
return await p.send_error_and_disconnect(910, data.timer_total)
active_ban = await Ban.query.where(Ban.penguin_id == data.id and Ban.expires >= datetime.now()).gino.first() active_ban = await Ban.query.where(Ban.penguin_id == data.id and Ban.expires >= datetime.now()).gino.first()
if active_ban is not None: if active_ban is not None:

View File

@ -1,9 +1,11 @@
from houdini import handlers from houdini import handlers
from houdini.handlers import XTPacket from houdini.handlers import XTPacket
from houdini.data.room import Room from houdini.data.room import Room
from houdini.data.penguin import Login
import random import random
import time import time
from datetime import datetime
@handlers.handler(XTPacket('j', 'js'), pre_login=True) @handlers.handler(XTPacket('j', 'js'), pre_login=True)
@ -26,7 +28,17 @@ async def handle_join_server(p, penguin_id: int, login_key: str):
penguin_standard_time = current_time * 1000 penguin_standard_time = current_time * 1000
server_time_offset = 7 server_time_offset = 7
await p.send_xt('lp', await p.string, p.data.coins, int(p.data.safe_chat), 1440, if p.data.timer_active:
minutes_until_timer_end = datetime.combine(datetime.today(), p.data.timer_end) - datetime.now()
minutes_until_timer_end = minutes_until_timer_end.total_seconds() // 60
minutes_played_today = await p.data.minutes_played_today
minutes_left_today = (p.data.timer_total.total_seconds() // 60) - minutes_played_today
p.egg_timer_minutes = int(min(minutes_until_timer_end, minutes_left_today))
else:
p.egg_timer_minutes = 24 * 60
await p.send_xt('lp', await p.string, p.data.coins, int(p.data.safe_chat), p.egg_timer_minutes,
penguin_standard_time, p.data.age, 0, p.data.minutes_played, penguin_standard_time, p.data.age, 0, p.data.minutes_played,
"membership_days", server_time_offset, int(p.data.opened_playercard), "membership_days", server_time_offset, int(p.data.opened_playercard),
p.data.map_category, p.data.status_field) p.data.map_category, p.data.status_field)

View File

@ -45,6 +45,37 @@ async def server_heartbeat(server):
for penguin in server.penguins_by_id.values(): for penguin in server.penguins_by_id.values():
if penguin.heartbeat < timer: if penguin.heartbeat < timer:
await penguin.close() await penguin.close()
async def server_egg_timer(server):
while True:
await asyncio.sleep(60)
for p in server.penguins_by_id.values():
if p.data.timer_active:
p.egg_timer_minutes -= 1
if p.client_type == ClientType.Vanilla:
minutes_until_timer_end = datetime.combine(datetime.today(), p.data.timer_end) - datetime.now()
minutes_until_timer_end = minutes_until_timer_end.total_seconds() // 60
if minutes_until_timer_end <= p.egg_timer_minutes + 1:
if p.egg_timer_minutes == 7:
await p.send_error(915, p.egg_timer_minutes, p.data.timer_start, p.data.timer_end)
elif p.egg_timer_minutes == 5:
await p.send_error(915, p.egg_timer_minutes, p.data.timer_start, p.data.timer_end)
else:
if p.egg_timer_minutes == 7:
await p.send_error(914, p.egg_timer_minutes, p.data.timer_total)
elif p.egg_timer_minutes == 5:
await p.send_error(914, p.egg_timer_minutes, p.data.timer_total)
await p.send_xt('uet', p.egg_timer_minutes)
if p.egg_timer_minutes <= 0:
await p.send_error_and_disconnect(916, p.data.timer_start, p.data.timer_end)
else:
if p.egg_timer_minutes <= 0:
await p.send_error_and_disconnect(910)
@handlers.handler(XTPacket('u', 'h')) @handlers.handler(XTPacket('u', 'h'))
@handlers.cooldown(59) @handlers.cooldown(59)
async def handle_heartbeat(p): async def handle_heartbeat(p):

View File

@ -40,6 +40,7 @@ from houdini.plugins import PluginManager
from houdini.commands import CommandManager from houdini.commands import CommandManager
from houdini.handlers.play.player import server_heartbeat from houdini.handlers.play.player import server_heartbeat
from houdini.handlers.play.player import server_egg_timer
class Houdini: class Houdini:
@ -93,6 +94,7 @@ class Houdini:
self.spawn_rooms = None self.spawn_rooms = None
self.heartbeat = None self.heartbeat = None
self.egg_timer = None
async def start(self): async def start(self):
self.config = config self.config = config
@ -228,6 +230,8 @@ class Houdini:
await self.plugins.setup(houdini.plugins) await self.plugins.setup(houdini.plugins)
self.heartbeat = asyncio.create_task(server_heartbeat(self)) self.heartbeat = asyncio.create_task(server_heartbeat(self))
self.egg_timer = asyncio.create_task(server_egg_timer(self))
async with self.server: async with self.server:
await self.server.serve_forever() await self.server.serve_forever()

View File

@ -9,6 +9,7 @@ class Penguin(Spheniscidae):
'data', 'muted', 'login_key', 'member', 'membership_days', 'data', 'muted', 'login_key', 'member', 'membership_days',
'avatar', 'walking_puffle', 'permissions', 'active_quests', 'avatar', 'walking_puffle', 'permissions', 'active_quests',
'buddy_requests', 'heartbeat', 'login_timestamp', 'buddy_requests', 'heartbeat', 'login_timestamp',
'egg_timer_minutes']
def __init__(self, *args): def __init__(self, *args):
super().__init__(*args) super().__init__(*args)
@ -28,12 +29,14 @@ class Penguin(Spheniscidae):
self.membership_days = 1 self.membership_days = 1
self.avatar = None self.avatar = None
self.walking_puffle = None self.walking_puffle = None
self.active_quests = None self.active_quests = None
self.buddy_requests = set()
self.heartbeat = time.time()
self.login_timestamp = None self.login_timestamp = None
self.egg_timer_minutes = None
@property @property
def party_state(self): def party_state(self):