nicht Savesicher

» Siedler Map Source Forum » Siedler DEdK Script Forum » nicht Savesicher

Seiten: 1

Peter-FS
#1
14.07.2017 14:40
Beiträge: 1086

nicht Savesicher

Hi,
mein Problem ist, dass nach dem Reload die Abfragen, ob ein Gebäude gebaut, bzw. zerstört wurde, nicht mehr ausgeführt wird.

Solange nicht gespeichert und neu geladen wird, funktioniert alles bestens. d.h. vermutlich werden die übergebenen Daten nicht gespeichert?

--Aufruf mit z.B. 
SetupDestroy_Haus(4, Entities.PB_Farm1, Entities.PU_Farmer)

function SetupDestroy_Haus(_nr, _type, _typeReplace, _AreaSize)
	SetupGebaut(_nr, _type, _typeReplace, _AreaSize)
	SetupDestroy{
		Target = "h".._nr,
		Callback = function()
			xWorker[_nr].Aktion = true --beendet den npc
			local p = GetPosition("haus".._nr)
			worker[_nr].EffectId = Logic.CreateEffect(GGL_Effects.FXTerrainPointer, p.X, p.Y, 2) --mittelpunkt effekt
			if _typeReplace ~= nil then --wenn nil, dann wird ein serf erstellt
				m_TryMoveEntity("worker".._nr, "serf"..GetRandom(1,7).."_pos", 400)
			end
		end,
	}
end

function SetupGebaut(_nr, _type, _typeReplace, _AreaSize)
    if _AreaSize == nil then _AreaSize = 800 end
	_gebaut = _gebaut or 0
	bauquest = {
			EntityTypes = {{_type,1}, },
			AreaPos = "haus".._nr, 
			AreaSize = _AreaSize, 
			Any = nil,
			Callback = function()
				if gvMission._winterAktiv == true then
					Logic.DestroyEffect(worker[_nr].EffectId)
					worker[_nr].EffectId = 100 --damit kein Hinweis mehr erscheint
					_gebaut = _gebaut +1 --wenn alle gebäude gebaut, dann kann das HQ gebaut werden
					Bauplan_Update()
					if _gebaut == 28 then
						_aufgabenErledigt = true 
						Message("Du hast alle Gebäude der Bevölkerung gebaut. Besuche jetzt den Bürgermeister")
					elseif _gebaut == 29 then --HQ gebaut
						DisableQuestInformation()
						SetupDestroy_SB() --prüfen ob sperre gesprengt
						_gebaut = 0
						StartQuest4_1()
					end
					if _typeReplace ~= nil then --
						ReplaceEntity("worker".._nr, _typeReplace)
						aktId = ChangePlayer("worker".._nr,1)
						Logic.PlayerReAttachAllWorker(1)
						--fehlende arbeiter im gebäude erstellen und neu zuordnen
						local BuildingID = Logic.GetSettlersWorkBuilding(aktId)
						local MaxNumberOfworkers = Logic.GetMaxNumWorkersInBuilding(BuildingID)	
						local CurrentMaxNumbersOfWorkers = Logic.GetBuildingWorkPlaceUsage(BuildingID)		
						--Message("B-Id: "..BuildingID.." / max worker: "..MaxNumberOfworkers.." / Current Workers: "..CurrentMaxNumbersOfWorkers)			
						for ix = 1,MaxNumberOfworkers - CurrentMaxNumbersOfWorkers do
							CreateEntity(1, _typeReplace, GetPosition( "serf"..ix.."_pos"), nil)
							Logic.PlayerReAttachAllWorker(1)
						end
					end
				elseif gvMission._sommerAktiv == true then
					--hier müssen Brunnen gebaut werden, dann werden alle Gebäude in der umgebung dem spieler übergeben
					worker[_nr].EffectId = 100 --damit kein Hinweis mehr erscheint
					xWorker[_nr].Aktion = true --beendet den npc
					_gebaut = _gebaut +1
					Bauplan_Update()
					if _gebaut ==6 then DisableQuestInformation() end
					if _typeReplace == nil then
						local _punkt = GetPosition("haus".._nr)
						local data = {Logic.GetPlayerEntitiesInArea(8,0, _punkt.X, _punkt.Y, _AreaSize, 16)}	
						for ix = 2, data[1]+1 do
							ChangePlayer(data[ix],1)
						end
						Logic.PlayerReAttachAllWorker(1)
					elseif _typeReplace == "hunter" then
						DestroyEntity("worker33")
						local _pos = GetPosition("vorhaus33")
						Logic.CreateEntity(Entities.PU_Hero10,_pos.X,_pos.Y,0,1)
						StartPlayer2() --ermöglicht den zugang zum nächsten Gegner
					elseif _typeReplace == "scout" then
						DestroyEntity("worker35")
						local _pos = GetPosition("vorhaus35")
						Logic.CreateEntity(Entities.PU_Scout,_pos.X,_pos.Y,0,1)	
					elseif _typeReplace == "foerster" then
						
						local _pos = GetPosition("vorhaus34")
						CreateEntity(8,Entities.CU_Hermit,_pos,"waldi")	
						DestroyEntity("worker34")
						StartCountdown(5,Startgaertner1,false)
					end
				end
				
			end,
    };
	SetupEstablish( bauquest )
