Ich bin Blei Entwickler für Bitfighter, ein Spiel, in erster Linie in C++ geschrieben, aber Lua Roboter Spieler Skript. Wir verwenden Lunar (eine Variante von Luna), um die Bits zusammen zu kleben.Erkennung von veralteten C++ Referenzen in Lua
Ich ringe nun mit, wie unsere Lua-Skripten wissen können, dass ein Objekt durch einen Hinweis muss durch den C++ Code gelöscht. Hier
einig Beispiel Roboter-Code (in Lua):
if needTarget then -- needTarget => global(?) boolean
ship = findClosest(findItems(ShipType)) -- ship => global lightUserData obj
end
if ship ~= nil then
bot:setAngleToPoint(ship:getLoc())
bot:fire()
end
Beachten Sie, dass Schiff nur gesetzt, wenn needTarget wahr ist, andernfalls wird der Wert aus einer vorherigen Iteration verwendet wird. Es ist durchaus möglich (wahrscheinlich sogar, wenn der Bot seinen Job gemacht hat :-), dass das Schiff getötet wurde (und sein Objekt wurde durch C++ gelöscht), seit die Variable zuletzt gesetzt wurde. Wenn dies der Fall ist, wird C++ eine Übereinstimmung haben, wenn wir ship: getLoc() aufrufen und normalerweise abstürzen.
Die Frage ist also, wie man am elegantesten mit der Situation und den Schaden begrenzen, wenn (wenn) ein Programmierer einen Fehler macht.
Ich habe einige Ideen. Erstens könnten wir eine Art von Lua-Funktion erstellen, die die C++ Code aufrufen kann, wenn ein Schiff oder ein anderes Element stirbt:
function itemDied(deaditem)
if deaditem == ship then
ship = nil
needTarget = true
end
end
Zweitens könnten wir eine Art Referenzzählung intelligenten Zeiger auf „magische Weise“ das Problem beheben implementieren . Aber ich hätte keine Ahnung, wo ich damit anfangen soll.
Drittens können wir irgendeine Art von Leblosigkeit Detektor (nicht sicher, wie das funktionieren würde), dass Bots wie so nennen könnte:
if !isAlive(ship) then
needTarget = true
ship = nil -- superfluous, but here for clarity in this example
end
if needTarget then -- needTarget => global(?) boolean
ship = findClosest(findItems(ShipType)) -- ship => global lightUserData obj
end
<...as before...>
Viertens konnte ich behalten nur die ID des Schiffes, anstatt eine Referenz, und Verwendung, die das Schiff Objekt in jedem Zyklus, wie diese zu erwerben:
local ship = getShip(shipID) -- shipID => global ID
if ship == nil then
needTarget = true
end
if needTarget then -- needTarget => global(?) boolean
ship = findClosest(findItems(ShipType)) -- ship => global lightUserData obj
shipID = ship:getID()
end
<...as before...>
Meine ideale Situation auch Fehler werfen intelligent würde. Wenn ich die getLoc() -Methode auf einem toten Schiff ausführen würde, würde ich gerne Fehlerbehandlungscode auslösen, um dem Bot entweder eine Chance zu geben, oder zumindest dem System zu erlauben, den Roboter zu töten und das Problem zu protokollieren vorsichtiger zu sein, wie ich meinen Bot codiere.
Das sind meine Ideen. Ich stehe auf # 1, aber es fühlt sich klobig an (und könnte viel Hin und Her mit sich bringen, da wir viele Objekte mit kurzen Lebenszyklen haben, mit denen wir zu kämpfen haben, von denen die meisten nicht verfolgt werden). Es könnte leicht zu vergessen sein, die Funktion itemDied() zu implementieren. # 2 ist ansprechend, weil ich mag mag, aber habe keine Ahnung, wie es funktionieren würde. # 3 & # 4 sind sehr einfach zu verstehen, und ich könnte meine Totheitserkennung nur auf die wenigen Objekte beschränken, die über die Spanne von mehreren Spielzyklen hinweg interessant sind (höchstwahrscheinlich ein einzelnes Schiff).
Dies hat ein weit verbreitetes Problem sein. Was denkst du über diese Ideen, und gibt es bessere da draußen?
Danke!
Hier ist meine aktuelle beste Lösung:
In C++, mein Schiff Objekt Schiff genannt, dessen Lebenszyklus von C++ gesteuert. Für jedes Schiff erstelle ich ein Proxy-Objekt namens LuaShip, das einen Zeiger auf das Schiff enthält, und Ship enthält einen Zeiger auf das LuaShip.Im Destruktor des Schiffs habe ich den Ship-Zeiger des LuaShips auf NULL gesetzt, was ich als Indikator dafür verwende, dass das Schiff zerstört wurde.
Mein Lua-Code hat nur einen Verweis auf das LuaShip, und so (zumindest theoretisch, da dieser Teil immer noch nicht richtig funktioniert) steuert Lua den Lebenszyklus des LuaShips, sobald das entsprechende Ship-Objekt verschwunden ist. So wird Lua immer ein gültiges Handle haben, auch nachdem das Ship-Objekt weg ist, und ich kann Proxy-Methoden für die Ship-Methoden schreiben, die nach Ship-NULL-Werten suchen.
Jetzt ist es meine Aufgabe, besser zu verstehen, wie Luna/Lunar den Lebenszyklus von Zeigern verwaltet und sicherstellt, dass meine LuaShips nicht gelöscht werden, wenn ihre Partner-Schiffe gelöscht werden, wenn noch etwas Lua-Code darauf zeigt. Das sollte sehr machbar sein.
Eigentlich war es nicht machbar (zumindest nicht von mir). Was zu funktionieren schien, war, das Schiff und die LuaShip-Objekte ein wenig zu entkoppeln. Jetzt, wenn das Lua-Skript ein LuaShip-Objekt anfordert, erstelle ich ein neues und übergebe es an Lua und lasse es von Lua löschen, wenn es fertig ist. Das LuaShip verwendet einen intelligenten Zeiger, um auf das Schiff zu verweisen. Wenn also das Schiff stirbt, wird dieser Zeiger auf NULL gesetzt, was das LuaShip-Objekt erkennen kann.
Es ist Aufgabe des Lua-Coders, vor der Verwendung zu überprüfen, ob das Schiff noch gültig ist. Wenn das nicht der Fall ist, kann ich die Sitation einfangen und eine ernste Fehlermeldung rauswerfen, anstatt das ganze Spiel zum Absturz zu bringen (wie es vorher passierte).
Jetzt hat Lua totale Kontrolle über den Lebenszyklus des LuaShips, C++ kann Schiffe löschen, ohne Probleme zu verursachen, und alles scheint reibungslos zu funktionieren. Der einzige Nachteil ist, dass ich möglicherweise viele LuaShip-Objekte erstelle, aber es ist wirklich nicht so schlimm.
Wenn Sie an diesem Thema interessiert sind, bitte die Mailingliste Thread sehe ich zu einem verwandten Konzept geschrieben, die zur Verfeinerung der oben in einigen Vorschlägen endet:
http://lua-users.org/lists/lua-l/2009-07/msg00076.html
haben Sie etwas aufwendiger versucht, wie [luabridge] (https://github.com/vinniefalco/LuaBridge) oder [luabind] (http://www.rasterbar.com/products/luabind/docs.html)) Beide erlauben Objekte mit gemischten Lebenszeiten (lua/C++) ohne Speicherlecks. –