SAMP.Lua

Изначально эта библиотека задумывалась как простой апи исключительно для обработки сетевых пакетов, но в процессе было решешо, что лучше бы сделать её полноценной библиотекой для работы с сампом, в будущем это позволит избавить от необходимости использования SAMPFUNCS. Пока реализован только модуль, значительно упрощающий работу с пакетами, так что говорить сейчас будем о нём.

SAMP.Events
Этот модуль добавляет событийную обработку входящих и исходящих RakNet пакетов. Имеет удобный API, полностью кастомизируем, предоставляет те же возможности, что и обычные хуки: чтение, перезапись, игнорирование.


Использование
Простой пример обработки исходящего сообщения в чат:
Lua:
local sampev = require 'lib.samp.events'

function sampev.onSendChat(msg)
  print('You said: ' .. msg)
end
Да, настолько просто. Нужно лишь загрузить библиотеку и добавить функцию с соответствующими аргументами, вот и всё.
Перезапись данных в пакете настолько же проста, нужно лишь вернуть из функции все значения в том же порядке, занеся их в таблицу.
Lua:
function sampev.onSendChat(msg)
  return {'I said: ' .. msg}
end
Будет дописывать текст "I said:" в начало каждого отправляемого сообщения.
Если вернуть из функции false, то пакет будет проигнорирован клиентом. Этот код запретит серверу изменять позицию игрока:
Lua:
function sampev.onSetPlayerPos(position)
  print(string.format('Server tried to change your position to %0.2f %0.2f %0.2f', position.x, position.y, position.z))
  return false
end
Структуры всех пакетов находятся в файле events.lua.

Перезапись исходящих пакетов синхронизации слегка отличается от всех остальных - они не требуют возврата аргументов, а вместо этого данные перезаписываются как в обычной таблице lua. Это сделано для повышения производительности.
Пример перезаписи позиции в исходящих данных синхронизации игрока:
Lua:
function sampev.onSendPlayerSync(data)
  print('Original position:', data.position.x, data.position.y, data.position.z)
  data.position.x = 1337
  data.position.y = 1488
  data.position.z = 228
end
Это применимо только в событиях onSendPlayerSync, onSendVehicleSync, onSendPassengerSync, onSendAimSync, onSendUnoccupiedSync, onSendTrailerSync, onSendBulletSync, onSendSpectatorSync.
Структуры всех пакетов синхронизации находятся в файле synchronization.lua.


Примеры скриптов
AntiCarJack - перехват и игнорирование входящего RPC и пакета синхронизации
Bubble Sniffer - перехват и обработка входящего RPC
DerpCam - перезапись данных исходящего пакета синхронизации
Chat Bliss - перезапись, игнорирование и обработка исходящего RPC


Кастомизация
API структурирован так, что позволяет вносить в него любые изменения, не прибегая к изменению исходных файлов модулей.
Добавление своего обработчика для серверного пакета проигрывания звука:
Lua:
local sampev = 'lib.samp.events'
local raknet = 'lib.samp.raknet'
sampev.INTERFACE.INCOMING_RPCS[raknet.RPC.PLAYSOUND] = {'onPlaySound', {soundId = 'int32'}, {x = 'float'}, {y = 'float'}, {z = 'float'}}
И теперь в тот же файл можно добавить функцию для обработки события:
Lua:
function sampev.onPlaySound(sound, x, y, z)
-- добавляем сообщение в лог
print(string.format('Sound %d at coords %0.2f, %0.2f, %0.2f', sound, x, y, z))
-- и отключаем звук, запрещая дальнейшую обработку пакета
return false
end
Следует сразу разобрать код регистрации события, чтобы стало понятнее.
Lua:
sampev.INTERFACE. -- поле INTERFACE - это все экспортируемые элементы модуля
INCOMING_RPCS -- обращение к списку входящих RPC
[raknet.RPC.PLAYSOUND] -- обращение к элементу таблицы INCOMING_RPCS по индексу, в данном случае INCOMING_RPCS - это таблица, содержащая список структур всех входящих RPC, а raknet.RPC.PLAYSOUND - идентификатор требуемого RPC
= -- присваиваем ему новое значение - таблицу с информацией о событии и структурой пакета
{'onPlaySound', -- название события, функция события будет использовать это имя
-- структура пакета. каждый параметр должен быть заключен в отдельную таблицу, иметь название и тип в формате {названиеПараметра = 'тип'}
{soundId = 'int32'}, {coords = 'vector3d'}}
Очевидно, что INCOMING_RPCS - это не единственная таблица, их четыре:
INCOMING_RPCS - входящие RPC
OUTCOMING_RPCS - исходящие RPC
INCOMING_PACKETS - входящие пакеты
OUTCOMING_PACKETS - исходящие пакеты

Новый тип тоже можно добавить без изменения исходников библиотеки:
Lua:
events.INTERFACE.BitStreamIO.fvector3 = { -- название типа после последней точки
   read = function(bs) -- функция чтения. первый аргумент - битстрим
     local vec = {}
     vec.x = raknetBitStreamReadFloat(bs)
     vec.y = raknetBitStreamReadFloat(bs)
     vec.z = raknetBitStreamReadFloat(bs)
     return vec
   end,
   write = function(bs, value) -- функция записи
     raknetBitStreamWriteFloat(bs, value.x)
     raknetBitStreamWriteFloat(bs, value.y)
     raknetBitStreamWriteFloat(bs, value.z)
   end
}
В случае, если пакет имеет какую-то сложную структуру, не описываемую даже с помощью пользовательских типов, то вместо структуры можно передать функцию, которая будет обрабатывать данные. Например как это сделано для RPC InitGame:
Lua:
INCOMING_RPCS[RPC.INITGAME] = {'onInitGame', onInitGameReader, onInitGameWriter} -- второй и третий аргумент - это функции чтения и записи
Для большего количества примеров смотрите исходный код.

Что касается всей библиотеки в целом, то она ещё находится на зачаточной стадии и обсуждать кроме планов нечего. По сути она должна заменить собой основную часть SAMPFUNCS - моддинг сампа.

