mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
Add set_dt/stage to on-demandhandler. Fix issue with loading
This commit is contained in:
parent
cc8584f839
commit
8dde1fbe38
3 changed files with 154 additions and 3 deletions
|
|
@ -1,5 +1,12 @@
|
|||
# Changelog
|
||||
|
||||
## Evennia Main branch
|
||||
|
||||
- Feature: Add `ON_DEMAND_HANDLER.set_dt(key, category, dt)` and
|
||||
`.set_stage(key, category, stage)` to allow manual tweaking of task timings,
|
||||
for example for a spell speeding a plant's growth. (Griatch)
|
||||
- Fix: Resolve a bug when loading on-demand-handler data from database.
|
||||
|
||||
## Evennia 3.2.0
|
||||
|
||||
Feb 25, 2024
|
||||
|
|
|
|||
|
|
@ -199,11 +199,17 @@ class OnDemandTask:
|
|||
self.iterations = 0 # only used with looping staging functions
|
||||
|
||||
self.stages = None
|
||||
self.stages_by_name = None
|
||||
|
||||
if isinstance(stages, dict):
|
||||
# sort the stages by ending time, inserting each state as {dt: (statename, callable)}
|
||||
_stages = {}
|
||||
for dt, tup in stages.items():
|
||||
# validate the input
|
||||
if not isinstance(dt, (int, float)):
|
||||
raise ValueError(
|
||||
"Each stage must given as a time-delta in seconds (int or float)."
|
||||
)
|
||||
if is_iter(tup):
|
||||
if len(tup) != 2:
|
||||
raise ValueError(
|
||||
|
|
@ -218,6 +224,7 @@ class OnDemandTask:
|
|||
_stages[dt] = tup
|
||||
|
||||
self.stages = {dt: tup for dt, tup in sorted(_stages.items(), reverse=True)}
|
||||
self.stages_by_name = {tup[0]: dt for dt, tup in self.stages.items()}
|
||||
|
||||
self.check(autostart=autostart)
|
||||
|
||||
|
|
@ -306,6 +313,23 @@ class OnDemandTask:
|
|||
|
||||
return self.check()[0]
|
||||
|
||||
def set_dt(self, dt):
|
||||
"""
|
||||
Set the time-delta since the task started manually. This allows you to 'cheat' the system
|
||||
and set the time manually. This is useful for testing or when a system manipulates the state
|
||||
somehow (like using a potion that speeds up the growth of a plant).
|
||||
|
||||
Args:
|
||||
dt (int): The time-delta to set. This is an absolute value in seconds, same as returned
|
||||
by `get_dt`.
|
||||
|
||||
Notes:
|
||||
Setting this will not on its own trigger any stage functions - this will only happen
|
||||
as normal, next time the state is checked and the stage is found to have changed.
|
||||
|
||||
"""
|
||||
self.start_time = OnDemandTask.runtime() - dt
|
||||
|
||||
def get_stage(self):
|
||||
"""
|
||||
Get the current stage of the task. If no stage was given, this will return `None` but
|
||||
|
|
@ -317,6 +341,30 @@ class OnDemandTask:
|
|||
"""
|
||||
return self.check()[1]
|
||||
|
||||
def set_stage(self, stage=None):
|
||||
"""
|
||||
Set the stage of the task manually. This allows you to 'cheat' the system and set the stage
|
||||
manually. This is useful for testing or when a system manipulates the state somehow (like
|
||||
using a potion that speeds up the growth of a plant). The given stage must be previously
|
||||
created for the given task. If task has no stages, this will do nothing.
|
||||
|
||||
Args:
|
||||
stage (str, optional): The stage to set. If `None`, the task will be reset to its
|
||||
initial (first) state.
|
||||
|
||||
Notes:
|
||||
Setting this will not on its own trigger any stage functions - this will only happen
|
||||
as normal, next time the state is checked and the stage is found to have changed.
|
||||
|
||||
"""
|
||||
if not self.stages:
|
||||
return
|
||||
|
||||
if stage is None:
|
||||
self.start_time = OnDemandTask.runtime() - min(self.stages.keys())
|
||||
elif stage in self.stages_by_name:
|
||||
self.start_time = OnDemandTask.runtime() - self.stages_by_name[stage]
|
||||
|
||||
|
||||
class OnDemandHandler:
|
||||
"""
|
||||
|
|
@ -338,7 +386,7 @@ class OnDemandHandler:
|
|||
This should be automatically called when Evennia starts.
|
||||
|
||||
"""
|
||||
self.tasks = ServerConfig.objects.conf("on_demand_timers", default=dict)
|
||||
self.tasks = dict(ServerConfig.objects.conf("on_demand_timers", default=dict))
|
||||
|
||||
def save(self):
|
||||
"""
|
||||
|
|
@ -520,6 +568,30 @@ class OnDemandHandler:
|
|||
task = self.get(key, category)
|
||||
return task.get_dt() if task else None
|
||||
|
||||
def set_dt(self, key, category, dt):
|
||||
"""
|
||||
Set the time-delta since the task started manually. This allows you to 'cheat' the system
|
||||
and set the time manually. This is useful for testing or when a system manipulates the state
|
||||
somehow (like using a potion that speeds up the growth of a plant).
|
||||
|
||||
Args:
|
||||
key (str, callable, OnDemandTask or Object): The unique identifier for the task. If a
|
||||
callable, will be called without arguments. If an Object, will be converted to a string.
|
||||
If an `OnDemandTask`, then all other arguments are ignored and the task will be used
|
||||
to identify the task to set the time-delta for.
|
||||
category (str, optional): The category of the task.
|
||||
dt (int): The time-delta to set. This is an absolute value in seconds, same as returned
|
||||
by `get_dt`.
|
||||
|
||||
Notes:
|
||||
Setting this will not on its own trigger any stage functions - this will only happen
|
||||
as normal, next time the state is checked and the stage is found to have changed.
|
||||
|
||||
"""
|
||||
task = self.get(key, category)
|
||||
if task:
|
||||
task.set_dt(dt)
|
||||
|
||||
def get_stage(self, key, category=None):
|
||||
"""
|
||||
Get the current stage of an on-demand task.
|
||||
|
|
@ -537,6 +609,31 @@ class OnDemandHandler:
|
|||
task = self.get(key, category)
|
||||
return task.get_stage() if task else None
|
||||
|
||||
def set_stage(self, key, category=None, stage=None):
|
||||
"""
|
||||
Set the stage of an on-demand task manually. This allows you to 'cheat' the system and set
|
||||
the stage manually. This is useful for testing or when a system manipulates the state
|
||||
somehow (like using a potion that speeds up the growth of a plant). The given stage must
|
||||
be previously created for the given task. If task has no stages, this will do nothing.
|
||||
|
||||
Args:
|
||||
key (str, callable, OnDemandTask or Object): The unique identifier for the task. If a
|
||||
callable, will be called without arguments. If an Object, will be converted to a
|
||||
string. If an `OnDemandTask`, then all other arguments are ignored and the task
|
||||
will be used to identify the task to set the stage for.
|
||||
category (str, optional): The category of the task.
|
||||
stage (str, optional): The stage to set. If `None`, the task will be reset to its
|
||||
initial (first) state.
|
||||
|
||||
Notes:
|
||||
Setting this will not on its own trigger any stage functions - this will only happen
|
||||
as normal, next time the state is checked and the stage is found to have changed.
|
||||
|
||||
"""
|
||||
task = self.get(key, category)
|
||||
if task:
|
||||
task.set_stage(stage)
|
||||
|
||||
|
||||
# Create singleton
|
||||
ON_DEMAND_HANDLER = OnDemandHandler()
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@ Unit tests for the scripts package
|
|||
from collections import defaultdict
|
||||
from unittest import TestCase, mock
|
||||
|
||||
from parameterized import parameterized
|
||||
|
||||
from evennia import DefaultScript
|
||||
from evennia.objects.objects import DefaultObject
|
||||
from evennia.scripts.manager import ScriptDBManager
|
||||
|
|
@ -19,6 +17,7 @@ from evennia.scripts.tickerhandler import TickerHandler
|
|||
from evennia.utils.create import create_script
|
||||
from evennia.utils.dbserialize import dbserialize
|
||||
from evennia.utils.test_resources import BaseEvenniaTest, EvenniaTest
|
||||
from parameterized import parameterized
|
||||
|
||||
|
||||
class TestScript(BaseEvenniaTest):
|
||||
|
|
@ -628,3 +627,51 @@ class TestOnDemandHandler(EvenniaTest):
|
|||
self.assertEqual(self.handler.get_dt("daffodil", "flower"), 10000)
|
||||
self.assertEqual(self.handler.get_stage("rose", "flower"), "dead")
|
||||
self.assertEqual(self.handler.get_stage("daffodil", "flower"), "dead")
|
||||
|
||||
@mock.patch("evennia.scripts.ondemandhandler.OnDemandTask.runtime")
|
||||
def test_set_dt(self, mock_runtime):
|
||||
START_TIME = 0
|
||||
|
||||
mock_runtime.return_value = START_TIME
|
||||
self.handler.batch_add(self.task1, self.task2)
|
||||
|
||||
for task in self.handler.tasks.values():
|
||||
task.start_time = START_TIME
|
||||
|
||||
self.assertEqual(self.handler.get_stage("rose", "flower"), "seedling")
|
||||
self.assertEqual(self.handler.get_stage("daffodil", "flower"), "seedling")
|
||||
|
||||
self.handler.set_dt("rose", "flower", 100)
|
||||
self.handler.set_dt("daffodil", "flower", 150)
|
||||
self.assertEquals(
|
||||
[task.start_time for task in self.handler.tasks.values()],
|
||||
[START_TIME - 100, START_TIME - 150],
|
||||
)
|
||||
self.assertEqual(self.handler.get_dt("rose", "flower"), 100)
|
||||
self.assertEqual(self.handler.get_dt("daffodil", "flower"), 150)
|
||||
self.assertEqual(self.handler.get_stage("rose", "flower"), "bud")
|
||||
self.assertEqual(self.handler.get_stage("daffodil", "flower"), "wilted")
|
||||
|
||||
@mock.patch("evennia.scripts.ondemandhandler.OnDemandTask.runtime")
|
||||
def test_set_stage(self, mock_runtime):
|
||||
START_TIME = 0
|
||||
|
||||
mock_runtime.return_value = START_TIME
|
||||
self.handler.batch_add(self.task1, self.task2)
|
||||
|
||||
for task in self.handler.tasks.values():
|
||||
task.start_time = START_TIME
|
||||
|
||||
self.assertEqual(self.handler.get_stage("rose", "flower"), "seedling")
|
||||
self.assertEqual(self.handler.get_stage("daffodil", "flower"), "seedling")
|
||||
|
||||
self.handler.set_stage("rose", "flower", "bud")
|
||||
self.handler.set_stage("daffodil", "flower", "wilted")
|
||||
self.assertEquals(
|
||||
[task.start_time for task in self.handler.tasks.values()],
|
||||
[START_TIME - 100, START_TIME - 150],
|
||||
)
|
||||
self.assertEqual(self.handler.get_dt("rose", "flower"), 100)
|
||||
self.assertEqual(self.handler.get_dt("daffodil", "flower"), 150)
|
||||
self.assertEqual(self.handler.get_stage("rose", "flower"), "bud")
|
||||
self.assertEqual(self.handler.get_stage("daffodil", "flower"), "wilted")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue