CustomGames.ru - Dota 2 пользовательские игры

Где следует объявлять глобальные переменные/таблицы?

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн justjew

  • 18
  • Мощь: 0
Вечная проблема при инициализации, компилятор ругается на nil value.
Каков вообще порядок загрузки скриптов? Где мне объявить таблицу, чтобы при инициализации проекта она уже существовала?
Либо, если я что-то не так понял, объясните пожалуйста

[Пример]
У меня есть таблица А = { B = {}, C = false, D = 3 }        (например)
Есть файл с некой логикой, в котором есть функция A.B:DoSmth()
Таблица объявлена НЕ В ЭТОЙ ФАЙЛЕ
При запуске проекта, компилятор пишет примерно так:
[ W VScript ]: Script Runtime Error: ...project\scripts\vscripts\file_with_the_function.lua:39: attempt to index global 'A' (a nil value)
« Последнее редактирование: 23-03-2016, 19:49:43 от justjew »

Оффлайн Илья

  • Супермодератор
  • 2041
  • Мощь: 19

Оффлайн justjew

  • 18
  • Мощь: 0
Почитай

Прочитал. Я создал файл, назвал его, скажем, A.lua. Объявил в нем нужные мне таблицы и функции
Код
A = { }

A.B = {}
A.B.SomeDigit = 0
A.B.SomeBool = false
A.B.SomeTable= {}

function A.B:SomeFunc()
     --[[
     здесь всякое всякое
     ]]--
end


A.С = {}
A.С.SomeDigit = 0
A.С.SomeBool = false
A.С.SomeTable= {}

function A.С:SomeFunc()
     --[[
     здесь всякое всякое
     ]]--
end

Во всех файла, в которых мне нужны эти таблицы, я прописал
Код
if A == nil then
  _G.A = class({})
end

require('A')

Но все равно есть проблемы. В цикле for в pairs я передаю A.B.SomeTable
[ W VScript ]: Script Runtime Error: ...ns\peoject\scripts\vscripts\addon_game_mode.lua:105: bad argument #1 to 'pairs' (table expected, got nil)

Оффлайн Илья

  • Супермодератор
  • 2041
  • Мощь: 19
Сейчас тебе пишет, что ожидают таблицу, а ты передаешь nil.

Скинь код, а то твой "примерный код" имеет ошибки:
1) не уверен, насколько правильно будет работать компилятор с переменными, в именах которых присутствует разделитель "точка";
2)"A.С:SomeFunc()" - для функций используются имя самого файла, а не переменной (A:SomeFunc())

Оффлайн Илья

  • Супермодератор
  • 2041
  • Мощь: 19
Еще можешь почитать про сам язык, хотя бы эту статью.

Оффлайн justjew

  • 18
  • Мощь: 0
Сейчас тебе пишет, что ожидают таблицу, а ты передаешь nil.

Скинь код, а то твой "примерный код" имеет ошибки:
1) не уверен, насколько правильно будет работать компилятор с переменными, в именах которых присутствует разделитель "точка";
2)"A.С:SomeFunc()" - для функций используются имя самого файла, а не переменной (A:SomeFunc())



Файл Dungeons.lua
Спойлер
Код
Dungeons = { }

Dungeons.bosses = {"npc_dota_Big_Bad_Troll", "npc_dota_Frostbang"}

Dungeons.ButcherDung = {}
Dungeons.ButcherDung.CountOfHeroesInside = 0
Dungeons.ButcherDung.Lock = false
Dungeons.ButcherDung.HeroesInside = {0}

function Dungeons.ButcherDung:OnHeroKilledInside()
     print("hero died in butcher dungeon")
     print(Dungeons.ButcherDung.CountOfHeroesInside .. " inside")

     Dungeons.ButcherDung.CountOfHeroesInside = Dungeons.ButcherDung.CountOfHeroesInside - 1

     print(Dungeons.ButcherDung.CountOfHeroesInside.." players are inside")
     print(Dungeons.ButcherDung.Lock)

     if Dungeons.ButcherDung.CountOfHeroesInside == 0 then
          Dungeons.ButcherDung.Lock = false
     end

     print(Dungeons.ButcherDung.Lock)
