Перейти к контенту

Рекомендуемые сообщения

malandrinus

Не очень понял, о какой функции вопрос.

О строке определения флага 'bList' - список? О комплекте функций по (рас)паковке таблиц?

Если о флаге - да, этот флаг будет использоваться для автоматического (если не задано 'ручками') изменения алгоритма упаковки таблицы, подпадающей под определение 'список' (последовательно проиндекситованная таблица).

Для этих таблиц паковаться будут только значения эдементов таблицы (value), индексы будут отбрасываться. При распаковке индексы автоматически восстанавливаются.

Обработка значений типа 'целое число более 9' - упаковывается в хекс-строку.

Обработка всех отличных от таблиц значений (строки, булевы) идет прежним алгоритмом.

Все типы элементов тоблиц, для которых не предусмотрена (рас)паковка (юзердаты объектов, функции, ...) - приводят к принудительному прерыванию процесса (рас)паковки вызовом прерывания игры (abort).

Сообщение об ошибке, передаваемое в 'abort' - дано самое простое и любой может его изменить/дополнить. Например у меня, в кодах вывод практически всех параметров процесса упаковки.

 

Если о комплекте функций - всего лишь осталось именно вышеупомянутый алгоритм определения списков заменить и перепроверить на 'вшивость' тестированием в игре.

Ну еще немного причесать код, чуть подоптимизировав некоторые моменты и немного сократив кол-во строк.

 

То, что выложено выше - уже с месяц гоняю под своей сборкой (Симбион) без спец.подстройки под новые алгориты. Ошибок/нареканий никаких, экономия ресурсов налицо, минусов никаких не замечено. Но, т.к. переход на эти варианты не имеет обратной совместимости с прежними сэйвами - хотелось бы именно мозговым штурмом и просто незамыленным взглядом со стороны - перепроверить 'себя' и убедиться в достаточности кодов для применения в модах.

 

Пока остановился на варианте:

  bList = #tTbl > 9 and next(tTbl) == 1 and not next(tTbl,#tTbl) --/ не мала, начинается с 1-го и нет хеша в конце

- т.е. малые таблицы (до 9-ти элементов) пакуются единым (полным) вариантом. И замещать одноразрядные индексы не имеет смысла на одноразрядный признак списка и ... лишняя подстраховка от возможных ошибок модмейкера.

Тестирую вариант - ставить ли один общий признак списка, а не на каждый элемент.

 

Как и любые иные подобные функции/коды/скрипты от модмейкеров - естественно эти коды подпадают под категорию 'никаких гарантий и используем как есть' и подразумевают, что при разработке мода модмекер, использующий упаковку какой-то своей таблицы - проверяет корректность такого действия в игре.

Просмотрев немалое кол-во модов с упаковкой таблиц - пока не встретил ни одного в котором возникали бы сомнения о составе таблиц и о корректности упаковки 'экономным способом'. Ограничение одно - при упаковке список чистится(!) от пустышек и естественно в распакованной таблице порядок индексов будет иным (сплошным). Но и это именно плюс упаковки, т.к. нигде пока не встречал потребности упаковывать списки в неизменнм виде. Если же возникнет такая потребность у кого-то - флагом 'false' запрещается и чистка и "экономия".

 

P.S.

--/------------------------------------------------------------------
--/ Паковка таблицы в строку (и обратная распаковка)
--/------------------------------------------------------------------
--/ Внимание! Строки в структуре не должны содержать символов с кодами 0-31.
--[[-----------------------------------------------------------------
  Формат упаковки:
    table     ::= ( list | subtable )
    list      ::= keytype nil valuetype ( value | subtable 0x5 )
    subtable  ::= keytype key valuetype ( value | subtable 0x5 )
    keytype   ::= ( 0x1 | 0x2 | 0x3 | 0x4 | 0x6 )
    valuetype ::= ( 0x1 | 0x2 | 0x3 | 0x4 )
--]]-----------------------------------------------------------------
local tPackChar = { --/ служебная таблица масок упаковки
  n = {1, string.char(1)}, --/ 'number'
  s = {2, string.char(2)}, --/ 'string'
  b = {3, string.char(3)}, --/ 'boolean'
  t = {4, string.char(4)}, --/ 'table'
  e = {5, string.char(5)}, --/ table-end
  l = {6, string.char(6)}, --/#+# table-list
  h = {7, string.char(7)}  --/#+# number-hex
}
--/------------------------------------------------------------------
--/ функции для совместимости с сэйвами на базе amk.script
--/------------------------------------------------------------------
--/ упаковка таблицы в строку - функция синоним прежней
function pack_array_to_string(tTbl,bList) --/< таблица [, (true|false) -флаг: список или нет]
  return Pack_Tbl(tTbl,bList) --/> String
end
--/ распаковка 'упакованной' строки в таблицу - функция синоним прежней
function unpack_array_from_string(sStr) --/< строка упакованной таблицы
  if sStr and sStr ~= '' then --/ защита от отсутствия или пустой строки
    --/ для совместимости с прежними сэйвами ----
    if sStr:sub(1,1) == string.char(1) then
      --/ старый формат упаковки был тэгирован символом c кодом '1'
      if sStr:sub(2,2) == tPackChar.n[2] or sStr:sub(2,2) == tPackChar.s[2] then
        --/ вторым символом начинается упакованная строка
        sStr = sStr:sub(2,-1) --/ отрезаем 1-ый символ
      end
    end
    --/< ----------------------------------------
    return Parse_Str(sStr) or {} --/> Table
  end
  return {} --/> ZeroTable
