Обход ограничений mp ranks.ltx (метод рекрита)

Материал из Mod Wiki.

(Различия между версиями)
Перейти к: навигация, поиск
Версия 21:04, 3 ноября 2010 (править)
Byurrer (Обсуждение | вклад)
(Новая: Многие модмейкеры которые создают апгрейд оружия да и вообще новое оружие в особенности улучшенное с...)
← К предыдущему изменению
Версия 12:02, 21 января 2011 (править) (отменить)
Spark95 (Обсуждение | вклад)

К следующему изменению →
Строка 209: Строка 209:
В планах совершенствование метода рекрта и доведение его работоспособности до 99,9% В планах совершенствование метода рекрта и доведение его работоспособности до 99,9%
-'''Авторы: Byurrer, spark95'''+'''Авторы: Byurrer, spark95''' Project S.I.P <br />
 +[http://forum.sip-game.ru Форум Project S.I.P]

Версия 12:02, 21 января 2011

Многие модмейкеры которые создают апгрейд оружия да и вообще новое оружие в особенности улучшенное сталкиваются с проблемой переполнения количества байт информации в секции файла mp_ranks.ltx Я же также не исключение, при составлении скрипта апгрейда оружия все шло отлично, тест также прошел на 5, но когда апгрейд стал подходить к концу, то есть необходимо было прописать все апгрейды оружия в ранги то тут произошел вылет. А прописал всего апгрейд ток для одного оружия. Но из всякой проблемы можно найти логический выход. Предлагаю свой, он был разработан не только мной но и моим но и коллегой spark95, на базе проекта S.I.P. Этот метод называется «рекрит» (REcreate) работает без вылетов на 99%. Алгоритм. Для начала необходимо продумать что и как когда и при каких условиях будет работать скрипт, так как мы его разрабатывали для нашего мода то примеры и все составляющие будут полностью либо частично взяты из модификации.

1.Объект выбрасывается
2.Подбирается НПС

И если оружие не прописано в рангах то вылет. Значит нужно чтобы НПС подбирал то оружие которое прописано в рангах значит нужно удалить то непрописанное выбрасываемое оружие и заспавнить на его месте точно такое же но прописанное в рангах, причем визуал и основные характеристики должны соответствовать тому выбрасываемому оружию (дабы не нарушить игровой процесс и симуляцию). Такой способ можно достичь путем снятия нет-пакета с выбрасываемого оружия и записи его на такое же оружие но не апгрейдное. Для начала отследим само выбрасывание: Открываем bind_stalker.script и напишем функцию с условием при котором будет производиться удаление:

local sip_b = 1 –переменная при определении которой будет производиться действие, по дефолту 1
function sip_bool(flag) – функция которая запускается сторонней функцией из другого скрипта дабы не совершить вылета, аргумент = число
	if flag == 1 then
	sip_b = 1
	else sip_b = 0
	end
end

операция присвоения производиться соответственно, дабы не спутать. ищем:

function actor_binder:on_item_drop (obj)
    level_tasks.proceed(self.object)
end 

Эта функция отслеживает выбрасывание чего-либо из инвентаря ГГ. И изменим так:

function actor_binder:on_item_drop (obj)
    level_tasks.proceed(self.object)
	if sip_b == 1 then
	project_sip.delete_weapon(obj)
	end
end

Что позволит обойти тот момент записи нет-пакета в несуществующий объект. Далее создаем скрипт project_sip.script и пишем в него следующее:

local sects = {}
local tab_id = {}
local tab_old_id = {}
local now_wpn_id
local sect_old
local sect – присвоим позже оригинальную секцию оружия которая в последующем будет использована для спавна
local orig_sect –переменной будет присвоена секция оружия 
local count = 0
local num
local new_id
local name – будет присвоено оригинальное название оружия
function delete_weapon(weapon) –функция удаления оружия, аргумент сам объект 
--таблица оружий которые прописаны в рангах
local wpn_tab = {"wpn_abakan","wpn_rpg7","wpn_ak74","wpn_fn2000","wpn_g36","wpn_groza","wpn_l85",
"wpn_lr300","wpn_mp5","wpn_rpg7","wpn_sig550","wpn_val","wpn_spas12","wpn_toz34","wpn_wincheaster1300",
"wpn_svd","wpn_svu","wpn_vintorez","wpn_beretta","wpn_colt1911","wpn_desert_eagle",
"wpn_fort","wpn_hpsa","wpn_pb","wpn_pm","wpn_sig220","wpn_walther"}

local wpn = weapon:section()
orig_sect = wpn
local pos_act  = db.actor:position()
pos_act.x = pos_act.x + 0.3 –оружие будет спавниться не в инвентарь к ГГ а в 30см от него, ибо при спавне в инвентарь нет-пакет в оружие не записывается.
--ниже проверяем что оружие действительно апгрейдное (в данном случае идет проверка не только на то что оружие апгрейдное но еще и на  то что оружие имеет секцию смены визуала)
	if string.find(wpn,"list") or string.find(wpn,"prugina") or string.find(wpn,"tormoz") or string.find(wpn,"sv1") or string.find(wpn,"sv2") or string.find(wpn,"sv3") or string.find(wpn,"sv4") then
		for k = 1, #wpn_tab do –запускаем цикл на выявление оригинала оружия (прописанного в рангах)
		name = k
		if string.find(wpn,wpn_tab[name]) then
		sect = wpn_tab[name]
		break –если условие выполняется то преждевременно останавливаем выполнение цикла
		end
		end
--ниже происходит запись в таблицы данных о секциях
	table.insert(sects,orig_sect)
	table.insert(tab_old_id,weapon:id())
--производим снятие нет-пакета, для этого подготовливаем все условия для этого
	local n_obj = alife():object(weapon:id()) – определяем объект
	local func_net = net_pack_sip.wpn_d_r(n_obj) – снимаем нет-пакет объекта
	alife():release(n_obj,true)
	local sobj = alife():create(sect,pos_act,db.actor:level_vertex_id(),db.actor:game_vertex_id()) – присвоим но не заспавним объект
		if sobj then
		table.insert(tab_id,sobj.id) – запишем id  оружия в таблицу для дальнейшей работы с ним
		net_pack_sip.wpn_d_w(func_net,sobj) – запишем на это оружие весь нет-пакет удаленного оружия
		end
	end
	return sobj – заспавним оружие
end

Вот практически можно сказать что все, однако когда ГГ возьмет это оружие то оно уже не будет таким каким оно было до выбрасывания!!! Исправим эту ситуацию. В биндере найдем следующий код:

function actor_binder:on_item_take (obj)
    level_tasks.proceed(self.object)
end
и изменим так:
function actor_binder:on_item_take (obj)
    level_tasks.proceed(self.object)
	project_sip.spawn_old_wpn(obj)
end

Эта функция отслеживает момент взятия ГГ какого-либо объекта, аргумент сам объект. В project_sip.script пропишем следующий код:

function spawn_old_wpn(obj)
	for k = 1, #tab_id do –запускаем цикл на вычисление идетификатора оружия которое было создано в момент удаления апгрейдного оружия (секция которого была записана ранее)
		if obj:id() == tab_id[k] then 
		num = k
		now_wpn_id = tab_id[num]	--получаем id объекта	
		sect_old = sects[num] – получаем секцию удаленного апгрейдного оружия
		spawn_del_weap(sect_old,now_wpn_id) – запускаем функцию снятия и записи нет-пакета в новое оружие, дабы не нарушить симуляцию
		break
		end
	end
end
--прототип данной функции не требует комментария, ибо расписывался ранее
function spawn_del_weap(sect_old,now_wpn_id)
local pos_act  = db.actor:position()
pos_act.x = pos_act.x + 0.3
local n_obj = alife():object(now_wpn_id)
local func_net = net_pack_sip.wpn_d_r(n_obj)
alife():release(n_obj,true)
local sobj = alife():create(sect_old,pos_act,db.actor:level_vertex_id(),db.actor:game_vertex_id())
	if sobj then
	new_id = sobj.id – записываем id оружия для перевода его к ГГ
	net_pack_sip.wpn_d_w(func_net,sobj)
	end
return sobj
end

function transfer_new_wpn() – данная функция предназначена для перевода нового заспавненго оружия (апгрейдного к ГГ)
	if new_id ~= nil then
	local wpn = level.object_by_id(new_id)
		if wpn then
		db.actor:transfer_item(wpn,db.actor)
		new_id = nil
		end
	else return
	end
end

Далее в биндере найдем:

function actor_binder:update(delta)
	object_binder.update(self, delta)

и ниже напишем:

project_sip.transfer_new_wpn() – для перевода оружия к ГГ
скрипт net_pack_sip.script в котором напишем следующий код:
function wpn_d_r(sobj)
local sv_sip = net_packet()
sobj:STATE_Write(sv_sip)
local size = sv_sip:w_tell()
sv_sip:r_seek(0)
local tab_config = {object_pack = {},visual_pack = {},item_pack = {},item_wpn_packet = {}}

local function up_vis_pack(visual_pack,sv_sip,size)
visual_pack.visual_name = sv_sip:r_stringZ()
visual_pack.vsu8u1 = sv_sip:r_u8()
	return visual_pack
end

	tab_config.object_pack.gvid = sv_sip:r_u16()
	tab_config.object_pack.obf32u1 = sv_sip:r_float()
	tab_config.object_pack.obs32u2 = sv_sip:r_s32()
	tab_config.object_pack.lvid = sv_sip:r_s32()
	tab_config.object_pack.oflags = sv_sip:r_s32()
	tab_config.object_pack.custom = sv_sip:r_stringZ()
	tab_config.object_pack.sid = sv_sip:r_s32()
	tab_config.object_pack.obs32u3 = sv_sip:r_s32()
	
	up_vis_pack(tab_config.visual_pack,sv_sip,size)
	
	tab_config.item_pack.condition = sv_sip:r_float()
	
	tab_config.item_wpn_packet.ammo_current = sv_sip:r_u16()
	tab_config.item_wpn_packet.ammo_elapsed = sv_sip:r_u16()
	tab_config.item_wpn_packet.weapon_state = sv_sip:r_u8()
	tab_config.item_wpn_packet.addon_flags = sv_sip:r_u8()
	tab_config.item_wpn_packet.ammo_type = sv_sip:r_u8()

		return tab_config
end

function wpn_d_w(tab_config,sobj)
local sv_sip = net_packet()
local function vis_pack_rd(visual_pack,sv_sip)
sv_sip:w_stringZ(visual_pack.visual_name)
sv_sip:w_u8(visual_pack.vsu8u1)
	return visual_pack
end

	sv_sip:w_u16(tab_config.object_pack.gvid)
	sv_sip:w_float(tab_config.object_pack.obf32u1)
	sv_sip:w_s32(tab_config.object_pack.obs32u2)
	sv_sip:w_s32(tab_config.object_pack.lvid)
	sv_sip:w_s32(tab_config.object_pack.oflags)
	sv_sip:w_stringZ(tab_config.object_pack.custom)
	sv_sip:w_s32(tab_config.object_pack.sid)
	sv_sip:w_s32(tab_config.object_pack.obs32u3)
	
	vis_pack_rd(tab_config.visual_pack,sv_sip)
	
	sv_sip:w_float(tab_config.item_pack.condition)

	sv_sip:w_u16(tab_config.item_wpn_packet.ammo_current)
	sv_sip:w_u16(tab_config.item_wpn_packet.ammo_elapsed)
	sv_sip:w_u8(tab_config.item_wpn_packet.weapon_state)
	sv_sip:w_u8(tab_config.item_wpn_packet.addon_flags)
	sv_sip:w_u8(tab_config.item_wpn_packet.ammo_type)

	sv_sip:w_u16(tab_config.object_pack.gvid)
	sv_sip:w_float(tab_config.object_pack.obf32u1)
	sv_sip:w_s32(tab_config.object_pack.obs32u2)
	sv_sip:w_s32(tab_config.object_pack.lvid)
	sv_sip:w_s32(tab_config.object_pack.oflags)
	sv_sip:w_stringZ(tab_config.object_pack.custom)
	sv_sip:w_s32(tab_config.object_pack.sid)
	sv_sip:w_s32(tab_config.object_pack.obs32u3)

local size = sv_sip:w_tell()
sv_sip:r_seek(0)
sobj:STATE_Read(sv_sip,size)
end

Работа с нет-пакетами будет описана в отдельной статье, объясню лишь общий смысл предназначения нет-пакета. Он предназначен для хранения состояния объекта и его характеристик и по сути своей является буфером обмена, в котором, и храниться вся эта информация, в последующем действии идет запись по определенным таблицам каждого вида характеристик. Во второй функции происходит запись того снятого состояния объекта к новосозданному. Эта операция напоминает алгоритм спавна all.spawn и неспроста! Ибо при статистином ставне через скрипт объекту также присваивается состояние которое записано как дефолтовое, а спавн через нет-пакет предусматривает широкий спектр выбора характеристик спавненного оружия что в положительную сторону влияет на симуляцию. Ну вот в общем то и все, теперь объясню почему этот метод рекрита работает на 99%. Потому что на выполнение этих всех процессов требуеться время, сам биндер запускается с периодом примерно 0,5 сек. (точно не помню), значит чтобы отследить либо выбрасывание оружия либо наоборот его взятие нужен один период биндера, далее также необходим второй период для перевода нового заспавненного оружия к ГГ, итого не для выполнения всех этих действий требуется как минимум 0,8 сек. Почему не переводиться при первом периоде биндера мне так и не удалось выяснить, но факт есть факт, соответственно если подойти в плотную к НПС и выбросит оружие произойдет вылет, если же произвести выбрасывание на некотором расстоянии к примеру на 10 см, то вылета не будет. Нагрузка на оперативную память не значительна так что можно смело использовать. В планах совершенствование метода рекрта и доведение его работоспособности до 99,9%

Авторы: Byurrer, spark95 Project S.I.P
Форум Project S.I.P

Личные инструменты