Скачать последнюю версию и следить за изменениями всегда можно на GitHub.
Установка: скачать samp.zip из последнего релиза и целиком скопировать папку 'samp' (не содержимое папки!) из архива в каталог 'moonloader/lib/'.

Любая помощь в разработке приветствуется, особенно с добавлением новых структур. Предложите Pull request на гитхабе или напишите в этой теме.

Ну и конечно же крохотное нано-спасибо hnnssy за помощь.
 
Последнее редактирование:

Salik_Davince

Известный
37
3
Поставил я логи хотел посмотреть смогу ли я зайти на сервер DL, по сути должен. Я скорее думаю как то можно отослать пакет о фейковом клиенте и зайти на сервер, но -

Код:
--{'onSendClientJoin', {version = 'int32'}, {mod = 'int8'}, {nickname = 'string8'}, {challengeResponse = 'int32'}, {joinAuthKey = 'string8'}, {clientVer = 'string8'}, {challengeResponse2 = 'int32'}}

function SE.onSendClientJoin(version, mod, nickname, challengeResponse, joinAuthKey, clientVer, challengeResponse2)
    sampAddChatMessage(string.format("version: %d / mod: %d / chR = %d / JAK = %s / clientVer = %s / chr2 = %d ", version, mod, challengeResponse, joinAuthKey, clientVer, challengeResponse2), 0xFFFFFF)
    clientVer = "0.3.DL-R1"
    sampAddChatMessage(string.format("version: %d / mod: %d / chR = %d / JAK = %s / clientVer = %s / chr2 = %d ", version, mod, challengeResponse, joinAuthKey, clientVer, challengeResponse2), 0xFFFFFF)
end

Захожу на сервер выводит - Incorrect Version, по сути я поменял версию, где то еще есть проверка на версию SAMP'a?
 

imring

Ride the Lightning
Всефорумный модератор
2,355
2,516
Поставил я логи хотел посмотреть смогу ли я зайти на сервер DL, по сути должен. Я скорее думаю как то можно отослать пакет о фейковом клиенте и зайти на сервер, но -

Код:
--{'onSendClientJoin', {version = 'int32'}, {mod = 'int8'}, {nickname = 'string8'}, {challengeResponse = 'int32'}, {joinAuthKey = 'string8'}, {clientVer = 'string8'}, {challengeResponse2 = 'int32'}}

function SE.onSendClientJoin(version, mod, nickname, challengeResponse, joinAuthKey, clientVer, challengeResponse2)
    sampAddChatMessage(string.format("version: %d / mod: %d / chR = %d / JAK = %s / clientVer = %s / chr2 = %d ", version, mod, challengeResponse, joinAuthKey, clientVer, challengeResponse2), 0xFFFFFF)
    clientVer = "0.3.DL-R1"
    sampAddChatMessage(string.format("version: %d / mod: %d / chR = %d / JAK = %s / clientVer = %s / chr2 = %d ", version, mod, challengeResponse, joinAuthKey, clientVer, challengeResponse2), 0xFFFFFF)
end

Захожу на сервер выводит - Incorrect Version, по сути я поменял версию, где то еще есть проверка на версию SAMP'a?
ты забыл вернуть это всё
Lua:
return {version, mod, nickname, challengeResponse, joinAuthKey, clientVer, challengeResponse2}
 

Salik_Davince

Известный
37
3
@imring так же осталось, ничего не происходит при смене :(

------------------------------

Andreas MultiPlayer\moonloader\lib\samp\events\core.lua:23: samp.events requires SAMPFUNCS

Значит все еще зависим? Я думал можно будет юзать в DL... Ждать так же?))
 

imring

Ride the Lightning
Всефорумный модератор
2,355
2,516
@imring так же осталось, ничего не происходит при смене :(

------------------------------

Andreas MultiPlayer\moonloader\lib\samp\events\core.lua:23: samp.events requires SAMPFUNCS

Значит все еще зависим? Я думал можно будет юзать в DL... Ждать так же?))
SAMP.lua зависим от SAMPFUNCS, но не MoonLoader.
 
  • Нравится
Реакции: AnWu

ak4k1y

Участник
71
7
Объясните пожалуйста как узнать цвет объекта установленного сервером? пытаюсь через
function sampev.onCreateObject(objectId, data)
end
, Но там нет такого, и вообще большинство переменных в data. показывают nil

Не понятно как считать переменные из таблицы data.materials , этой таблицы как буд то нет
 
Последнее редактирование:

FYP

Известный
Автор темы
Администратор
1,758
5,723
Обновление.
Были добавлены события для всех RPC и пакетов, которые есть в SA-MP, выявлены почти все неизвестные значения пакетов и структур синхронизации, есть некоторые исправления.
Некоторые изменения пришлось откатить ради сохранения обратной совместимости, все эти изменения вместе с новыми фичами будут в следующем крупном обновлении.
  • Новые события серверных RPC: onClientCheck, onDestroyActor, onDestroyWeaponPickup, onEditAttachedObject, onToggleCameraTargetNotifying, onEnterSelectObject, onPlayerExitVehicle, onVehicleTuningNotification, onServerStatisticsResponse, onEnterEditObject, onVehicleDamageStatusUpdate, onDisableVehicleCollisions, onToggleWidescreen, onSetVehicleTires, onSetPlayerDrunkVisuals, onSetPlayerDrunkHandling, onApplyActorAnimation, onClearActorAnimation, onSetActorFacingAngle, onSetActorPos, onSetActorHealth, onSetPlayerObjectNoCameraCol
  • Новые события клиентских RPC: onSendMoneyIncreaseNotification, onSendNPCJoin, onSendServerStatisticsRequest, onSendPickedUpWeapon, onSendCameraTargetUpdate, onSendGiveActorDamage
  • Новые события серверных пакетов: onAuthenticationRequest, onConnectionRequestAccepted, onConnectionLost, onConnectionBanned, onConnectionAttemptFailed, onConnectionNoFreeSlot, onConnectionPasswordInvalid, onConnectionClosed
  • Новые события клиентских пакетов: onSendWeaponsUpdate, onSendAuthenticationResponse
  • Выявлены неизвестные значения большинства RPC, пакетов и структур синхронизации
  • Исправлено событие onApplyPlayerAnimation: недостающий параметр frameDelta
  • Исправлено потенциальное неопределенное поведение при обработке исходящих пакетов синхронизации
 