end
--/------------------------------------------------------------------
--/ Упаковка таблицы 'tTbl' в строку 'sStr'
--/------------------------------------------------------------------
function Pack_Tbl(tTbl,bList) --/< таблица [, флаг: список или нет]
  if type(tTbl) ~= 'table' then
    printf("Pack_Tbl:Not_Table=["..type(tTbl).."]:<Warning!>")
    return "" --/> не таблица
  end
  local iFirstIdx = next(tTbl) --/ 1-й элемент таблицы
  if not iFirstIdx then return "" end --/> таблица пуста
  --/#+# проверка: таблица типа 'список'? -----
  --/ TODO: требует перепроверки на корректность работы с различными таблицами
  if bList == nil then --/ если не задан тип таблицы - определяем 'список' или нет
    --/ элементов 'списка' > 0, 1-й индекс начинается с 1 и за 'списком' отсутствует хеш-элемент
    local iCnt = #tTbl --/ длина индексированной части таблицы
    bList = iCnt > 0 and iFirstIdx == 1 and not next(tTbl,iCnt) --/ флаг списка (true|false)
  end
  --/< ----------------------------------------
  --/ упаковка ключа (индекса) элемента таблицы
  local function Pack_Key(sStr,key)
    local sType = type(key)
    if sType == 'number' then
      if key > 9 and key == math.floor(key) then --/ 2-х байтовое или более и целочисленное?
        sStr = sStr .. tPackChar.h[2] .. string.format('%X', key) --/ метка хекс-строки
      else
        sStr = sStr .. tPackChar.n[2] .. key
      end
    elseif sType == 'string' then
      sStr = sStr .. tPackChar.s[2] .. key
    else
      abort("Pack_Tbl:UnSupported_KeyType=" .. tostring(sType)
    end
    return sStr --/>
  end
  --/ упаковка значения элемента таблицы
  local function Pack_Value(sStr,value)
    local sType = type(value)
    if sType == 'number' then
      if value > 9 and value == math.floor(value) then --/ 2-х байтовое или более и целочисленное?
        sStr = sStr .. tPackChar.h[2] .. string.format('%X', value) --/ метка хекс-строки
      else
        sStr = sStr .. tPackChar.n[2] .. value
      end
    elseif sType == 'string' then
      sStr = sStr .. tPackChar.s[2] .. value
    elseif sType == 'boolean' then
      sStr = sStr .. tPackChar.b[2] .. ((value and "1") or "0")
    elseif sType == 'table' then
      sStr = sStr .. tPackChar.t[2] .. this.Pack_Tbl(value) .. tPackChar.e[2] --/> рекурсивный вызов
    else
      abort("Pack_Tbl:UnSupported_ValueType=" .. tostring(sType)
    end
    return sStr --/>
  end
  --/ all pack
  local sStr = ""
  if bList then --/ упаковывается список?
    sStr = tPackChar.l[2] --/ маркер списка (list)
    for _,v in ipairs(tTbl) do
      sStr = Pack_Value(sStr,v)
    end
  else --/ полная упаковка (ключ и значение)
    for k,v in pairs(tTbl) do
      sStr = Pack_Key(sStr,k)
      sStr = Pack_Value(sStr,v)
    end
  end
  return sStr,bList --/> строка и признак списка
end
--/------------------------------------------------------------------
--/ Распаковка в таблицу 'tTbl' строки 'sStr' (или части строки от 'at')
--/------------------------------------------------------------------
function Parse_Str(sStr,at)
  local tTbl,iLen = {},sStr:len()
  local key,value,bList
  if not at then at = 1 end --/ парсинг с начала строки
  local iByte = string.byte(sStr:sub(at,at))--/ численное значение at-го символа в строке
  local bList = iByte == tPackChar.l[1] --/ флаг: таблица типа 'список'? (table-list)
  if bList then --/ 'список'?
    at = at +1 --/ переход к следующему символу строки
  end
  while at < iLen do --/ (суб)строка не закончилась?
    iByte = string.byte(sStr:sub(at,at))--/ численное значение at-го символа в строке
    at = at +1 --/ переход к следующему символу строки
    if not bList then --/ не список?
      --/ парсинг 'key'
      if     iByte == tPackChar.n[1] then --/ 'number'?
        key,at = Get_Num(sStr,at)
      elseif iByte == tPackChar.h[1] then --/#+# 'number-hex'?
        key,at = Get_Num(sStr,at,true) --/< 'true' - флаг распаковка хекс-строки
      elseif iByte == tPackChar.s[1] then --/ 'string'?
        key,at = Get_Str(sStr,at)
      elseif iByte == tPackChar.e[1] then --/ конец (суб)таблицы? (table-end)
        return tTbl,at --/> субстрока субтаблицы закончилась - выход из функции
      else
        abort("Parse_Str:(%s):UnSupported_TypeKey=" .. tostring(iByte)
      end
      iByte = string.byte(sStr:sub(at,at))--/ численное значение at-го символа в строке
      at = at +1 --/ переход к следующему символу строки
    elseif iByte == tPackChar.e[1] then --/ конец списка?
      iByte = string.byte(sStr:sub(at,at))--/ численное значение at-го символа в строке
      at = at +1 --/ переход к следующему символу строки
    end
    --/ парсинг 'value'
    if iByte == tPackChar.n[1] then --/ 'number'?
      value,at = Get_Num(sStr,at)
    elseif iByte == tPackChar.h[1] then --/#+# 'number-hex'?
      value,at = Get_Num(sStr,at,true) --/< 'true' - флаг распаковка хекс-строки
    elseif iByte == tPackChar.s[1] then --/ 'string'?
      value,at = Get_Str(sStr,at)
    elseif iByte == tPackChar.b[1] then --/ 'boolean'?
      value,at = Get_Bool(sStr,at)
    elseif iByte == tPackChar.t[1] then --/ 'table'?
      value,at = this.Parse_Str(sStr,at) --/ рекурсивный вызов для 'табличных субстрок'
    else
      abort("Parse_Str:(%s):UnSupported_TypeValue=" .. tostring(iByte)
    end
    if bList then --/ элемент списка?
      table.insert(tTbl, value) --/ добавляем в таблицу типа 'список' (table-list)
    else
      tTbl[key] = value
    end
  end
  return tTbl, at --/>
end
--/------------------------------------------------------------------
--/ служебные функции
--/------------------------------------------------------------------
--/ по-символьный парсер строки 'sStr' от at до первого 'управляющего' символа
function Get_Str(sStr,at) --/< стринг(строка) и начальный индекс в нем
  local iLen = sStr:len() --/ индекс конца стринга(строки)
  for i=at,iLen do
    if string.byte(sStr:sub(i,i)) < 32 then --/ 'управляющий' символ?
      if i == at then --/ 1-ым символом идет управляющий? (пустая строка)
        return "", i --/> zero-string,iNext
      end
      --/ начальная часть (суб)строки и индекс первого упр.символа
      return sStr:sub(at,i-1), i --/> sSubStr,iNext
    end
  end
  --/ вся (суб)строка до конца и индекс 'после конца'
  return sStr:sub(at,iLen), iLen+1 --/> sSubStr,iNext
end
--/ перевод части (от 'at') строки 'sStr' в число (десятичное)
function Get_Num(sStr,at)
  local sSubStr,iNext = Get_Str(sStr,at)
  local iNum = nil
  if bHex then --/ распаковка хекс-строки?
    iNum = tonumber(sSubStr,16) --/ перевод хекс-строки в десятичное число ('0x'..sSubStr)
  else
    iNum = tonumber(sSubStr) --/ перевод строки в десятичное число
  end
    return iNum, iNext --/>
  elseif sSubStr == "" then --/ пустая субстрока?
    return 0, iNext --/> #?# не будем пока прерывать
  else
    abort("Get_Num:SubStr=" .. tostring(sSubStr)
  end
end
--/ перевод части (от 'at') части строки 'sStr' в булево значение (true|false)
function Get_Bool(sStr,at)
  local sSubStr,iNext = Get_Str(sStr,at)
  return (sSubStr == "1" or string.lower(sSubStr:match('^%s*(%S*)')) == 'true'), iNext --/>
end
--/------------------------------------------------------------------

 

Пример практичеккого применения:

В игре в таблицу запоминаются игровые идентификаторы (ID) объектов.

Для 198 объектов:

Паковка таблицы амк-вариантом: 1925 байт

Паковка таблицы 'экономным': 1065 байт

 

 

Примечание: Для списка - 1 (одна) метка на весь список.

Проверено - работает безощибочно с таблицами непример и такого типа:

{"s1",2,"s3",4,"s5",nil,nil,["f"]=false,6,"s7",8,{"b1","b2","b3"},10,"s11",nil,nil,nil,["t"]=true }

Исправил ошибку распаковки вложенных списков. 10:20 MCK --/ Artos

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Artos, слово - не воробей, поэтому вот тебе тоже

Если учишь кого-то жизни вместо того, чтобы попытаться помочь, то неплохо было бы научиться - для начала - понимать то, о чём пишешь сам (не совершая при этом детских грамматических ошибок).

Итак, пройдёмся сначала:

твоя реплика первого поста (главное выделено мной, =VENOM=) :

Именно для этого гулага в all.spawn'е организован респавнер 'esc2_respawn_bandits_fabrika', в котором и прописаны секции, которые будут спавниться (esc_bandit_respawn_1, esc_bandit_respawn_2)...

...и второго:

2. Где-то мною упомянута что респавнеры плодят объекты привязанные к гулагам? Само собою, отреспавненные объекты подчиняются тем конфигам, которые определены их секцией. Это кому-то нужно доказывать?

Не находишь странным, что сначала пишешь одно, а затем сам же от этого открещиваешься? Да ещё при этом неуклюже оправдываясь? Поэтому, специально для тебя (т.к. остальные в курсе) вот сделал несколько скринов (раз на словах с первого раза не доходит :D), доказывающие тот простой факт, что респонеры порождают NPC, не привязываясь ни к каким гулагам (локация Кордон, смарты esc_lager и esc_fabrika_bandit, второй после "зачистки", заполняемые сталкерами, порождёнными совершенно разными респонерами, и никаких "от ближайшей", как ты изволил выразиться):

8ec80c534d50aa7e25840e17d27bc820.jpg f6eb401b105a92f61d5ddcd8080cfd79.jpg e7321194863762ddcd23201ecef87b3b.jpg

 

А вот смарт esc_fabrika_bandit с изменёнными параметрами smart_terrain_presets.ltx - видно, что даже бандит "Фраер" прибежал через пол-Зоны, чтобы поселиться на Кордоне (остальные с рангом "мастер" порождены респонерами):

4b20cdeb2126d3abfb4476c260a9d178.jpg 051d90b8738bc67828c3c1030e16dd08.jpg daa55b72475385886363a3ad10cc94dd.jpg

 

Ну, и ещё кое-что, достойное внимания :D:

Простая правка строки респавнера, добавляющая иль заменяющая секции - и после перекомпиляции алл.спавна - АТП заматереит (после смерти существующих).

Что там "заматереит", гулаг или респонер? Гулаг от правки строки респонера ни на грамм не "заматереит", ни после смерти существующих, никогда вообще. А вот респонер станет плодить неписей с изменёнными парамертами.

 

Так что держи, Дружок, свой запал при себе, и запомни, что тема эта - не театр одного актёра, разглагольствующего о том, кому что стоит делать, а кому чего не не стоит, а для взаимопомощи моддеров.

[x]

Изменено пользователем Artos
Ссылка на комментарий

=VENOM=

Если бы не некая информация (да еще со скринами), которая может быть полезна незнающим -снес бы пост как злостный флуд.

Оставляю решение до модератора раздела ...

Понимаю, что задето было некое самолюбие и кто-то тебе посмел возразить и поправить, ткнув носом в ошибки (хотя и сам же допустил пару ... не считая "детских грамматических ошибок")

Но для чего же продолжать упорно спорить, домысливая за других, переходя на личность и продолжая упорно долдонить свое, не обращая (иль не признавая) аргументы?

 

Не для спора иль оправдания, а токмо справедливости ради, пройдемся по списку:

1. Oбъект класса 'respawn' (ты его, как понимаю, обзываешь'респонер') спавнит только NPC, как ты утверждаешь?

Нет, респавнятся и монстры и вещи ... Нужны доказательства? Готов их привести.

 

2. Процитированная моя фраза:

Именно для этого гулага в all.spawn'е организован респавнер 'esc2_respawn_bandits_fabrika', в котором и прописаны секции, которые будут спавниться (esc_bandit_respawn_1, esc_bandit_respawn_2)...

2.1. Согласен, фраза не совсем удачная, т.к. не дал пояснений, о которых упомянут в последующем посте:

Слова о связи этого конкретного респавнера 'esc2_respawn_bandits_fabrika' упомянута именно из-за его закомментированной логики связанной с конкретным гулагом. И его близким расположением - ведь работа выбирается от ближайшей ...
Прекрасно понятно (другим, а не тебе) что разработчиками этот респавнер предназначался именно для этого гулага. Хотя по сути, он также может служить и для других гулагов.

2.3. С логикой у тебя явно не лады. В моей фразе говорится о предназначении респавнера для гулагу, но(!) где ты увидел то, что говорится о привязке заспавненных объектов этим респавнером в исходному гулагу??? Слова "в котором и прописаны секции, которые будут спавниться" говорят ТОЛЬКО о том, чем и какие секции будут спавниться и НЕ более! С чего в твоем воображении всплывает привязка заспавненых объектов вообще к какому либо гулагу? И тем более я уже ранее пояснял, что заспавненные объекты будут привязаны к чему-то только руководствуясь своей секцией спавна (кастомдаты, профиль иль подобное).

Или кто-то из нас не умеет читать по-русски или у кого-то воспаленная фантазия и попытки всеми НЕправдами хоть как-то оправдаться.

 

3. Ну слава Б. хоть тому, что великих и безусловных преимуществ скриптового спавна перед правкой all.spawn'а ты не стал притягивать за уши к оправданиям, а то б я прям растерялся ... ;-) Да и о своей выдумке со спавном одного мастер-бандоса перестал упоминать. И на том спасибо.

 

4. Ну вымысел о "моих" советах по созданию новых секций мы проскочим ...

 

5. Как и об очень познавательной, но не к месту упомянутой информации о предикатах ...

 

6. Подошли к моей ошибке по забывчивости, которую и признал и извинился.

Мои слова, повторенные мною дважды похоже придется разжевать до состояния пюре, чтобы ну совсем уж до непонятливых дошло:

Простая правка строки респавнера, добавляющая иль заменяющая секции - и после перекомпиляции алл.спавна - АТП заматереет (после смерти существующих).

а) Исправив в all.spawn'е (alife_l01_escape.ltx) в секции объекта класса 'respawn' (с одноименной секцией) с именем 'esc2_respawn_bandits_fabrika' строку:

respawn_section = esc_bandit_respawn_2,12, esc_bandit_respawn_1,9

на такую:

respawn_section = cit_bandit_respawn_2,99 ;--/ секция бандита-мастера с вероятностью спавна 99%

- после перекомпиляции all.spawn'а получим в результате, что респавнер будет с вероятностью 99% пытаться 6 раз (с каждым запуском игры) заспавнить бандита-мастера (естественно при начале НИ).

Вариаций может быть множество, например, просто добавить ', cit_bandit_respawn_2,50' , чтобы и прежние ранги спавнились ...

б) Внеся, забытую мною, правку в 'smart_terrain_presets.ltx' в секцию [l01_escape]:

bandit = novice, experienced, veteran, master

- получим в результате, что респавнер вблизи гулага, находящегося на АТП, будет спавнить бандитов-мастеров, которые могут быть приняты в этот АТП-шный гулаг - в результате АТП заматереет. Если тобою не воспринимается ассоциация с "заматерелый бандит" (бандит-мастер в игре) и место где их немало - "заматерелый АТП" - то ... могу только посочувствовать. Спрашивавшему лнкс'у это не потребовалось разжевывать.

Итого: Правка пары строчек и перекомпиляция all.spawn'а - ву-а-ля. Осталось только освободить от прежних (исходных) бандитов АТП и дождаться респавна 'бандос-мастер'ов.

 

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

Насчет "детских грамматических ошибок" - сам себя ругаю, за то, что нередко допускаю немало оЧепяток ... Но, ругая других именно за грамматические ошибки, все же и различаю - опечатался или безграмотно написал. К своему сожалению, пишу 'с головы', нередко отвлекаясь и никак не могу себя заставить каждую фразу перепроверять на чекерах ... Грешен ...

 

И последнее:

=VENOM=: ... и запомни, что тема эта - не театр одного актёра, разглагольствующего о том, кому что стоит делать, а кому чего не не стоит, а для взаимопомощи моддеров

Подождем конечно реакции модератора и он даст свою трактовку.

От себя пока же скажу: То, что к моему сожалению, с некоторого времени в топике пока преобладают мои посты, говорит не о театре, а о том, что другие или не находят достаточно времени или желания писать на каждый вопрос ... Разглагольствования это иль все же нечто полезное - решаешь не ты, а и сами читающие и тот же модератор. Думаю, что долго разглагольствующего не будут держать в кураторах топиков. Ну а про взаимопомощь - ... не хочется провоцировать дальнейший флуд, но то, что ты называешь взаимопомощью (как ранее в топиках) скорее 'подачки в час по чайной ложке' для начинающих модмейкеров, да и для более опытных - 'ни шатко ни валко' и большей частью по мелочам.

Тебе что-то мешает почаще чем раз в каждую ночь 'вылезать на сцену' и давать свои 'сольные арии'? Вопросов и тем за эти дни не мало, на которые и ты бы мог дать правильный ответ/совет, если считаешь тут идет разглагольствование ...

 

Примечание: Цель моих многословных 'разглагольствований' никак не сязана с тем, что мне хочется кого-то покритиковать иль что-то свое показать, а - желание научить многих задавать правильно (информаивно) вопросы, отучить давать пустые ответы и пробудить у многих модмейкеров желание думать и создавать/улучшать, а не копипастить ...

 

Ну и запомни теперь уже ты: Пока в топике куратором - я, бесполезный флуд, оффтопик, ошибки и неточности в ответах, лень и нахлебничество, безграмотность - будут пресекаться (мягко иль жестко), не взирая на возраст, 'заслуги' иль иное. К 'взаимопомощи' это не имеет никакого отношения, ИМХО.

О соблюдении правил форума - нет и речи, это не требует ни пояснений ни напоминаний.

 

 

[x]

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Добрый день!

Помогите найти пути лечения такого вылета:

! Unknown command: ZAMET:weather_update___day___[5]

! Unknown command: ZAMET:***______sar_monolith_general___--___State:___0___--___Total___population:___11/11___--___Non___exclusive___population:___0/0

! Unknown command: ZAMET:***______sar_monolith_sklad___--___State:___0___--___Total___population:___5/5___--___Non___exclusive___population:___0/0

! Unknown command: ZAMET:*SND*___play___SND___to___[state]___for___[bar_bar_lisiy]

! Unknown command: ZAMET:ERROR:___Watchdog___100.Reason___cn___on_news___offline_alife___exit

 

FATAL ERROR

 

[error]Expression : fatal error

[error]Function : CScriptEngine::lua_error

[error]File : E:\stalker\patch_1_0004\xr_3da\xrGame\script_engine.cpp

[error]Line : 73

[error]Description : <no expression>

[error]Arguments : LUA error: ...files (x86)\s.t.a.l.k.e.r\gamedata\scripts\_g.script:20: bad argument #2 to 'format' (string expected, got no value)

 

 

ТЧ + АМК. Добавлены локации новые, убраны некоторые старые (Кордон, Свалка, Агропром, ТД и радар)

Вылет (или завис, то так, то так) возникает рандомно. Находишься на локации какое-то время и может случиться такой вылет. От локации не зависит - на любой такое происходит.

Про Ватчдоги читал на форумах много всего, но в данном случае не понятно где искать.

Основываясь на логе, error содержит строку: cn on_news offline_alife exit

Эта строка присутствует в файле: news_main.script

    local gtime = game_minutes()
    
    if (gtime - timer_alife_showed > timer_alife_freq) then
        amk.oau_reason="cn on_news offline_alife start"
        amk_offline_alife.offline_alife()
        amk.oau_reason="[b]cn on_news offline_alife exit[/b]"
        timer_alife_showed = game_minutes()
    end

 

Это конструкция из большой функции on_news()

Вот она целиком:

function on_news()
    local avail = {}
    if news_stack then 
        amk.oau_reason="cn on_news first pass"
        for k,v in pairs(news_stack) do
            if v.activated == nil then
                if (v.lifetime > game_minutes()) then
                    if (v.timeout < game_minutes()) then -- Новость актуальна.
                        --table.insert(avail, k)
                    else
                        mylog("Not ready yet - ".. v.from) -- Еще не время.
                    end
                else -- Новость устарела.
                        mylog("Too old - "..v.from..": "..v.text)
                    table.remove(news_stack, k)
                end
            else -- Новость уже была.
                table.remove(news_stack, k)
            end
        end
        amk.oau_reason="cn on_news sort"
        -- Отсортируем.
        table.sort(news_stack, news_sort)
        --amk.dump_table(news_stack)
        amk.oau_reason="cn on_news second pass"
        for k,v in pairs(news_stack) do
            if v.activated == nil then
                if (v.lifetime > game_minutes()) then
                    if (v.timeout < game_minutes()) then -- Новость актуальна.
                        table.insert(avail, k)
                    else
                            mylog("Not ready yet - ".. v.from..": "..v.text) -- Еще не время.
                    end
                else -- Новость устарела.
                        mylog("Too old - "..v.from..": "..v.text)
                    table.remove(news_stack, k)
                end
            else -- Новость уже была.
                table.remove(news_stack, k)
            end
        end
    end
    
    if avail and table.getn(avail) > 0 then
        amk.oau_reason="cn on_news get available"
        --local t = avail[math.random(table.getn(avail))]
        local t = avail[1]
        local z = news_stack[t]
        if (z) then
            local bAlive = false
            local m_author_id = tonumber(z.author_id)
            if (m_author_id ~= nil) then
                amk.oau_reason="cn on_news check author"
                bAlive = false
                local obj = alife():object(m_author_id)
                amk.oau_reason="cn on_news check author obj"
                if (obj) then
                    amk.oau_reason="cn on_news author obj exists"
                    if (IsStalker(obj)) then
                        amk.oau_reason="cn on_news author obj is NPC"
                        if IsNpcStalker(obj) then
                            amk.oau_reason="cn on_news check author alive"
                    if (obj.alive and obj:alive()==true and obj.health and obj:health() > 0) then
                        if (_debug == true) then amk.add_spot_on_map(obj.id, "red_location", z.from..": "..z.text) end
                                amk.oau_reason="cn on_news author is alive"
                        bAlive = true
                    end
                end
                    end
                end
            else
                bAlive = true
            end
            if (bAlive == true) then
                amk.oau_reason="cn on_news show_news"
                --show_news(z.from, z.text, z.timeout, z.showtime, z.section)
                show_news(z.text, z.from, 0, z.showtime, z.section)
                amk.oau_reason="cn on_news set activated"
                z.activated = game_minutes()
            else
                amk.oau_reason="cn on_news show_news alive is false"
            end
        end
    else
--        mylog("on_news [5] - no news ")
    end    

    amk.oau_reason="cn on_news continue"

    if (timer_next_blow == 0) then
        local name, delay
        for a=1,100,1 do
        local tmp = amk.load_variable("gt"..a,nil)
            if tmp ~= nil then
                name     = amk.load_variable("gt"..a, nil)        
                delay     = amk.load_variable("gd"..a, nil)
                if (name and delay and name == "blow_shift") then
                    timer_next_blow = delay
                    --next_blow(delay)
                end
            end
        end    
    end

    local gtime = game_minutes()
    
    if (gtime - timer_alife_showed > timer_alife_freq) then
        amk.oau_reason="cn on_news offline_alife start"
        amk_offline_alife.offline_alife()
        amk.oau_reason="cn on_news offline_alife exit"
        timer_alife_showed = game_minutes()
    end
    if (gtime - timer_blow_showed > timer_blow_freq) then
        do_blow_news()
    end
    if (gtime - timer_eternal_stalker > timer_eternal_stalker_freq) then
        do_eternal_stalker()    
    end
    --[[ if (gtime - timer_random_spawn > timer_random_spawn_freq) then
        do_seen()
    end ]]
    if (gtime - timer_def_spawn > timer_def_spawn_freq) then
        do_seen_monster()    
    end    
    if (gtime - timer_daytime_showed > timer_daytime_freq) then
        on_daytime()
    end
end

 

Видимо, что-то не нравится связанное с сообщением о предстоящем выбросе.

Возможно, кто-то сможет помочь в этом вопросе.

Также присутствует в этой конструкции ссылка на функцию: offline_alife() из файла: amk_offline_alife.script

Фот эта функция:


--генерируем оффлайн события

function offline_alife()

 

local lname = maps[math.random(table.getn(maps))]

-- update_tables(lname)

-- amk.mylog("Offline_alife - "..lname)

local st = 0

amk.oau_reason="cn offline_alife chp1"

if off_npcs[lname] then st = table.getn(off_npcs[lname].stalkers) end

if st>0 then

amk.oau_reason="cn offline_alife chp2"

for search = 1,search_intensivity do

amk.oau_reason="cn offline_alife chp3"

local rnd = math.random(st)

amk.oau_reason="cn offline_alife chp4"

if off_npcs[lname].stalkers[rnd] then

amk.oau_reason="cn offline_alife chp5"

local victim = alife():object(off_npcs[lname].stalkers[rnd].id)

amk.oau_reason="cn offline_alife chp6"

if victim and not victim.online and victim.health and victim.can_switch_online and victim:health()>0 and victim:can_switch_online() and victim:name() == off_npcs[lname].stalkers[rnd].name then

amk.oau_reason="cn offline_alife chp7 "..tostring(victim and victim:name())

local vdata = collect_info(victim,lname)

amk.oau_reason="cn offline_alife chp8 "..tostring(victim and victim:name())

if table.getn(vdata.enemies)>0 then

--есть вражина - воюем нах!

amk.oau_reason="cn offline_alife chp9 "..tostring(victim and victim:name())

on_enemies_found(victim, vdata)

break --прерываем цикл - событие отработано

elseif table.getn(vdata.monsters)>0 then

--есть монстрятина - видели, слышали, убили, сдохли...

amk.oau_reason="cn offline_alife chp10 "..tostring(victim and victim:name())

on_monsters_found(victim, vdata)

break --прерываем цикл - событие отработано

elseif table.getn(vdata.corpses.stalkers)>0 then

--есть труп сталкера

amk.oau_reason="cn offline_alife chp11 "..tostring(victim and victim:name())

on_npc_corpses_found(victim, vdata)

break --прерываем цикл - событие отработано

elseif table.getn(vdata.corpses.monsters)>0 then

--есть труп монстра

amk.oau_reason="cn offline_alife chp12 "..tostring(victim and victim:name())

on_monster_corpses_found(victim, vdata)

break --прерываем цикл - событие отработано

elseif table.getn(vdata.weapons.seen)>0 then

--есть бесхозное оружие

amk.oau_reason="cn offline_alife chp13 "..tostring(victim and victim:name())

on_weapons_found(victim, vdata)

break --прерываем цикл - событие отработано

elseif table.getn(vdata.artefacts)>0 then

--есть арты

amk.oau_reason="cn offline_alife chp14 "..tostring(victim and victim:name())

on_artifacts_found(victim, vdata)

break --прерываем цикл - событие отработано

elseif table.getn(vdata.inv_boxes)>0 then

--есть контейнеры. Надо обыскать.

amk.oau_reason="cn offline_alife chp18 "..tostring(victim and victim:name())

on_inv_boxes_found(victim, vdata)

break --прерываем цикл - событие отработано

elseif items[victim.id] and table.getn(items[victim.id]) > 0 then

--попробуем продать всякого

amk.oau_reason="cn offline_alife chp15 "..tostring(victim and victim:name())

-- amk.mylog("Offline: lets trade")

amk.oau_reason="cn offline_alife chp17 "..tostring(victim and victim:name())

process_trade(victim)

-- amk.mylog("Offline: trade done")

break

else

--amk.mylog("__")

end

end

end

end

end

amk.oau_reason="cn offline_alife end"

end[code]

 

 

Заключайте коды в тэги [cоde], дабы не 'убивать' отступы и не коверкать некоторые сочетания символов.

--/ Artos

Изменено пользователем Artos
Ссылка на комментарий

antreg

Твой вылет говорит, что проблема, повлекшая зависание апдейта биндера актора (см. в bind_stalker.script) возникла после выполнения строки 2373 (amk.oau_reason="cn on_news offline_alife exit") в файле 'news_main.script'.

Наличие 'exit' в строке 'watchdog'-а, говорит о том, что после обращения к скрипту 'amk_offline_alife', последний вернул управление вызвавшей функции. Что говорит об отсутствии до настоящего момента критичной ошибки.

К сожалению, далее вызовы идут к другим функциям скрипта 'news_main.on_news()' и где наступила ошибка, приведшея к зависанию биндера определить точно невозможно.

Добавлены локации новые, убраны некоторые старые (Кордон, Свалка, Агропром, ТД и радар)

А вот это как раз и может провоцировать ошибки в скрипте 'news_main', т.к. он (совместно с 'amk_offline_alife.script') обрабатывает все, занесенные в их конфиги локации.

Если тобою не сделаны необходимые поправки для удаленных/добавленных локаций - коды скриптов могут спотыкаться в самых разных местах ... для неизвестных или отсутствующих локаций (в зависимости что не подправлено).

Т.к. вызов 'news_main' ассинхронен с остальными событиями в игре и периодически (и рандомно) вызывается в самое разное время не зависимо от текущей локации - у тебя и возникант ошибка вне зависимости от локации.

 

В общем анализировать влияние своих извенений с локациями на коды скриптов новостей и офф-лайн-алайфа и адаптировать последние. Сделать это можно только тебе, т.к. что ты внес в свою игру - другим не ведомо. Если бы не объем изменений (добавленя локации), то предложил бы тебе выложить свои правки ... По сути требуется ковыряться имея всем коды игры. ... Ну или отказаться полностью или частично от новостей и оффлайн-алайфа, отключив эти скрипты/функции.

Попробуй ремить (закомментировать) вызовы функций 'do_blow_news()', 'do_eternal_stalker()', 'do_seen_monster()' все или по одиночке - может сузишь круг поиска ошибки.

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий
Где я такое сказал?
Как упомянул Аrtоs, некоторые заходят через двери - значит гость. А мне нравиться лазить через форточку - значит вор. Получай по чём попало.

Я принял твои слова именно как совет ходить всё-таки через двери.

Artos,

Но ведь это только говорит об упорядоченности ключей. А что насчёт значений? Ведь в качестве значений может быть что угодно: числа, строки, таблицы, пользовательские объекты.

Хоть и не ко мне обращался, но всё же каким-то боком касается. Цитата :

Вопрос-1: Как оптимально определить тип таблицы 'список' ... и не полный перебор списка на поиск 'дыр' в индексах... Т.е. ...определение именно списка, а не иного типа массива.

Где в условиях задачи указана необходимось проверки на тип значений таблицы? Необходимо было выяснить тип самой таблицы. Иначе я сразу бы сказал что без перебора никак.

Ссылка на комментарий

Gun12

Как раз, полчаса назад, поправил свою оплошность в функции распаковки, которая касается твоего вопроса.

 

Изначальный и обновленный алгоритмы упаковки таблиц проверяют тип всех значений ключей/индексов (число, строка) и полей (число, строка, булево, таблица) внутри цикла упаковки, отсекая все остальные значения. Если значение НЕ в числе разрешенных - принудительное прерывание -> 'abort'.

 

Изменение алгоритма упаковки с (целью экономии) потребовало вынести ДО упаковки проверку на тип упаковываемой КОРНЕВОЙ таблицы. Не разумно выполнять каждый раз ту же проверку внутри цикла одной и той же таблицы, тип ее и содержание не меняются.

Все значения ключей (они могут быть только числом или строкою) и все значения полей - проверяются как и ранее внутри цикла упаковки. Если помимо числа/строки/булева встречается таблица - функция упаковки выполняет рекусивный вызов самой себя и, прервав основной цикл, запускает НОВЫЙ подцикл по упаковке вложенной таблицы. Для этой субтаблицы уже вновь выполняется проверка 'список или нет'. По окончании подцикла - возобновляется прерванный цикл.

 

Т.о., отвечая на твой вопрос, исходя из исходного алгоритмане - не имеет смысла предварительная проверка самих значений таблицы, т.к. они перепроверяются внутри цикла упаковки для каждой (суб)таблицы. Поэтому и не указал в условиях по задаче определения типа таблицы.

 

Вопрос о (не)желательности предварительной проверки значений (элементов) таблицы можно конечно поднять, но это уже третий автономный аспект возможного повышения удобств упаковки для модмейкера.

Исходя из того, что модмейкер все же обязан проверить написанные им коды в работе/игре и то, что при некорректном использовании данной функции упаковки, последует однозначный вылет - этот вопрос не завязан на аспектах по 'экономичности' упаковки.

Но можно и по этому поводу порассуждать. Типа: что важнее - затратить время на предварительный цикл проверки допустимых значений и НЕ выполняя упаковку (а это потеря данных!) - вежливо в логе растолковать модмейкеру об ограничениях применений упаковки. Иль сэкономив время ... фатальным вылетом и логом ругнуться, что мол думать нужно что упаковать собрался. ;)

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Поздно заметил, но всё же отвечу.

Что же в итоге?...проверка: имеются элементы 'списка', 1-й индекс начинается с 1 и за 'списком' отсутствует хеш-элемент
Конечно ДА. Такой проверки достаточно. Именно это я пытался доказать всё это время. Изменено пользователем Gun12
Ссылка на комментарий
Artos, я оказывается использовал не kurit sidya_ 0, а stoya_kurit_2_0. Т. к. с kurit sidya_ 0 были вылеты, а с stoya_kurit_2_0 не было вылетов. Давно пробовал сделать, по этому в памяти осталось что использовал kurit sidya_ 0... Вообщем, вот, сам посмотри.
Ссылка на комментарий

Начал создавать смарты от выброса, вот только что-то не получилось - Выброс не настал...

[smart_terrain]

squad_id = 22

max_population = 1

safe_restr = surge_forester_cave_hide_smart_1; surge_forester_cave_hide_smart_2

Локи в скриптах зареганы.

 

Выводы модмейкера:

1)Вылетает - это хорошо. Значит, работает :)

