enforce exclusivity of only one active Game at a time
a prior commit made this determination for now, for simplicity's sake (and also what are the odds of running two games at once on the same codebase), but it was'n really enforced until now Signed-off-by: Brian S. Stephan <bss@incorporeal.org>
This commit is contained in:
parent
0ad687669e
commit
4a8babf39e
@ -180,20 +180,19 @@ class IdleRPG(Plugin):
|
||||
"""Check for characters who have leveled up, and log as such in the channel."""
|
||||
while self.check_for_level_ups:
|
||||
time.sleep(self.SLEEP_BETWEEN_LEVEL_CHECKS)
|
||||
self._level_up_games()
|
||||
self._level_up_characters()
|
||||
|
||||
def _level_up_games(self):
|
||||
"""Find games under management and level up characters within them, updating their channel."""
|
||||
logger.debug("checking for level ups in games")
|
||||
for game in Game.objects.filter(active=True):
|
||||
logger.debug("checking for level ups in %s", game)
|
||||
for character in Character.objects.levelable(game):
|
||||
logger.debug("going to try to level up %s", character)
|
||||
character.level_up()
|
||||
self.bot.reply(None, f"{character.name}, the {character.character_class}, has attained level "
|
||||
f"{character.level}! Next level at {character.next_level_str()}.",
|
||||
explicit_target=game.channel.name)
|
||||
character.save()
|
||||
def _level_up_characters(self):
|
||||
"""Level up characters in the active game, updating their channel."""
|
||||
game = Game.objects.get(active=True)
|
||||
logger.debug("checking for level ups in %s", game)
|
||||
for character in Character.objects.levelable(game):
|
||||
logger.debug("going to try to level up %s", character)
|
||||
character.level_up()
|
||||
self.bot.reply(None, f"{character.name}, the {character.character_class}, has attained level "
|
||||
f"{character.level}! Next level at {character.next_level_str()}.",
|
||||
explicit_target=game.channel.name)
|
||||
character.save()
|
||||
|
||||
|
||||
plugin = IdleRPG
|
||||
|
18
idlerpg/migrations/0008_game_one_enabled_at_a_time.py
Normal file
18
idlerpg/migrations/0008_game_one_enabled_at_a_time.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.0.5 on 2024-05-18 14:41
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('idlerpg', '0007_remove_character_one_player_character_per_game_and_more'),
|
||||
('ircbot', '0020_alter_alias_id_alter_botuser_id_alter_ircchannel_id_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddConstraint(
|
||||
model_name='game',
|
||||
constraint=models.UniqueConstraint(models.F('active'), condition=models.Q(('active', True)), name='one_enabled_at_a_time'),
|
||||
),
|
||||
]
|
@ -26,7 +26,8 @@ class Game(models.Model):
|
||||
"""Options for the Game and its objects."""
|
||||
|
||||
constraints = [
|
||||
models.UniqueConstraint("active", "channel", name="one_game_per_channel"),
|
||||
models.UniqueConstraint('active', 'channel', name='one_game_per_channel'),
|
||||
models.UniqueConstraint('active', condition=models.Q(active=True), name='one_enabled_at_a_time'),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
|
11
tests/fixtures/simple_character.json
vendored
11
tests/fixtures/simple_character.json
vendored
@ -37,7 +37,7 @@
|
||||
"model": "ircbot.ircchannel",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"name": "#level_test",
|
||||
"name": "#duplicate_test",
|
||||
"server": 1,
|
||||
"autojoin": false,
|
||||
"topic_msg": "",
|
||||
@ -56,15 +56,6 @@
|
||||
"channel": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "idlerpg.game",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"name": "level test",
|
||||
"active": true,
|
||||
"channel": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "idlerpg.character",
|
||||
"pk": 1,
|
||||
|
@ -5,7 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""
|
||||
import logging
|
||||
|
||||
from django.db import transaction
|
||||
from django.db.utils import IntegrityError
|
||||
from django.test import TestCase
|
||||
from ircbot.models import IrcChannel
|
||||
|
||||
from idlerpg.models import Game
|
||||
|
||||
@ -22,3 +25,16 @@ class GameTest(TestCase):
|
||||
game = Game.objects.get(pk=1)
|
||||
logger.debug(str(game))
|
||||
assert str(game) == "test in #test on default (active)"
|
||||
|
||||
def test_cant_have_two_active(self):
|
||||
"""Test that if we create another game, it's disabled, and can't be active until the first is disabled."""
|
||||
channel = IrcChannel.objects.get(pk=2)
|
||||
game = Game.objects.get(pk=1)
|
||||
new_game = Game.objects.create(name='new one', channel=channel)
|
||||
|
||||
assert game.active is True
|
||||
assert new_game.active is False
|
||||
with self.assertRaises(IntegrityError):
|
||||
with transaction.atomic():
|
||||
new_game.active = True
|
||||
new_game.save()
|
||||
|
@ -262,7 +262,7 @@ class IrcPluginTest(TestCase):
|
||||
mock_event = mock.MagicMock()
|
||||
mock_event.source = 'bss!bss@bss_login'
|
||||
mock_event.recursing = False
|
||||
game = Game.objects.get(pk=2)
|
||||
game = Game.objects.get(pk=1)
|
||||
test_char = Character.objects.register('test_login', game, 'test', 'bss!bss@bss_login', 'tester')
|
||||
test_char.log_out()
|
||||
test_char.next_level = datetime.datetime.fromisoformat('2024-05-17 17:00:00-00:00')
|
||||
@ -283,7 +283,7 @@ class IrcPluginTest(TestCase):
|
||||
# the ordering of this surprises me... keep an eye on it
|
||||
self.mock_bot.reply.assert_has_calls([
|
||||
mock.call(None, "test_login, the level 0 tester, is now online from nickname bss. "
|
||||
"Next level at 2024-05-17 17:00:00 UTC.", explicit_target='#level_test'),
|
||||
"Next level at 2024-05-17 17:00:00 UTC.", explicit_target='#test'),
|
||||
mock.call(mock_event, "test_login, the level 0 tester, has been successfully logged in."),
|
||||
])
|
||||
|
||||
@ -317,7 +317,7 @@ class IrcPluginTest(TestCase):
|
||||
mock_event = mock.MagicMock()
|
||||
mock_event.source = 'bss!bss@bss_logout'
|
||||
mock_event.recursing = False
|
||||
game = Game.objects.get(pk=2)
|
||||
game = Game.objects.get(pk=1)
|
||||
test_char = Character.objects.register('test_logout', game, 'test', 'bss!bss@bss_logout', 'tester')
|
||||
|
||||
match = re.match(IdleRPG.LOGOUT_COMMAND_PATTERN, 'LOGOUT')
|
||||
@ -338,7 +338,7 @@ class IrcPluginTest(TestCase):
|
||||
mock_event.source = 'bss!bss@bss_remove'
|
||||
mock_event.recursing = False
|
||||
|
||||
game = Game.objects.get(pk=2)
|
||||
game = Game.objects.get(pk=1)
|
||||
test_char = Character.objects.register('test_remove', game, 'test', 'bss!bss@bss_remove', 'tester')
|
||||
match = re.match(IdleRPG.LOGIN_COMMAND_PATTERN, 'REMOVEME')
|
||||
self.plugin.handle_remove(self.mock_connection, mock_event, match)
|
||||
@ -356,7 +356,7 @@ class IrcPluginTest(TestCase):
|
||||
mock_event.source = 'bss2!bss@bss_remove'
|
||||
mock_event.recursing = False
|
||||
|
||||
game = Game.objects.get(pk=2)
|
||||
game = Game.objects.get(pk=1)
|
||||
test_char = Character.objects.register('test_remove', game, 'test', 'bss!bss@bss_remove', 'tester')
|
||||
match = re.match(IdleRPG.LOGIN_COMMAND_PATTERN, 'REMOVEME')
|
||||
self.plugin.handle_remove(self.mock_connection, mock_event, match)
|
||||
@ -422,9 +422,9 @@ class IrcPluginTest(TestCase):
|
||||
|
||||
self.plugin.seen_hostmasks.remove('bss3!bss@bss')
|
||||
|
||||
def test_level_up_games(self):
|
||||
def test_level_up_characters(self):
|
||||
"""Test the walking of games and characters to level them up."""
|
||||
game = Game.objects.get(pk=2)
|
||||
game = Game.objects.get(pk=1)
|
||||
char_1 = Character.objects.register('test_level_1', game, 'test', 'test_1!test@test', 'tester')
|
||||
char_2 = Character.objects.register('test_level_2', game, 'test', 'test_2!test@test', 'tester')
|
||||
char_2.log_out()
|
||||
@ -434,7 +434,7 @@ class IrcPluginTest(TestCase):
|
||||
char_1.save()
|
||||
char_2.save()
|
||||
# only one should level up, since char_2 isn't logged in
|
||||
self.plugin._level_up_games()
|
||||
self.plugin._level_up_characters()
|
||||
|
||||
char_1 = Character.objects.get(pk=char_1.pk)
|
||||
char_2 = Character.objects.get(pk=char_2.pk)
|
||||
|
Loading…
Reference in New Issue
Block a user