pipsqueak

Участник
57
39
Обновление.
Были добавлены события для всех RPC и пакетов, которые есть в SA-MP, выявлены почти все неизвестные значения пакетов и структур синхронизации, есть некоторые исправления.
Некоторые изменения пришлось откатить ради сохранения обратной совместимости, все эти изменения вместе с новыми фичами будут в следующем крупном обновлении.
  • Новые события серверных RPC: onClientCheck, onDestroyActor, onDestroyWeaponPickup, onEditAttachedObject, onToggleCameraTargetNotifying, onEnterSelectObject, onPlayerExitVehicle, onVehicleTuningNotification, onServerStatisticsResponse, onEnterEditObject, onVehicleDamageStatusUpdate, onDisableVehicleCollisions, onToggleWidescreen, onSetVehicleTires, onSetPlayerDrunkVisuals, onSetPlayerDrunkHandling, onApplyActorAnimation, onClearActorAnimation, onSetActorFacingAngle, onSetActorPos, onSetActorHealth, onSetPlayerObjectNoCameraCol
  • Новые события клиентских RPC: onSendMoneyIncreaseNotification, onSendNPCJoin, onSendServerStatisticsRequest, onSendPickedUpWeapon, onSendCameraTargetUpdate, onSendGiveActorDamage
  • Новые события серверных пакетов: onAuthenticationRequest, onConnectionRequestAccepted, onConnectionLost, onConnectionBanned, onConnectionAttemptFailed, onConnectionNoFreeSlot, onConnectionPasswordInvalid, onConnectionClosed
  • Новые события клиентских пакетов: onSendWeaponsUpdate, onSendAuthenticationResponse
  • Выявлены неизвестные значения большинства RPC, пакетов и структур синхронизации
  • Исправлено событие onApplyPlayerAnimation: недостающий параметр frameDelta
  • Исправлено потенциальное неопределенное поведение при обработке исходящих пакетов синхронизации
А как же RakPeer пакеты ?
 
Последнее редактирование:

FYP

Известный
Автор темы
Администратор
1,758
5,723
А как же RakPeer пакеты ?
сервисные пакеты не доходят до событий сампфункса (onReceivePacket и другие в мунлоадере). более того, их нельзя перехватывать в потоке игры, поскольку они обрабатываются в отдельном потоке ракнета.
 
  • Нравится
  • Клоун
Реакции: Fott и pipsqueak

paulohardy

вы еще постите говно? тогда я иду к вам
Всефорумный модератор
1,891
1,254
Обновление.
Были добавлены события для всех RPC и пакетов, которые есть в SA-MP, выявлены почти все неизвестные значения пакетов и структур синхронизации, есть некоторые исправления.
Некоторые изменения пришлось откатить ради сохранения обратной совместимости, все эти изменения вместе с новыми фичами будут в следующем крупном обновлении.
  • Новые события серверных RPC: onClientCheck, onDestroyActor, onDestroyWeaponPickup, onEditAttachedObject, onToggleCameraTargetNotifying, onEnterSelectObject, onPlayerExitVehicle, onVehicleTuningNotification, onServerStatisticsResponse, onEnterEditObject, onVehicleDamageStatusUpdate, onDisableVehicleCollisions, onToggleWidescreen, onSetVehicleTires, onSetPlayerDrunkVisuals, onSetPlayerDrunkHandling, onApplyActorAnimation, onClearActorAnimation, onSetActorFacingAngle, onSetActorPos, onSetActorHealth, onSetPlayerObjectNoCameraCol
  • Новые события клиентских RPC: onSendMoneyIncreaseNotification, onSendNPCJoin, onSendServerStatisticsRequest, onSendPickedUpWeapon, onSendCameraTargetUpdate, onSendGiveActorDamage
  • Новые события серверных пакетов: onAuthenticationRequest, onConnectionRequestAccepted, onConnectionLost, onConnectionBanned, onConnectionAttemptFailed, onConnectionNoFreeSlot, onConnectionPasswordInvalid, onConnectionClosed
  • Новые события клиентских пакетов: onSendWeaponsUpdate, onSendAuthenticationResponse
  • Выявлены неизвестные значения большинства RPC, пакетов и структур синхронизации
  • Исправлено событие onApplyPlayerAnimation: недостающий параметр frameDelta
  • Исправлено потенциальное неопределенное поведение при обработке исходящих пакетов синхронизации
После обновы вылезает ошибка при создании текстдрава через битстрим, почему так?
передаю таблицей, до установки новой версии всё было ок
Код:
local bs = raknetNewBitStream()
handler.on_show_textdraw_writer(bs, {tonumber(id), {flags = data.flags, letterWidth = data.letterWidth, letterHeight = data.letterHeight, letterColor = data.letterColor, lineWidth = data.lineWidth, lineHeight = data.lineHeight, boxColor = data.boxColor, shadow = data.shadow, outline = data.outline, backgroundColor = data.backgroundColor, style = data.style, selectable = data.selectable, position = data.position, modelId = data.modelId, rotation = data.rotation, zoom = data.zoom, color = data.color, text = data.text}})
raknetEmulRpcReceiveBitStream(134, bs)
raknetDeleteBitStream(bs)
[ML] (error) script.lua: E:\Grand Theft Auto San Andreas\moonloader\script.lua:45: attempt to call field 'on_show_textdraw_writer' (a nil value)
stack traceback:
E:\Grand Theft Auto San Andreas\moonloader\script.lua:45: in function 'createTextDraw'
E:\Grand Theft Auto San Andreas\moonloader\script.lua:27: in function 'getServer'
E:\Grand Theft Auto San Andreas\moonloader\script.lua:17: in function 'callback'
...eft Auto San Andreas\moonloader\lib\samp\events\core.lua:79: in function <...eft Auto San Andreas\moonloader\lib\samp\events\core.lua:53>
 
  • Bug
  • Нравится
Реакции: Ya Zaregalsya и pipsqueak