2) Если хочешь сделать что-то хорошо, делай сам!

3) Если падёшь духом, падёт и мод.

4) Он живой... :o

Ссылка на комментарий

_Призрак_,

Можно ли каким то способом получить объект инвентарь или же просто открыть его?

Ты можешь получить это окно через MainInputReciever, когда оно уже открылось, но не можешь открыть штатными средствами.

Изменено пользователем malandrinus
 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Ссылка на комментарий

А если мы не открывали раньше инвентарь? В билдах была функция CUIInventoryWnd() возвращающая инвентарь, но что с ней случилось в финалке?

Изменено пользователем _Призрак_

Freedom

Ссылка на комментарий

У меня следующий вопрос.В моем моде на апдейте актора стоит функция проверки текущей локации, ниже.

function level_spec_ops()
local level_gg = level.name()
if level_gg == "zaton" then
avs_info.zaton_spec_ops()
end
end

 

 

То есть если текущий уровень - Затон, то идет вызов другой функции, выполняющей проверку на инфопоршни:

function zaton_spec_ops()
if db.actor:dont_has_info("my2") and db.actor:has_info("zat_bandit_vs_dolg") then
avs_spawn_add.spawn_dolg_bandit_scene()
db.actor:give_info_portion("my2")
end
end

 

 

