Просмотр полной версии : [Function] SetPlayerPosEx
Всем привет.
В группе форума столкнулся на одного интересного персонажа, он не мог решить проблему с подгрузкой объектов. Накидал ему функцию чтобы "фризило", воть. Сейчас успокоился, немного оптимизировал и добавил функционала и делюсь с вами.
Параметры:
*обязательные*
playerid - id телепортируемого игрока
x, y, z - координаты X, Y, Z телепортируемого места
*не обязательные*
angle - угол поворота
virtualworldid - id виртуального мира
interiorid - id интеръера
vehicletp - режим телепорта транспорта (1 - ТП с транспортом, 0 - Без). П.с: условии для проверки на нахождение в транспорте не требуется, функция это предусматривает.
passengertp - режим телепорта пассажиров (работает при включенном "vehicletp"): 0 - слапнуть, 1 - телепортировать вместе.
freezetime - время до разморозки игрока (используйте 0 чтобы не замораживать). Default: 0
Пример использования:
CMD:tp(playerid)
{
SetPlayerPosEx(playerid, 0.0, 0.0, 2.0);
return SendClientMessage(playerid, -1, !"Вы телепортированы в центр карты.");
}
Функция:
stock
SetPlayerPosEx(playerid, Float:x, Float:y, Float:z, Float:angle = 0.0,
virtualworldid = -1, interiorid = -1, vehicletp = 0, passengertp = 0, freezetime = 0)
{
new
vehicleid = GetPlayerVehicleID(playerid);
#if defined Streamer_IncludeFileVersion
Streamer_UpdateEx(playerid, x, y, z, virtualworldid, interiorid);
#endif
if(!vehicletp || GetPlayerState(playerid) != PLAYER_STATE_DRIVER)
{
SetPlayerPos(playerid, x, y, z);
if(-1 != interiorid)
SetPlayerInterior(playerid, interiorid);
if(-1 != virtualworldid)
SetPlayerVirtualWorld(playerid, virtualworldid);
if(0.0 != angle)
SetPlayerFacingAngle(playerid, angle);
if(freezetime)
{
TogglePlayerControllable(playerid, 0);
SetTimerEx(!"@__unfreezeLoadInt", freezetime, 0, !"i", playerid);
}
return SetCameraBehindPlayer(playerid);
}
static
Float:pos_x,
Float:pos_y,
Float:pos_z;
GetPlayerPos(playerid, pos_x, pos_y, pos_z);
if(-1 != interiorid)
LinkVehicleToInterior(vehicleid, interiorid);
if(-1 != virtualworldid)
SetVehicleVirtualWorld(vehicleid, virtualworldid);
#if defined foreach
foreach(Player, i)
#else
for(new i; i < MAX_PLAYERS; i++)
#endif
{
if(GetPlayerVehicleID(i) == vehicleid)
{
if(!passengertp)
{
#if defined Streamer_IncludeFileVersion
Streamer_UpdateEx(i, x, y, z, virtualworldid, interiorid);
#endif
if(-1 != interiorid)
SetPlayerInterior(i, interiorid);
if(-1 != virtualworldid)
SetPlayerVirtualWorld(i, virtualworldid);
SetCameraBehindPlayer(i);
}
else
SetPlayerPos(i, pos_x, pos_y+0.5, pos_z+1.0);
}
}
SetVehiclePos(vehicleid, x, y, z + 1.0);
if(angle != 0.0)
SetVehicleZAngle(vehicleid, angle);
SetPlayerPos(playerid, x, y, z);
PutPlayerInVehicle(playerid, vehicleid, 0);
return SetCameraBehindPlayer(playerid);
}
@__unfreezeLoadInt(playerid);
@__unfreezeLoadInt(playerid)
return TogglePlayerControllable(playerid, 1);
Автор: Danny Moore
http://pro-pawn.ru/showthread.php?6278
Daniel_Cortez
06.03.2018, 23:48
http://pro-pawn.ru/showthread.php?6278
Следует заметить, что тот инклуд был написан ещё в конце 2013-го, я тогда не учёл возможность телепортации пассажиров в транспорте (которая учтена в этой теме). Впрочем, это не так уж и сложно добавить.
Следует заметить, что тот инклуд был написан ещё в конце 2013-го, я тогда не учёл возможность телепортации пассажиров в транспорте (которая учтена в этой теме). Впрочем, это не так уж и сложно добавить.
Думаю, что вариант ниже вполне подойдёт (если нет - укажите на ошибки, пожалуйста). Правда, пришлось сначала делать проверку с tppassenger и уже после запускать цикл, ибо как-то не хотелось создавать 3 переменные при каждой итерации (в случае с функцией ТС`а игроков телепортирует на координаты playerid и немного в сторону, в этом случае их просто смещает с их координат).
stock SetPlayerPosEx(playerid, Float:x, Float:y, Float:z, interior = cellmin, world = cellmin, tpcar = 1, tppassenger = 1)
{
Streamer_ToggleIdleUpdate(playerid, 1);
if(dc_spp__control{playerid})
{
TogglePlayerControllable(playerid, 0);
SetTimerEx("@__dc_spp__unfreeze", DC_SPP__FREEZE_TIME, 0, "d", playerid);
}
Streamer_UpdateEx(playerid, x, y, z, world, interior);
if(interior != cellmin)
SetPlayerInterior(playerid, interior);
if(world != cellmin)
SetPlayerVirtualWorld(playerid, world);
if(tpcar && GetPlayerState(playerid) == PLAYER_STATE_DRIVER)
{
new
veh = GetPlayerVehicleID(playerid);
if(world != cellmin)
SetVehicleVirtualWorld(veh, world);
SetVehiclePos(veh, x, y, z);
if(tppassenger)
{
#if defined foreach
foreach(new i: Player)
#elseif defined GetPlayerPoolSize
for(new i = GetPlayerPoolSize(); i >= 0; i--)
#else
for(new i = MAX_PLAYERS; i >= 0; i--)
#endif
{
if(0 == IsPlayerConnected(i))
continue;
if(i != playerid && GetPlayerVehicleID(i) == veh)
{
if(interior != cellmin)
SetPlayerInterior(i, interior);
if(world != cellmin)
SetPlayerVirtualWorld(i, world);
}
}
}
else
{
new
Float:pos_x,
Float:pos_y,
Float:pos_z;
#if defined foreach
foreach(new i: Player)
#elseif defined GetPlayerPoolSize
for(new i = GetPlayerPoolSize(); i >= 0; i--)
#else
for(new i = MAX_PLAYERS; i >= 0; i--)
#endif
{
if(0 == IsPlayerConnected(i))
continue;
if(i != playerid && GetPlayerVehicleID(i) == veh)
{
GetPlayerPos(i, pos_x, pos_y, pos_z);
SetPlayerPos(i, pos_x, pos_y + 0.5, pos_z + 1.0);
}
}
}
}
else
SetPlayerPos(playerid, x, y, z);
}
Daniel_Cortez
07.03.2018, 12:59
Думаю, что вариант ниже вполне подойдёт (если нет - укажите на ошибки, пожалуйста). Правда, пришлось сначала делать проверку с tppassenger и уже после запускать цикл, ибо как-то не хотелось создавать 3 переменные при каждой итерации (в случае с функцией ТС`а игроков телепортирует на координаты playerid и немного в сторону, в этом случае их просто смещает с их координат.
Спасибо, конечно, но я уже добавил нужный код, правда, не настолько сложный (хотя бы потому, что в моём варианте нет опции tppassenger, хоть я и могу добавить её в будущем, если кому понадобится).
EDIT: Очень некрасиво смотрится, когда одна ветка if взята в фигурные скобки, а другая нет, сбивает с толку.
if(tpcar && GetPlayerState(playerid) == PLAYER_STATE_DRIVER)
{
// ...
}
else
SetPlayerPos(playerid, x, y, z);
Поскольку после ветки else больше никакого кода нет (конец функции), ИМХО лучше сделать ветвление по принципу отсечки, без else.
if(tpcar == 0 || GetPlayerState(playerid) != PLAYER_STATE_DRIVER)
return SetPlayerPos(playerid, x, y, z);
// ...
Также в цикле с перебором игроков вызывается IsPlayerConnected() - зачем? Мало того, что это не нужно в случае с foreach, так проверка на подключение и без того встроена в другие функции, работающие с ID игроков. Например, GetPlayerVehicleID() вернёт 0 (неправильный ID транспорта), если игрок не подключен, т.е. можно сделать так:
if (GetPlayerVehicleID() != veh)
continue;
Вот так элегантно можно вызовом одной функции и проверить подключение, и получить ID ТС игрока.
Учитывать возможность того, что функция GetPlayerPoolSize() не объявлена, тоже сомнительно, времена 0.3z прошли ещё 3 года назад.
Касаемо содержимого цикла, проверку на равенство i и playerid можно выкинуть, вынеся действия только с playerid в ветку if, в которой обрабатывается ситуация, когда игрок не за рулём (см. выше).
if(tpcar == 0 || GetPlayerState(playerid) != PLAYER_STATE_DRIVER)
{
if(interior != -1)
SetPlayerInterior(playerid, interior);
if(world != -1)
SetPlayerVirtualWorld(playerid, world);
return SetPlayerPos(playerid, x, y, z);
}
Также можно сэкономить несколько байт за счёт упаковки строк.
Скоро обновлю функцию. Меня больше беспокоит то, что если игрок заморожен "в другом скрипте" (например командой /freeze) мой скрипт разморозит его. Если есть мысли по этой теме - буду рад их услышать.
Daniel_Cortez
07.03.2018, 22:36
Скоро обновлю функцию. Меня больше беспокоит то, что если игрок заморожен "в другом скрипте" (например командой /freeze) мой скрипт разморозит его. Если есть мысли по этой теме - буду рад их услышать.
Насколько знаю, нет такой функции, которой можно узнать состояние заморозки игрока, и которая правильно работает при заморозке из других скриптов. ИМХО, самый железный способ здесь - перехватить функцию TogglePlayerControllable из плагина, чтобы отслеживать заморозку из всех скриптов, и из того же плагина предоставить функцию IsPlayerControllable. Перебор это или нет - вам решать.
EDIT: Либо это, либо взаимодействие с помощью PVar'ов.
Daniel_Cortez,
Увы, скорее всего так и есть. Думал вынести функцию в отдельный инклюд и перехватить функцию TogglePlayerControllable в скрипте, но я счёл это "вмешательством" в чужой код. Увы, не знаток в написании плагинов, скорее всего так и оставлю. Пользователям остается предусматривать это в своих модах, или коллективно просить кую добавить функцию IsPlayerControllable :dirol:
Функция обновлена до версии 1.2.
Исправлена ошибка, когда транспорту задавалось неправильный ID виртуального мира.
Добавлена поддержка стримера, теперь загрузка объектов начинается до телепорта игрока в указанное место.
а зачем эти условия?
if(-1 != interiorid)
SetPlayerInterior(playerid, interiorid);
if(-1 != virtualworldid)
SetPlayerVirtualWorld(playerid, virtualworldid);
if(0.0 != angle)
SetPlayerFacingAngle(playerid, angle);
по дефолту установить 0 заместо -1
Float:angle = 0.0, virtualworldid = 0, interiorid = 0
SetPlayerInterior(playerid, interiorid);
SetPlayerVirtualWorld(playerid, virtualworldid);
SetPlayerFacingAngle(playerid, angle);
ну с углом поворота можно и оставить условие...
Ну так а если тебе нужно телепортировать игрока, который находится в виртуальном мире, в тот же виртуальный мир (пусть даже нулевой)? Проверить условие будет быстрее и проще, нежели отправить пакет игроку, дабы тот установил виртуальный мир по новой.
Ну так а если тебе нужно телепортировать игрока, который находится в виртуальном мире, в тот же виртуальный мир (пусть даже нулевой)? Проверить условие будет быстрее и проще, нежели отправить пакет игроку, дабы тот установил виртуальный мир по новой.
Использовать SetPlayerPos а если даже из мира в мир телепортировать и миры одинаковы, сработает и условие и пакет отправится. А если ты заведомо знаешь что и интерьер и мир равны, проще и быстрее будет дефолтная SetPlayerPos
EDD:сижу и думаю, что за х**ню я написал
Использовать SetPlayerPos а если даже из мира в мир телепортировать и миры одинаковы, сработает и условие и пакет отправится. А если ты заведомо знаешь что и интерьер и мир равны, проще и быстрее будет дефолтная SetPlayerPos
EDD:сижу и думаю, что за х**ню я написал
Ты немного не понимаешь предназначения данной функции. Она нужна, в основном, чтоб телепортировать игроков на серверный маппинг, который должен успеть прогрузиться.
Если я, например, сделал большой интерьер, но, дабы не было проблем с прогрузкой, разделил его на комнаты и расположил их на расстоянии (так, чтоб они не попадали в зону стрима), то зачем мне тревожить виртуальный мир и интерьер в случае перехода между комнатами? Если сделать функцию такой, какой предложил ты, интерьер и виртуальный мир придётся устанавливать всегда (иначе игроки будут перемещаться в нулевой виртуальный мир и нулевой интерьер). В текущем же случае я могу просто не передавать значения в аргументы виртуального мира/интерьера и никакие пакеты отправляться не будут.
Ты немного не понимаешь предназначения данной функции. Она нужна, в основном, чтоб телепортировать игроков на серверный маппинг, который должен успеть прогрузиться.
Если я, например, сделал большой интерьер, но, дабы не было проблем с прогрузкой, разделил его на комнаты и расположил их на расстоянии (так, чтоб они не попадали в зону стрима), то зачем мне тревожить виртуальный мир и интерьер в случае перехода между комнатами? Если сделать функцию такой, какой предложил ты, интерьер и виртуальный мир придётся устанавливать всегда (иначе игроки будут перемещаться в нулевой виртуальный мир и нулевой интерьер). В текущем же случае я могу просто не передавать значения в аргументы виртуального мира/интерьера и никакие пакеты отправляться не будут.
да, я понял.
Powered by vBulletin® Version 4.2.0 Copyright © 2024 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot