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

  • Автор темы Автор темы justjew
  • Дата начала Дата начала

justjew

Пользователь
19 Мар 2016
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)
 
[quote author=Илья link=topic=781.msg3165#msg3165 date=1458772506]
Почитай
[/quote]

Прочитал. Я создал файл, назвал его, скажем, 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)
 
Сейчас тебе пишет, что ожидают таблицу, а ты передаешь nil.

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

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

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

Сеттер - метод 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)
....
Естественно, пиши их тело как самому нужно. Можешь поэлементно менять, а не целиком.
 
[quote author=Илья link=topic=781.msg3170#msg3170 date=1458850123]
Глобальные переменные одного файла не являются глобальными для другого (они локальны на фоне всех файлов).

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

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

Сеттер - метод 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)
....
Естественно, пиши их тело как самому нужно. Можешь поэлементно менять, а не целиком.
[/quote]

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

Я тоже на java прогаю, да и почувствовал в твоих комментах это. С практикой быстро освоишь скрипт луа.
 
Последнее редактирование модератором:
То ли лыжи не едут, то ли я ...
Даже используя геттеры/сеттеры, все работает не так, как мне надо
Геттером получаю 3, сеттером меняю на 5, но потом геттером снова получаю 3

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

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

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

вот файл 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
_______________________________

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