Фунция определяет проверку на инфопоршни и идет вызов спавн-функции, и ставиться заглушка.Вопросы.

1)На сколько сильно данная кострукция грузит биндер?

2)Можно ли по факту получения инфопоршня не ставить заглушку?Или же все таки надо?

3)Прошу, подскажите, может есть какая-нибудь упрощенная функия для данного творения?

Просто данной конструкцией планируеться проверять инфопоршни на всех локациях мода(стандарт+мап_пак Кости В).

Изменено пользователем panzyuza
Ссылка на комментарий

panzyuza

Вообще сами GSC для таких целей делали в спавне space_restrictor-ы на нужные локации и на них уже вешали логику, которая проверяла наличие инфы и делала нужные вещи.

 

Но если со спавном возится не хочется, то можно и скриптами.

 

Для начала совет - когда пишешь скрипты, старайся отделять начало строки пробелами\TAB. для пущей понятности, тоесть так:

function level_spec_ops()
local level_gg = level.name()
  if level_gg == "zaton" then
    avs_info.zaton_spec_ops() 
  end
end

 

 

Поверь, так гораздо удобней в первую очередь для тебя :)

 

По вопросам:

1) Слишком сильно грузить по идее не должна, ручаться не буду но вообще если и будет грузить то по минимуму. Даже если их много. Перебарщивать конечно тоже не стоит, но ничего критического не будет. А вообще всё зависет от сложности скриптвых проверок. Проверка на наличие инфы по идее быстро работает, а вот если ты начнёшь например отмерять дистанции или прочие вещи делать, то это уже серьёзней будет, но думаю пока ты очень много таких функций не сделаешь, производительность серьёзно не упадёт.

 