pipsqueak

Участник
57
39
После обновы вылезает ошибка при создании текстдрава через битстрим, почему так?
передаю таблицей, до установки новой версии всё было ок
Код:
local bs = raknetNewBitStream()
handler.on_show_textdraw_writer(bs, {tonumber(id), {flags = data.flags, letterWidth = data.letterWidth, letterHeight = data.letterHeight, letterColor = data.letterColor, lineWidth = data.lineWidth, lineHeight = data.lineHeight, boxColor = data.boxColor, shadow = data.shadow, outline = data.outline, backgroundColor = data.backgroundColor, style = data.style, selectable = data.selectable, position = data.position, modelId = data.modelId, rotation = data.rotation, zoom = data.zoom, color = data.color, text = data.text}})
raknetEmulRpcReceiveBitStream(134, bs)
raknetDeleteBitStream(bs)
[ML] (error) script.lua: E:\Grand Theft Auto San Andreas\moonloader\script.lua:45: attempt to call field 'on_show_textdraw_writer' (a nil value)
stack traceback:
E:\Grand Theft Auto San Andreas\moonloader\script.lua:45: in function 'createTextDraw'
E:\Grand Theft Auto San Andreas\moonloader\script.lua:27: in function 'getServer'
E:\Grand Theft Auto San Andreas\moonloader\script.lua:17: in function 'callback'
...eft Auto San Andreas\moonloader\lib\samp\events\core.lua:79: in function <...eft Auto San Andreas\moonloader\lib\samp\events\core.lua:53>
Попробуй добавить в конец файла handlers.lua lib -> samp -> events -> handlers.lua

Lua:
--- onShowTextDraw
function handler.on_show_textdraw_reader(bs)
    local read = BitStreamIO.bs_read
    local data = {}
    local textdrawId = read.int16(bs)
    data.flags = read.int8(bs)
    data.letterWidth = read.float(bs)
    data.letterHeight = read.float(bs)
    data.letterColor = read.int32(bs)
    data.lineWidth = read.float(bs)
    data.lineHeight = read.float(bs)
    data.boxColor = read.int32(bs)
    data.shadow = read.int8(bs)
    data.outline = read.int8(bs)
    data.backgroundColor = read.int32(bs)
    data.style = read.int8(bs)
    data.selectable = read.int8(bs)
    data.position = read.vector2d(bs)
    data.modelId = read.int16(bs)
    data.rotation = read.vector3d(bs)
    data.zoom = read.float(bs)
    data.color = read.int32(bs)
    data.text = read.string16(bs)
    return {textdrawId, data}
end

function handler.on_show_textdraw_writer(bs, data)
    local write = BitStreamIO.bs_write
    local textdrawId = data[1]
    local data = data[2]
    write.int16(bs, textdrawId)
    write.int8(bs, data.flags)
    write.float(bs, data.letterWidth)
    write.float(bs, data.letterHeight)
    write.int32(bs, data.letterColor)
    write.float(bs, data.lineWidth)
    write.float(bs, data.lineHeight)
    write.int32(bs, data.boxColor)
    write.int8(bs, data.shadow)
    write.int8(bs, data.outline)
    write.int32(bs, data.backgroundColor)
    write.int8(bs, data.style)
    write.int8(bs, data.selectable)
    write.vector2d(bs, data.position)
    write.int16(bs, data.modelId)
    write.vector3d(bs, data.rotation)
    write.float(bs, data.zoom)
    write.int32(bs, data.color)
    write.string16(bs, data.text)
end
 
Последнее редактирование:
  • Нравится
Реакции: paulohardy

paulohardy

вы еще постите говно? тогда я иду к вам
Всефорумный модератор
1,891
1,254
Попробуй добавить в конец файла handlers.lua lib -> samp -> events -> handlers.lua

Lua:
--- onShowTextDraw
function handler.on_show_textdraw_reader(bs)
    local read = BitStreamIO.bs_read
    local data = {}
    local textdrawId = read.int16(bs)
    data.flags = read.int8(bs)
    data.letterWidth = read.float(bs)
    data.letterHeight = read.float(bs)
    data.letterColor = read.int32(bs)
    data.lineWidth = read.float(bs)
    data.lineHeight = read.float(bs)
    data.boxColor = read.int32(bs)
    data.shadow = read.int8(bs)
    data.outline = read.int8(bs)
    data.backgroundColor = read.int32(bs)
    data.style = read.int8(bs)
    data.selectable = read.int8(bs)
    data.position = read.vector2d(bs)
    data.modelId = read.int16(bs)
    data.rotation = read.vector3d(bs)
    data.zoom = read.float(bs)
    data.color = read.int32(bs)
    data.text = read.string16(bs)
    return {textdrawId, data}
end

function handler.on_show_textdraw_writer(bs, data)
    local write = BitStreamIO.bs_write
    local textdrawId = data[1]
    local data = data[2]
    write.int16(bs, textdrawId)
    write.int8(bs, data.flags)
    write.float(bs, data.letterWidth)
    write.float(bs, data.letterHeight)
    write.int32(bs, data.letterColor)
    write.float(bs, data.lineWidth)
    write.float(bs, data.lineHeight)
    write.int32(bs, data.boxColor)
    write.int8(bs, data.shadow)
    write.int8(bs, data.outline)
    write.int32(bs, data.backgroundColor)
    write.int8(bs, data.style)
    write.int8(bs, data.selectable)
    write.vector2d(bs, data.position)
    write.int16(bs, data.modelId)
    write.vector3d(bs, data.rotation)
    write.float(bs, data.zoom)
    write.int32(bs, data.color)
    write.string16(bs, data.text)
end
@FYP, потерял onShowTextDraw
handler.lua:
-- This file is part of the SAMP.Lua project.
-- Licensed under the MIT License.
-- Copyright (c) 2016, FYP @ BlastHack Team <blast.hk>
-- https://github.com/THE-FYP/SAMP.Lua

local bs_io = require 'samp.events.bitstream_io'
local utils = require 'samp.events.utils'
local bsread, bswrite = bs_io.bs_read, bs_io.bs_write
local handler = {}