end


Dungeons.FrostbangDung = {}
Dungeons.FrostbangDung.CountOfHeroesInside = 0
Dungeons.FrostbangDung.Lock = false
Dungeons.FrostbangDung.HeroesInside = {0}

function Dungeons.FrostbangDung:OnHeroKilledInside()
     print("hero died in frostbang dungeon")
     print(Dungeons.FrostbangDung.CountOfHeroesInside .. " inside")

     Dungeons.FrostbangDung.CountOfHeroesInside = Dungeons.FrostbangDung.CountOfHeroesInside - 1

     print(Dungeons.FrostbangDung.CountOfHeroesInside.." players are inside")
     print(Dungeons.FrostbangDung.Lock)

     if Dungeons.FrostbangDung.CountOfHeroesInside == 0 then
          Dungeons.FrostbangDung.Lock = false
     end

     print(Dungeons.FrostbangDung.Lock)
end
[свернуть]

Файл frostbang_dung_script.lua
Спойлер
Код
if Dungeons == nil then
  _G.Dungeons = class({})
end

require('Dungeons')

function OpenDoor()
local EntryDoorObs1 = Entities:FindByName(nil, "frostbang_dung_door_obs1")
local EntryDoorObs2 = Entities:FindByName(nil, "frostbang_dung_door_obs2")
local EntryDoorObs3 = Entities:FindByName(nil, "frostbang_dung_door_obs3")
if Dungeons.FrostbangDung.Lock == false then
EntryDoorObs1:SetEnabled(false, false)
EntryDoorObs2:SetEnabled(false, false)
EntryDoorObs3:SetEnabled(false, false)
end
end

function OnePassed(event)
if Dungeons.FrostbangDung.Lock == false then
Dungeons.FrostbangDung.CountOfHeroesInside = Dungeons.FrostbangDung.CountOfHeroesInside + 1
print("One hero passed inside - " .. Dungeons.FrostbangDung.CountOfHeroesInside)

HeroName = event.activator:GetEntityIndex()
table.insert(Dungeons.FrostbangDung.HeroesInside, HeroName)

for i=1,#Dungeons.FrostbangDung.HeroesInside do
print(Dungeons.FrostbangDung.HeroesInside[i])
end
end
end

function LockDoor()
Dungeons.FrostbangDung.Lock = true
EntryDoorObs1 = Entities:FindByName(nil, "frostbang_dung_door_obs1")
EntryDoorObs2 = Entities:FindByName(nil, "frostbang_dung_door_obs2")
EntryDoorObs3 = Entities:FindByName(nil, "frostbang_dung_door_obs3")
EntryDoorObs1:SetEnabled(true, true)
EntryDoorObs2:SetEnabled(true, true)
EntryDoorObs3:SetEnabled(true, true)
print("Door is now locked")
print(Dungeons.FrostbangDung.CountOfHeroesInside.." players are inside")

end
[свернуть]
Такого же плана файл butcher_dung_script.lua

И addon_game_mode.lua (весь не буду скидывать)
Спойлер
Код
function CheckIfKilledInDung( name )
for key,v in pairs(Dungeons) do
print("-------------------------------")
print("from CheckIfKilledInDung func")
print(v.HeroesInside[1])
print("-------------------------------")

if has_value(v.HeroesInside, name) then
return true
end
end
return false
end

function CheckWhichDung( tbl, name )
for key,val in pairs(tbl) do
if has_value(val, name) then
return val
else
return val
end
end
end

function IsBoss( name )
if has_value(Dungeons.bosses, name) then
return true
else
return false
end
end