2) Не совсем понял вопрос, но твой текущий вариант работает правильно. Скрипт спавна долговцев будет вызван лишь раз при получении инфы "zat_bandit_vs_dolg", а дальше условие не будет выполнятся из за инфы my2

 

3) Создаёшь отдельный скрипт. В него пишешь эту таблицу и функцию update() ниже, саму же функцию update()

ставишь на апдейт из скрипта bind_stalker.script

 

-- Вот образец таблицы, там где ... подразумевается что надо писать по аналогии
local info_table = {
              zaton = {
             --  Имя инфы              =      имя скрипта, имя функции
                  zat_bandit_vs_dolg =     {"my_script", "my_fnct"},
                  <другая инфа>     =     {...},
                    ... 
                          },
              jupiter = {...},
              ...
                          } 

-- Это ставишь на апдейт в бинд сталкере, ф-я должна быть в одном скрипте с таблицей info_table
function update()
local ln   = level.name() -- текущее имя уровня
local itbl = info_table[ln] -- таблица с инфопоршнями для ТЕКУЩЕГО уровня ГГ

  for info, params in pairs(itbl) do
   if db.actor:has_info(info) and db.actor:dont_has_info(info.."_old") then
     _G[params[1]][params[2]]()
    db.actor:give_info_portion(info.."_old")
   end
  end
