Gross

Members
  • Content count

    6
  • Joined

  • Last visited

  • Days Won

    5

Gross last won the day on June 5 2017

Gross had the most liked content!

Community Reputation

9 Neutral

1 Follower

About Gross

  • Rank
    Newbie

Recent Profile Visitors

243 profile views
  1. Попробуй из 'main.css' убери вот это: display: none; на 16 строке, тогда окно начнет появлятся прям при спавне игрока, если этого не происходит, значит он у тебя не грузит html c веб-сервера по какой то причине
  2. Один из способов работы с UI клиента, с помощью CEF(HTML), на примере модального окна со списком игроков(ник, ip, ping) Дабы не использовать хостинг, развернем веб-сервер прямо в игровом сервере. Начнём. Создаем в каталоге 'packages/keker' папку 'ui' (в ней будут лежать клиентские файлы) и файл 'web.js', и объявляем его в 'packages/keker/index.js' добавив туда строку: require('./web'); В 'web.js' вставляем этот код: const http = require('http'); const fs = require('fs'); const path = require('path'); const url = require('url'); const mimeType = { // mime типы по расширениям файлов '.ico': 'image/x-icon', '.html': 'text/html', '.js': 'text/javascript', '.json': 'application/json', '.css': 'text/css', '.png': 'image/png', '.jpg': 'image/jpeg', '.wav': 'audio/wav', '.mp3': 'audio/mpeg', '.svg': 'image/svg+xml', '.pdf': 'application/pdf', '.doc': 'application/msword', '.eot': 'appliaction/vnd.ms-fontobject', '.ttf': 'aplication/font-sfnt' }; http.createServer(function (req, res) { res.setHeader('Access-Control-Allow-Origin', '*'); // разрешаем кросс-деменые запросы let parsedUrl = url.parse(req.url); // отсекаем от url все лишнее let filePath = __dirname+'/ui' + parsedUrl.pathname; // Парсим url в путь к файлу let ext = path.extname(filePath); // получаем расширение файла if(req.url=="/api/players_list.json"){ // отдельная ссылка для генерации JSON списка игроков let pl = { online: mp.players.length, slots: mp.players.size, players: [] } mp.players.forEach(player => { pl.players.push({ name: player.name, ip: player.ip, ping: player.ping }); }); res.writeHead(200, { 'Content-Type': mimeType['.json'] }); res.end(JSON.stringify(pl), 'utf-8'); } else { fs.readFile(filePath, function(error, content) { if (error) { if(error.code == 'ENOENT'){ // если файл отсутсвует res.writeHead(404, { 'Content-Type': 'text/plain' }); res.end('404 Not Found'); } else { // другие ошибки res.writeHead(500); res.end('Error: '+error.code+' ..\n'); } } else { res.writeHead(200, { 'Content-Type': mimeType[ext] || 'text/plain' }); res.end(content, 'utf-8'); } }); } }).listen(8080); // вешаем наш веб сервер на свободный порт, у меня это 8080 Он создает веб-сервер для выдачи статики из нашей папки 'ui'. В папку 'ui' добавляем наш HTML и CSS и JS файлы, HTML и CSS комментировать не буду, тут у всех на свой вкус players_list.html: <div class="p-list"> <p>Игроков онлайн: 0/100</p> <table id="pl-table" border="0" cellpadding="5"> <tr> <th>Имя:</th> <th>IP:</th> <th>Ping:</th> </tr> <tr><td>Nick</td><td>0.0.0.0</td><td>0</td></tr> </table> </div> main.css: .p-list { cursor: none; position: absolute; top: 20%; left: 20%; width: 60%; height: 60%; background: rgba(96,125,139,0.8); text-align: center; align-content: center; color: #eee; font-size: 18px; overflow-y: scroll; border: 1px solid #eee; border-radius: 5px; display: none; } .p-list p { padding: 8px 0px; } .p-list table { width: 100%; color: #eee; } .p-list tr { text-align: center; } .p-list td { border-top: 1px solid #eee; width: 30%; } ::-webkit-scrollbar { width: 12px; } ::-webkit-scrollbar-track { -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); border-radius: 10px; } ::-webkit-scrollbar-thumb { background: #37474F; border-radius: 10px; -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.5); } Туда же добавим и JS файл который будет отвечать за функционал. JQuery у нас уже подключен, его можно спокойно использовать. main.js: const addr = "http://127.0.0.1:8080/"; // Здесь обязательно задаем адресс вашего сервера и порт на котором висит веб var pl_enable = false; // флаг проверки открыто/скрыто окно со списком игроков var css_el = document.createElement("link"); // создаем элемент подключающий css css_el.rel = "stylesheet"; css_el.href = addr+"main.css"; $("head").append(css_el);// подключаем его в head $.get( addr+"players_list.html", function( data ) { // загружаем HTML нашего модального окна $("body").append( data ); // вставляем его в body }); $("body").keydown(function( e ) { // событие нажания на кнопку if(e.which == 9){ // 9 KeyCode кнопки TAB if(pl_enable){ // если модальное окно открыто скрываем его pl_enable = false; $('.p-list').hide(); } else { pl_enable = true; $.getJSON( addr+"api/players_list.json", function( data ) { // получаем список игроков $(".p-list p").html("<b>Игроков онлайн: "+data.online+"/"+data.slots+"</b>"); // кол-во онлайна let str = "<tr><th>Ник:</th><th>IP:</th><th>Ping:</th></tr>"; for(let i = 0; i < data.players.length; i++){ str += "<tr><td>"+data.players[i].name+"</td><td>"+data.players[i].ip+"</td><td>"+data.players[i].ping+"</td>"; } $("#pl-table").html(str); // запихиваем список в модальное окно }); $('.p-list').show(); // делаем его видимым } mp.invoke("focus", pl_enable); // отключаем игровой процесс делаем видимым курсор (он лагучий и находится под меню) //курсор можно накатать свой но нам это пока не надо } }); Теперь нужно отослать наш скрипт на исполнение игроку, я это сделал в 'common.js' на событие о подключении игрока: player.outputChatBox("<script src='http://127.0.0.1:8080/main.js'></script>"); // указываем ваш адрес сервера и веб порт /*кавычки только так, снаружи двойные внутри одинарные, по другому не сработало, если у вас обьем кода больше не забывайте экранировать кавычки */ Ну вот и все, теперь при нажатии на TAB в игре, должно открыться модальное окно со списком игроков. Так же в папку 'ui' можно полностью перенести стандартное меню и изменять уже его, переход на него будет выполнятся так: player.outputChatBox("<script>document.location.href = 'http://127.0.0.1:8080/index.html';</script>"); // не забываем подставить свой адрес и порт Так же в клиентских скриптах можно использовать этот метод для отправки команд на сервер: mp.invoke("command", "команда агрумент1 агрумент2 ..."); Веб-сервер выдает большинство mime типов так что можно подключать всякие фреймворки типа Bootstrap, Angular, React и прочие плюшки.
  3. Пример создания зон, территорий, и событий когда игрок входит/покидает их. Зоны будут 2х типов 2D и 3D, различия между ними в том что 3D зона имеет высоту равную ее радиусу, то есть если игрок находится выше или ниже радиуса зоны то он в ней не находится, 2D же зоны не имеют высоты и игрок находясь на любом уровне на/под ними все равно находится внутри. Создаем в каталоге 'packages/keker' файл 'zones.js', объявим его в 'packages/keker/index.js' добавив туда строку: require("./zones"); Добавляем в 'zones.js' этот код: mp.Vector3.Distance = function (v1, v2){ return (Math.sqrt(Math.pow((v2.x - v1.x),2) + Math.pow((v2.y - v1.y),2)+ Math.pow((v2.z - v1.z),2))); } mp.Vector3.Distance2D = function (v1, v2){ return (Math.sqrt(Math.pow((v2.x - v1.x),2) + Math.pow((v2.y - v1.y),2))); } var Zone = class Zone { constructor(n ,v, r, t){ this.name = n; // Название зоны this.center = v; // Центральная точка this.radius = r; // Радиус this.type = t; // Тип 2D или 3D this.insidePlayers = []; // Массив игроков находящихся в зоне this.interval = InitInterval(this); } BroadcastMessage(s){ // Фунция рассылки сообщения игрокам находящимся в нутри этой зоны this.insidePlayers.forEach(player => { player.outputChatBox(s); }); } } function InitInterval(zone){ return setInterval(function(){ mp.players.forEach(player => { let dist = (zone.type=="2D") ? mp.Vector3.Distance2D(player.position, zone.center) : mp.Vector3.Distance(player.position, zone.center); if(dist < zone.radius && zone.insidePlayers.indexOf(player) < 0){ zone.insidePlayers.push(player); mp.events.call("playerEnterZone", zone, player); } else if (dist > zone.radius && zone.insidePlayers.indexOf(player) >= 0){ zone.insidePlayers.splice(zone.insidePlayers.indexOf(player), 1); mp.events.call("playerExitZone", zone, player); } }) }, 500); } var Zones = class Zones { constructor(){ this._Zone = Zone; this.zones = []; } Add(n, v, r, t){ if(this.zones[n]) this.Remove(n); let z = new this._Zone(n, v, r, t); this.zones[n] = z; return z; } AddZone3D(n, v, r){ return this.Add(n, v, r, '3D'); } AddZone2D(n, v, r){ return this.Add(n, v, r, '2D'); } Remove(n){ let z = this.zones[n]; clearInterval(z.interval); delete this.zones[n]; } Get(n){ return this.zones[n]; } } mp.Zones = new Zones(); mp.events.add({"playerQuit" : (player, reason, kickReason) => { for(let key in mp.Zones.zones) { // Удаление игрока из зоны при выходе let zone = mp.Zones.zones[key]; if (zone.insidePlayers.indexOf(player) >= 0){ zone.insidePlayers.splice(zone.insidePlayers.indexOf(player), 1); } } } }); Теперь в любом удобном месте, или в 'events/common.js' добавляем события для зон: mp.events.add({ "playerEnterZone": (zone, player) => { /* Событие когда игрок вошел в зону на входе получаем zone - обьект зоны, и игрока - player */ }, "playerExitZone": (zone, player) => { /* Событие когда игрок покинул зону на входе получаем zone - обьект зоны, и игрока - player */ } }); Методы и свойства для работы с зонами: let zone = mp.Zones.AddZone3D("zone1", new mp.Vector3(10, 25, 46), 10); // Создает 3D зону с названием zone1, в точке X:10;Y:25;Z:46; и радиусом 10 let zone = mp.Zones.AddZone2D("zone1", new mp.Vector3(10, 25, 46), 10); // Создает 2D зону с названием zone1, в точке X:10;Y:25;Z:46; и радиусом 10 let zone = mp.Zones.Get('zone1'); // Получает зону с названием zone1 mp.Zones.Remove('zone1'); // Удаляет зону zone1 zone.BroadcastMessage("Сообщение"); // Рассылает игрокам находящимся в зоне чат сообщение; zone.insidePlayers // Массив с игроками находящимися в зоне zone.name // Название зоны Прошу строго не судить так как это костыльный метод, пока данный функционал не добавят в API.
  4. В этом топике будет приведен пример добавления некоторых методов в стандартное API RageMP, основной целью этого действа является сокращение кода и ускорение разработки в будущих скриптах. Пример: // За место этого: mp.players.forEach(_player => { _player.outputChatBox("Hello!!!"); }); //Можно будет использовать удобное сокращенное: mp.players.BroadcastMessage("Hello!!!"); Начнём. Создаем в каталоге 'packages/keker' файл 'new-api.js', и сразу же объявим его в 'packages/keker/index.js' добавив туда строку: require('./new-api'); Теперь начнем добавлять наш код в 'new-api.js', начнем с методов для работы с векторами, точнее для вычисления дистанции между ними: mp.Vector3.Distance = function (v1, v2){ return Math.abs(Math.sqrt(Math.pow((v2.x - v1.x),2) + Math.pow((v2.y - v1.y),2)+ Math.pow((v2.z - v1.z),2))); } // функция вычисляющая расстояние между двумя точками в пространстве X;Y;Z; mp.Vector3.Distance2D = function (v1, v2){ return Math.abs(Math.sqrt(Math.pow((v2.x - v1.x),2) + Math.pow((v2.y - v1.y),2))); } // функция вычисляющая расстояние между двумя точками на плоскости X;Y; Теперь их можно вызывать в любом месте вашего кода. Пример: let distance = mp.Vector3.Distance(player.position, player.veh.position); // Вернет расстояние от игрока до его машины в пространстве X;Y;Z let distance = mp.Vector3.Distance2D(player.position, player.veh.position); // Вернет расстояние от игрока до его машины в горизонтальной плоскости X;Y; Теперь добавим в 'new-api.js' методы broadcast'a сообщений и удобного спавна машин: mp.players.BroadcastMessage = function(s, v, d, c){ if(typeof v == 'undefined'){ // если функция вызвана с 1 параметром BroadcastMessage("Wellcome!!!"); this.forEach( player => { player.outputChatBox(s); }); } else if( typeof v == 'string'){ // если функция вызвана с параметром цвета BroadcastMessage("Wellcome!!!", "#ddd"); this.forEach(player => { player.outputChatBox("<font color='"+v+"'>"+s+"</font>"); }); } else if(typeof v == 'object' && typeof d == 'number'){ // если функция вызвана с параметром радиуса действия BroadcastMessage("Wellcome!!!", new mp.Vector3(0, 0, 0), 50); this.forEach(player => { if(Math.pow((player.position.x - v.x), 2) + Math.pow((player.position.y - v.y), 2) + Math.pow((player.position.z - v.z), 2) < Math.pow(d, 2)){ // проверяем находится ли игрок в заданом радиусе if(typeof c == 'string') { // если функция вызвана со всеми параметрами BroadcastMessage("Wellcome!!!", new mp.Vector3(0, 0, 0), 50, "#ddd"); player.outputChatBox("<font color='"+c+"'>"+s+"</font>"); } else { player.outputChatBox(s); } } }); } } // функция выводящая сообщение в чат либо всем игрокам онлайн, либо игрокам находящимся в определенном радиусе, так же позволяет задать цвет текста mp.vehicles.Spawn = function(m, x, y, z){ if(typeof x == 'number' && typeof y == 'number' && typeof z == 'number'){ return this.new(mp.joaat(m), new mp.Vector3(x, y, z)); } else if(typeof x == "object") { return this.new(mp.joaat(m), x); } } // Спавн транспорта в заданной точке, либо по координатам X;Y;Z, возвращает созданый транспорт Их вызов в дальнейшем будет выглядеть так: //за место этого довольно маштабного кода: mp.players.forEach(_player => { _player.outputChatBox("<font color='#ddd'>Hello!!!</font>"); }); // Теперь можно использовать это, эти несколько вариантов mp.players.BroadcastMessage("Hello!!!"); // Разошлет сообщение всем игрокам сервера mp.players.BroadcastMessage("Hello!!!", "#ddd"); // Разошлет сообщение всем игрокам сервера, цвет текста будет #ddd mp.players.BroadcastMessage("Hello!!!", player.position, 50); // Разошлет сообщение всем игрокам в радиусе 50м от текущего, Local Chat mp.players.BroadcastMessage("Hello!!!", player.position, 50, "red"); // Разошлет сообщения всем игрокам в радиусе 50м от текущего, цвет текста красный // Удобный спавн траспорта // За место этого: let veh = mp.vehicles.new(mp.joaat('sultanrs'), new mp.Vector3(200, 14, 25)); // Теперь можно использовать это: let veh = mp.vehicles.Spawn('sultanrs', 200, 14, 25); // Создаст транспорт в указаных координатах, и вернет его в переменную veh //или это: let pos = player.postion; pos.x += 2; let veh = mp.vehicles.Spawn('sultanrs', pos); // Создаст транспорт в указанной точке и вернет его Ну и пару методов для работы с игроком, можно как добавить в 'new-api.js' это: mp.events.add({"playerJoin": player => { player.TeleportTo = function(x, y, z){ if(typeof x == 'object'){ // если первый параметр является вектором this.position = x; } else if(typeof x == 'number' && typeof y == 'number' && typeof z == 'number'){ // если координаты заданы по отдельности this.position = new mp.Vector3(x, y, z); } } // функция телепорта игрока к заданой точке, либо по координатам X;Y;Z; player.Message = function(s, c){ if(typeof s == 'string' && typeof c == 'string'){ // если задан цвет this.outputChatBox("<font color='"+с+"'>"+s+"</font>"); } else if (typeof s == 'string'){ this.outputChatBox(s); } } // функция для быстрой отправки сообщения игроку в чат, с возможностью задать цвет текста } }); Либо вставить код от сюда в 'packages/keker/evens/common.js', вызов этих методов будет выглядеть так: // Телепорт игрока player.TeleportTo(player.veh.position.x-2, player.veh.position.y, player.veh.postion.z); // Телепортирует игрока к точке сбоку от его машины let pos = player.veh.position; pos.x -= 2 player.TeleportTo(pos); // сделает тоже самое только сдесь в функцию передается вектор а не координаты // Удобный вывод сообщений игроку, с возможностью задать цвет текста player.Message("Hello!!!"); // Отправит сообщение в чат игроку player.Message("Hello!!!", "#ddd"); // Отправит сообщение в чат игроку, цвет текста #ddd Ну вот и все, надеюсь, что кому нибудь пригодится!
  5. tutorial Add Command Line to server console

    Why, for quick installation through NPM?
  6. Create file 'commandline.js' to dir 'packages/keker' with the following code: const readline = require('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); function ParseCmd(s){ var args = s.split(" "); var cmd = args[0].toLowerCase(); var res = ''; switch(cmd){ case "ban": mp.players.forEach(player => { if(player.name.toLowerCase() == args[1].toLowerCase()){ player.ban("Console"); res = " Player "+player.name+" was banned!!!"; } }); break; case "kick": mp.players.forEach(player => { if(player.name.toLowerCase() == args[1].toLowerCase()){ player.kick("Console"); res = " Player "+player.name+" was kicked!!!"; } }); break; case "tppos": if(args.length>4){ mp.players.forEach(player => { if(player.name.toLowerCase() == args[1].toLowerCase()){ player.position = new mp.Vector3(parseFloat(args[2]), parseFloat(args[3]), parseFloat(args[4])); res = " Player "+player.name+" was teleported to X:"+parseFloat(args[2])+" Y:"+parseFloat(args[3])+" Z:"+parseFloat(args[4])+"!!!"; } }); } else { res = " Invalid arguments!!!" } break; case "give.weapons": if(args.length>3){ mp.players.forEach(player => { if(player.name.toLowerCase() == args[1].toLowerCase()){ player.giveWeapon(mp.joaat(args[2]), parseInt(args[3])); res = " Player "+player.name+" received weapons!!!"; } }); } else { res = " Invalid arguments!!!" } break; case "status": res = "\n Players: "+mp.players.length+"/"+mp.players.size+"\n Vehicles: "+mp.vehicles.length+"\n Objects: "+mp.objects.length+"\n Wheather: "+mp.environment.weather+"\n Game Time: "+mp.environment.time.hour+"h\n Uptime: "+process.uptime()+"\n"; break; case "online": res = "\n Online: "+mp.players.length+"/"+mp.players.size+"\n "; mp.players.forEach(player => { res += player.name+" | "+player.ip+" | "+player.ping+"\n "; }); break; default: res = " Unknown command!!!"; break; } return res; } rl.on('line', (s) => { var res = ParseCmd(s); console.log(res); }); After that, append to file 'packages/keker/index.js' the following line: require("./commandline"); Then you can execute commands on the server console. The list of available commands as seen from the code: ban <PlayerName> -> Kiked player kick <PlayerName> -> Baned player tppos <PlayerName> <X> <Y> <Z> -> Teleport player to coordinates give.weapons <PlayerName> <WeaponName> <Amount> -> Give weapon to player status -> Show server info online -> Show players list with info(Name,IP,Ping)