error: virtual call

» Siedler Map Source Forum » Siedler DEdK Script Forum » error: virtual call

Seiten: 1

Play4FuN
#1
17.02.2018 23:38
Beiträge: 704

error: virtual call

Mir ist bewusst, dass dieser Fehler wohl vom internen C++ Code kommen wird. Nachdem ich google fragte, war mir zwar auch klar, was das in etwa bedeutet, aber daran ändern kann ich wohl leider nix ...

Finde das Problem jedoch sehr interessant (und natürlich mega nervig). Folgendes:

Auf der Karte sind 8 Lehmgruben verteilt, die sammel ich erst mal so ein:

tCLAYMINES = { Logic.GetEntities( Entities.XD_ClayPit1, 16) }


Ich habe ne KI, die fleißig baut. Läuft alles super, Gebäude werden "live" nach und nach in den ConstructionPlan eingefügt.

Ich habe nen Trigger...

TRIGGER_ONCREATED = Trigger.RequestTrigger( Events.LOGIC_EVENT_ENTITY_CREATED, "", "EV_ON_ENTITY_CREATED", 1)

... der wie folgt aussieht:

function EV_ON_ENTITY_CREATED()
	local ent_ID = Event.GetEntityID()
	local ent_typ = Logic.GetEntityTypeName(Logic.GetEntityType(ent_ID))
	local ent_P = GetPlayer(ent_ID)
	local ent_pos = GetPosition(ent_ID)
	
	if KI[ent_P] ~= nil then
		
		if (Logic.IsBuilding(ent_ID) == 1) and (ent_P > 0) and (ent_P < 9) then
			if tCLAYMINES ~= nil then
				if tCLAYMINES[1] > 0 then
					for i = 2, tCLAYMINES[1]+1 do
						if (GetDistance(GetPosition(tCLAYMINES[i]), GetPosition(ent_ID)) < 2000) and (Logic.GetSector(ent_ID) == Logic.GetSector(tCLAYMINES[i])) then
							if Logic.GetSector(ent_ID) == 0 or Logic.GetSector(tCLAYMINES[i]) == 0 then
								Message("error: 0 sector")	-- does not happen
							end
							
							if KI[ent_P].minesToBuild == nil then
								KI[ent_P].minesToBuild = {}
							end
							--LuaDebugger.Break()
							if not IstDrin(tCLAYMINES[i], KI[ent_P].minesToBuild) then
								--Trigger.UnrequestTrigger(TRIGGER_ONCREATED)
								table.insert(KI[ent_P].minesToBuild, tCLAYMINES[i])
								Message(i.." - player "..ent_P.." builds clay mine at "..GetPosition(tCLAYMINES[i]).X.."; "..GetPosition(tCLAYMINES[i]).Y)
								GUI.ScriptSignal(GetPosition(tCLAYMINES[i]).X, GetPosition(tCLAYMINES[i]).Y, 0)	-- green
								--KI_BuildWorkPlace(ent_P, Entities.PB_ClayMine1, GetPosition(tCLAYMINES[i]))
								--KI_StartBuild(ent_P, Entities.PB_ClayMine1, GetPosition(tCLAYMINES[i]), 0)
								--KI_StartBuild(ent_P, Entities.PB_ClayMine1, ent_pos, 0)
								-- Error: virtual call
							end
						end
					end
				end
			end
		end
		
	end
	
end



Dabei sieht KI_StartBuild aktuell so aus:

function KI_StartBuild(_pID, _type, _pos, _level)	-- return: empty (0/1)

	if KI[_pID].defeated == true then
		return false
	end
	local _position
	if _pos == 0 then
		_position = invalidPosition
	else
		if type(_pos) == "table" then
			_position = {}
			_position.X = _pos.X
			_position.Y = _pos.Y
			
		elseif type(_pos) == "string" then
			_position = GetPosition(_pos)
		end
	end
	
	local empty = AI.Village_ConstructionQueueIsEmpty(_pID)
	
	local _constructionplan = {{ type = _type, pos = _position, level = (_level or 0) }}
	FeedAiWithConstructionPlanFile(_pID, _constructionplan)
	
	return empty
	
end


Die Rückgabe empty benötige ich nur an anderer Stelle...

Der einzelne Aufruf von

KI_StartBuild(1, Entities.PB_ClayMine1, GetPosition(tCLAYMINES[6]), 0)

ohne Trigger klappt ohne Probleme, die KI baut ne Lehmmine und alle sind glücklich

Wird aber ein Gebäude in der Nähe platziert und die ifs im Trigger-Event abgeklappert, kommt es fast sofort bis einige Sekunden nach dem Minenbau zum Absturz mit der Meldung virtual call, game turn ... hilft mir ja nicht.

Ich muss also ne ähnliche Lösung finden für meine Ansprüche ... aber wo zum Teufel kommt dieser Fehler zustande?

Auch wenn ich den Trigger verwende, den Baubefehl jedoch an anderer Stelle verwende, stürzt das Spiel nicht (zumindest nicht direkt) ab ... Mysteriös.

____________________
LG Play4FuN

Siedler DEdK Mapping + Scripting Tutorials

mcb
#2
18.02.2018 00:14
Beiträge: 1472

Was genau willst du den mit dem Trigger erreichen? Ich glaube, das Problem liegt darin, das du den Auftrag gibst eine Lehmmine zu bauen, das den Trigger auslöst, was nochmal den Auftrag für eine Lehmmine in derselben Position ergibt (was dann zum crash führt, weil Siedler keine Parameter prüft).