end

 

Это далеко не лучший пример, но он удобней чем твой текущий вариант. Суть в том что при каждом апдейте идёт перебор таблицы

с инфопоршнями ТЕКУЩЕГО уровня ГГ, и если ГГ получил этот инфопоршень, то вызывается функция (в моём примере функция function my_fnct() из скрипта my_script.script)

 

Дальше после вызова функции, ГГ выдаётся инфопоршень вида <название инфы>_old, тоесть в данном примере после того как ГГ получит инфу zat_bandit_vs_dolg, вызовится функция и ГГ получит инфу zat_bandit_vs_dolg_old, которая не позволит скрипту вызвать функцию второй раз.

 

Саму функцию можно легко совершенствовать при необходимости.

 

Писал без проверки, мог где то в скрипте сделать ошибку.

 

А вообще по хорошему лучше делай как GSC, через space_restrictor-ы, мой вариант чисто для тех, кто не хочет иметь с ними дело.

 

 

Изменено пользователем *Shoker*

Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О

Мастер аномалий на свою заднюю точку.

Ссылка на комментарий
Gun12: Именно это я пытался доказать всё это время.

Gun12И большое спасибо что доказал! :-)

Т.к. данная проверка предназгачени не просто для некой локальной функции, а от нее зависят все сэйвы в игре, то предпочитаю не действовать как многие ... по принципу "у меня работает и ладно", а 2х7 раз отмерить и только тогда применять.