--- onSendGiveDamage, onSendTakeDamage
function handler.rpc_send_give_take_damage_reader(bs)
    local take = bsread.bool(bs) -- 'true' is take damage
    local data = {
        bsread.int16(bs), -- playerId
        bsread.float(bs), -- damage
        bsread.int32(bs), -- weapon
        bsread.int32(bs), -- bodypart
        take,
    }
    return (take and 'onSendTakeDamage' or 'onSendGiveDamage'), data
end

function handler.rpc_send_give_take_damage_writer(bs, data)
    bswrite.bool(bs, data[5]) -- give or take
    bswrite.int16(bs, data[1]) -- playerId
    bswrite.float(bs, data[2]) -- damage
    bswrite.int32(bs, data[3]) -- weapon
    bswrite.int32(bs, data[4]) -- bodypart
end

--- onInitGame
function handler.rpc_init_game_reader(bs)
    local settings                 = {}
    settings.zoneNames             = bsread.bool(bs)
    settings.useCJWalk             = bsread.bool(bs)
    settings.allowWeapons          = bsread.bool(bs)
    settings.limitGlobalChatRadius = bsread.bool(bs)
    settings.globalChatRadius      = bsread.float(bs)
    settings.stuntBonus            = bsread.bool(bs)
    settings.nametagDrawDist       = bsread.float(bs)
    settings.disableEnterExits     = bsread.bool(bs)
    settings.nametagLOS            = bsread.bool(bs)
    settings.tirePopping           = bsread.bool(bs)
    settings.classesAvailable      = bsread.int32(bs)
    local playerId                 = bsread.int16(bs)
    settings.showPlayerTags        = bsread.bool(bs)
    settings.playerMarkersMode     = bsread.int32(bs)
    settings.worldTime             = bsread.int8(bs)
    settings.worldWeather          = bsread.int8(bs)
    settings.gravity               = bsread.float(bs)
    settings.lanMode               = bsread.bool(bs)
    settings.deathMoneyDrop        = bsread.int32(bs)
    settings.instagib              = bsread.bool(bs)
    settings.normalOnfootSendrate  = bsread.int32(bs)
    settings.normalIncarSendrate   = bsread.int32(bs)
    settings.normalFiringSendrate  = bsread.int32(bs)
    settings.sendMultiplier        = bsread.int32(bs)
    settings.lagCompMode           = bsread.int32(bs)
    local hostName                 = bsread.string8(bs)
    local vehicleModels = {}
    for i = 0, 212 - 1 do
        vehicleModels[i] = bsread.int8(bs)
    end
    settings.vehicleFriendlyFire = bsread.bool32(bs)
    return {playerId, hostName, settings, vehicleModels, settings.vehicleFriendlyFire}
end

function handler.rpc_init_game_writer(bs, data)
    local settings = data[3]
    local vehicleModels = data[4]
    bswrite.bool(bs, settings.zoneNames)
    bswrite.bool(bs, settings.useCJWalk)
    bswrite.bool(bs, settings.allowWeapons)
    bswrite.bool(bs, settings.limitGlobalChatRadius)
    bswrite.float(bs, settings.globalChatRadius)
    bswrite.bool(bs, settings.stuntBonus)
    bswrite.float(bs, settings.nametagDrawDist)
    bswrite.bool(bs, settings.disableEnterExits)
    bswrite.bool(bs, settings.nametagLOS)
    bswrite.bool(bs, settings.tirePopping)
    bswrite.int32(bs, settings.classesAvailable)
    bswrite.int16(bs, data[1]) -- playerId
    bswrite.bool(bs, settings.showPlayerTags)
    bswrite.int32(bs, settings.playerMarkersMode)
    bswrite.int8(bs, settings.worldTime)
    bswrite.int8(bs, settings.worldWeather)
    bswrite.float(bs, settings.gravity)
    bswrite.bool(bs, settings.lanMode)
    bswrite.int32(bs, settings.deathMoneyDrop)
    bswrite.bool(bs, settings.instagib)
    bswrite.int32(bs, settings.normalOnfootSendrate)
    bswrite.int32(bs, settings.normalIncarSendrate)
    bswrite.int32(bs, settings.normalFiringSendrate)
    bswrite.int32(bs, settings.sendMultiplier)
    bswrite.int32(bs, settings.lagCompMode)
    bswrite.string8(bs, data[2]) -- hostName
    for i = 1, 212 do
        bswrite.int8(bs, vehicleModels[i])
    end
    bswrite.bool32(bs, settings.vehicleFriendlyFire)
end

--- onInitMenu
function handler.rpc_init_menu_reader(bs)
    local colWidth2
    local rows = {}
    local columns = {}
    local readColumn = function(width)
        local title = bsread.fixedString32(bs)
        local rowCount = bsread.int8(bs)
        local column = {title = title, width = width, text = {}}
        for i = 1, rowCount do
            column.text[i] = bsread.fixedString32(bs)
        end
        return column
    end
    local menuId = bsread.int8(bs)
    local twoColumns = bsread.bool32(bs)
    local menuTitle = bsread.fixedString32(bs)
    local x = bsread.float(bs)
    local y = bsread.float(bs)
    local colWidth1 = bsread.float(bs)
    if twoColumns then
        colWidth2 = bsread.float(bs)
    end
    local menu = bsread.bool32(bs)
    for i = 1, 12 do
        rows[i] = bsread.int32(bs)
    end
    columns[1] = readColumn(colWidth1)
    if twoColumns then
        columns[2] = readColumn(colWidth2)
    end
    return {menuId, menuTitle, x, y, twoColumns, columns, rows, menu}
end