end



____________________
Man muss nicht alles wissen, man muss nur wissen wo es steht!

mcb
#2
14.07.2017 18:46
Beiträge: 1472

Das Problem sind die upvalues. Kleines Beispiel:

function foo()
   local upvalue = 5
   local function bar()
      upvalue = upvalue + 10
   end
end


Die innere Funktion bar hat zugriff auf die lokale variable upvalue der funktion foo. Siedler speichert diese upvalues aber nicht, nach dem laden funktioniert also nichts mehr.
Dasselbe passiert bei deinen Callbacks. Die Lösung ist relativ einfach: Keine upvalues verwenden. Hier kannst du einfach alle benötigten Variablen im table ablegen, dieses table wird dem callback als erster Parameter übergeben.

Peter-FS
#3
15.07.2017 00:10
Beiträge: 1086

Klappt irgendwie trotzdem nicht.
Ich habe z.B. 28 Häuser h1-h28 und übergebe der Funktion die _nr.
und verschiedene andere Parameter.
Wie meinst du das mit dem table?
So geht es nicht, da wird in allen Funktionen die gleiche Nr verwendet.

function SetupDestroy_Haus(_nr, _type, _typeReplace, _AreaSize)
	xParameter1={}
	xParameter1 = {xNr = _nr, xType =_type, xTypeReplace =_typeReplace, xAreaSize=_AreaSize }	
	SetupDestroy{
                xParameter1,
		Target = "h"..xParameter1.xNr,
		Callback = function()
			xWorker[xParameter1.xNr].Aktion = true --beendet den npc
			local p = GetPosition("haus"..xParameter1.xNr)
			worker[xParameter1.xNr].EffectId = Logic.CreateEffect(GGL_Effects.FXTerrainPointer, p.X, p.Y, 2) --mittelpunkt effekt
			if xParameter1.xTypeReplace ~= nil then --wenn nil, dann wird ein serf erstellt
				m_TryMoveEntity("worker"..xParameter1.xNr, "serf"..GetRandom(1,7).."_pos", 400)
			end
		end,
	}
end



____________________
Man muss nicht alles wissen, man muss nur wissen wo es steht!

mcb
#4
15.07.2017 01:19
Beiträge: 1472

Jetzt legst du ein globales table an, das bei jedem Aufruf überschrieben wird.
Ich meinte das so:

function SetupDestroy_Haus(_nr, _type, _typeReplace, _AreaSize)
	SetupDestroy{
                xNr = _nr, xType =_type, xTypeReplace =_typeReplace, xAreaSize=_AreaSize,
		Target = "h".._nr,
		Callback = function(xParameter1)
			xWorker[xParameter1.xNr].Aktion = true --beendet den npc
			local p = GetPosition("haus"..xParameter1.xNr)
			worker[xParameter1.xNr].EffectId = Logic.CreateEffect(GGL_Effects.FXTerrainPointer, p.X, p.Y, 2) --mittelpunkt effekt
			if xParameter1.xTypeReplace ~= nil then --wenn nil, dann wird ein serf erstellt
				m_TryMoveEntity("worker"..xParameter1.xNr, "serf"..GetRandom(1,7).."_pos", 400)
			end
		end,
	}
end

Peter-FS
#5
15.07.2017 16:13
Beiträge: 1086

Geht noch nicht

Das funktioniert leider so auch noch nicht richtig.
Folgendes Problem:

xNr = _nr, xType =_type, xTypeReplace =_typeReplace, xAreaSize=_AreaSize,


