-
Posts
200 -
Joined
-
Last visited
Posts posted by N1kS
-
-
Vim - очень классный редактор для кода с поддержкой расширений/плагинов. Подсветка синтаксиса, предпросмотр картинок, команды, snippet. Поддержка проектов, миникарта. Этакий комбайн все в одном. при этом минималистически выглядит и достаточно удобный.
- 1
-
Для получения информации от сервера используется UDP ASE порт, по стандарту он игровой+123, то есть если игровой 22003, то ASE порт 22126. Спецификацию ASE порта можно найти тут: https://github.com/multitheftauto/mtasa-blue/blob/master/Server/mods/deathmatch/logic/ASE.cpp#L246-L341
- 2
-
47 minutes ago, Kernell said:
Никогда не используйте SELECT * в своих проектах, всегда указывайте реально нужные поля для выборки.
Предположим(по примеру), что мне необходимо получить id, name, surname, age, adminLevel конкретного игрока, зачем мне указывать конкретные поля для выборки, если * - это и есть все необходимые поля? Другой вопрос, если при создании таблицы создаются дополнительные колонки, например created_at, updated_at, которые нам знать не нужно. В таком случае - да, это замедлит скорость запроса, да и мы забьем память совершенно не нужной нам информацией.
SELECT * FROM `players` WHERE id=1
SELECT `id`, `name`, `surname`, `age`, `adminLevel` FROM `players` WHERE id=1
Совет совершенно верный, но лишь для частных случаев. Всегда нужно понимать, какие поля необходимы в конечном результате запроса. Чуть позже обновлю тему и допишу данный совет.
-
Нет, не ошибаетесь, не совсем то написал. Ресурсы запущены всегда, просто нужно будет установить порядок, какой запуститься первым, а какой второй. Далее с помощью события onClientResourceStart уже отслеживать.
- 1
-
Самый простой вариант - запускать основной ресурс, назовем его для примера Core, далее после запуска основного ресурса запускаются уже вспомогательные ресурсы из основного ресурса(его нужно будет добавить в ACL с правами админа), Vehilces, Weapons, Skins, опять же для примера. Соответственно пишем, что качаются вспомогательные ресурсы, отслеживаем состояние того или иного вспомогательного ресурса, после его запуска убираем текст о том, что качается тот или иной ресурс.
-
- Popular Post
Данный урок предполагает, что вы уже знаете, что такое MySQL, как это работает и зачем это нужно, если же нет - ознакомитесь с данным уроком и вернитесь сюда! Цель данного урока - донести до вас некоторые вещи, которые вы, возможно, не понимаете или даже не задумывались о них.
Немного теории
MySQL - свободная реляционная система управления базами данных. Для работы с базой используется язык структурированных запросов(он же SQL). Более подробную и интересующую Вас информацию об SQL, Вы сможете найти на просторах интернета. Мы же поговорим о ключевых моментах работы с MySQL. SQL имеет 4 основных оператора для манипуляции с данными.
- SELECT - выбор данных, удовлетворяющих заданные условия.
- INSERT - добавление новых данных.
- UPDATE - изменение существующих данных.
- DELETE - удаление указанных данных
Я не буду рассказывать вам о существующих типах данных MySQL, как создавать или удалять таблицы, я лишь хочу поделиться с вами ключевыми вещами, которые помогут вам оптимизировать работу вашего сервера и уменьшить нагрузку на него.
Рассмотрим на основе примера
В качестве примера для данного урока будет использоваться таблица с названием players, имеющая следующие столбцы:
`id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `surname` varchar(255) NOT NULL, `age` tinyint(3) NOT NULL, `adminLevel` tinyint(3) NOT NULL DEFAULT '0', PRIMARY KEY (`id`)
Тут я думаю все понятно, никаких проблем быть не должно. Для примера рассмотрим несколько запросов.
Получаем всех игроков:
SELECT `id`, `name`, `surname`, `age`, `adminLevel` FROM `players`
Получаем игрока с конкретным id:
SELECT `id`, `name`, `surname`, `age`, `adminLevel` FROM `players` WHERE id=117
Получаем всех игроков, имя которых равно какому-то конкретному значению:
SELECT `id`, `name`, `surname`, `age`, `adminLevel` FROM `players` WHERE name="Bobby"
Получаем первых 10 игроков, возраст которых равен 19 лет:
SELECT `id`, `name`, `surname`, `age`, `adminLevel` FROM `players` WHERE age=19 LIMIT 10
Получаем всех игроков, возраст которых больше или равен 18 годам:
SELECT `id`, `name`, `surname`, `age`, `adminLevel` FROM `players` WHERE age >= 18
Ну тут все просто, пришло время рассмотреть все на основе конкретных примеров и указать ключевые особенности.
Неправильный выбор функции для формирования запроса
Это первая и наиболее часто встречающаяся ошибка, которую я вижу в коде различных разработчиков. Для формирования запроса к MySQL в МТА существует 2 функции, а именно: dbExec и dbQuery. Обе функции выполняют запрос, но их главная особенность заключается в том, что dbQuery возвращает какой-либо результат и тем самым занимает оперативную память сервера, а dbExec нет. Очень часто разработчики забывают использовать dbFree после запроса, для создания, редактирования или удаления какой-то записи. Рассмотрим на основе простого примера создания нового пользователя:
local Name = "Bobby" local Surname = "Raily" local Age = 23 dbExec(dbConnection, "INSERT INTO `players` (name, surname, age) VALUES(?, ?, ?)", Name, Surname, Age)
Опять же, все просто, сформировали простой запрос, создали новую запись в таблице players с заданными значениями. Можно, конечно, реализовать это с помощью dbQuery, но обязательно не стоит забывать про dbFree! Казалось бы, а что такого? Но все дело в том, что если у вас на сервере зарегистрируется большое количество игроков, то это порядком забьет память ненужной ерундой, проще говоря мусором, который хранить на сервере нет никакой необходимости.
local Name = "Bobby" local Surname = "Raily" local Age = 23 local Query = dbQuery(dbConnection, "INSERT INTO `players` (name, surname, age) VALUES(?, ?, ?)", Name, Surname, Age) dbFree(Query)
Я надеюсь, что вы четко и ясно уяснили для себя этот пункт, на это стоит обратить особое внимание.
Некорректное использование dbQuery для получения результата запроса
Очень часто вам необходимо получить какие-то данные из базы данных. В этом нам помогают dbQuery и dbPoll. Если внимательно посмотреть на синтаксис функции dbQuery, то вы увидите, что в качестве первого необязательного аргумента она принимает callback функцию. Что же это такое и зачем это нужно? Я настоятельно рекомендую вам как можно внимательнее и ответственнее подойти к этому вопросу, т.к. многие разработчики до сих пор не до конца уловили суть данного аргумента и не понимают из-за чего происходят "фризы" во время работы того или иного скрипта. Предположим, что у нас зарегистрировано 100 000 уникальных игроков(для крупного проекта - вполне себе реально, но мы рассматриваем все в теории). Нам необходимо получить список всех имеющихся игроков. Вы должны понимать, что это не произойдет моментально, в любом случае на данную операцию будет затрачено какое-то количество времени. Рассмотрим два примера, использование запроса без callback функции и с ней соответственно:
local Players = dbPoll(dbQuery(dbConnection, "SELECT * FROM `players`"), -1) for Index, PlayerData in ipairs(Players) do print(PlayerData.name) end
function CallbackFunction(qh, tag, score) local Players = dbPoll(qh, 0) for Index, PlayerData in ipairs(Players) do print(PlayerData.name) end end dbQuery(CallbackFunction, dbConnection, "SELECT `id`, `name`, `surname`, `age`, `adminLevel` FROM `players`")
Время, занявшее на выполнение данного запроса, составило 489 мс. Так в чем же характерная особенность между первым и вторым способом? Особенность заключается в том, что пока выполняется получение данных из базы первым способом, то работа нашего сервера приостановиться на время, которое необходимо для выполнения данного запроса, что может негативно повлиять на всех игроков, в результате могут возникнуть такие вещи как фризы, рассинхронизация и т.д. Поэтому вы четко должны понимать для себя нужно вам это или нет. Если же вам необходимо, чтобы работа сервера была приостановлена на время выполнения запроса - используйте первый вариант, если же нет - второй. Если же вы до этого имели опыт с другими ЯП, то вероятнее всего понимаете, что такое синхронное и асинхронное выполнение. Первый вариант - это синхронное выполнение, второй - асинхронное.
Выполнение лишней работы посредством Lua
Так же очень часто наблюдаю картину, когда многие разработчики выполняют лишнюю работу, а именно предпринимают лишние действия, которые можно было сформировать в результате SQL запроса. SQL существует довольно большое количество времени и за это время овладел всеми необходимыми функциями, операторами и прочими вещами для формирование корректного запроса. К примеру мы хотим получить id всех игроков, adminLevel которых выше или равен 2.
Как видно из запроса - мы сразу же получаем список игроков, уровень которых равен или больше 2
function CallbackFunction(qh, tag, score) local Players = dbPoll(qh, 0) for Index, PlayerData in ipairs(Players) do print(PlayerData.id) end end dbQuery(CallbackFunction, dbConnection, "SELECT `id`, `name`, `surname`, `age`, `adminLevel` FROM `players` WHERE adminLevel >= 2")
Но иногда мне приходится видеть, как некоторые разработчики получают список всех игроков и начинают проверь их adminLevel посредством Lua, что само по себе не имеет никакого смысла, т.к это выполнение лишней работы.
function CallbackFunction(qh, tag, score) local Players = dbPoll(qh, 0) for Index, PlayerData in ipairs(Players) do if PlayerData.adminLevel >= 2 then print(PlayerData.id) end end end dbQuery(CallbackFunction, dbConnection, "SELECT `id`, `name`, `surname`, `age`, `adminLevel` FROM `players`")
Заключение
Надеюсь, что вы не зря потратили свое время и подчеркнули для себя какие-то полезные вещи, которые в последствии помогут вам при разработке собственного игрового режима или мода. Если же у вас остались какие то вопросы или вам что-то непонятно - вы можете оставлять свои вопросы в данной теме.
- 5
-
Ну делай тогда все в одному ресурсе, ты создаешь из мухи слона, на самом то деле.
-
@fabervox, я говорил, что скрипт сложный? Что за идиотская причина просто трепать языком? Напиши скрипт, запусти у себя, сделай замеры по времени и выложи исходный код сюда.
-
@Essle, ну реализовать то можно, но это будет громоздко и будет занимать не малое кол-во времени, да и зачем? Куда проще запустить стандартный editor, полетать, удалить необходимые тебе мировые объекты, сохранить это все и просто в последствии запускать отдельным ресурсом при необходимости.
-
@Jonathan.P, а что на счет файла utils.lua и type="shared"? Как по мне - самый адекватный вариант подключения необходимых функций для работы, это во-первых. Во-вторых, ты серьезно хочешь сказать, что ты используешь хотя бы 20-25% своего "набора некоторых функций" в каждом ресурсе? Не думаю. Используй необходимые тебе функции для работы конкретного ресурса, зачем что-то усложнять?
-
Спасибо за наводку!
Shader_tex_names - отличная прога, мне помогла.
Это не прога, а скрипт.
Дое......ся
Ты горишь?
-
Почему вы поворачиваете стрелку на скорость авто, а не угол? Если скорость выше, чем макс. скорость на спидометре - ваша стрелка уйдет за отсечку. Используйте функцию ниже, чтобы стрелка не уходила куда не нужно.
function math.clamp(val, lower, upper) if lower > upper then lower, upper = upper, lower end return math.max(lower, math.min(upper, val)) end
-
Спасибо за наводку!
Shader_tex_names - отличная прога, мне помогла.
Это не прога, а скрипт.
-
Works for me:
function fileSave( sFile, sData ) if fileExists( sFile ) then fileDelete( sFile ); end local pFile = fileCreate( sFile ); fileWrite( pFile, sData ); fileClose( pFile ); end function fileLoad( sFile ) local pFile = fileOpen( sFile, true ); local sData = fileRead( pFile, fileGetSize( pFile ) ); fileClose( pFile ); return sData; end local FROM="example.lua" local TO="compiled.luac" fetchRemote( "https://luac.multitheftauto.com/?compile=1&debug=0&obfuscate=0", function(data) print( tostring( data ) ) fileSave( TO, data ) end, fileLoad( FROM ), true );
-
1. Большая ли будет нагрузка, если сделать к примеру 200-1000 setElementData с разными ключами и значениями в них? Изменяться они будут только 1 раз, при входе на сервер, а далее только буду получать значения с этих ключей.
2. И что именно дает 4й аргумент (синхронизация с сервером), при каких условиях его можно использовать?
3. Повлияет ли это как-то на нагрузку сервера?
Если же нагрузка большая будет, то какие альтернативные варианты Вы можете предложить? Буду крайне благодарен за ответы.
1. Лучше использовать таблицу, т.к скорость выше с таблицы.
2. Этот аргумент означает, что если вы повести дату с сервера, то сможете получить к ней доступ на клиенте.
3. Оперативная память.
-
Покажите саму функцию, пожалуйста. Нагрузка на сервер зависит именно от функции. Если функция сама по себе емкая, то при таймере 60000, 60 - вы будете нагружать сервер 60 раз, при 3600000, 1 - один раз.
-
You can write it...
function fileSave( File, Data ) if( fileExists( File ) ) then fileDelete( File ); end local File = fileCreate( File ); fileWrite( File, Data ); fileClose( File ); end function fileLoad( File ) return fileRead( File, fileGetSize( File ) ); end
-
Okay. I have to cut my image through pixel shader from angle. Small exaple for 2 cases:
Ok, done: http://pastebin.com/nMX2q4by.
Close please.
-
Который жрет нормальных 4 байта, а не 8.
-
Hello guys!
I'm trying to make speedometer and need your help. I need to cut image around the circle, depending on the angle (from 0 to 360 degrees)
Image:
-
Если пинг между игроков и сервером 500мс, то в 2 конца это 1 секунда. Ну такое...
Да, секунда задержки для стрельбы это много.
Есть предложения по лучше как это можно сделать? Мне кажется можно сразу с сервера на определенные клиенты.
Будет куда рациональнее.
-
Если пинг между игроков и сервером 500мс, то в 2 конца это 1 секунда. Ну такое...
-
Да просто шифруйте модель и все. Пусть у клиента лежит зашифрованная модель. Вряд ли она ему пригодится.
-
Надеюсь суть ясна, если что - добро пожаловать в скайп.
Вакансии НПО "Проект GREIS"
in Russian / Русский
Posted · Edited by N1kS
C#, C++, готов сотрудничать, скайп в подписи.