Как написать свой скрипт?
Для многих будет вопросом, как же создать собственный скрипт, и что для этого необходимо. В данной статье мы пробежимся по нескольким аспектам.
Содержание |
Часть 1.
Для начала необходимо определиться, что мы хотим от нашего скрипта.
Образец для учебника:
- Статистика смертей/убийств игрока.
- Пишем в чат, кто и кого убил + его новую стату.
*После респауна игрока, награждаем его бутылочной ракетницей.
Подберём список необходимых нам для этого функций и событий. Функции:
- player.giveWeapon() - Выдать оружие
- player.sendMessage() - Отправить сообщение
- eventHandlers.add() - Добавить событие
- broadcastMessage() - Будем использовать удобный вариант для рассылки сообщений всем
События:
- onPlayerKnockedOut - Событие смерти игрока.
- onPlayerSpawn - Событие респауна игрока.
Помимо этого ещё пригодится RGB(), для настройки цвета сообщений.
Часть 2.
Создаём новый файл с расширением .js и открываем его любым редактором. (Рекомендуется Notepad++)
Так как этот учебник должен быть больше правильным чем лёгким, будем делать так, как рекомендуется разработчиками.
'use strict'; //Особенности JavaScript, которые "заставляют" писать скрипт правильно. "Use Strict" более чувствителен к ошибкам. global.gm = {}; //Глобальная таблица, охватывающая все скрипты в ресурсе. function init() { //Код который будет выполняться после запуска скрипта } function shutdown() { //Код который будет выполняться после остановки скрипта }
Сохраним данный файл под названием server_main.js в папке /myscript
Сам по себе скрипт не запустится, поэтому необходим файл meta.xml, который содержит в себе информацию о ресурсе, и всех его скриптах.
Примерно так будет выглядеть ваш meta.xml
<meta> <info name="Название ресурса" author="Имя автора" type="script" version="1.0"/> <script src="server_main.js" type="server" boot="true"/> </meta>
Про клиентскую и серверную сторону можете вкратце глянуть здесь: Ссылка
Про то как должна выглядеть meta.xml, что и зачем: Ссылка
Для примера, мы выведем части ресурса в другие скрипты, которые позже подключим с помощью require().
В Meta.xml добавляем 2 строки с названиями colors и events, обязательно до скрипта с тегом "boot".
В итоге получим следующее:
<meta> <info name="Название ресурса" author="Имя автора" type="script" version="1.0"/> <script src="colors.js" type="server"/> <script src="events.js" type="server"/> <script src="server_main.js" type="server" boot="true"/> </meta>
Далее создаём соответствующие файлы, и начинаем писать.
Часть 3.
Регистрируем цвета в глобальной таблице global.gm.
Для этого открываем colors.js и пишем:
'use strict'; module.exports = { }
module.exports - таблица которая будет читаться функцией require(), поэтому всё необходимое упаковываем в неё.
'use strict'; module.exports = { colors : { die : new RGB(255,0,0), //Красный цвет kill : new RGB(50,255,50), //Зелёный } }
Далее необходимо сделать так, что бы основной скрипт server_main.js зарегистрировал цвета. Делается это следующим образом:
В таблицу global.gm = {} вставляем функцию require() с ссылкой на наш скрипт colors.js.
global.gm = { colors : require("/colors.js") };
Ура! Теперь global.gm.colors.die будет красный цвет, как мы указали в colors.js.
Часть 4.
Регистрируем события в файле events.js. Начинаем с уже знакомого образца.
'use strict'; module.exports = { }
Но на этот раз он будет слегка другим, т.к. colors была всего лишь таблицей - сейчас мы создаём класс.
'use strict'; module.exports = class Name { }
Сразу необходимо подготовить массив, в котором будет храниться статистика игроков.
'use strict'; module.exports = class Name { construct() { this.PlayerStats = []; //Пустой массив PlayerStats } }
construct - постоянная функция, которая вызывается при использовании класса в функции new(), что нам и необходимо.
Далее приступаем к написанию функции которая меняет статистику игроков.
'use strict'; module.exports = class Name { construct() { this.PlayerStats = []; //Пустой массив PlayerStats } changeStatCount (player,attacker) { if (!!player) { if (!this.PlayerStats[player.id]) {this.PlayerStats[player.id] = [0,0]}; //Если в массиве нет значений, создать "нулёвый". [0] = смерти, [1] = убийства. this.PlayerStats[player.id][0]++; //Добавляем +1 смерть погибшему if (!!attacker) { //Если атакующий есть if (!this.PlayerStats[attacker.id]) {this.PlayerStats[attacker.id] = [0,0]}; this.PlayerStats[attacker.id][1]++; //Добавляем +1 убийство убийце } else { //Атакующего нет } } } }
Далее пораскинув мозгами понимаем что ловим баг, после выхода игрока с сервера необходимо чистить его ячейку массива, что-бы игрок попавший на его ID не получил "чужую" статистику.
Нам необходимо событие "когда игрок выходит с сервера".
- onPlayerDisconnect - Событие отключения игрока.
Дополняем наш скрипт.
'use strict'; module.exports = class Name { construct() { this.PlayerStats = []; //Пустой массив PlayerStats } changeStatCount (player,attacker) { if (!!player) { if (!this.PlayerStats[player.id]) {this.PlayerStats[player.id] = [0,0]}; //Если в массиве нет значений, создать "нулёвый". [0] = смерти, [1] = убийства. this.PlayerStats[player.id][0]++; //Добавляем +1 смерть погибшему if (!!attacker) { //Если атакующий есть if (!this.PlayerStats[attacker.id]) {this.PlayerStats[attacker.id] = [0,0]}; this.PlayerStats[attacker.id][1]++; //Добавляем +1 убийство убийце } else { //Атакующего нет } } } clearStats (player) { if (!!this.PlayerStats[player.id]) {this.PlayerStats[player.id] = null}; //Удаляем таковую, если имеется } }
Далее чего-то не хватает, точно, сообщения в чате! А так же подключаем скрипт BroadcastMessage(), для удобства.
Дополняем наш скрипт.
'use strict'; module.exports = class Name { construct() { this.PlayerStats = []; //Пустой массив PlayerStats } broadcastMessage(color, message) { if (!!color && !!message) { for (let i = 0; i < bullymp.players.length; i++) { if (!!bullymp.players[i]) { bullymp.players[i].sendMessage(color, message); } } } } changeStatCount (player,attacker) { if (!!player) { if (!this.PlayerStats[player.id]) {this.PlayerStats[player.id] = [0,0]}; //Если в массиве нет значений, создать "нулёвый". [0] = смерти, [1] = убийства. this.PlayerStats[player.id][0]++; //Добавляем +1 смерть погибшему var _playerStat = "(" + this.PlayerStats[player.id][0] + "/" + this.PlayerStats[player.id][1] + ")"; if (!!attacker) { //Если атакующий есть if (!this.PlayerStats[attacker.id]) {this.PlayerStats[attacker.id] = [0,0]}; this.PlayerStats[attacker.id][1]++; //Добавляем +1 убийство убийце var _attackerStat = "(" + this.PlayerStats[attacker.id][0] + "/" + this.PlayerStats[attacker.id][1] + ")"; attacker.sendMessage(global.gm.colors.kill,"[STATS] You kill " + player.name + " " + _playerStat + ".") return this.broadcastMessage(global.gm.colors.die,"[STATS] " + player.name + " " + _playerStat + " was killed by " + attacker.name + " " + _attackerStat + ".") } else { //Атакующего нет return this.broadcastMessage(global.gm.colors.die,"[STATS] " + player.name + " " + _playerStat + " doe.") } } } clearStats (player) { if (!!this.PlayerStats[player.id]) {this.PlayerStats[player.id] = null}; //Удаляем таковую, если имеется } }
Остаётся прикрепить функции к событиям?
'use strict'; module.exports = class Name { construct() { this.PlayerStats = []; //Пустой массив PlayerStats } broadcastMessage(color, message) { if (!!color && !!message) { for (let i = 0; i < bullymp.players.length; i++) { if (!!bullymp.players[i]) { bullymp.players[i].sendMessage(color, message); } } } } changeStatCount (player,attacker) { if (!!player) { if (!this.PlayerStats[player.id]) {this.PlayerStats[player.id] = [0,0]}; //Если в массиве нет значений, создать "нулёвый". [0] = смерти, [1] = убийства. this.PlayerStats[player.id][0]++; //Добавляем +1 смерть погибшему var _playerStat = "(" + this.PlayerStats[player.id][0] + "/" + this.PlayerStats[player.id][1] + ")"; if (!!attacker) { //Если атакующий есть if (!this.PlayerStats[attacker.id]) {this.PlayerStats[attacker.id] = [0,0]}; this.PlayerStats[attacker.id][1]++; //Добавляем +1 убийство убийце var _attackerStat = "(" + this.PlayerStats[attacker.id][0] + "/" + this.PlayerStats[attacker.id][1] + ")"; attacker.sendMessage(global.gm.colors.kill,"[STATS] You kill " + player.name + " " + _playerStat + ".") return this.broadcastMessage(global.gm.colors.die,"[STATS] " + player.name + " " + _playerStat + " was killed by " + attacker.name + " " + _attackerStat + ".") } else { //Атакующего нет return this.broadcastMessage(global.gm.colors.die,"[STATS] " + player.name + " " + _playerStat + " doe.") } } } clearStats (player) { if (!!this.PlayerStats[player.id]) {this.PlayerStats[player.id] = null}; //Удаляем таковую, если имеется } events_attach() { eventHandlers.add("onPlayerDisconnect", this.clearStats); eventHandlers.add("onPlayerKnockedOut", this.changeStatCount); } }
Осталось заставить всё это работать? Возвращаемся к server_main.js и вписываем events.js.
'use strict'; //Особенности JavaScript, которые "заставляют" писать скрипт правильно. "Use Strict" более чувствителен к ошибкам. global.gm = { colors : require("/colors.js"), events : require("/events.js") }; //Глобальная таблица, охватывающая все скрипты в ресурсе. function init() { //Код который будет выполняться после запуска скрипта } function shutdown() { //Код который будет выполняться после остановки скрипта }
Остаётся запустить global.gm.events.events_attach() из под init(), но не тут то было. construct - постоянная функция, которая вызывается при использовании класса в функции new(), что нам и необходимо.
Поэтому events : require("/events.js") меняем на events : new (require("/events.js"))()
И в конце добавляем global.gm.events.events_attach() в функцию init().
'use strict'; //Особенности JavaScript, которые "заставляют" писать скрипт правильно. "Use Strict" более чувствителен к ошибкам. global.gm = { colors : require("/colors.js"), events : new (require("/events.js"))() }; //Глобальная таблица, охватывающая все скрипты в ресурсе. function init() { global.gm.events.events_attach() //Код который будет выполняться после запуска скрипта } function shutdown() { //Код который будет выполняться после остановки скрипта }