Wie kommen eigentlich die ganzen Fehler?
Waren die schon immer drin in PAE und wir haben einfach trotzdem gespielt? Oder sind die jetzt neu entstanden mit dem PB Mod Merge?
Wie kommen eigentlich die ganzen Fehler?
Waren die schon immer drin in PAE und wir haben einfach trotzdem gespielt? Oder sind die jetzt neu entstanden mit dem PB Mod Merge?
Meine Stories:
Civ4 PAE - Valheim - Transport Fever 2 - Subnautica - Planet Zoo - Sons of the Forest
Achtung Spoiler:
Ich denke mal, relativ seltene Situationen bei PAE.
Viele spielen auch ohne Pythonfehlermeldungen. Weiterhin war mindesten ein Problem kartenspezifisch.
Wir haben meine ich nur 4 Fehler aus dem PB Mod beheben müssen ? Und das waren fast immer nur fehlen Importe, da PAE sauberer programmiert wurde und nicht einfach alles importiert.
Achtung Spoiler:
Ein CtD ist besonnders schwer aufzuklären, weil er keine genaue Ortsangabe hinterlässt. Ursache ist meist nicht die Syntax sondern der logiche Programm-Ablauf.
Ursprünglich dachte ich, die von Marcus gefundenenen CtD hätten die selbe Ursache. Es sind aber 3 verschiedene. Außerdem muss ich mich noch in PAE und Python einarbeiten, daher waren meine ersten Lösugsansätze falsch. Die beiden nun geklärten Fehler, stammen aus PAE_VI. Das ist der letzte Rest an Fehlern, die über die Jahre gefunden und behoben wurden. Alles "einfache" ist halt schon erledigt.
Offen ist jetzt noch ein Fehler aus Save 2. Das ist noch spannend, weil in dem Save u. a. ein Event triggert und ein General stirbt. Somit, viele Möglichkeiten für falsche Fährten ....
Aber an jenem Morgen war es Magie gewesen. Und es hörte nicht auf, Magie zu sein,
nur weil man [inzwischen] eine Erklärung dafür hatte ... (Terry Pratchett)
Das ist etwas komplizierter als es aussieht.
Bei der KI muss ich das Schritt für Schritt selber tun.
Dieses doUpgradeRang bei der KI:
da überprüfe ich ja vorher mit canUpgradeUnit, ob da ein != -1 rauskommt.
Und dann überprüfe ich in doUpgradeRang mit canUpgradeUnit ob er Upgraden soll oder gleich ne neue Unit daraus machen soll.
Das hat schon seinen Sinn. Ich wollte das jetzt fast löschen, hätte aber die Auswirkung, dass die KI sonst jede Runde upgradet oder ne neue Unit macht.
Beim menschlichen Spieler checke ich ja auch vorher canUpgradeUnit und zeige dann den Button, wenns ok ist (!= -1).
Die Prätorianer-Sache ist für die KI auch wichtig: Hier überprüfe ich die Anzahl bestehender Einheitenklassen.
Erst wenns von allem eine Unit gibt, dann soll er erst einen Präti draus machen.
Vielleicht liegt aber der Fehler dort, weil ich dort nicht mit RETURN abschließe, wenn er einen Präti macht:
Bei dem ganzen fetten Block von # LEGION zu Praetorians probier mal ein return True zu machen (wie oben im code, ich kann die Zeile im php-gedöngs nicht färben):PHP-Code:
# PAE 6.5 Katapult -> Feuerkatapult
if pUnit.isHasPromotion(gc.getInfoTypeForString("PROMOTION_ACCURACY3")):
if pUnit.getUnitClassType() == gc.getInfoTypeForString("UNITCLASS_CATAPULT"):
PAE_Unit.doUpgradeVeteran(pUnit, gc.getInfoTypeForString("UNIT_FIRE_CATAPULT"), True)
return True
# Unit Rang Promo -------
if pUnit.isHasPromotion(gc.getInfoTypeForString("PROMOTION_COMBAT4")):
# LEGION zu Praetorians
if iUnitType in L.LUnits4Praetorians:
if not pTeam.isHasTech(gc.getInfoTypeForString("TECH_GRENZHEER")):
if pOwner.getUnitClassCount(gc.getInfoTypeForString("UNITCLASS_PRAETORIAN")) == 0:
if pOwner.getUnitClassCount(gc.getInfoTypeForString("UNITCLASS_LEGION_TRIBUN")):
if (pOwner.getUnitClassCount(gc.getInfoTypeForString("UNITCLASS_LEGION_CENTURIO")) or
pOwner.getUnitClassCount(gc.getInfoTypeForString("UNITCLASS_LEGION_CENTURIO2")) ):
if (pOwner.getUnitClassCount(gc.getInfoTypeForString("UNITCLASS_LEGION_OPTIO")) or
pOwner.getUnitClassCount(gc.getInfoTypeForString("UNITCLASS_LEGION_OPTIO2")) ):
iNewUnit = gc.getInfoTypeForString("UNIT_PRAETORIAN")
PAE_Unit.doUpgradeVeteran(pUnit, iNewUnit, True)
return True
# KI: immer und kostenlos
iNewUnit = PAE_Unit.canUpgradeUnit(pUnit)
if iNewUnit != -1: # and CvUtil.getScriptData(pUnit, ["P", "t"]) == "RangPromoUp":
if PAE_Unit.doUpgradeRang(iOwner, pUnit.getID()):
return True
[...]
if (pOwner.getUnitClassCount(gc.getInfoTypeForString("UNITCLASS_LEGION_CENTURIO")) or
pOwner.getUnitClassCount(gc.getInfoTypeForString("UNITCLASS_LEGION_CENTURIO2")) ):
if (pOwner.getUnitClassCount(gc.getInfoTypeForString("UNITCLASS_LEGION_OPTIO")) or
pOwner.getUnitClassCount(gc.getInfoTypeForString("UNITCLASS_LEGION_OPTIO2")) ):
iNewUnit = gc.getInfoTypeForString("UNIT_PRAETORIAN")
PAE_Unit.doUpgradeVeteran(pUnit, iNewUnit, True)
return True
# KI: immer und kostenlos
[...]
Kastell: Das klingt logisch und die CIV-Abfrage (Rom/Etrusker) habe ich nun schon vor doKastell in der AI_UnitUpgrade eingebaut und nicht erst bei canUpgradeUnit.
"Barbarische" Legionen (also übergelaufene Legionen) sollen nicht upgraden, denke ich. Das hat keinen Sinn. Das Hierarchie-System bei Überläufern ist flöten gegangen. Wer soll sie denn belobigen? Sich selbst? Sie können sich zwar im Rang noch rühmen, aber das wars. Praktisch, wenn sie nochmal überlaufen, behalten sie ihren aktuellen Rang und können dann upgraden.
So ein Militärsystem ist ja Regierungssache. Natürlich könnten sie sagen: hey, in unserer alten Heimat wär jetzt einer von uns Optio/Centurio oder Tribun... aber ich fände das komisch. Den Straßenbau sollen sie aber beibehalten. Das ist ja Know-How, das man nutzen kann.
Pie's Ancient Europe (PAE)
Erlebe mit dieser CIV IV Mod(ifikation) hautnah das Zeitalter der Antike bis ins letzte Detail!
Mit bahnbrechenden Erweiterungen und vielen ein- und erstmaligen Features.
- Pie's Ancient Europe (letztes Update: 22.12.2022)
... im Übrigen bin ich der Meinung, dass Karthago wieder aufgebaut werden muss!
Pie, bei canUpgradeUnit-doUpgradeRang-canUpgradeUnit wird nur eine aktuelle Einheit geprüft. Ist das Upgrade erlaubt, wird diese Einheit ein zweites mal überrpüft, ob sie erlaubt ist. Das kostet doch dopoelte Rechenzeit. Wenn es keine Erlaubnis gibt, würde ohne vorheriger Check eben wieder aus doUgradeRang heraus gesprungen. Wenn das ein Array von mehreren Einheiten wäre, könnte ich es als Reduzierung der Rechenzeit verstsehen, so nicht. [Man könnte das Save von Marcus als Benchmarck für die Rechenzeit verwenden.]
Das Problem bei dieser Konstruktion ist, das evtl. die Information verloren geht, welche Einheit nun AI_Update verlassen muss und welche bleiben darf. Ich habe hier keinen Zusammenhang mit dem CtD gefunden. [Wollte aber auf die mMn überflüssige Abfrage hinweisen].
----
Bei der Prätorianer-Sache ist das der Fall. Durch diese falsche (und von mir gestrichene) Abfrage geht die CtD-Info verloren. Der Witz ist ja, die Überrpüfung dieser Prätorianer findet trotzdem statt. Nur eben etwas später in einer Unterfunktion. Wenn ich dort den "Praetorianer-Check" einbaue, wird die "Erledigt"-Info sauber nach oben geleitet.
---
Was doKastell betrifft:
Man könnte die Bezahlung innerhalb von doKastell umstellen. Nur würde dann der CtD nicht abgefangen. Ich benutze die Gelegenheit um 2 Fliegen mit einer Klappe zu erschlagen.
----
Den letzten CtD habe ich noch nicht gefunden. Gefühlt, wird da auch irgendwo eine verschachtelte Schleife doppelt durchlaufen. Das könte auch der eigentliche Grund für den CtD beim Iberer sein.
---
Ich habe noch keinen logischen Grund gefunden, warum das immer "Fourage"-Einheiten waren. Es hilft nicht der Einheit "Fourage" wegzunehmen.
Der Etrusker hat auch Prätorianer mit "Keil" die keinen Ärger machen. Ich das rur ein seltsamer Zufall?![]()
Geändert von Rob Anybody (20. August 2024 um 02:09 Uhr)
Aber an jenem Morgen war es Magie gewesen. Und es hörte nicht auf, Magie zu sein,
nur weil man [inzwischen] eine Erklärung dafür hatte ... (Terry Pratchett)
Doppelter Check:
Nein, das hat sehr wohl seinen Sinn. Mit dem ersten canUpgrade Check verhindere ich, dass Einheiten, die mit Rängen oder Beförderungen gar nichts am Hut haben, in einer schnelleren Funktion als die doUpgrade (weil dort ja mehr abgefragt wird als nur canUpgrade) abgefangen werden.
In der doUpgradeRang, wenn ich also weiß, dass die Einheit befördert werden soll, checke ich canUpgrade nochmal, damit ich weiß, ob ich nur einen Rang höher gehen soll (canUpgrade = False) oder ob ich die Einheit zu einer neuen Einheit (offizierseinheit) umwandeln muss (canUpgrade = True).
Ist irgendwie komisch, aber geht schneller.
Doppelt durchlaufen macht nix. Endloses Durchlaufen würde zu einem endlos turn führen, aber nicht zu einem CtD. Das hat dann schon was gröberes. Ich komm eh bald dazu, die SAVES zu checken.... im Moment macht mir die neue Unifi Dream Machine in der Arbeit zu schaffen....
Pie's Ancient Europe (PAE)
Erlebe mit dieser CIV IV Mod(ifikation) hautnah das Zeitalter der Antike bis ins letzte Detail!
Mit bahnbrechenden Erweiterungen und vielen ein- und erstmaligen Features.
- Pie's Ancient Europe (letztes Update: 22.12.2022)
... im Übrigen bin ich der Meinung, dass Karthago wieder aufgebaut werden muss!
Pie, ich kümmere mich gerade um die Karte fürs neue PB95. Ich mache hier weiter, wenn ich damit durch bin.
Aber an jenem Morgen war es Magie gewesen. Und es hörte nicht auf, Magie zu sein,
nur weil man [inzwischen] eine Erklärung dafür hatte ... (Terry Pratchett)
Könntest du eventuell nochmal die 4 Error Saves gesammelt hier hochladen ?
Sonst habe ich bei der Fehlersuche mit dem PB sehr erfolgreich mit try/except gearbeitet. Dies so könnten wir auf jeden Fall den CtD abfangen.
In Verbindung damit, um zu sehen, wo es schiefläuft habe ich von cIV auch noch NiTextOut(String) gefunden. Muss über Pythonextensions erst importiert werden, erzeugt aber eine Ausgabe über die Konsole. Läuft aber scheinbar nicht mit dem Spiel, also lieber andere Ausgaben wählen.
Achtung Spoiler:
Alle 4 Save habe ich hier zusammengestellt. https://www.civforum.de/showthread.p...=1#post9357205
Save 1 (Iberer will Praetorianer aufwerten) und 3+4 (Konstantin hat Grenzheer erforscht und darf Praetorianer nicht mehr updaten) sind geklärt.
Die Lösung zu 1 in GameUtils "AI_unitUpdate":
Die Lösung zu 3+4 in PAE_Units:Code:# Legion Kastell # KI: immer, aber mit Kosten # nie hoeher als Tribun/General if pUnit.isHasPromotion(gc.getInfoTypeForString("PROMOTION_RANG_ROM_1")) and not pUnit.isHasPromotion(gc.getInfoTypeForString("PROMOTION_RANG_ROM_15")) or \ pUnit.isHasPromotion(gc.getInfoTypeForString("PROMOTION_RANG_ROM_LATE_1")) and not pUnit.isHasPromotion(gc.getInfoTypeForString("PROMOTION_RANG_ROM_LATE_10")): # RobA: Korrektur Kastell-Kosten und CtD bei nicht römischen Völkern iCiv = pOwner.getCivilizationType() if iCiv == gc.getInfoTypeForString("CIVILIZATION_ROME") or iCiv == gc.getInfoTypeForString("CIVILIZATION_ETRUSCANS"): # Kostet 25, aber wegen Reserve if pOwner.getGold() > 50: PAE_Unit.doKastell(iOwner, pUnit.getID()) else: return True # Terrain Promos - Ausbildner / Trainer (in City)
Code:def doUpgradeVeteran(pUnit, iNewUnit, bChangeCombatPromo): if iNewUnit == -1: return # RobA: Praetorianer Check (im 2 Jhd. n. Chr. wurden Praetorianer abgeschafft) eingefügt if iNewUnit == gc.getInfoTypeForString("UNIT_PRAETORIAN"): iOwner = pUnit.getOwner() pOwner = gc.getPlayer(iOwner) pTeam = gc.getTeam(pOwner.getTeam()) if pTeam.isHasTech(gc.getInfoTypeForString("TECH_GRENZHEER")): return if not iNewUnit in range(gc.getNumUnitInfos()): ... Anmerkung: Die fehlerhaften Zeilen bei GameUtils "AI_unitUpdate" können nun komplett entfernt werden.
Bei Save 2 kann ich mir mitlerweile eine fehlerhafte Zuordnung (Etrusker = Rom) vorstellen. Allerdings, die Zuordnung in canUpgrade ist korrekt.![]()
Aber an jenem Morgen war es Magie gewesen. Und es hörte nicht auf, Magie zu sein,
nur weil man [inzwischen] eine Erklärung dafür hatte ... (Terry Pratchett)
try/except ist keine Lösung (für Save 2).
Ich habe die gesamte Funktion von AI_unitUpdate in einer Abschnitt und ich habe weiterhin den Absturz.
Wobei das bei genauer Betrachtung auch keine große Überraschung ist.
Zweiter Versuch mit Zufallszahlen (CvUtil.myRandom(10, "Start AI_unitUpdate")/CvUtil.myRandom(10, "Ende AI_unitUpdate")) in der Funktion, die im MPLog.txt erscheinen deutet an, dass AI_unitUpdate hier nicht direkt das Problem ist.
Die letzte Zeile im Log ist:
Rand = 912277390 on 192476 (Ende AI_unitUpdate) - wobei ich ganz vergessen habe, Ende immer reinzuschreiben, wenn bevor die Funktion beendet
Also liegt der Fehler wahrscheinlich wo anders ?
Achtung Spoiler:
Ich suche ständig wo anders und komme dann doch wieder auf "AI_unitUpdate" zurück. Es gibt ein logisches Problem im Programmablauf, das uns beim Ende von AI_unitUpdate auf die Füße fällt.
Aber an jenem Morgen war es Magie gewesen. Und es hörte nicht auf, Magie zu sein,
nur weil man [inzwischen] eine Erklärung dafür hatte ... (Terry Pratchett)
Entsprechende GameUtils und das Log.
Zum Nachbilden müssen eventuell noch zusätzliche Logging Sachen in der .ini aktiviert werden.
Frage: Hatte die schlechte Lösung diesen 2. Fehler behoben ?
Achtung Spoiler:
Danke ich schaue mir das bei Gelgenheit an.
Ja, meine "Dynamit"-Lösung hat bei allen 4 Saves den CtD verhindert. Das ist aber, als würde man wilkürlich Einheiten löschen bis es keinen CtD mehr gibt.
Aber an jenem Morgen war es Magie gewesen. Und es hörte nicht auf, Magie zu sein,
nur weil man [inzwischen] eine Erklärung dafür hatte ... (Terry Pratchett)
Das diese zu grobe Lösung funktioniert hat aber laut dem log AI_unitUpdate durchläuft deutet ja an, dass der Fehler vermutlich wo anders liegt, aber vom Verhalten von AI_unitUpdate ausgelöst wird.
Eventuell ist das Problem, dass False zurück gegeben wird ?
Denn ich habe den Ende Eintrag aktuell nur, wenn die Funktion durchläuft, ohne dass was passiert ist. Also False zurück gegeben wird.
Deine "Lösung" hat ja vorzeitig True zurück gegeben.
Achtung Spoiler:
Ja, es geht um die Rückgabe von True. Diese sollte aber nur in begründeten Fällen erfolgen.
Wenn man einen Brunnen hat, in dem ein Kind gefallen ist (und weitere hineinfallen können) dann kann man den Brunnen mit einer schweren Steinplatte verschließen oder einen Zaun drumherum stellen. Beim Zaun muss man hoffen, das er kein Loch hat oder irgendwann umfällt ...
In diesem Bild ist meine Lösung zu Save 3+4 eine Steinplatte. Egal wann, egal von wo, egal von wem die Funktion doUpgradeVeteran aufgerufen wird: Der Fix hält.
Bei doKastell ( Save 1) errichte ich einen Zaun. Ich sage einfach du (Iberer) darfst hier nicht weiter gehen. Ich denke, ich muss aber doch noch einmal hinter den Zaun schauen, was da genau passiert. Es könnte das selbe sein, was dem Etrusker passiert (den echten Römern ist das bisher nicht passiert).![]()
Aber an jenem Morgen war es Magie gewesen. Und es hörte nicht auf, Magie zu sein,
nur weil man [inzwischen] eine Erklärung dafür hatte ... (Terry Pratchett)