FINISTERRAE version 2.3

Are you looking for fun Custom Dungeons that you could play or do you want to share your mod with others? Then this forum is for you!
User avatar
Duncan1246
Posts: 404
Joined: Mon Jan 19, 2015 7:42 pm

Re: FINISTERRAE version 1

Post by Duncan1246 »

minmay wrote:You do not know what upvalues are, yet you are using them all over? Well, I guess this should be required reading: http://www.lua.org/manual/5.1/manual.html#2.6
Here is an example of you using an upvalue:

Code: Select all

function uplevel()
  local match=0
  fw.script:set('party.Finisterrae.onTurn',function(hook,party,dir)
    if (party.go.x == 27 and party.go.y == 23 and party.go.level == pathreal_block_1.level) or
    (party.go.x == 28 and party.go.y == 23 and party.go.level == path_block_1.level)    then 
      nume=nume+1
      if nume==5 then nume=0 end
      if dir==1 then
        match=match+1
      else match=0
      end
      if match==4 then
        playSound("teleport") 
        party.go:setPosition(22,23,0,3,path_block_1.level)
        fw.script:remove('party.Finisterrae.onTurn')
        nume=0 
      end
    end
  end)
end
Here, the match variable is an upvalue.
So, if I understand your example, the declaration of match has to be inside the fw_hook? If it is so, I have effectivly a bunch of same errors... and a save when the hook is active causes a crash. Imo, the only way to fix this is to use a global variable instead (if the "match" is inside the hook, the script can't work and must be rebuild...). What do you think?
Thanks for your explanation!
For the story, my experience in programming is very short (almost nothing before 2014 where I begin my first mod). I shall like to learn more, but it's not so easy to do it alone.
Duncan
The Blue Monastery (LOG1)
download at:http://www.nexusmods.com/grimrock/mods/399/?

Finisterrae(LOG2)
download at:http://www.nexusmods.com/legendofgrimrock2/mods/61/?
User avatar
Zo Kath Ra
Posts: 940
Joined: Sat Apr 21, 2012 9:57 am
Location: Germany

Re: FINISTERRAE version 1

Post by Zo Kath Ra »

Duncan1246 wrote:
minmay wrote:It is a bug in your mod, and it definitely exists. The solution is very simple: stop using upvalues. I see in your dungeon.lua that you are defining lots of upvalues in places where they will cause a crash if the game is saved.
So, I haven't be able to see them! Can you give me one example in my mod, so I understand what is wrong?

EDIT; as I write before, I don't understand why the issue don't occurs when I test the Nathaniel last save. I was thinking that using upvalues causes failure 100% of time if the situation is identical. But it is not true... I would appreciate an explanation, If you have the time to give it.
Duncan
1) Load the savegame from viewtopic.php?f=23&t=12816&start=120#p105385

2) As Nathaniel pointed out in the same post:
There has been a steady crash in location Cian's Mansoleum while trying to save game after taking power gem and pressing on the lever and a button on the wall.
So: all you have to do is pull the lever at 19/4

3) Now try to save => the game crashes
User avatar
Duncan1246
Posts: 404
Joined: Mon Jan 19, 2015 7:42 pm

Re: FINISTERRAE version 1

Post by Duncan1246 »

Zo Kath Ra wrote: So: all you have to do is pull the lever at 19/4

3) Now try to save => the game crashes
The correct order is: 1) pull the lever, to start the air_pit, go up, push the button, and pick up the gem. If you do so (and no more), all is correct (because the party hook is deactivated) and save works. But, effectively if you pull the lever a second time, or if you save after pulling the lever and before picking the gem, you have the save crash caused by the upvalues.

I have added "disable self" to the lever now, but the upvalue issue can occurs still if a save is made between the two actions. I hope Minmay (or another guy more skilled in Lua then I am... ) can suggest a solution. Rewriting some of these scripts is a hard work, and the result could be worse...
The Blue Monastery (LOG1)
download at:http://www.nexusmods.com/grimrock/mods/399/?

Finisterrae(LOG2)
download at:http://www.nexusmods.com/legendofgrimrock2/mods/61/?
minmay
Posts: 2789
Joined: Mon Sep 23, 2013 2:24 am

Re: FINISTERRAE version 1

Post by minmay »

The solution is to stop using upvalues and it is not hard. If you need persistent variables then make them permanent (declare them without the 'local' keyword) instead of making them into upvalues. The only reason to use upvalues is dynamic creation of functions, which you are not doing.
Grimrock 1 dungeon
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
User avatar
Zo Kath Ra
Posts: 940
Joined: Sat Apr 21, 2012 9:57 am
Location: Germany

Re: FINISTERRAE version 1