function CheckWhoWasKilled( event )
  local killedEntity = EntIndexToHScript(event.entindex_killed)
  local sCreatureName = killedEntity:GetUnitName()
  local vSpawnLoc = killedEntity.vSpawnLoc

  if (vSpawnLoc == nil) then
    vSpawnLoc = killedEntity:GetOrigin()
  end

  local vSpawnVector = killedEntity.vSpawnVector
  local index = killedEntity:GetEntityIndex()
  local inDung = CheckIfKilledInDung(index)

print(sCreatureName .. " was kiled. Index - "..index..". In Dung - ")
print(inDung)

if killedEntity:IsHero() and inDung then
print("HERO was kiled in dung")
players_in_dung = CheckWhichDung(Dungeons, index)
players_in_dung.OnHeroKilledInside()
table.remove(players_in_dung.HeroesInside, indexof(players_in_dung.HeroesInside, index))
    elseif killedEntity:IsHero() == false and IsBoss(Dungeons, sCreatureName) == false then
    print("world creature was kiled")
    GameRules:GetGameModeEntity():SetContextThink(string.format( "CreatureThink_%d", event.entindex_killed ), function () SpawnUnit(sCreatureName, vSpawnLoc, vSpawnVector) end, nCREATURE_RESPAWN_TIME)
    end
end
[свернуть]

Ошибку генерит в функции CheckIfKilledInDung в if has_value
Там пишет, что передан не table а nil

Оффлайн Илья

  • Супермодератор
  • 2041
  • Мощь: 19
Глобальные переменные одного файла не являются глобальными для другого (они локальны на фоне всех файлов).

Можешь создать сеттеры и геттеры для редактирования и использования твоей таблицы.

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

Если не знаешь о геттерах и сеттерах
Сеттер - метод Set. Служит для установления чего-либо. Геттер - метод Get. Служит для получения чего-либо. В ООП используются для изменений характеристик объекта.
К примеру, пусть у тебя есть скрипт (файл) MyAddon и  таблица в нем GlobalTable. Тогда:

Код
function MyAddon:SetTable(NewTable)
GlobalTable = NewTable
end

function MyAddon:GetTable()
return GlobalTable
end

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

....
local table = MyAddon:GetTable()
table = абра-кадабра + сим-салабим
MyAddon:SetTable(table)
....
Естественно, пиши их тело как самому нужно. Можешь поэлементно менять, а не целиком.
[свернуть]
« Последнее редактирование: 24-03-2016, 20:13:17 от Илья »

Оффлайн justjew

  • 18
  • Мощь: 0
Глобальные переменные одного файла не являются глобальными для другого (они локальны на фоне всех файлов).

Можешь создать сеттеры и геттеры для редактирования и использования твоей таблицы.

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

Если не знаешь о геттерах и сеттерах
Сеттер - метод Set. Служит для установления чего-либо. Геттер - метод Get. Служит для получения чего-либо. В ООП используются для изменений характеристик объекта.
К примеру, пусть у тебя есть скрипт (файл) MyAddon и  таблица в нем GlobalTable. Тогда:

Код
function MyAddon:SetTable(NewTable)
GlobalTable = NewTable
end

function MyAddon:GetTable()
return GlobalTable
end

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

....
local table = MyAddon:GetTable()
table = абра-кадабра + сим-салабим
MyAddon:SetTable(table)
....
Естественно, пиши их тело как самому нужно. Можешь поэлементно менять, а не целиком.
[свернуть]

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

Оффлайн Илья

  • Супермодератор
  • 2041
  • Мощь: 19
спасибо большое, не знал, что глобальные переменные на самом деле не такие уж глобальные
про геттеры и сеттеры знаю (на java программировал), просто хотел без них обойтись

Я тоже на java прогаю, да и почувствовал в твоих комментах это. С практикой быстро освоишь скрипт луа.

Оффлайн justjew

  • 18
  • Мощь: 0