function handler.rpc_init_menu_writer(bs, data)
    local columns = data[6]
    bswrite.int8(bs, data[1])      -- menuId
    bswrite.bool32(bs, data[5])    -- twoColumns
    bswrite.fixedString32(bs, data[2]) -- title
    bswrite.float(bs, data[3])     -- x
    bswrite.float(bs, data[4])     -- y
    -- columns width
    bswrite.float(bs, columns[1].width)
    if data[5] then
        bswrite.float(bs, columns[2].width)
    end
    bswrite.bool32(bs, data[8]) -- menu
     -- rows
    for i = 1, 12 do
        bswrite.int32(bs, data[7][i])
    end
    -- columns
    for i = 1, (data[5] and 2 or 1) do
        bswrite.fixedString32(bs, columns[i].title)
        bswrite.int8(bs, #columns[i].text)
        for r, t in ipairs(columns[i].text) do
            bswrite.fixedString32(bs, t)
        end
    end
end

--- onMarkersSync
function handler.packet_markers_sync_reader(bs)
    local markers = {}
    local players = bsread.int32(bs)
    for i = 1, players do
        local playerId = bsread.int16(bs)
        local active = bsread.bool(bs)
        if active then
            local vector3d = require 'vector3d'
            local x, y, z = bsread.int16(bs), bsread.int16(bs), bsread.int16(bs)
            table.insert(markers, {playerId = playerId, active = true, coords = vector3d(x, y, z)})
        else
            table.insert(markers, {playerId = playerId, active = false})
        end
    end
    return {markers}
end

function handler.packet_markers_sync_writer(bs, data)
    bswrite.int32(bs, #data)
    for i = 1, #data do
        local it = data[i]
        bswrite.int16(bs, it.playerId)
        bswrite.bool(bs, it.active)
        if it.active then
            bswrite.int16(bs, it.coords.x)
            bswrite.int16(bs, it.coords.y)
            bswrite.int16(bs, it.coords.z)
        end
    end
end

--- onPlayerSync
function handler.packet_player_sync_reader(bs)
    local has_value = bsread.bool
    local data = {}
    local playerId = bsread.int16(bs)
    if has_value(bs) then data.leftRightKeys = bsread.int16(bs) end
    if has_value(bs) then data.upDownKeys = bsread.int16(bs) end
    data.keysData = bsread.int16(bs)
    data.position = bsread.vector3d(bs)
    data.quaternion = bsread.normQuat(bs)
    data.health, data.armor = utils.decompress_health_and_armor(bsread.int8(bs))
    data.weapon = bsread.int8(bs)
    data.specialAction = bsread.int8(bs)
    data.moveSpeed = bsread.compressedVector(bs)
    if has_value(bs) then
        data.surfingVehicleId = bsread.int16(bs)
        data.surfingOffsets = bsread.vector3d(bs)
    end
    if has_value(bs) then
        data.animationId = bsread.int16(bs)
        data.animationFlags = bsread.int16(bs)
    end
    return {playerId, data}
end

function handler.packet_player_sync_writer(bs, data)
    local playerId = data[1]
    local data = data[2]
    bswrite.int16(bs, playerId)
    bswrite.bool(bs, data.leftRightKeys ~= nil)
    if data.leftRightKeys then bswrite.int16(bs, data.leftRightKeys) end
    bswrite.bool(bs, data.upDownKeys ~= nil)
    if data.upDownKeys then bswrite.int16(bs, data.upDownKeys) end
    bswrite.int16(bs, data.keysData)
    bswrite.vector3d(bs, data.position)
    bswrite.normQuat(bs, data.quaternion)
    bswrite.int8(bs, utils.compress_health_and_armor(data.health, data.armor))
    bswrite.int8(bs, data.weapon)
    bswrite.int8(bs, data.specialAction)
    bswrite.compressedVector(bs, data.moveSpeed)
    bswrite.bool(bs, data.surfingVehicleId ~= nil)
    if data.surfingVehicleId then
        bswrite.int16(bs, data.surfingVehicleId)
        bswrite.vector3d(bs, data.surfingOffsets)
    end
    bswrite.bool(bs, data.animationId ~= nil)
    if data.animationId then
        bswrite.int16(bs, data.animationId)
        bswrite.int16(bs, data.animationFlags)
    end
end

--- onVehicleSync
function handler.packet_vehicle_sync_reader(bs)
    local data = {}
    local playerId = bsread.int16(bs)
    local vehicleId = bsread.int16(bs)
    data.leftRightKeys = bsread.int16(bs)
    data.upDownKeys = bsread.int16(bs)
    data.keysData = bsread.int16(bs)
    data.quaternion = bsread.normQuat(bs)
    data.position = bsread.vector3d(bs)
    data.moveSpeed = bsread.compressedVector(bs)
    data.vehicleHealth = bsread.int16(bs)
    data.playerHealth, data.armor = utils.decompress_health_and_armor(bsread.int8(bs))
    data.currentWeapon = bsread.int8(bs)
    data.siren = bsread.bool(bs)
    data.landingGear = bsread.bool(bs)
    if bsread.bool(bs) then
        data.trainSpeed = bsread.int32(bs)
    end
    if bsread.bool(bs) then
        data.trailerId = bsread.int16(bs)
    end
    return {playerId, vehicleId, data}
end

function handler.packet_vehicle_sync_writer(bs, data)
    local playerId = data[1]
    local vehicleId = data[2]
    local data = data[3]
    bswrite.int16(bs, playerId)
    bswrite.int16(bs, vehicleId)
    bswrite.int16(bs, data.leftRightKeys)
    bswrite.int16(bs, data.upDownKeys)
    bswrite.int16(bs, data.keysData)
    bswrite.normQuat(bs, data.quaternion)
    bswrite.vector3d(bs, data.position)
    bswrite.compressedVector(bs, data.moveSpeed)
    bswrite.int16(bs, data.vehicleHealth)
    bswrite.int8(bs, utils.compress_health_and_armor(data.playerHealth, data.armor))
    bswrite.int8(bs, data.currentWeapon)
    bswrite.bool(bs, data.siren)
    bswrite.bool(bs, data.landingGear)
    bswrite.bool(bs, data.trainSpeed ~= nil)
    if data.trainSpeed ~= nil then
        bswrite.int32(bs, data.trainSpeed)
    end
    bswrite.bool(bs, data.trailerId ~= nil)
    if data.trailerId ~= nil then
        bswrite.int16(bs, data.trailerId)
    end
end

--- onVehicleStreamIn
function handler.rpc_vehicle_stream_in_reader(bs)
    local data = {modSlots = {}}
    local vehicleId = bsread.int16(bs)
    data.type = bsread.int32(bs)
    data.position = bsread.vector3d(bs)
    data.rotation = bsread.float(bs)
    data.interiorColor1 = bsread.int8(bs)
    data.interiorColor2 = bsread.int8(bs)
    data.health = bsread.float(bs)
    data.interiorId = bsread.int8(bs)
    data.doorDamageStatus = bsread.int32(bs)
    data.panelDamageStatus = bsread.int32(bs)
    data.lightDamageStatus = bsread.int8(bs)
    data.tireDamageStatus = bsread.int8(bs)
    data.addSiren = bsread.int8(bs)
    for i = 1, 14 do
        data.modSlots[i] = bsread.int8(bs)
    end
    data.paintJob = bsread.int8(bs)
    data.bodyColor1 = bsread.int32(bs)
    data.bodyColor2 = bsread.int32(bs)
    return {vehicleId, data}
end

function handler.rpc_vehicle_stream_in_writer(bs, data)
    local vehicleId = data[1]
    local data = data[2]
    bswrite.int16(bs, vehicleId)
    bswrite.int32(bs, data.type)
    bswrite.vector3d(bs, data.position)
    bswrite.float(bs, data.rotation)
    bswrite.int8(bs, data.interiorColor1)
    bswrite.int8(bs, data.interiorColor2)
    bswrite.float(bs, data.health)
    bswrite.int8(bs, data.interiorId)
    bswrite.int32(bs, data.doorDamageStatus)
    bswrite.int32(bs, data.panelDamageStatus)
    bswrite.int8(bs, data.lightDamageStatus)
    bswrite.int8(bs, data.tireDamageStatus)
    bswrite.int8(bs, data.addSiren)
    for i = 1, 14 do
        bswrite.int8(bs, data.modSlots[i])
    end
    bswrite.int8(bs, data.paintJob)
    bswrite.int32(bs, data.bodyColor1)
    bswrite.int32(bs, data.bodyColor2)
end

local MATERIAL_TYPE = {
    NONE = 0,
    TEXTURE = 1,
    TEXT = 2,
}

local function read_object_material(bs)
    local data = {}
    data.materialId = bsread.int8(bs)
    data.modelId = bsread.int16(bs)
    data.libraryName = bsread.string8(bs)
    data.textureName = bsread.string8(bs)
    data.color = bsread.int32(bs)
    data.type = MATERIAL_TYPE.TEXTURE
    return data
end

local function write_object_material(bs, data)
    bswrite.int8(bs, data.type)
    bswrite.int8(bs, data.materialId)
    bswrite.int16(bs, data.modelId)
    bswrite.string8(bs, data.libraryName)
    bswrite.string8(bs, data.textureName)
    bswrite.int32(bs, data.color)
end

local function read_object_material_text(bs)
    local data = {}
    data.materialId = bsread.int8(bs)
    data.materialSize = bsread.int8(bs)
    data.fontName = bsread.string8(bs)
    data.fontSize = bsread.int8(bs)
    data.bold = bsread.int8(bs)
    data.fontColor = bsread.int32(bs)
    data.backGroundColor = bsread.int32(bs)
    data.align = bsread.int8(bs)
    data.text = bsread.encodedString2048(bs)
    data.type = MATERIAL_TYPE.TEXT
    return data
end

local function write_object_material_text(bs, data)
    bswrite.int8(bs, data.type)
    bswrite.int8(bs, data.materialId)
    bswrite.int8(bs, data.materialSize)
    bswrite.string8(bs, data.fontName)
    bswrite.int8(bs, data.fontSize)
    bswrite.int8(bs, data.bold)
    bswrite.int32(bs, data.fontColor)
    bswrite.int32(bs, data.backGroundColor)
    bswrite.int8(bs, data.align)
    bswrite.encodedString2048(bs, data.text)
end

--- onSetObjectMaterial
function handler.rpc_set_object_material_reader(bs)
    local objectId = bsread.int16(bs)
    local materialType = bsread.int8(bs)
    local material
    if materialType == MATERIAL_TYPE.TEXTURE then
        material = read_object_material(bs)
    elseif materialType == MATERIAL_TYPE.TEXT then
        material = read_object_material_text(bs)
    end
    local ev = materialType == MATERIAL_TYPE.TEXTURE and 'onSetObjectMaterial' or 'onSetObjectMaterialText'
    return ev, {objectId, material}
end

function handler.rpc_set_object_material_writer(bs, data)
    local objectId = data[1]
    local mat = data[2]
    bswrite.int16(bs, objectId)
    if mat.type == MATERIAL_TYPE.TEXTURE then
        write_object_material(bs, mat)
    elseif mat.type == MATERIAL_TYPE.TEXT then
        write_object_material_text(bs, mat)
    end
end

--- onCreateObject
function handler.rpc_create_object_reader(bs)
    local data = {materials = {}, materialText = {}}
    local objectId = bsread.int16(bs)
    data.modelId = bsread.int32(bs)
    data.position = bsread.vector3d(bs)
    data.rotation = bsread.vector3d(bs)
    data.drawDistance = bsread.float(bs)
    data.noCameraCol = bsread.bool8(bs)
    data.attachToVehicleId = bsread.int16(bs)
    data.attachToObjectId = bsread.int16(bs)
    if data.attachToVehicleId ~= 0xFFFF or data.attachToObjectId ~= 0xFFFF then
        data.attachOffsets = bsread.vector3d(bs)
        data.attachRotation = bsread.vector3d(bs)
        data.syncRotation = bsread.bool8(bs)
    end
    data.texturesCount = bsread.int8(bs)
    while raknetBitStreamGetNumberOfUnreadBits(bs) >= 8 do
        local materialType = bsread.int8(bs)
        if materialType == MATERIAL_TYPE.TEXTURE then
            table.insert(data.materials, read_object_material(bs))
        elseif materialType == MATERIAL_TYPE.TEXT then
            table.insert(data.materialText, read_object_material_text(bs))
        end
    end
    data.materials_text = data.materialText -- obsolete
    return {objectId, data}
end

function handler.rpc_create_object_writer(bs, data)
    local objectId = data[1]
    local data = data[2]
    bswrite.int16(bs, objectId)
    bswrite.int32(bs, data.modelId)
    bswrite.vector3d(bs, data.position)
    bswrite.vector3d(bs, data.rotation)
    bswrite.float(bs, data.drawDistance)
    bswrite.bool8(bs, data.noCameraCol)
    bswrite.int16(bs, data.attachToVehicleId)
    bswrite.int16(bs, data.attachToObjectId)
    if data.attachToVehicleId ~= 0xFFFF or data.attachToObjectId ~= 0xFFFF then
        bswrite.vector3d(bs, data.attachOffsets)
        bswrite.vector3d(bs, data.attachRotation)
        bswrite.bool8(bs, data.syncRotation)
    end
    bswrite.int8(bs, data.texturesCount)
    for _, it in ipairs(data.materials) do
        write_object_material(bs, it)
    end
    for _, it in ipairs(data.materialText) do
        write_object_material_text(bs, it)
    end
end

function handler.rpc_update_scores_and_pings_reader(bs)
    local data = {}
    for i = 1, raknetBitStreamGetNumberOfBytesUsed(bs) / 10 do
        local playerId = bsread.int16(bs)
        local playerScore = bsread.int32(bs)
        local playerPing = bsread.int32(bs)
        data[playerId] = {score = playerScore, ping = playerPing}
    end
    return {data}
end

function handler.rpc_update_scores_and_pings_writer(bs, data)
    for id, info in pairs(data[1]) do
        bswrite.int16(bs, id)
        bswrite.int32(bs, info.score)
        bswrite.int32(bs, info.ping)
    end
end

function handler.packet_weapons_update_reader(bs)
    local playerTarget = bsread.int16(bs)
    local actorTarget = bsread.int16(bs)
    local weapons = {}
    local count = raknetBitStreamGetNumberOfUnreadBits(bs) / 32
    for i = 1, count do
        local slot = bsread.int8(bs)
        local weapon = bsread.int8(bs)
        local ammo = bsread.int16(bs)
        weapons[i] = {slot = slot, weapon = weapon, ammo = ammo}
    end
    return {playerTarget, actorTarget, weapons}
end

function handler.packet_weapons_update_writer(bs, data)
    bswrite.int16(bs, data[1])
    bswrite.int16(bs, data[2])
    for i, weap in ipairs(data[3]) do
        bswrite.int8(bs, weap.slot)
        bswrite.int8(bs, weap.weapon)
        bswrite.int16(bs, weap.ammo)
    end
end

--- onShowTextDraw
function handler.on_show_textdraw_reader(bs)
    local data = {}
    local textdrawId = bsread.int16(bs)
    data.flags = bsread.int8(bs)
    data.letterWidth = bsread.float(bs)
    data.letterHeight = bsread.float(bs)
    data.letterColor = bsread.int32(bs)
    data.lineWidth = bsread.float(bs)
    data.lineHeight = bsread.float(bs)
    data.boxColor = bsread.int32(bs)
    data.shadow = bsread.int8(bs)
    data.outline = bsread.int8(bs)
    data.backgroundColor = bsread.int32(bs)
    data.style = bsread.int8(bs)
    data.selectable = bsread.int8(bs)
    data.position = bsread.vector2d(bs)
    data.modelId = bsread.int16(bs)
    data.rotation = bsread.vector3d(bs)
    data.zoom = bsread.float(bs)
    data.color = bsread.int32(bs)
    data.text = bsread.string16(bs)
    return {textdrawId, data}
end

function handler.on_show_textdraw_writer(bs, data)
    local textdrawId = data[1]
    local data = data[2]
    bswrite.int16(bs, textdrawId)
    bswrite.int8(bs, data.flags)
    bswrite.float(bs, data.letterWidth)
    bswrite.float(bs, data.letterHeight)
    bswrite.int32(bs, data.letterColor)
    bswrite.float(bs, data.lineWidth)
    bswrite.float(bs, data.lineHeight)
    bswrite.int32(bs, data.boxColor)
    bswrite.int8(bs, data.shadow)
    bswrite.int8(bs, data.outline)
    bswrite.int32(bs, data.backgroundColor)
    bswrite.int8(bs, data.style)
    bswrite.int8(bs, data.selectable)
    bswrite.vector2d(bs, data.position)
    bswrite.int16(bs, data.modelId)
    bswrite.vector3d(bs, data.rotation)
    bswrite.float(bs, data.zoom)
    bswrite.int32(bs, data.color)
    bswrite.string16(bs, data.text)
end

return handler
 
Последнее редактирование:
  • Нравится
Реакции: Ciske

FYP

Известный
Автор темы
Администратор
1,758
5,723
После обновы вылезает ошибка при создании текстдрава через битстрим, почему так?
передаю таблицей, до установки новой версии всё было ок
обработчики битстрима из samp.events.handlers не являются частью апи библиотеки, они только для внутреннего использования. обработчик onShowTextDraw был заменён описанием структуры, этой функции больше нет, вот и вылазит ошибка. работа самого события onShowTextDraw никак не была нарушена. https://github.com/THE-FYP/SAMP.Lua/blob/master/samp/events.lua#L142
Попробуй добавить в конец файла handlers.lua lib -> samp -> events -> handlers.lua
нельзя ничего добавлять в сторонние библиотеки.
 
  • Клоун
Реакции: Fott

paulohardy

вы еще постите говно? тогда я иду к вам
Всефорумный модератор
1,891
1,254
обработчики из samp.events.handlers не являются частью апи библиотеки, они только для внутреннего использования. обработчик onShowTextdraw был заменён описанием структуры, этой функции больше нет, вот и вылазит ошибка.
Проблема в том, что если записывать битстрим не используя handler.on_show_textdraw_writer то вылезает ошибка о большом размере текстдрава, из-за чего так может получаться?
 

FYP

Известный
Автор темы
Администратор
1,758
5,723
Проблема в том, что если записывать битстрим не используя handler.on_show_textdraw_writer то вылезает ошибка о большом размере текстдрава, из-за чего так может получаться?
из-за неправильной записи
 
  • Клоун
Реакции: Fott