Все мои опыты с самыми различными структурами таблиц (каких в игре врядли кто выдумает) дали только положительный результат.

Дочищая чистовой вариант с данной проверкой, думаю вопроос закрыт на данный момент.

 

Добавлено через 10 мин.:

Кивач

Попробуй ответить мне на вопрос: "А что я завтра должен сделать, о чем вчера записал где-то на листочке?" ;-)

Думается мне, что врядли что вразумительное и конкретное ответишь.

1. Если ты в своих ковыряниях что-то как-то обозвал - глупо другого спрашивать: "А может так нужно писать имя?".

2. Ты мне предлагаешь записаться к тебе в тестеры и суфлеры? Рассматривать измененные тобою коды и подсказывать что ты когда-то сделал и как нужно теперь этим пользоваться? Сорри, но у меня иные планы и на подобное нет ни времени, ни желания.

3. Когда что-то делаешь, нужно не копипастить, а понимать то, что ты делаешь и для чего. Тогда по прошествию времени несложно будет, взглянув на сделанное вспомнить и использовать.

 

И последнее, во всех твоих постах отсутствует вопрос, если не считать вопросом: "А так ли я пишу когда-то мною придуманное имя?"

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

*Shoker*, просто у меня проблема со спейс рестрикторами.Есть рестриктор с такой логикой:

