diff --git a/.gitignore b/.gitignore index 897d53e47..894dab556 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,6 @@ # Build results [Dd]ebugPublic/ -[Dd]ebug/ [Rr]elease/ [Rr]eleases/ [Xx]64/ diff --git a/P3D/Debug/BoundingBoxRenderer.vb b/P3D/Debug/BoundingBoxRenderer.vb new file mode 100644 index 000000000..5fa93cd89 --- /dev/null +++ b/P3D/Debug/BoundingBoxRenderer.vb @@ -0,0 +1,58 @@ +Public Class BoundingBoxRenderer + +#Region "Fields" + + Shared verts(8) As VertexPositionColor + Shared indices As Int16() = New Int16() {0, 1, 1, 2, 2, 3, 3, 0, 0, 4, 1, 5, 2, 6, 3, 7, 4, 5, 5, 6, 6, 7, 7, 4} + Shared effect As BasicEffect + +#End Region + + Public Shared Sub Render(ByVal box As BoundingBox, ByVal graphicsDevice As GraphicsDevice, ByVal view As Matrix, ByVal projection As Matrix, ByVal color As Color) + If effect Is Nothing Then + effect = New BasicEffect(graphicsDevice) + effect.VertexColorEnabled = True + effect.LightingEnabled = False + End If + + Dim corners() As Vector3 = box.GetCorners() + For i = 0 To 7 + verts(i).Position = corners(i) + verts(i).Color = color + Next + + effect.View = view + effect.Projection = projection + + For Each pass As EffectPass In effect.CurrentTechnique.Passes + pass.Apply() + + graphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.LineList, verts, 0, 8, indices, 0, CInt(indices.Length / 2)) + Next + End Sub + + Public Shared Sub Render(ByVal frustum As BoundingFrustum, ByVal graphicsDevice As GraphicsDevice, ByVal view As Matrix, ByVal projection As Matrix, ByVal color As Color) + If effect Is Nothing Then + effect = New BasicEffect(graphicsDevice) + effect.VertexColorEnabled = True + effect.LightingEnabled = False + End If + + Dim corners() As Vector3 = frustum.GetCorners() + For I = 0 To 7 + verts(I).Position = corners(I) + verts(I).Color = color + Next + + effect.View = view + effect.Projection = projection + + For Each pass As EffectPass In effect.CurrentTechnique.Passes + pass.Apply() + + graphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.LineList, verts, 0, 8, indices, 0, CInt(indices.Length / 2)) + Next + + End Sub + +End Class \ No newline at end of file diff --git a/P3D/Debug/DebugDisplay.vb b/P3D/Debug/DebugDisplay.vb new file mode 100644 index 000000000..3a118fee0 --- /dev/null +++ b/P3D/Debug/DebugDisplay.vb @@ -0,0 +1,93 @@ +Public Class DebugDisplay + + ''' + ''' Renders the debug information. + ''' + Public Shared Sub Draw() + If Core.CurrentScreen.CanDrawDebug = True Then + Dim isDebugString As String = "" + If GameController.IS_DEBUG_ACTIVE = True Then + isDebugString = " (Debugmode / " & System.IO.File.GetLastWriteTime(System.Reflection.Assembly.GetExecutingAssembly.Location).ToString() & ")" + End If + + Dim ActionscriptActive As Boolean = True + If Core.CurrentScreen.Identification = Screen.Identifications.OverworldScreen Then + ActionscriptActive = CType(Core.CurrentScreen, OverworldScreen).ActionScript.IsReady + End If + + Dim thirdPersonString As String = "" + If Screen.Camera.Name = "Overworld" Then + Dim c As OverworldCamera = CType(Screen.Camera, OverworldCamera) + If c.ThirdPerson = True Then + thirdPersonString = " / " & c.ThirdPersonOffset.ToString() + End If + End If + + Dim s As String = GameController.GAMENAME & " " & GameController.GAMEDEVELOPMENTSTAGE & " " & GameController.GAMEVERSION & " / FPS: " & Math.Round(Core.GameInstance.FPSMonitor.Value, 0) & isDebugString & Environment.NewLine & + Screen.Camera.Position.ToString() & thirdPersonString & Environment.NewLine & Screen.Camera.Yaw & "; " & Screen.Camera.Pitch & Environment.NewLine & + "E: " & _drawnVertices.ToString() & "/" & _maxVertices.ToString() & Environment.NewLine & + "C: " & _maxDistance.ToString() & " A: " & ActionscriptActive.ToString() + + If Core.GameOptions.ContentPackNames.Count() > 0 Then + Dim contentPackString As String = "" + For Each ContentPackName As String In Core.GameOptions.ContentPackNames + If contentPackString <> "" Then + contentPackString &= ", " + End If + contentPackString &= ContentPackName + Next + contentPackString = "Loaded ContentPacks: " & contentPackString + s &= Environment.NewLine & contentPackString + End If + + Core.SpriteBatch.DrawInterfaceString(FontManager.MainFont, s, New Vector2(7, 7), Color.Black) + Core.SpriteBatch.DrawInterfaceString(FontManager.MainFont, s, New Vector2(5, 5), Color.White) + End If + End Sub + +#Region "RenderDataTracking" + + 'Values for tracking render data of the level. + Private Shared _drawnVertices As Integer = 0 + Private Shared _maxVertices As Integer = 0 + Private Shared _maxDistance As Integer = 0 + + ''' + ''' The amount of vertices rendered in the last frame. + ''' + Public Shared Property DrawnVertices() As Integer + Get + Return _drawnVertices + End Get + Set(value As Integer) + _drawnVertices = value + End Set + End Property + + ''' + ''' The maximum amount of vertices that are present in the current scene. + ''' + Public Shared Property MaxVertices() As Integer + Get + Return _maxVertices + End Get + Set(value As Integer) + _maxVertices = value + End Set + End Property + + ''' + ''' The distance of the vertex to the camera, that is the furthest away from the camera. + ''' + Public Shared Property MaxDistance() As Integer + Get + Return _maxDistance + End Get + Set(value As Integer) + _maxDistance = value + End Set + End Property + +#End Region + +End Class \ No newline at end of file diff --git a/P3D/Debug/DebugFileWatcher.vb b/P3D/Debug/DebugFileWatcher.vb new file mode 100644 index 000000000..12608f8b3 --- /dev/null +++ b/P3D/Debug/DebugFileWatcher.vb @@ -0,0 +1,82 @@ +''' +''' This class watches the maps and scripts folders of the project to automatically +''' copy changed files on map reloads to the bin directory. +''' +Public Class DebugFileWatcher + + Private Shared _changedFiles As List(Of String) + Private Shared _watchers As List(Of FileSystemWatcher) + Private Shared _isWatching As Boolean = False + + Shared Sub New() + _changedFiles = New List(Of String)() + _watchers = New List(Of FileSystemWatcher)() + End Sub + + Public Shared Sub TriggerReload() + ' copy all changed files + SyncLock _changedFiles + Dim projectPath = GetProjectPath() + Dim targetPath = AppDomain.CurrentDomain.BaseDirectory + + For Each changedFile In _changedFiles + Dim relativeFile = changedFile.Remove(0, projectPath.Length + 1) + Dim targetFile = Path.Combine(targetPath, relativeFile) + + File.Copy(changedFile, targetFile, True) + Next + + ' clear the changed files afterwards + _changedFiles.Clear() + End SyncLock + End Sub + + Private Shared Function GetProjectPath() As String + Return New DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory).Parent.Parent.Parent.FullName + End Function + + Public Shared Sub StartWatching() + If Not _isWatching Then + _isWatching = True + + Dim projectPath = GetProjectPath() + + ' MAPS + Dim mapsPath = Path.Combine(projectPath, "Content\Data\maps") + Dim mapsWatcher = New FileSystemWatcher With { + .Path = mapsPath, + .NotifyFilter = NotifyFilters.LastWrite, + .IncludeSubdirectories = True + } + + AddHandler mapsWatcher.Changed, AddressOf OnChanged + mapsWatcher.EnableRaisingEvents = True + + _watchers.Add(mapsWatcher) + + ' SCRIPTS + Dim scriptsPath = Path.Combine(projectPath, "Content\Data\Scripts") + Dim scriptsWatcher = New FileSystemWatcher With { + .Path = scriptsPath, + .NotifyFilter = NotifyFilters.LastWrite, + .IncludeSubdirectories = True + } + + AddHandler scriptsWatcher.Changed, AddressOf OnChanged + scriptsWatcher.EnableRaisingEvents = True + + _watchers.Add(scriptsWatcher) + End If + End Sub + + Private Shared Sub OnChanged(source As Object, e As FileSystemEventArgs) + SyncLock _changedFiles + Dim file = e.FullPath + If Not _changedFiles.Contains(file) Then + Logger.Debug("File changed: " + file) + _changedFiles.Add(file) + End If + End SyncLock + End Sub + +End Class diff --git a/P3D/Debug/DotNetVersion.vb b/P3D/Debug/DotNetVersion.vb new file mode 100644 index 000000000..78b30ca0d --- /dev/null +++ b/P3D/Debug/DotNetVersion.vb @@ -0,0 +1,59 @@ +''' +''' A class to supply .Net installation information. +''' +Public Class DotNetVersion + + ''' + ''' Returns .Net installation information. + ''' + Public Shared Function GetInstalled() As String + Dim output As String = "" + + Try + Using ndpKey As Microsoft.Win32.RegistryKey = Microsoft.Win32.RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, Microsoft.Win32.RegistryView.Registry32).OpenSubKey("SOFTWARE\Microsoft\NET Framework Setup\NDP\") + For Each versionKeyName As String In ndpKey.GetSubKeyNames() + If versionKeyName.StartsWith("v") Then + Dim versionKey As Microsoft.Win32.RegistryKey = ndpKey.OpenSubKey(versionKeyName) + Dim name As String = DirectCast(versionKey.GetValue("Version", ""), String) + Dim sp As String = versionKey.GetValue("SP", "").ToString() + Dim install As String = versionKey.GetValue("Install", "").ToString() + If install = "" Then + 'no install info, ust be later + output &= versionKeyName & " " & name & Environment.NewLine + Else + If sp <> "" AndAlso install = "1" Then + output &= versionKeyName & " " & name & " SP" & sp & Environment.NewLine + End If + End If + If name <> "" Then + Continue For + End If + For Each subKeyName As String In versionKey.GetSubKeyNames() + Dim subKey As Microsoft.Win32.RegistryKey = versionKey.OpenSubKey(subKeyName) + name = DirectCast(subKey.GetValue("Version", ""), String) + If name <> "" Then + sp = subKey.GetValue("SP", "").ToString() + End If + install = subKey.GetValue("Install", "").ToString() + If install = "" Then + 'no install info, ust be later + output &= versionKeyName & " " & name & Environment.NewLine + Else + If sp <> "" AndAlso install = "1" Then + output &= " " & subKeyName & " " & name & " SP" & sp & Environment.NewLine + ElseIf install = "1" Then + output &= " " & subKeyName & " " & name & Environment.NewLine + End If + End If + Next + End If + Next + End Using + Catch ex As Exception + output &= "Error getting .Net installation information." + End Try + + Return output + End Function + +End Class \ No newline at end of file diff --git a/P3D/Debug/FPSMonitor.vb b/P3D/Debug/FPSMonitor.vb new file mode 100644 index 000000000..c38fdb32b --- /dev/null +++ b/P3D/Debug/FPSMonitor.vb @@ -0,0 +1,31 @@ +Public Class FPSMonitor + + Public Value As Double + Public Sample As TimeSpan + + Private sw As Stopwatch + Private Frames As Integer + + Public Sub New() + Me.Sample = TimeSpan.FromMilliseconds(100) + + Value = 0 + Frames = 0 + sw = Stopwatch.StartNew() + End Sub + + Public Sub Update(ByVal GameTime As GameTime) + If sw.Elapsed > Sample Then + Me.Value = Frames / sw.Elapsed.TotalSeconds + + Me.sw.Reset() + Me.sw.Start() + Me.Frames = 0 + End If + End Sub + + Public Sub DrawnFrame() + Me.Frames += 1 + End Sub + +End Class \ No newline at end of file diff --git a/P3D/Debug/ForcedCrash.vb b/P3D/Debug/ForcedCrash.vb new file mode 100644 index 000000000..c4fe27c6c --- /dev/null +++ b/P3D/Debug/ForcedCrash.vb @@ -0,0 +1,32 @@ +Public Class ForcedCrash + + Shared Delay As Single = 14.0F + + Public Shared Sub Update() + If KeyBoardHandler.KeyDown(KeyBindings.DebugKey) = True And KeyBoardHandler.KeyDown(Keys.C) = True Then + Debug.Print("CRASH IN: " & Delay.ToString()) + Delay -= 0.1F + If Delay <= 0.0F Then + Crash() + End If + Else + Delay = 14.0F + End If + End Sub + + Private Shared Sub Crash() + Dim canCrash As Boolean = True + If Core.Player.loadedSave = True Then + If Core.Player.IsGamejoltSave = True Or Core.Player.SandBoxMode = False Then + canCrash = False + End If + End If + If canCrash = True Then + Dim ex As New Exception("Forced the game to crash.") + Throw ex + Else + Delay = 14.0F + End If + End Sub + +End Class \ No newline at end of file diff --git a/P3D/Debug/Logger.vb b/P3D/Debug/Logger.vb new file mode 100644 index 000000000..6dd1f3a61 --- /dev/null +++ b/P3D/Debug/Logger.vb @@ -0,0 +1,543 @@ +Imports System.Management +Imports System.Windows.Forms + +Public Class Logger + + Public Enum LogTypes + Message + Debug + ErrorMessage + Warning + Entry + End Enum + + Private Const CRASHLOGSEPARATOR As String = "---------------------------------------------------------------------------------" + + Private Shared History As New List(Of String) + Public Shared DisplayLog As Boolean = False + + Private Shared ErrorHeaders() As String = {"I AM ERROR!", + "Minecraft crashed.", + "Missingno.", + "1 ERROR", + "GET TO DA CHOPPA", + "Fire attacks might be super effective...", + "Does this help?", + "Work! Pleeeeeeeease?", + "WHAT IS THIS?", + "I find your lack of [ERROR] disturbing.", + "Blame Darkfire.", + "RTFM", + "FEZ II announced.", + "At least it's not a Blue Screen.", + "Kernel PANIC", + "I'm sorry, Dave, I'm afraid I can't do that.", + "Never gonna give you up ~", + "Wouldn't have happend with Swift.", + "Team Rocket blasting off again!", + "Snorlax just sat on your computer!", + "Wut?", + "Mojang buys Microsoft! Get your new Mojang operating system now. With more blocks and scrolls.", + "HλLF-LIFE 2 confirmed", + "(╯°□°)╯︵ ┻━┻"} + + Const LOGVERSION As String = "2.4" + + Public Shared Sub Log(ByVal LogType As LogTypes, ByVal Message As String) + Try + Dim currentTime As String = GetLogTime(Date.Now) + + Dim LogString As String + If LogType = LogTypes.Entry Then + LogString = "]" & Message + Else + LogString = LogType.ToString() & " (" & currentTime & "): " & Message + End If + + Debug("Logger: " & LogString) + + Dim Log As String = "" + + If IO.File.Exists(GameController.GamePath & "\log.dat") = True Then + Log = IO.File.ReadAllText(GameController.GamePath & "\log.dat") + End If + + If Log = "" Then + Log = LogString + Else + Log &= Environment.NewLine & LogString + End If + + IO.File.WriteAllText(GameController.GamePath & "\log.dat", Log) + Catch ex As Exception : End Try + End Sub + + Public Shared Function LogCrash(ByVal ex As Exception) As String + Try + Dim w32ErrorCode As Integer = -1 + + Dim w32 = TryCast(ex, System.ComponentModel.Win32Exception) + If w32 IsNot Nothing Then + w32ErrorCode = w32.ErrorCode + End If + + Dim logName As String = "" + With My.Computer.Clock.LocalTime + Dim month As String = .Month.ToString() + If month.Length = 1 Then + month = "0" & month + End If + Dim day As String = .Day.ToString() + If day.Length = 1 Then + day = "0" & day + End If + Dim hour As String = .Hour.ToString() + If hour.Length = 1 Then + hour = "0" & hour + End If + Dim minute As String = .Minute.ToString() + If minute.Length = 1 Then + minute = "0" & minute + End If + Dim second As String = .Second.ToString() + If second.Length = 1 Then + second = "0" & second + End If + logName = .Year & "-" & month & "-" & day & "_" & hour & "." & minute & "." & second & "_crash.dat" + End With + + Dim ContentPacks As String = "{}" + If Not Core.GameOptions Is Nothing Then + ContentPacks = Core.GameOptions.ContentPackNames.ArrayToString() + End If + + Dim GameMode As String = "[No GameMode loaded]" + If Not GameModeManager.ActiveGameMode Is Nothing Then + GameMode = GameModeManager.ActiveGameMode.Name + End If + + Dim OnlineInformation As String = "GameJolt Account: FALSE" + If Not Core.Player Is Nothing Then + OnlineInformation = "GameJolt Account: " & Core.Player.IsGameJoltSave.ToString().ToUpper() + If Core.Player.IsGameJoltSave = True Then + OnlineInformation &= " (" & GameJoltSave.GameJoltID & ")" + End If + End If + + Dim ScriptInfo As String = "Actionscript: No script running" + If Not CurrentScreen Is Nothing Then + If CurrentScreen.Identification = Screen.Identifications.OverworldScreen Then + If CType(CurrentScreen, OverworldScreen).ActionScript.IsReady = False Then + ScriptInfo = "Actionscript: " & ActionScript.CSL().ScriptName & "; Line: " & ActionScript.CSL().CurrentLine + End If + End If + End If + + Dim ServerInfo As String = "FALSE" + If ConnectScreen.Connected = True Then + ServerInfo = "TRUE (" & JoinServerScreen.SelectedServer.GetName() & "/" & JoinServerScreen.SelectedServer.GetAddressString() & ")" + End If + + Dim GameEnvironment As String = "[No Game Environment loaded]" + If Not CurrentScreen Is Nothing Then + GameEnvironment = CurrentScreen.Identification.ToString() + End If + + Dim IsSandboxMode As String = "False" + If Not Core.Player Is Nothing Then + IsSandboxMode = Core.Player.SandBoxMode.ToString() + End If + + Dim gameInformation As String = GameController.GAMENAME & " " & GameController.GAMEDEVELOPMENTSTAGE & " version: " & GameController.GAMEVERSION & " (" & GameController.RELEASEVERSION & ")" & Environment.NewLine & + "Content Packs: " & ContentPacks & Environment.NewLine & + "Active GameMode: " & GameMode & Environment.NewLine & + OnlineInformation & Environment.NewLine & + "Playing on Servers: " & ServerInfo & Environment.NewLine & + "Game Environment: " & GameEnvironment & Environment.NewLine & + ScriptInfo & Environment.NewLine & + "File Validation: " & Security.FileValidation.IsValid(True).ToString() & Environment.NewLine & + "Sandboxmode: " & IsSandboxMode + + Dim ScreenState As String = "[Screen state object not available]" + If Not CurrentScreen Is Nothing Then + ScreenState = "Screen state for the current screen (" & CurrentScreen.Identification.ToString() & ")" & Environment.NewLine & Environment.NewLine & + CurrentScreen.GetScreenStatus() + End If + + Dim architectureString As String = "32 Bit" + If Environment.Is64BitOperatingSystem = True Then + architectureString = "64 Bit" + End If + + Dim specs As String = "Operating system: " & My.Computer.Info.OSFullName & " [" & My.Computer.Info.OSVersion & "]" & Environment.NewLine & + "Core architecture: " & architectureString & Environment.NewLine & + "System time: " & My.Computer.Clock.LocalTime.ToString() & Environment.NewLine & + "System language: " & Globalization.CultureInfo.CurrentCulture.EnglishName & "(" & Globalization.CultureInfo.CurrentCulture.ThreeLetterWindowsLanguageName & ") / Loaded game language: " & Localization.LanguageSuffix & Environment.NewLine & + "Decimal separator: " & GameController.DecSeparator & Environment.NewLine & + "Available physical memory: " & Math.Round((My.Computer.Info.TotalPhysicalMemory / Math.Pow(1024, 3)), 2).ToString() & " Gigabyte" & Environment.NewLine & + "Available logical processors: " & Environment.ProcessorCount.ToString() + + Dim innerException As String = "NOTHING" + If Not ex.InnerException Is Nothing Then + innerException = ex.InnerException.Message + End If + Dim message As String = "NOTHING" + If Not ex.Message Is Nothing Then + message = ex.Message + End If + Dim source As String = "NOTHING" + If Not ex.Source Is Nothing Then + source = ex.Source + End If + Dim StackTrace As String = "NOTHING" + If Not ex.StackTrace Is Nothing Then + StackTrace = ex.StackTrace + End If + + Dim helpLink As String = "No helplink available." + If Not ex.HelpLink Is Nothing Then + helpLink = ex.HelpLink + End If + + Dim BaseException As Exception = ex.GetBaseException() + + Dim data As String = "NOTHING" + If Not ex.Data Is Nothing Then + data = "Items: " & ex.Data.Count + If ex.Data.Count > 0 Then + data = "" + For i = 0 To ex.Data.Count - 1 + If data <> "" Then + data &= Environment.NewLine + End If + data &= "[" & ex.Data.Keys(i).ToString() & ": """ & ex.Data.Values(i).ToString() & """]" + Next + End If + End If + + Dim informationItem As New ErrorInformation(ex) + + Dim objDump As New ObjectDump(Core.CurrentScreen) + Dim screenDump As String = objDump.Dump + + Dim content As String = + "Kolben Games Crash Log V " & LOGVERSION & Environment.NewLine & + GameController.GAMENAME & " has crashed!" & Environment.NewLine & + "// " & ErrorHeaders(Random.Next(0, ErrorHeaders.Length)) & Environment.NewLine & Environment.NewLine & + CRASHLOGSEPARATOR & Environment.NewLine & Environment.NewLine & + "Game information:" & Environment.NewLine & Environment.NewLine & + gameInformation & Environment.NewLine & Environment.NewLine & + CRASHLOGSEPARATOR & Environment.NewLine & Environment.NewLine & + ScreenState & Environment.NewLine & Environment.NewLine & + CRASHLOGSEPARATOR & Environment.NewLine & Environment.NewLine & + "System specifications:" & Environment.NewLine & Environment.NewLine & + specs & Environment.NewLine & Environment.NewLine & + CRASHLOGSEPARATOR & Environment.NewLine & Environment.NewLine & + ".Net installation information:" & Environment.NewLine & Environment.NewLine & + DotNetVersion.GetInstalled() & Environment.NewLine & + CRASHLOGSEPARATOR & Environment.NewLine & Environment.NewLine & + GetGraphicsCardInformation() & Environment.NewLine & Environment.NewLine & + CRASHLOGSEPARATOR & Environment.NewLine & Environment.NewLine & + "Error information:" & Environment.NewLine & + Environment.NewLine & "Message: " & message & + Environment.NewLine & "InnerException: " & innerException & + Environment.NewLine & "BaseException: " & BaseException.Message & + Environment.NewLine & "HelpLink: " & helpLink & + Environment.NewLine & "Data: " & data & + Environment.NewLine & "Source: " & source & + Environment.NewLine & "Win32 Errorcode: " & w32ErrorCode.ToString() & Environment.NewLine & Environment.NewLine & + CRASHLOGSEPARATOR & Environment.NewLine & Environment.NewLine & + informationItem.ToString() & Environment.NewLine & Environment.NewLine & + CRASHLOGSEPARATOR & Environment.NewLine & Environment.NewLine & + "CallStack: " & Environment.NewLine & Environment.NewLine & + StackTrace & Environment.NewLine & Environment.NewLine & + CRASHLOGSEPARATOR & Environment.NewLine & Environment.NewLine & + "Enviornment dump: " & Environment.NewLine & Environment.NewLine & + screenDump & Environment.NewLine & Environment.NewLine & + CRASHLOGSEPARATOR & Environment.NewLine & Environment.NewLine & + "You should report this error." & Environment.NewLine & Environment.NewLine & "Go to ""http://pokemon3d.net/forum/forums/6/create-thread"" to report this crash there." + + IO.File.WriteAllText(GameController.GamePath & "\" & logName, content) + + MessageBox.Show(GameController.GAMENAME & " has crashed!" & Environment.NewLine & "---------------------------" & Environment.NewLine & Environment.NewLine & "Here is further information:" & + Environment.NewLine & "Message: " & ex.Message & + Environment.NewLine & Environment.NewLine & "You should report this error. When you do this, please attach the crash log to the report. You can find the file in your ""Pokemon"" folder." & Environment.NewLine & Environment.NewLine & "The name of the file is: """ & logName & """.", + "Pokémon3D crashed!", MessageBoxButtons.OK, MessageBoxIcon.Error) + + + Process.Start("explorer.exe", "/select,""" & GameController.GamePath & "\" & logName & """") + + 'Returns the argument to start the launcher with: + Return """CRASHLOG_" & GameController.GamePath & "\" & logName & """ " & + """ERRORTYPE_" & informationItem.ErrorType & """ " & + """ERRORID_" & informationItem.ErrorID & """ " & + """GAMEVERSION_" & GameController.GAMEDEVELOPMENTSTAGE & " " & GameController.GAMEVERSION & """ " & + """CODESOURCE_" & ex.Source & """ " & + """TOPSTACK_" & ErrorInformation.GetStackItem(ex.StackTrace, 0) & """" + Catch exs As Exception + MessageBox.Show(exs.Message & Environment.NewLine & exs.StackTrace) + End Try + + Return "" + End Function + + Shared longestStackEntryName As String = "GameModeManager.SetGameModePointer" + + Public Shared Sub Debug(ByVal message As String) + Dim stackTraceEntry As String = Environment.StackTrace.SplitAtNewline()(3) + + While stackTraceEntry.StartsWith(" ") = True + stackTraceEntry = stackTraceEntry.Remove(0, 1) + End While + stackTraceEntry = stackTraceEntry.Remove(0, stackTraceEntry.IndexOf(" ") + 1) + stackTraceEntry = stackTraceEntry.Remove(stackTraceEntry.IndexOf("(")) + Dim pointString As String = stackTraceEntry.Remove(stackTraceEntry.LastIndexOf(".")) + stackTraceEntry = stackTraceEntry.Remove(0, pointString.LastIndexOf(".") + 1) + + Dim stackOutput As String = stackTraceEntry + + If stackOutput.Length > longestStackEntryName.Length Then + longestStackEntryName = stackOutput + Else + While stackOutput.Length < longestStackEntryName.Length + stackOutput &= " " + End While + End If + + Diagnostics.Debug.Print(stackOutput & StringHelper.Tab & "| " & message) + History.Add("(" & GetLogTime(Date.Now) & ") " & message) + End Sub + + Public Shared Sub DrawLog() + If DisplayLog = True And History.Count > 0 And Not FontManager.ChatFont Is Nothing Then + Dim items As New List(Of String) + Dim max As Integer = History.Count - 1 + + Dim itemCount As Integer = 10 + If windowSize.Height > 680 Then + itemCount += CInt(Math.Floor((windowSize.Height - 680) / 16)) + End If + + Dim min As Integer = max - itemCount + If min < 0 Then + min = 0 + End If + + Dim maxWidth As Integer = 0 + For i = min To max + Dim s As Single = FontManager.ChatFont.MeasureString(History(i)).X * 0.51F + If CInt(s) > maxWidth Then + maxWidth = CInt(s) + End If + Next + + Canvas.DrawRectangle(New Rectangle(0, 0, maxWidth + 10, (itemCount + 1) * 16 + 2), New Color(0, 0, 0, 150)) + + Dim c As Integer = 0 + For i = min To max + SpriteBatch.DrawString(FontManager.ChatFont, History(i), New Vector2(5, 2 + c * 16), Color.White, 0F, Vector2.Zero, 0.51F, SpriteEffects.None, 0F) + c += 1 + Next + End If + End Sub + + Private Shared Function GetLogTime(ByVal d As Date) As String + Dim hour As String = d.Hour.ToString() + Dim minute As String = d.Minute.ToString() + Dim second As String = d.Second.ToString() + + If hour.Length = 1 Then + hour = "0" & hour + End If + If minute.Length = 1 Then + minute = "0" & minute + End If + If second.Length = 1 Then + second = "0" & second + End If + + Return hour & ":" & minute & ":" & second + End Function + + Private Shared Function GetGraphicsCardInformation() As String + Dim CardName As String = "" + Dim CardRAM As String = "" + + Dim WmiSelect As New ManagementObjectSearcher("root\CIMV2", "SELECT * FROM Win32_VideoController") + + For Each WmiResults As ManagementObject In WmiSelect.Get() + Try + If CardName <> "" Then + CardName &= "; " + CardRAM &= "; " + End If + + CardName &= WmiResults.GetPropertyValue("Name").ToString() + CardRAM &= WmiResults.GetPropertyValue("AdapterRAM").ToString() + Catch ex As Exception + + End Try + Next + + Return "Graphics Card information:" & Environment.NewLine & Environment.NewLine & + "[CardName(s): """ & CardName & """]" & Environment.NewLine & + "[CardRAM(s) : """ & CardRAM & """]" + End Function + + Public Class ErrorInformation + + Public ErrorID As Integer = -1 + Public ErrorType As String = "" + Public ErrorDescription As String = "" + Public ErrorSolution As String = "" + + Public ErrorIDString As String = "-1" + + Public Sub New(ByVal EX As Exception) + Dim stackTrace As String = EX.StackTrace + + If Not stackTrace Is Nothing Then + Dim currentIndex As Integer = 0 + Dim callSub As String = "" + +analyzeStack: + callSub = GetStackItem(EX.StackTrace, currentIndex) + + Select Case callSub + 'asset issues (000-099): + Case "Microsoft.Xna.Framework.Content.ContentManager.OpenStream" + ErrorID = 1 + ErrorDescription = "The game was unable to load an asset (a Texture, a Sound or Music)." + ErrorSolution = "Make sure the file requested exists on your system." + Case "_2._5DHero.MusicManager.PlayMusic" + ErrorID = 2 + ErrorDescription = "The game was unable to play a music file." + ErrorSolution = "Make sure the file requested exists on your system. This might be caused by an invalid file in a ContentPack." + Case "Microsoft.Xna.Framework.Graphics.Texture.GetAndValidateRect" + ErrorID = 3 + ErrorDescription = "The game was unable to process a texture file." + ErrorSolution = "Code composed by Microsoft caused this issue. This might be caused by an invalid file in a ContentPack." + Case "Microsoft.Xna.Framework.Graphics.Texture2D.CopyData[T]" + ErrorID = 4 + ErrorDescription = "The game was unable to process a texture file." + ErrorSolution = "Code composed by Microsoft caused this issue. This might be caused by an invalid file in a ContentPack. Try to update your Graphics Card drivers." + Case "Microsoft.Xna.Framework.Media.MediaQueue.Play" + ErrorID = 5 + ErrorDescription = "The game was unable to load or play a music file." + ErrorSolution = "It is likely that the Windows Media Player is not installed on your computer or is wrongly configured. Please reinstall the Windows Media Player." + + 'GameJoltIssues (100-199) + Case "_2._5DHero.GameJolt.APICall.SetStorageData" + ErrorID = 100 + ErrorDescription = "The was unable to connect to a GameJolt server because you tried to send a command without being logged in to GameJolt." + ErrorSolution = "This happend because you got logged out from GameJolt due to connection problems. Ensure that your connection to the internet is constant." + + 'scripts (200-299) + Case "_2._5DHero.ScriptCommander.DoNPC" + ErrorID = 200 + ErrorDescription = "The game crashed trying to execute an NPC related command (starting with @npc.)" + ErrorSolution = "If this happend during your GameMode, inspect the file mentioned under ""Actionscript""." + Case "_2._5DHero.Trainer..ctor" + ErrorID = 201 + ErrorDescription = "The game was unable to initialize a new instance of a trainer class." + ErrorSolution = "If this is caused by your GameMode, make sure the syntax in the trainer file is correct." + Case "_2._5DHero.ScriptComparer.GetArgumentValue" + ErrorID = 202 + ErrorDescription = "The game crashed trying to process a script." + ErrorSolution = "If this is caused by your GameMode, make sure the syntax in the script or map file is correct." + + + 'Crashes generated by game code (300-399) + Case "_2._5DHero.ForcedCrash.Crash" + ErrorID = 300 + ErrorDescription = "The game crashed on purpose." + ErrorSolution = "Don't hold down F3 and C at the same time for a long time ;)" + Case "_2._5DHero.Security.ProcessValidation.ReportProcess" + ErrorID = 301 + ErrorDescription = "A malicious process was detected. To ensure that you are not cheating or hacking, the game closed." + ErrorSolution = "Close all processes with the details given in the Data of the crashlog." + Case "_2._5DHero.Security.FileValidation.CheckFileValid" + ErrorID = 302 + ErrorDescription = "The game detected edited or missing files." + ErrorSolution = "For online play, ensure that you are running the unmodded version of Pokémon3D. You can enable Content Packs." + + 'misc errors (900-999) + Case "Microsoft.Xna.Framework.Graphics.SpriteFont.GetIndexForCharacter" + ErrorID = 900 + ErrorDescription = "The game was unable to display a certain character which is not in the standard latin alphabet." + ErrorSolution = "Make sure the GameMode you are playing doesn't use any invalid characters in its scripts and maps." + Case "_2._5DHero.Player.LoadPlayer" + ErrorID = 901 + ErrorDescription = "The game failed to load a save state." + ErrorSolution = "There are multiple reasons for the game to fail at loading a save state. There could be a missing file in the player directory or corrupted files." + Case "Microsoft.Xna.Framework.BoundingFrustum.ComputeIntersectionLine" + ErrorID = 902 + ErrorDescription = "The game failed to set up camera mechanics." + ErrorSolution = "This error is getting produced by an internal Microsoft class. Please redownload the game if this error keeps appearing." + Case "_2._5DHero.Pokemon.Wild" + ErrorID = 903 + ErrorDescription = "The game crashed while attempting to generate a new Pokémon." + ErrorSolution = "This error could have multiple sources, so getting a solution here is difficult. If you made your own Pokémon data file for a GameMode, check it for invalid values." + + Case "-1" + 'No stack line found that applies to any error setting. + ErrorID = -1 + ErrorDescription = "The error is undocumented in the error handling system." + ErrorSolution = "NaN" + Case Else + currentIndex += 1 + GoTo analyzeStack + End Select + End If + + If ErrorID > -1 Then + ErrorIDString = ErrorID.ToString() + While ErrorIDString.Length < 3 + ErrorIDString = "0" & ErrorIDString + End While + End If + End Sub + + Public Overrides Function ToString() As String + If ErrorID > -1 And ErrorID < 100 Then + ErrorType = "Assets" + ElseIf ErrorID > 99 And ErrorID < 200 Then + ErrorType = "GameJolt" + ElseIf ErrorID > 199 And ErrorID < 300 Then + ErrorType = "Scripts" + ElseIf ErrorID > 299 And ErrorID < 400 Then + ErrorType = "Forced Crash" + ElseIf ErrorID > 899 And ErrorID < 1000 Then + ErrorType = "Misc." + Else + ErrorType = "NaN" + End If + + Dim s As String = "Error solution:" & Environment.NewLine & "(The provided solution might not work for your problem)" & Environment.NewLine & Environment.NewLine & + "Error ID: " & ErrorID & Environment.NewLine & + "Error Type: " & ErrorType & Environment.NewLine & + "Error Description: " & ErrorDescription & Environment.NewLine & + "Error Solution: " & ErrorSolution + Return s + End Function + + Public Shared Function GetStackItem(ByVal stack As String, ByVal i As Integer) As String + If i >= stack.SplitAtNewline().Count Then + Return "-1" + End If + + Dim line As String = stack.SplitAtNewline()(i) + Dim callSub As String = line + + While callSub.StartsWith(" ") = True + callSub = callSub.Remove(0, 1) + End While + callSub = callSub.Remove(0, callSub.IndexOf(" ") + 1) + callSub = callSub.Remove(callSub.IndexOf("(")) + + Return callSub + End Function + + End Class + +End Class \ No newline at end of file diff --git a/P3D/Debug/ObjectDump.vb b/P3D/Debug/ObjectDump.vb new file mode 100644 index 000000000..cc40b1471 --- /dev/null +++ b/P3D/Debug/ObjectDump.vb @@ -0,0 +1,202 @@ +Imports System.Collections +Imports System.Reflection + +''' +''' A class to access the dump of variables of an object. +''' +Public Class ObjectDump + + Public ReadOnly Property Dump As String = "" + + Public Sub New(ByVal sender As Object) + If sender Is Nothing Then + Dump = "Object reference not set to an instance of an object." + Else + Dim fields() As FieldInfo = sender.GetType().GetFields(BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.Static) + Dim properties() As PropertyInfo = sender.GetType().GetProperties(BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.Static) + + Dump = + "--------------------------------------------------" & Environment.NewLine & + "Generated Fields:" & Environment.NewLine & + "--------------------------------------------------" & Environment.NewLine + + For Each field As FieldInfo In fields + If Dump <> "" Then + Dump &= Environment.NewLine + End If + + Dim fieldAccessToken As String = "" + Dim fieldNameToken As String = "" + Dim fieldTypeToken As String = "" + Dim fieldValueToken As String = "" + + If field.IsPublic Then + fieldAccessToken = "Public " + ElseIf field.IsPrivate Then + fieldAccessToken = "Private " + ElseIf field.IsFamily Then + fieldAccessToken = "Protected " + End If + + If field.IsStatic Then + fieldAccessToken &= "Shared " + End If + + fieldNameToken = field.Name + fieldTypeToken = field.FieldType.Name + + If field.FieldType.IsArray Then + fieldValueToken = DumpArray(field.GetValue(sender)) + ElseIf field.FieldType.IsGenericType Then + If field.FieldType.Name = "List`1" Then + fieldTypeToken = $"List(Of {field.FieldType.GetGenericArguments()(0).Name})" + fieldValueToken = DumpGenericArray(field.GetValue(sender), "List`1") + ElseIf field.FieldType.Name = "Dictionary`2" Then + fieldTypeToken = $"Dictionary(Of {field.FieldType.GetGenericArguments()(0).Name}, {field.FieldType.GetGenericArguments()(1).Name})" + fieldValueToken = DumpGenericArray(field.GetValue(sender), "Dictionary`2") + End If + ElseIf field.FieldType.Name = "Texture2D" Then + fieldValueToken = DumpTexture2D(field.GetValue(sender)) + Else + fieldValueToken = DumpObject(field.GetValue(sender)) + End If + + Dump &= fieldAccessToken & fieldNameToken & " As " & fieldTypeToken & " = " & fieldValueToken + Next + + Dump &= Environment.NewLine & Environment.NewLine & + "--------------------------------------------------" & Environment.NewLine & + "Generated Property:" & Environment.NewLine & + "--------------------------------------------------" & Environment.NewLine + + For Each [property] As PropertyInfo In properties + If [property].CanRead Then + If Dump <> "" Then + Dump &= Environment.NewLine + End If + + Dim propertyNameToken As String = "" + Dim propertyTypeToken As String = "" + Dim propertyValueToken As String = "" + + propertyNameToken = [property].Name + propertyTypeToken = [property].PropertyType.Name + + If [property].PropertyType.IsArray Then + propertyValueToken = DumpArray([property].GetValue(sender)) + ElseIf [property].PropertyType.IsGenericType Then + If [property].PropertyType.Name = "List`1" Then + propertyTypeToken = $"List(Of {[property].PropertyType.GetGenericArguments()(0).Name})" + propertyValueToken = DumpGenericArray([property].GetValue(sender), "List`1") + ElseIf [property].PropertyType.Name = "Dictionary`2" Then + propertyTypeToken = $"Dictionary(Of {[property].PropertyType.GetGenericArguments()(0).Name}, {[property].PropertyType.GetGenericArguments()(1).Name})" + propertyValueToken = DumpGenericArray([property].GetValue(sender), "Dictionary`2") + End If + ElseIf [property].PropertyType.Name = "Texture2D" Then + propertyValueToken = DumpTexture2D([property].GetValue(sender)) + Else + propertyValueToken = DumpObject([property].GetValue(sender)) + End If + + Dump &= "Property " & propertyNameToken & " As " & propertyTypeToken & " = " & propertyValueToken + End If + Next + End If + End Sub + + Private Function DumpArray(ByVal obj As Object) As String + Try + If obj IsNot Nothing Then + Dim listValue As Array = CType(obj, Array) + If listValue.Length = 0 Then + Return "{}" + Else + Return "{" & String.Join(", ", listValue.Cast(Of Object).Select(Function(a) + Return a.ToString() + End Function).ToArray()) & "}" + End If + Else + Return "Nothing" + End If + Catch ex As Exception + Return "Array too complex to dump." + End Try + End Function + + Private Function DumpGenericArray(ByVal obj As Object, ByVal genericType As String) As String + Try + If obj IsNot Nothing Then + If genericType = "List`1" Then + Dim listValue As Array = CType(obj.GetType().GetMethod("ToArray").Invoke(obj, Nothing), Array) + If listValue.Length = 0 Then + Return "{}" + Else + Return "{" & String.Join(", ", listValue.Cast(Of Object).Select(Function(a) + Return a.ToString() + End Function).ToArray()) & "}" + End If + ElseIf genericType = "Dictionary`2" Then + Dim dictionaryKeys As Array = CType(obj.GetType().GetProperty("Keys").GetValue(obj), IEnumerable).Cast(Of Object).ToArray() + Dim dictonaryValues As Array = CType(obj.GetType().GetProperty("Values").GetValue(obj), IEnumerable).Cast(Of Object).ToArray() + + If dictionaryKeys.Length = 0 OrElse dictonaryValues.Length = 0 Then + Return "{}" + Else + Dim result As String = "" + For i As Integer = 0 To dictionaryKeys.Length - 1 + If i > 0 Then + result &= ", " + End If + result &= "{" & dictionaryKeys.Cast(Of Object)()(i).ToString() & ", " & dictonaryValues.Cast(Of Object)()(i).ToString() & "}" + Next + Return "{" & result & "}" + End If + Else + Return "Generic Type too complex to dump." + End If + Else + Return "Nothing" + End If + Catch ex As Exception + Return "Generic Type too complex to dump." + End Try + End Function + + Private Function DumpTexture2D(ByVal obj As Object) As String + Try + If obj IsNot Nothing Then + Dim textureName As String = "" + Dim width As Integer = Convert.ToInt32(obj.GetType().GetProperty("Width").GetValue(obj)) + Dim height As Integer = Convert.ToInt32(obj.GetType().GetProperty("Height").GetValue(obj)) + + If String.IsNullOrEmpty((obj.GetType().GetProperty("Name").GetValue(obj)?.ToString())) Then + textureName = """""" + Else + textureName = obj.GetType().GetProperty("Name").GetValue(obj)?.ToString() + End If + + Return $"{{Name = {textureName}, Width = {width}, Height = {height}}}" + Else + Return "Nothing" + End If + Catch ex As Exception + Return "Texture2D too complex to dump." + End Try + End Function + + Private Function DumpObject(ByVal obj As Object) As String + Try + If obj IsNot Nothing Then + If String.IsNullOrEmpty(obj.ToString()) Then + Return """""" + Else + Return obj.ToString() + End If + Else + Return "Nothing" + End If + Catch ex As Exception + Return "Object too complex to dump." + End Try + End Function +End Class \ No newline at end of file