DM Guide 13
Это 13 глава перевода оригинального руководства по Dream Maker от разработчиков.
Остальные главы руководства и статьи о программировании на коде BYOND от любителей на русском.
Глава 13: События в реальном времени
Я – Время, разрушитель миров. -- Бхагават Гита
До сих пор, все события, происходившие в мире, зависели от данных, вводимых игроком. Мир по-настоящему оживает, вместе с событиями, генерируемыми самим миром. Их мы и рассмотрим в данной главе.
Обычно код выполняется настолько быстро, насколько быстро компьютер может его обработать. Когда команды запланированы в соответствии с течением времени, это называется выполнением в реальном времени. События, генерируемые миром, обычно выполняются в реальном времени, или происходят в течение некоторого времени после запуска и не имеют большого интереса для игроков.
Команда sleep
Собственно говоря, выполнение в реальном времени – это вопрос откладывания выполнения кода на определенный промежуток времени. DM для этого предусматривает команду sleep. Она останавливает выполнение текущей операции на определенный промежуток времени.
sleep(Delay) Delay – промежуток времени для ожидания в 10-ых секунд
Мультипользовательское окружение, такое как мир BYOND, не может тратить время впустую: оно всегда должно быть готово отреагировать на ввод информации. Важно осознавать, что sleep только останавливает текущую операцию и вызывающие ее процедуры. В то время как одна операция спит, другие будут нормально работать.
Есть несколько других «спящих» команд в DM, каждая со своим назначением. Фактически, вы уже видели подобную команду – а именно prompt. Она заставляет операцию заснуть до тех пор, пока игрок не закончит ввод данных. Их объединяет то, что они заставляют текущую процедуру и вызывающие ее временно остановить выполнение и продолжить его позднее.
Следующий пример использует sleep для расчета времени движения небес.
proc/Weather() for() world << "The sun rises in the east." sleep(500) world << "The noon day sun rises high in the sky." sleep(500) world << "The sun sinks low in the west." sleep(1000)
Команда for без всяких параметров, как оно написано здесь - один из путей создания бесконечного цикла. Если тело такого цикла никогда не останавливается, то это приведет к остановке мира и последующему игнорированию дальнейшего ввода данных. Однако, в качестве предосторожности, код, наподобие бесконечного цикла, который продолжается слишком долго, отменяется для предотвращения блокировки целого мира. Таким образом, желаемый эффект может быть достигнут ожиданием внутри цикла. Периодическое сообщение о времени видно всем в мире.
Команда spawn
Команда spawn схожа с sleep, но не задерживает всю процедуру, а только отсрочивает текущую команду или блок команд. Выполнение просто пропускает выбранный код и возвращается к нему через определенный промежуток времени.
spawn(Delay) Statement Delay – отложенное время в 10-ых секунд.
Выбор между spawn и sleep зачастую заключается лишь в том, какой командой вам удобнее воспользоваться в конкретной ситуации. В большинстве случаев каждую из них можно использовать для достижения одной и той же цели. Структура кода обычно сама определяет какой из них удобнее воспользоваться. Если вы хотите провести дополнительную обработку после задержанного кода, то лучше использовать spawn.
Следующий пример использует spawn для дезинфицирования комнаты.
area/sickroom //how long to wait before clean cycle var/const/alarm = 100 //moment when countdown started var/start_time = 0 Enter(var/mob/entrant) if(!start_time) start_time = world.time spawn(alarm) for(entrant in src) entrant << "The disinfectant hits you. Aaahhhh!" del entrant start_time = 0 //ready for another round var/time_left = (alarm - (world.time - start_time))/10 entrant << "In [time_left] second\s this room will be disinfected." entrant << "Have a nice day!" return 1
Когда кто-то в первый раз заходит в комнату, триггер устанавливается и смертельный код откладывается. Операция enter продолжает информировать каждого входящего о том, сколько времени осталось. Когда наступает нужный момент, грязное дело совершается внутри отсроченного блока кода. Заметьте, что когда отложенный код выполняется, он автоматически останавливается в конце блока, как будто это совершенно другая операция.
Расчет времени
Когда интенсивно используется выполнение в реальном времени, полезно знать то, как всё это происходит изнутри. Этот раздел описывает шестеренки и пружины, благодаря которым мир тикает.
Потоки выполнения
Мир DM - однопоточный. Это значит, что только один кусок кода может выполняться одновременно. В другом случае, вам бы пришлось заботиться о гораздо большем количестве потенциальных проблем в коде. Например, если бы отсроченный блок кода, наподобие предыдущего примера, удалял объекты из мира, могли бы возникнуть проблемы, в случае, когда эти объекты используются одновременно другим кодом. Если бы код попытался получить доступ к переменным или операциям удаленных объектов, это привело бы к завершению, возможно, оставляя некоторые важные операции незаконченными.
Если хотите параллелей, собственно говоря, вы можете рассекать мир на многочисленные сервера. Если бы у вас было много CPU в одном компьютере или множество компьютеров, вы бы создали параллельные вселенные!
С тех пор, как существует только одиночный непрерывный поток выполнения, вы можете быть увереннее, когда пишете код. Между одной командой и следующей, ничего не происходит. Если объект существует в конце одной команды, то он будет существовать и в начале следующей.
Единственным исключением в этом правиле являются спящие операции. В этом случае, вам следует осознавать, что всё что угодно может произойти во время паузы. Например, переменная, относящаяся к объекту, может обнулиться, потому что объект был удален. Перед тем как полагаться на спящую команду, следует всё перепроверить, чтобы убедиться, что ничего не произошло.
Переменная src используется как раз для этого. Когда src спящей операции удаляется, сама операция отменяется. Это почти всегда дает желаемый результат и проблема точной проверки отпадает. Если вы не хотите, чтобы операция отменилась, вам всегда следует ставить переменную src на ноль перед засыпанием. Это делает операцию независимой от существования src объекта.