custom_data = <<END
[logic]
active = sr_idle

[sr_idle]
on_actor_inside = nil %+esc_lager_ghost_spawn%
END

 

 

 

При заходе актера активная секция уходит в nil, и выдаеться инфопоршень, спавнящий двух зомби.У зомби в спавне такая логика:

custom_data = <<END
[spawner]
cond = {+esc_lager_ghost_spawn}
END

 

 

Шейп рестриктора 5.Проблема заключаеться в том, что пока рестриктор в алайфе, при заходе все нормально спавниться.Но стоит побегать по локации, не заходя в него, и при возврате инфопоршень выдаеться, но зомби не спавняться.В чем причина-не пойму.Биндер рестрикторов не трогал.

И нужно ли регистрировать инфопоршень с приставкой old?

Изменено пользователем panzyuza
Ссылка на комментарий

panzyuza*Shoker*)

 

1. Уже дал *Shoker* пояснения.

2. Что ты называешь заглушкой? Если под заглушкой ты называешь выдачу инфопоршня "my2", то о каком 'факте получения инфопоршня' спрашиваешь? Что-то ты о 'масле-масляном' спросил ...

3. Упрощенных функция подобного нет. По сути ты уже и используешь самое простое - набор из трех простейших проверок.

То, о чем *Shoker* сказал, насчет GSC и их 'space_restrictor'-ов - это скорее ... чепуха.

Такой спейс-рестриктор должен тогда быть размером со всю локацию (весь затон в его радиусе), его логика, точнее схема логики займет побольше ресурсов, чем твои проверки. Только одно достоинство - этот рестриктор не будет занимать ресурсы на других локациях.

Упомянут *Shoker*'ом и другой (табличный) вариант оптимизации, но ... он действенен для значительного кол-ва однотипных проверок на инфопоршни, а для пары-тройки - только наоборот загрузит апдейтер излишними переборами по таблице.

 

Если хочется оптимизировать подобные проверки/вызовы, и не только такого типа, и не только из апдейтера актора - то это уже иной подход и требует серьезного разговора. Не зря же в игре и серьезных модах сделаны системы коллбэков и лаунчеров.

Для серьезной модификации желателен условно назовем 'лайнчер', который в нужное время мог бы начинать выволнять требуемые вызовы нужных функций и в нужное время иль по заданным условиям прекращать это делать, тем самым экономя ресурсы игры.

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

panzyuza

Вынеси поиск имени локации в НЕТ-спавн. Нет смысла гонять его при каждом апдейте. Достаточно определить один раз при загрузке.

CurrentLevel = level.name()

Соответственно измени функцию :

function level_spec_ops()
    if db.actor:dont_has_info("my2") and CurrentLevel  == "zaton" then
        avs_info.zaton_spec_ops()
    end
end

В ней я поставил первой проверкой наличие инфопроции, расчитывая что она будет выдана в ближайшее время.

Если же она, по задумке, будет "висеть" у тебя достаточно долго, то первой проверкой ставь CurrentLevel == "zaton".

(Ну не могу не заставить себя "украсть" какую-то миллисекундочку :-))

Ну и измени оставшуюся функцию :

function zaton_spec_ops()
    local actor = db.actor
    if actor:has_info("zat_bandit_vs_dolg") then
        avs_spawn_add.spawn_dolg_bandit_scene()
        actor:give_info_portion("my2")
    end
end

Хотя в твоём варианте было всего два обращения к глобальным данным db.actor, и сохранение этой таблицы локально вроде не очень то нужно, но будем учиться делать правильно.

Ну и в конце концов уменьши частоту апдейтов (если не помешает задуманному)

Изменено пользователем Gun12
Ссылка на комментарий

Gun12, panzyuza

Тогда уж выносить, так все потребное :-), :

local Actor = nil --/ клиентский объект актора (ГГ)
local CurrentLevel = "" --/ текущий уровень

function actor_binder:net_spawn(data)
  --/ ... прежний код
  Actor = self.object --/ клиентский объект актора (ГГ)
  CurrentLevel =  level.name() --/ текущий уровень
  return true
end

function actor_binder:update(delta)
  --/ ... прежний код
  if (self.my_update_time or 0) < time then
    if CurrentLevel  == "zaton" then
      self.my_update_time = time + 1000 --/ апдейт 1 раз в сек
      if Actor:dont_has_info("my2") then
        avs_info.zaton_spec_ops()
      end
    else
      self.my_update_time = time + 999999 --/ апдейт 1 раз в ...
    end
  end
end

- заодно и переменную 'Actor' можно в других местах применять для оптимизации

При допустимости - можно все проверки и выдачу инфопоршня в апдейт засунуть и вызывать только собственно спавн.

P.S. Внес отключение периода проверки на НЕ затонах.

Изменено пользователем Artos

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

Создать аккаунт

Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!

Зарегистрировать новый аккаунт

Войти

Есть аккаунт? Войти.

Войти
  • Недавно просматривали   1 пользователь

×
×
  • Создать...