То ли лыжи не едут, то ли я ...
Даже используя геттеры/сеттеры, все работает не так, как мне надо
Геттером получаю 3, сеттером меняю на 5, но потом геттером снова получаю 3

Он при каждом обращении заново читает файл что ли?
Мне надо чтобы я один раз вызвал файл с несколькими таблицами и затем работал с ними, и чтобы они были, так сказать, динамическими. Чтобы, если я задаю новое значение, оно оставалось таковым, а не загружало дефолтное значение из файла
« Последнее редактирование: 26-03-2016, 22:30:47 от justjew »

Оффлайн Илья

  • Супермодератор
  • 2041
  • Мощь: 19
Если ты будешь хранить свою глобалку в главном файле-скрипте, то работать с ней динамически таким образом можно. Но если она будет лежать во второстепенном файле, то да, там каждый раз по новому грузятся переменные, т.е. дефолт.

У меня пока не возникало подобных проблем. Попробуй разобраться с занесением переменных в глобалку компилятора, что в видео демонстрировали.

Оффлайн justjew

  • 18
  • Мощь: 0
Если ты будешь хранить свою глобалку в главном файле-скрипте, то работать с ней динамически таким образом можно. Но если она будет лежать во второстепенном файле, то да, там каждый раз по новому грузятся переменные, т.е. дефолт.

У меня пока не возникало подобных проблем. Попробуй разобраться с занесением переменных в глобалку компилятора, что в видео демонстрировали.
друг, глянь как я сделал и скажи, что тут не так

вот файл Dungeons.lua
Спойлер
Код
Dungeons = { }

Dungeons.ButcherDung = {}
Dungeons.ButcherDung.CountOfHeroesInside = 0
Dungeons.ButcherDung.Lock = false
Dungeons.ButcherDung.HeroesInside = {}
     
Dungeons.FrostbangDung = {}
Dungeons.FrostbangDung.CountOfHeroesInside = 0
Dungeons.FrostbangDung.Lock = false
Dungeons.FrostbangDung.HeroesInside = {}


--------------------------------------------------
-------------FROSTBANG DUNGEON--------------------
--------------------------------------------------

function Dungeons.FrostbangDung:SetCountOfHeroesInside( value )
     print("from dungeon.lua | CountOfHeroesInside before =")
     print(Dungeons.FrostbangDung.CountOfHeroesInside)

     Dungeons.FrostbangDung.CountOfHeroesInside = value

     print("from dungeon.lua | CountOfHeroesInside after =")
     print(Dungeons.FrostbangDung.CountOfHeroesInside)
end

function Dungeons.FrostbangDung:GetCountOfHeroesInside( )
     return Dungeons.FrostbangDung.CountOfHeroesInside
end

function Dungeons.FrostbangDung:SetLock( value )
     Dungeons.FrostbangDung.Lock = value
end

function Dungeons.FrostbangDung:GetLock( )
     return Dungeons.FrostbangDung.Lock
end

function Dungeons.FrostbangDung:AddHeroInside( value )
     table.insert(Dungeons.FrostbangDung.HeroesInside, value)
end

function Dungeons.FrostbangDung:GetHeroesInsideTable( )
     return Dungeons.FrostbangDung.HeroesInside
end

--------------------------------------------------
--------------BUTCHER DUNGEON--------------------
--------------------------------------------------

function Dungeons.ButcherDung:SetCountOfHeroesInside( value )
     Dungeons.ButcherDung.CountOfHeroesInside = value
end

function Dungeons.ButcherDung:GetCountOfHeroesInside( )
     return Dungeons.ButcherDung.CountOfHeroesInside
end

function Dungeons.ButcherDung:SetLock( value )
     Dungeons.ButcherDung.Lock = value
end

function Dungeons.ButcherDung:GetLock( )
     return Dungeons.ButcherDung.Lock
end