Post by Zo Kath Ra »

Duncan1246 wrote:I have added "disable self" to the lever now, but the upvalue issue can occurs still if a save is made between the two actions. I hope Minmay (or another guy more skilled in Lua then I am... ) can suggest a solution. Rewriting some of these scripts is a hard work, and the result could be worse...
If you want to fix this function:

Code: Select all

function upparty()
	local dx=0
	local dy=0
	local h=0
  dungeon_air_pit_1.light:enable()
  dungeon_air_pit_1.sound:enable()
  dungeon_air_pit_1.particle:enable()
 fw.script:set('party.Finisterrae.onMove',function(hook,party,dir)
  local parx=party.go.x
  local pary=party.go.y
  local el=party.go.elevation
  local fac=party.go.facing
 		if parx==15 and pary==7 and dir==1 then
			dx=1 dy=0 h=1
			party.go.party:shakeCamera(0.03,4,0.5)
		elseif parx==16 and pary==8 and dir==0 then
			dx=0 dy=-1 h=1
			party.go.party:shakeCamera(0.03,4,0.5)
		elseif parx==17 and pary==7 and dir==3 then
			dx=-1 dy=0 h=1
			party.go.party:shakeCamera(0.03,4,0.5)
		elseif parx==16 and pary==6 and dir==2 then
			dx=0 dy=1 h=1
			party.go.party:shakeCamera(0.04,4,0.5)
		else return
		end
		
		party.go:setPosition(parx+dx,pary+dy,fac,h,party.go.level)
		if (party.go.x==16 and party.go.y==7 and party.go.elevation==1) and (dir==2 or dir==3) then 
		turnpf_timer.timer:stop()
		turnparty_timer.timer:start()
		turnpf_timer.timer:start() end	
	end)
end
Then you just have to remove the keyword "local" from each of these lines:
local dx=0
local dy=0
local h=0
minmay
Posts: 2789
Joined: Mon Sep 23, 2013 2:24 am

Re: FINISTERRAE version 1

Post by minmay »

Zo Kath Ra wrote:
Duncan1246 wrote:I have added "disable self" to the lever now, but the upvalue issue can occurs still if a save is made between the two actions. I hope Minmay (or another guy more skilled in Lua then I am... ) can suggest a solution. Rewriting some of these scripts is a hard work, and the result could be worse...
If you want to fix this function:

Code: Select all

function upparty()
	local dx=0
	local dy=0
	local h=0
  dungeon_air_pit_1.light:enable()
  dungeon_air_pit_1.sound:enable()
  dungeon_air_pit_1.particle:enable()
 fw.script:set('party.Finisterrae.onMove',function(hook,party,dir)
  local parx=party.go.x
  local pary=party.go.y
  local el=party.go.elevation
  local fac=party.go.facing
 		if parx==15 and pary==7 and dir==1 then
			dx=1 dy=0 h=1
			party.go.party:shakeCamera(0.03,4,0.5)
		elseif parx==16 and pary==8 and dir==0 then
			dx=0 dy=-1 h=1
			party.go.party:shakeCamera(0.03,4,0.5)
		elseif parx==17 and pary==7 and dir==3 then
			dx=-1 dy=0 h=1
			party.go.party:shakeCamera(0.03,4,0.5)
		elseif parx==16 and pary==6 and dir==2 then
			dx=0 dy=1 h=1
			party.go.party:shakeCamera(0.04,4,0.5)
		else return
		end
		
		party.go:setPosition(parx+dx,pary+dy,fac,h,party.go.level)
		if (party.go.x==16 and party.go.y==7 and party.go.elevation==1) and (dir==2 or dir==3) then 
		turnpf_timer.timer:stop()
		turnparty_timer.timer:start()
		turnpf_timer.timer:start() end	
	end)
end
Then you just have to remove the keyword "local" from each of these lines:
local dx=0
local dy=0
local h=0
Actually this won't do what you want it to because the environment of the function will change to the fw ScriptComponent when the game is reloaded, removing those variables. Read section 2 here. Instead you should move the variables inside the function, since you are never using them outside the function anyway:

Code: Select all