im Debugger ist zu sehen, dass die Werte nicht zugewiesen werden.
xNr ist nil, obwohl _nr einen Wert hat.

Wenn ich im Debugmodus die Funktion (xNr = _nr) markiere, hat xNr anschließend den richtigen Wert.

Zeigt sich auch so beim Spielen der Map!

Was mir jetzt noch dazu einfällt, wäre ein globales Table mit den Werten der 28 Häuser erstellen. Das könnte ich dann für SetupDestroy und SetupEstablish verwenden.
Verstehen kann ich es aber immer noch nicht wirklich, warum das so nicht geht.

Noch jemand Ideen dazu?

____________________
Man muss nicht alles wissen, man muss nur wissen wo es steht!

mcb
#6
15.07.2017 16:59
Beiträge: 1472

Die Variablen werden auch in einem table gespeichert. Also ist der Wert von _G.xNr nil, weil der nicht benutzt wird. Gespeichert wird dieser Wert in dem table, das du SetupDestroy übergibst (praktisch als zusätzliche Parameter).
Wird dann der Callback aufgerufen, bekommt er dieses table als erstes Argument übergeben und man kommt savegamesicher wieder an die Variablen dran.
(Intern wird das auch nur in einem globalen table gespeichert:

DataTable[_Index].Callback(DataTable[_Index])

)

(Ich weiß schon, warum ich meine Jobs immer selbst schreibe, diese Quest-Funktionen sind ziemlich blöd gemacht )

Peter-FS
#7
15.07.2017 18:27
Beiträge: 1086

SetupDestroy und SetupEstablish funktionieren eigentlich immer sehr gut.
Ich könnte ja auch 28 eigene Funktionen erstellen, dann würde es auch problemlos funktionieren.
Es geht nur nicht, da ich die Parameter übergebe.

____________________
Man muss nicht alles wissen, man muss nur wissen wo es steht!

mcb
#8
15.07.2017 19:08
Beiträge: 1472

Du kannst auch Jobs Parameter übergeben

Peter-FS
#9
15.07.2017 23:26
Beiträge: 1086

Das hilft mir und meinem momentanen Problem aber nicht.

Die Parameter, die ich übergebe, ändern sich 28 mal bzw. ist ja eigentlich egal wie oft. Diese Werte brauche ich in der Funktion bzw. im Table Save sicher und nicht, das diese erst im Callback zugewiesen werden! Da wird dann der falsche Wert abgefragt.

____________________
Man muss nicht alles wissen, man muss nur wissen wo es steht!

mcb
#10
16.07.2017 00:12
Beiträge: 1472

Sie werden eben nicht erst im Callback zugewiesen. Sie werden zugewiesen, wenn du das table erstellst, mit dem du SetupEstablish aufrufst. Da wird dieses table gespeichert und später als Parameter übergeben.

local t = {
   foo = 1, --hier im table gespeichert, ausgeführt wenn das table erstellt wird
   Callback = function(t)
      Message(t.foo) --hier zugriff auf den parameter t, ausgeführt wenn der callback aufgerufen wird
   end,
}

Peter-FS
#11
17.07.2017 09:30
Beiträge: 1086

Das ist aber nicht ganz das, was ich habe! So mag es ja funktionieren.
Das Problem sind die Parameter, die übergeben werden. Evtl. nicht ByVal sondern ByRef???

Rufe das Ganze z.B. 3x mit verschiedenen Werten auf und du bekommst im Callback 3x den gleichen Wert.

function Irgendwas(_nr)
local t = {
   foo = _nr, --hier im table gespeichert, ausgeführt wenn das table erstellt wird
   Callback = function(t)
      Message(t.foo) --hier zugriff auf den parameter t, ausgeführt wenn der callback aufgerufen wird
   end,
end
}



____________________
Man muss nicht alles wissen, man muss nur wissen wo es steht!

mcb
#12
17.07.2017 12:26
Beiträge: 1472

In Lua sind das meiste Referenzen. number und bool sind auf jeden Fall Werte, nil existiert nur ein mal (macht also keinen Unterschied) der Rest sind Referenzen (insbesondere tables, strings und funktionen).
Wichtig ist das aber nur bei tables und funktionen mit upvalues (und userdata/coroutines, die sind aber in Siedler-Lua selten).

totalwarANGEL
#13
18.07.2017 18:49
Beiträge: 2123

Also, ich kann mir nicht erklären, wieso das nicht funktionieren sollte. Habe das schon 100 Mal so gemacht und so viel Unterschied kann zwischen AeK und DEdK auch nicht sein.