function Dungeons.ButcherDung:AddHeroInside( value )
     table.insert(Dungeons.ButcherDung.HeroesInside, value)
end

function Dungeons.ButcherDung:GetHeroesInsideTable( )
     return Dungeons.ButcherDung.HeroesInside
end
[свернуть]

вот один из файлов, в котором мне нужны те таблицы
Спойлер
Код
if Dungeons == nil then
  _G.Dungeons = class({})
end

require('Dungeons')

function OpenDoor()
local EntryDoorObs1 = Entities:FindByName(nil, "frostbang_dung_door_obs1")
local EntryDoorObs2 = Entities:FindByName(nil, "frostbang_dung_door_obs2")
local EntryDoorObs3 = Entities:FindByName(nil, "frostbang_dung_door_obs3")

local Lock = Dungeons.FrostbangDung:GetLock()

if Lock == false then
EntryDoorObs1:SetEnabled(false, false)
EntryDoorObs2:SetEnabled(false, false)
EntryDoorObs3:SetEnabled(false, false)
end
end

function OnePassed(event)
local Lock = Dungeons.FrostbangDung:GetLock()
if Lock == false then
local CountOfHeroesInside = Dungeons.FrostbangDung:GetCountOfHeroesInside()
CountOfHeroesInside = CountOfHeroesInside + 1
Dungeons.FrostbangDung:SetCountOfHeroesInside(CountOfHeroesInside)

print("One hero passed inside - " .. CountOfHeroesInside)

HeroIndex = event.activator:GetEntityIndex()
Dungeons.FrostbangDung:AddHeroInside(HeroIndex)
end
end

function LockDoor()
Dungeons.FrostbangDung:SetLock(true)

local EntryDoorObs1 = Entities:FindByName(nil, "frostbang_dung_door_obs1")
local EntryDoorObs2 = Entities:FindByName(nil, "frostbang_dung_door_obs2")
local EntryDoorObs3 = Entities:FindByName(nil, "frostbang_dung_door_obs3")

EntryDoorObs1:SetEnabled(true, true)
EntryDoorObs2:SetEnabled(true, true)
EntryDoorObs3:SetEnabled(true, true)

print("Door is now locked")
print(CountOfHeroesInside .. " players are inside")
end

function Dungeons.FrostbangDung:OnHeroKilledInside()
    local CountOfHeroesInside = Dungeons.FrostbangDung:GetCountOfHeroesInside()
    local Lock = Dungeons.FrostbangDung:GetLock()
    print("hero died in frostbang dungeon")
    print(CountOfHeroesInside .. " inside")

    CountOfHeroesInside = CountOfHeroesInside - 1
    Dungeons.FrostbangDung:SetCountOfHeroesInside(CountOfHeroesInside)

    print(CountOfHeroesInside.." players are inside")
    print(Lock)

    if CountOfHeroesInside == 0 then
        Dungeons.FrostbangDung:SetLock(false)
    end

    print(Lock)
end
[свернуть]

не знаю почему, но все функции, кроме OnHeroKilledInside работают нормально.
В OnHeroKilledInside GetCountOfHeroesInside получает 0, не смотря на то, что он не 0 (вызов LockDoor() это доказывает), к тому же, вызов SetCountOfHeroesInside именно из этой функции не отписывает ничего в консоль, в то время как вызов этой же функции из других функции - отписывает.
я потихоньку с ума сходить начинаю


_______________________________
EDITED
_______________________________

Разобрался в чем косяк. Сам дурак, панику развел попусту.
Ошибка вообще не связана с этим кодом.
Тут все идеально работает.
« Последнее редактирование: 29-03-2016, 19:30:32 от justjew »

Оффлайн Илья

  • Супермодератор
  • 2041
  • Мощь: 19
Ты бы скинул свой addon_game_mod.lua и тот файл, где ты вызываешь эту функцию: Dungeons.FrostbangDung:OnHeroKilledInside()