function upparty()
  dungeon_air_pit_1.light:enable()
  dungeon_air_pit_1.sound:enable()
  dungeon_air_pit_1.particle:enable()
 fw.script:set('party.Finisterrae.onMove',function(hook,party,dir)
  local parx=party.go.x
  local pary=party.go.y
  local el=party.go.elevation
  local fac=party.go.facing
  local dx=0
  local dy=0
  local h=0
 		if parx==15 and pary==7 and dir==1 then
			dx=1 dy=0 h=1
			party.go.party:shakeCamera(0.03,4,0.5)
		elseif parx==16 and pary==8 and dir==0 then
			dx=0 dy=-1 h=1
			party.go.party:shakeCamera(0.03,4,0.5)
		elseif parx==17 and pary==7 and dir==3 then
			dx=-1 dy=0 h=1
			party.go.party:shakeCamera(0.03,4,0.5)
		elseif parx==16 and pary==6 and dir==2 then
			dx=0 dy=1 h=1
			party.go.party:shakeCamera(0.04,4,0.5)
		else return
		end
		
		party.go:setPosition(parx+dx,pary+dy,fac,h,party.go.level)
		if (party.go.x==16 and party.go.y==7 and party.go.elevation==1) and (dir==2 or dir==3) then 
		turnpf_timer.timer:stop()
		turnparty_timer.timer:start()
		turnpf_timer.timer:start() end	
	end)
end
If you have more than one reference to a function in your dungeon, its environment will potentially change when the game is saved and loaded, so you should only use the function's local namespace (not that of its containing script entity) and the global namespace. If you need to use variables belonging to this specific script entity in that function then you actually need to do something like this:

Code: Select all

dx=0
dy=0
h=0
function setDx(v)
  dx=v
end
function setDy(v)
  dy=v
end
function setH(v)
  h=v