Oder ist es bei mir schon wieder zu lange her?

____________________
Die Welt ist arschlochförmig und wir leben in der Mitte.

Peter-FS
#14
19.07.2017 07:14
Beiträge: 1086

Also ausser in Lua habe ich mit solchen Funktionen überhaupt keine Probleme. Ok, die werden allerdings auch nicht gespeichert und wieder aufgerufen. Hmmmm????

Na ja, jetzt halt für jeden Aufruf eine eigene Funktion.
Asser es hat noch jemand eine Idee!

____________________
Man muss nicht alles wissen, man muss nur wissen wo es steht!

mcb
#15
19.07.2017 12:13
Beiträge: 1472

Also eigentlich müsste das funktionieren. Kannst du noch mal das entsprechende Script posten?

Ansonsten würde ich dir Vorschlagen, selber einen Job zu schreiben und dem Parameter zu übergeben (hast du einen Trigger-Fix?) . Falls du wirklich bei den Quest-Funktionen bleiben willst, hab ich auch noch ein Script, das Mithilfe von metatables zusätzliche Parameter beim Aufruf einer Funktion einfügt.

Settlerman
#16
04.08.2017 12:50
Beiträge: 238

Frage zu den Upvalues:
Wenn ich mir eine Funktion schreibe, der einen Parameter übergebe und innerhalb der Funktion einen Trigger starte welcher den Parameter verwendet und auch überschreibt, wird das dann auch nicht gespeichert?

mcb
#17
04.08.2017 13:11
Beiträge: 1472

Ja, wird auch nicht gespeichert. parameter sind nichts anderes als lokale Variablen, die beim Funktionsaufruf initialisiert werden.
Wenn du einen Trigger-Fix hast kannst du ein table benutzen, um einen ähnlichen Effekt zu erzielen:

function foo(bar)
   StartSimpleJob(function(t)
      Message(t.bar)
      t.bar = t.bar + 1
   end, {bar = bar})
end

Settlerman
#18
04.08.2017 13:21
Beiträge: 238

Das ganze läuft bei mir momentan so:

function CreateBush(_position)

	-- erstellt einen Busch an der gegebenen Position
	
	local EntityID = Logic.CreateEntity(Entities.XD_Bush1, _position.X, _position.Y);
	
	-- Abfrage der Jahreszeiten, 
	
	Trigger.RequestTrigger( Events.LOGIC_EVENT_EVERY_SECOND, nil, function()
	if Spring == true then
		local EntityID = ReplaceEntity(EntityID, Entities.XD_Bush1);
		else if Summer == true then
			local EntityID = ReplaceEntity(EntityID,Entities.XD_Bush4);
			else if Autumn == true then
			local EntityID = ReplaceEntity(EntityID,Entities.XD_BushMoor2);
				else if Winter == true then
				local EntityID = ReplaceEntity(EntityID, Entities.XD_DeadBush1);
				end
			end
		end
	end		
	
	end, 1 , nil, nil)	

end


Also muss ich die einzelnen Positionen und die IDs in einem table speichern um sie nach dem Laden weiter verwenden zu können?

mcb
#19
04.08.2017 13:49
Beiträge: 1472

Ja. Es gäbe aber für diesen Fall auch noch bessere Möglichkeiten:
1) Aufruf der Funktion nach jedem ändern der Variablen, spart jede menge Rechenzeit (ich würd auch die 4 Variablen durch eine ersetzen).
2) Nur das Model ändern, dann muss kein neues Entity erstellt werden.
Die lassen sich sogar beide kombinieren

Settlerman
#20
04.08.2017 14:07
Beiträge: 238

Die am Anfang definierte Variable EntityID würde das Speichern und laden aber überleben, wenn sie nicht im Trigger überschrieben wird, oder?

mcb
#21
04.08.2017 14:32
Beiträge: 1472

Nein, würde sie nicht. Um ein wie auch immer geartetes table wirst du wohl kaum drumherum kommen (Außer du startest für jedes Entity einen Job und übergibst die id als Parameter, die du dann aber nicht ändern kannst).

Settlerman
#22
04.08.2017 14:33
Beiträge: 238

Ok, schade. Danke für die Hilfe.
lg

Seiten: 1

SiteEngine v1.5.0 by nevermind, ©2005-2007
Design by SpiderFive (www.siedler-games.de) - English translation by juja

Impressum