わかりました、ここで本当に奇妙な状況が発生しています。まず、背景を説明する必要があります。XNA エンジンで作成されたゲームの AI エージェントを作成しています。設定方法としては、エージェントのフレームワークを使用して .dll を生成し、ゲームが実行時にエージェントをロードするために使用することになっています。
私はゲームのコードにアクセスできます (何が起こっているかを確認できます)。この時点で、他の人のエージェントを自分のエージェントの出発点として使用しています。最近、ゲーム (およびそれに伴うフレームワーク) にいくつかの変更がありました。そのほとんどは、クラスとインターフェイスの名前でした。つまり、エージェントを最新の状態にする必要がありました。そのため、フレームワークの新しいバージョンでエージェントをコンパイルできるようにするために必要なすべての更新を行った後、問題が発生しました。これは、.dll をロードするゲームのコードです。
// dynamically load assembly from file GeometryFriendsAgents.dll
Assembly agentsDLL = Assembly.LoadFile(path);
// get type of classes BallAgent and SquareAgent from just loaded Assembly
Type circleType = AgentsDLL.GetType("GeometryFriendsAgents.CircleAgent");
Type rectangleType = AgentsDLL.GetType("GeometryFriendsAgents.RectangleAgent");
try {
// create instances of classes BallAgent and SquareAgent
npcCircle = (ICircleAgent)Activator.CreateInstance(circleType);
npcRectangle = (IRectangleAgent)Activator.CreateInstance(rectangleType);
}catch(TargetInvocationException e){
throw e.InnerException;
}
パスが正しいことを確認できます。ゲームを実行しようとすると、try/catch 内の行で TargetInvocationException がスローされます (エージェントが自動的に読み込まれます)。内部例外 (FormatException) を確認するために try/catch を追加しました。VisualStudio は、入力文字列が正しい形式ではないという追加情報を提供します。
エージェント コードのどの部分がこれに関連するのかはわかりませんが、奇妙な部分にはまだ到達していません。私が使用している実装では、エージェントは LearningCenter クラスを利用しています。このクラスは、基本的にエージェントの学習ファイルを読み書きします。クラスの開始時に、学習ファイルのパスが保存されます。
protected const string path = @"..\..\..\..\Agents\";
だから、ここで物事が奇妙になります。これは学習ファイルの正しいパスです。以前に間違いを犯したとき、このパスがありました(以前はコード全体で何度も繰り返されていました)
protected const string path = @"..\..\..\..\Agents";
間違ったパスで .dll をビルドすると、エージェントを正常にロードでき、ゲームが実行されます。問題は、パスが正しくないことです。LearningCenter が学習ファイルを書き込もうとすると、DirectoryNotFoundException で明らかに失敗します。問題の方法は次のとおりです。
public void EndGame(float knownStatesRatio) {
if (_toSave) {
FileStream fileStream = new FileStream(path + _learningFolder + "\\Ratios.csv", FileMode.Append);
StreamWriter sw = new StreamWriter(fileStream);
sw.WriteLine(knownStatesRatio);
sw.Close();
fileStream.Close();
fileStream = new FileStream(path + _learningFolder + "\\IntraPlatformLearning.csv", FileMode.Create);
DumpLearning(fileStream, _intraplatformPlayedStates);
fileStream.Close();
if (interPlatform) {
fileStream = new FileStream(path + _learningFolder + "\\InterPlatformLearning.csv", FileMode.Create);
DumpLearning(fileStream, _interplatformPlayedStates);
fileStream.Close();
}
}
}
新しいファイルストリームを作成すると、すぐに例外が発生します。\
欠落を変数にシフトしようとしましたが、_learningFolder
そうすると最初の問題に戻ります。パスが正しくない限り、ゲームを実行できます...
また、この前に、同じ場所で最初に別の TargetInvocationException に遭遇したことにも言及する必要があります。この問題は、エージェント クラスの可視性を public に変更することで修正されました。
パスの問題が実際の問題を隠している可能性があることは理解していますが、次にどこを見ればよいかわかりません。
編集: 最初の問題のスタック トレースは次のとおりです。
GeometryFriends.exe!GeometryFriends.AI.AgentsManager.LoadAgents() Line 396
GeometryFriends.exe!GeometryFriends.Levels.SinglePlayerLevel.LoadLevelContent() Line 78
GeometryFriends.exe!GeometryFriends.Levels.Level.LoadContent() Line 262
GeometryFriends.exe!GeometryFriends.ScreenSystem.ScreenManager.LoadContent() Line 253
Microsoft.Xna.Framework.Game.dll!Microsoft.Xna.Framework.DrawableGameComponent.Initialize()
GeometryFriends.exe!GeometryFriends.ScreenSystem.ScreenManager.Initialize() Line 221
Microsoft.Xna.Framework.Game.dll!Microsoft.Xna.Framework.Game.Initialize()
GeometryFriends.exe!GeometryFriends.Engine.Initialize() Line 203
Microsoft.Xna.Framework.Game.dll!Microsoft.Xna.Framework.Game.RunGame(bool useBlockingRun)
Microsoft.Xna.Framework.Game.dll!Microsoft.Xna.Framework.Game.Run()
GeometryFriends.exe!GeometryFriends.Program.Main(string[] args) Line 16
最初に失敗するエージェントは CircleAgent で、コンストラクターは次のとおりです。
public CircleAgent() {
//Change flag if agent is not to be used
SetImplementedAgent(true);
lastMoveTime = DateTime.Now;
lastRefreshTime = DateTime.Now;
currentAction = 0;
rnd = new Random(DateTime.Now.Millisecond);
model = new CircleWorldModel(this);
learningCenter = new CircleLearningCenter(model);
learningCenter.InitializeLearning();
startTime = DateTime.Now;
}
編集 2:わかりました、私は FormatException のソースにゾーンインすることができました。CircleLearningCenter のこのメソッド (最初の if のステートメント) でエラーが発生します。
public override void addStateMovementValue(string[] lineSplit, string stateId, ref Dictionary<string, Dictionary<int, double>> lessons) {
if (!lineSplit[1].Equals("0")) {
lessons[stateId].Add(Moves.ROLL_LEFT, double.Parse(lineSplit[1]));
}
if (!lineSplit[2].Equals("0")) {
lessons[stateId].Add(Moves.ROLL_RIGHT, double.Parse(lineSplit[2]));
}
if (!lineSplit[3].Equals("0")) {
lessons[stateId].Add(Moves.JUMP, double.Parse(lineSplit[3]));
}
}
これは、LearningCenter のこのメソッドによって呼び出されます。
private void createLearningFromFile(FileStream fileStream, ref Dictionary<string, Dictionary<int, double>> lessons) {
lessons = new Dictionary<string, Dictionary<int, double>>();
StreamReader sr = new StreamReader(fileStream);
string line;
while ((line = sr.ReadLine()) != null) {
string[] lineSplit = line.Split(',');
string stateId = lineSplit[0];
lessons.Add(stateId, new Dictionary<int, double>());
addStateMovementValue(lineSplit, stateId, ref lessons);
}
}
次に、このメソッドによって呼び出されます (円のコンストラクターで呼び出されます)。
public void InitializeLearning() {
if (File.Exists(Path.Combine(Path.Combine(path, _learningFolder), "IntraPlatformLearning.csv"))) {
FileStream fileStream = new FileStream(Path.Combine(Path.Combine(path, _learningFolder),"IntraPlatformLearning.csv"), FileMode.Open);
createLearningFromFile(fileStream, ref _intraplatformLessonsLearnt);
fileStream.Close();
} else {
createEmptyLearning(ref _intraplatformLessonsLearnt);
}
if (File.Exists(Path.Combine(Path.Combine(path, _learningFolder), "InterPlatformLearning.csv"))) {
FileStream fileStream = new FileStream(Path.Combine(Path.Combine(path, _learningFolder), "InterPlatformLearning.csv"), FileMode.Open);
createLearningFromFile(fileStream, ref _interplatformLessonsLearnt);
fileStream.Close();
} else {
createEmptyLearning(ref _interplatformLessonsLearnt);
}
}
明確でない場合、CircleLearningCenter は LearningCenter のサブクラスです。また、テキストの壁で申し訳ありませんが、私は頭がおかしいです。