end
function upparty()
  dungeon_air_pit_1.light:enable()
  dungeon_air_pit_1.sound:enable()
  dungeon_air_pit_1.particle:enable()
 fw.script:set('party.Finisterrae.onMove',function(hook,party,dir)
  local parx=party.go.x
  local pary=party.go.y
  local el=party.go.elevation
  local fac=party.go.facing
 		if parx==15 and pary==7 and dir==1 then
			goround_script.script.setDx(1) goround_script.script.setDy(0) goround_script.script.setH(1)
... etc
This is not exactly convenient, so if you want to use this sort of hook in combination with persistent variables that belong to the script entity, you should probably change the hook framework to store the id of the entity, ScriptComponent, and function, like it does for connectors, instead of storing the actual function there.

Technically you can guarantee which environment a function with multiple references will end up with, if you are able to ensure that the savegame code reaches the relevant entities in a predictable order - I think that if you put the fw script entity at the bottom right corner of the last-numbered level, and kept permanent references to all your hook functions in the ScriptComponents where you apply them, the functions would keep their original ScriptComponents' environment (assuming, of course, that you do not have even more references to them somewhere else). But this would be very risky, bad practice; I would strongly recommend making your hook functions environment-independent instead.
Grimrock 1 dungeon
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
User avatar
Duncan1246
Posts: 404
Joined: Mon Jan 19, 2015 7:42 pm

Re: FINISTERRAE version 1

Post by Duncan1246 »

minmay wrote:
Zo Kath Ra wrote:
Duncan1246 wrote:I have added "disable self" to the lever now, but the upvalue issue can occurs still if a save is made between the two actions. I hope Minmay (or another guy more skilled in Lua then I am... ) can suggest a solution. Rewriting some of these scripts is a hard work, and the result could be worse...
If you want to fix this function /... / you just have to remove the keyword "local" from each of these lines:
local dx=0
local dy=0
local h=0
Actually this won't do what you want it to because the environment of the function will change to the fw ScriptComponent when the game is reloaded, removing those variables. Read section 2 here. Instead you should move the variables inside the function, since you are never using them outside the function anyway:

Code: Select all

function upparty()
  dungeon_air_pit_1.light:enable()
  dungeon_air_pit_1.sound:enable()
  dungeon_air_pit_1.particle:enable()
 fw.script:set('party.Finisterrae.onMove',function(hook,party,dir)
  local parx=party.go.x
  local pary=party.go.y
  local el=party.go.elevation
  local fac=party.go.facing
  local dx=0
  local dy=0
  local h=0 /...
 
First thanks for your help. I choose the first solution of Minmay, test it and it works perfectly. The problem was that I didn't see first that the hook acts like the blocks mentioned in Lua's guide, so I place these local variables in the wrong place. Now I have to scan all similar occurrences to find the upvalues... quite a job!
minmay wrote: If you have more than one reference to a function in your dungeon, its environment will potentially change when the game is saved and loaded, so you should only use the function's local namespace (not that of its containing script entity) and the global namespace. If you need to use variables belonging to this specific script entity in that function then you actually need to do something like this:

Code: Select all

dx=0
dy=0
h=0
function setDx(v)
  dx=v
end
function setDy(v)
  dy=v
end
function setH(v)
  h=v
end
function upparty()
  dungeon_air_pit_1.light:enable()
  dungeon_air_pit_1.sound:enable()
  dungeon_air_pit_1.particle:enable()
 fw.script:set('party.Finisterrae.onMove',function(hook,party,dir)
  local parx=party.go.x
  local pary=party.go.y
  local el=party.go.elevation
  local fac=party.go.facing
 		if parx==15 and pary==7 and dir==1 then
			goround_script.script.setDx(1) goround_script.script.setDy(0) goround_script.script.setH(1)
... etc
I note this, for the moment I think I haven't such multiple reference, but I will look for them
minmay wrote: This is not exactly convenient, so if you want to use this sort of hook in combination with persistent variables that belong to the script entity, you should probably change the hook framework to store the id of the entity, ScriptComponent, and function, like it does for connectors, instead of storing the actual function there.

Technically you can guarantee which environment a function with multiple references will end up with, if you are able to ensure that the savegame code reaches the relevant entities in a predictable order - I think that if you put the fw script entity at the bottom right corner of the last-numbered level, and kept permanent references to all your hook functions in the ScriptComponents where you apply them, the functions would keep their original ScriptComponents' environment (assuming, of course, that you do not have even more references to them somewhere else). But this would be very risky, bad practice; I would strongly recommend making your hook functions environment-independent instead.
I am not sure I understand this, particularly "kept permanent references to all your hook functions in the ScriptComponents where you apply them", I will appreciate an example if it isn't too much to ask

Fixing this issue (in Cian's mausoleum), I correct some others things: add walls elevation 1 above the secrets pedestals, add invisible wall to avoid picking up the power gem through the portcullis, delete a useless ladder (test relic). Going down from the moving bridge made the party jump like a crazy kangourou, so I modify the script to avoid this.

Thanks a lot you two for your time!
Duncan
The Blue Monastery (LOG1)
download at:http://www.nexusmods.com/grimrock/mods/399/?

Finisterrae(LOG2)
download at:http://www.nexusmods.com/legendofgrimrock2/mods/61/?
User avatar
Duncan1246
Posts: 404
Joined: Mon Jan 19, 2015 7:42 pm

Re: FINISTERRAE version 1

Post by Duncan1246 »

Hunting upvalues... found three more in "Both sides of god" and "Four jewels" where I suspected they were (some saving crashes pointed out in these levels). One of them was on a single tile (saving on that tile made crash) !!
To be continued...
For the players: don't worry about that, solutions exist already (post here and I will give you the appropriate solution). A new version will be released as soon as these fixs are done.
The Blue Monastery (LOG1)
download at:http://www.nexusmods.com/grimrock/mods/399/?

Finisterrae(LOG2)
download at:http://www.nexusmods.com/legendofgrimrock2/mods/61/?
minmay
Posts: 2789
Joined: Mon Sep 23, 2013 2:24 am

Re: FINISTERRAE version 1

Post by minmay »

Duncan1246 wrote:I am not sure I understand this, particularly "kept permanent references to all your hook functions in the ScriptComponents where you apply them", I will appreciate an example if it isn't too much to ask
If you don't understand every part of
minmay wrote:Technically you can guarantee which environment a function with multiple references will end up with, if you are able to ensure that the savegame code reaches the relevant entities in a predictable order - I think that if you put the fw script entity at the bottom right corner of the last-numbered level, and kept permanent references to all your hook functions in the ScriptComponents where you apply them, the functions would keep their original ScriptComponents' environment (assuming, of course, that you do not have even more references to them somewhere else).
then you definitely shouldn't try to actually do it, because it's a fragile and bad solution like I said. Just use temporary variables.
Grimrock 1 dungeon
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
User avatar
Duncan1246
Posts: 404
Joined: Mon Jan 19, 2015 7:42 pm

Re: FINISTERRAE version 1

Post by Duncan1246 »

minmay wrote:If you don't understand every part of
minmay wrote:Technically you can guarantee which environment a function with multiple references will end up with, if you are able to ensure that the savegame code reaches the relevant entities in a predictable order - I think that if you put the fw script entity at the bottom right corner of the last-numbered level, and kept permanent references to all your hook functions in the ScriptComponents where you apply them, the functions would keep their original ScriptComponents' environment (assuming, of course, that you do not have even more references to them somewhere else).
then you definitely shouldn't try to actually do it, because it's a fragile and bad solution like I said. Just use temporary variables.
Ok then, anyway I have already used the two others methods (in some scripts the first don't work) and for the moment the saving tests are successful. Does you have seen upvalues usage elsewhere than in script calling fw hooks?
The Blue Monastery (LOG1)
download at:http://www.nexusmods.com/grimrock/mods/399/?

Finisterrae(LOG2)
download at:http://www.nexusmods.com/legendofgrimrock2/mods/61/?
Post Reply