Play4FuN
#3
18.02.2018 07:47
Beiträge: 704

Jou daran hab ich auch schon gedacht, dazu ist ja minesToBuild und die Abfrage IstDrin da, um genau das zu verhindern. Denke das sollte eigtl nicht der Fall sein (?)
Zudem: wenn ich "normal" 2x den Auftrag gebe an einer Stelle etwas zu bauen, passiert schlimmstenfalls dass die KI nix baut, so einen crash hatte ich da noch nicht.

Den Trigger nutze ich so, weil die KI eine entsprechende Mine nur dann bauen soll, wenn es die sozusagen erschlossen hat (also eigene Gebäude sehr nah gebaut)

____________________
LG Play4FuN

Siedler DEdK Mapping + Scripting Tutorials

mcb
#4
18.02.2018 21:36
Beiträge: 1472

Vielleicht noch ne EntityTyp-Abfrage einbauen?

Play4FuN
#5
18.02.2018 22:48
Beiträge: 704

Ich habe

(string.find(ent_typ, "mine") == nil)

als Bedingung hinzugefügt - leider ohne Änderung.

Nachtrag: ich muss es natürlich mit "Mine" versuchen ... ich check das nochmal

____________________
LG Play4FuN

Siedler DEdK Mapping + Scripting Tutorials

Kantelo
#6
19.02.2018 01:10
Beiträge: 357

Es könnte sein, dass der Fehler darin liegt, dass bei einem Bau einer Lehmmine, in Wirklichkeit gleich 3 Entities erstellt werden:
1. Entities.PB_ClayMine1
2. Entities.ZB_ConstructionSiteClayMine1
3. (!) Entities.PB_GenericMine

Ob es sich jetzt tasächlich um ein relevantes Gebäude handelt kann man zum Beispiel abfragen mit Logic.IsEntityInCategory(ent_ID,EntityCategories.Workplace)

Play4FuN
#7
19.02.2018 09:18
Beiträge: 704

Okay, doch das müsste jetzt ja durch

(string.find(ent_typ, "Mine") == nil)

auch abgefangen werden! Werde da noch weiter experimentieren.

____________________
LG Play4FuN

Siedler DEdK Mapping + Scripting Tutorials

warrior1024
#8
19.02.2018 19:15
Beiträge: 345

Was würde dagegen sprechen, den Aufruf aus dem Trigger rauszuschieben, also so etwas wie:

DelayedCall( "KI_StartBuild", {ent_P,Entities.PB_ClayMine1, ent_pos, 0})


im Trigger und sowas wie

DelayedCallTable = {}
function DelayedCall( _f, _args)
    if table.getn(DelayedCallTable) == 0 then
        StartSimpleHiResJob("DelayedCallJob")
    end
    table.insert( DelayedCallTable, {f=_f, args = _args})
end
function DelayedCallJob()
    for k,v in pairs(DelayedCallTable) do
        _G[v.f](unpack(v.args))
    end
    DelayedCallTable = {}
    return true
end


als Comfort?
Ist schnell zusammengebastelt und ungetestet, aber im Prinzip verschiebt man die Ausführung aus dem Trigger in den nächsten HiResJob-Tick.

____________________
"Banken machen keine Fehlentscheidungen! Haben Euch das Eure Eltern nicht beigebracht?"
- Bankier Samael Silren, Enderal

mcb
#9
19.02.2018 19:52
Beiträge: 1472

@Kantelo: Wusste nicht mal, das BuildingSites und GenericMines bei sowas auftauchen. Ich benutze in solchen Fällen immer

--- Original: Noigi
-- Erweitert: mcb, mehrere Entitytypen
--
-- Gibt zurück, ob ein Entity von einem der angegebenen Typen ist.
--
-- Parameter:
-- - id			Entity (id, name)
-- - ...		typen (Entities.XXX, XXX)
--
-- Rückgabe:
-- - true/false
--
function IsEntityOfType(id, ...)
	if IsDestroyed(id) then
		return false
	end
	local ty = Logic.GetEntityType(GetID(id))
	assert(table.getn(arg)>0)
	for _,t in ipairs(arg) do
		if type(t)=="string" then
			t = Entities[t]
		end
		if ty == t then
			return true
		end
	end
	return false
end

da bekomme ich nur die Entitytypen die ich genau haben will.

@Play4Fun: string.find hilft nicht gegen die beiden, da beide Mine als Substring haben.

Play4FuN
#10
19.02.2018 20:04
Beiträge: 704

Das mit dem Delay ist unnötig, wenn ich es hinbekomme, dass der Aufruf nur dann gestartet wird, wenn er es auch wirklich soll, also genau ein mal.

Die Funktion von Noigi sieht hilfreich aus.

Das mit dem String verstehe ich nicht ganz, wenn ...

t = "entity"
string.find(t, "Mine")
-->nil


während z.B.

s = "GenericMine"
string.find(s, "Mine")
-->(8,11)

also nil wenn kein Treffer und Anfang und Ende falls gefunden ... sollte also doch passen.
Nochmal zur Erklärung: ist "Mine" im String (entity Typ) enhalten, dann wird der Bauaufruf NICHT aufgerufen.

____________________
LG Play4FuN

Siedler DEdK Mapping + Scripting Tutorials

mcb
#11
19.02.2018 21:34
Beiträge: 1472

Ok, wenn du das so eingebaut hast, sollte es fuktionieren.

Seiten: 1

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

Impressum