From 243e9bb7ee9c9f517eecfb50344301bb77106325 Mon Sep 17 00:00:00 2001 From: kazimuth Date: Tue, 19 May 2015 12:09:41 -0400 Subject: [PATCH 1/4] Pass errors from connection thread to main thread --- Assets/MapGen/DFConnection.cs | 84 ++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 26 deletions(-) diff --git a/Assets/MapGen/DFConnection.cs b/Assets/MapGen/DFConnection.cs index d1448c007..b1d0cc4c2 100644 --- a/Assets/MapGen/DFConnection.cs +++ b/Assets/MapGen/DFConnection.cs @@ -7,6 +7,7 @@ // Will eventually run actual communication on a separate thread. // Singleton-y - attached to a GameObject. using System.Threading; +using System.Net.Sockets; public class DFConnection : MonoBehaviour { @@ -237,6 +238,10 @@ void OnDestroy() { Disconnect(); } + public sealed class DFRemoteException : System.Exception { + public DFRemoteException(System.Exception inner) : base("Remote exception!", inner) {} + } + private abstract class ConnectionMode { public static ConnectionMode GetConnectionMode(DFConnection connection, bool runOnAltThread) { if (runOnAltThread) { @@ -262,16 +267,20 @@ private sealed class UnityThreadMode : ConnectionMode { public UnityThreadMode(DFConnection connection) : base(connection) {} public override void Poll() { - // No need for locks, single threaded. - connection.networkClient.suspend_game(); - connection.viewInfoCall.execute(null, out connection._netViewInfo); - connection.unitListCall.execute(null, out connection._netUnitList); - RemoteFortressReader.BlockList resultList; - connection.blockListCall.execute(connection.blockRequest, out resultList); - foreach (RemoteFortressReader.MapBlock block in resultList.map_blocks) { - connection.pendingBlocks.EnqueueAndDisplace(new DFCoord(block.map_x, block.map_y, block.map_z), block); + try { + // No need for locks, single threaded. + connection.networkClient.suspend_game(); + connection.viewInfoCall.execute(null, out connection._netViewInfo); + connection.unitListCall.execute(null, out connection._netUnitList); + RemoteFortressReader.BlockList resultList; + connection.blockListCall.execute(connection.blockRequest, out resultList); + foreach (RemoteFortressReader.MapBlock block in resultList.map_blocks) { + connection.pendingBlocks.EnqueueAndDisplace(new DFCoord(block.map_x, block.map_y, block.map_z), block); + } + connection.networkClient.resume_game(); + } catch (System.Exception e) { + throw new DFRemoteException(e); } - connection.networkClient.resume_game(); } public override void Terminate() { @@ -284,16 +293,31 @@ public override void Terminate() { private sealed class AltThreadMode : ConnectionMode { private static readonly System.TimeSpan SLEEP_TIME = System.TimeSpan.FromMilliseconds(16); + // Use to terminate computation thread private volatile bool finished; + // Said thread private readonly Thread connectionThread; + // Catch errors on the throwing thread and catch them on the main thread + private System.Object errorLock; + private System.Exception crashError; public AltThreadMode(DFConnection connection) : base(connection) { finished = false; + errorLock = new Object(); + crashError = null; connectionThread = new Thread(new ThreadStart(this.RunForever)); connectionThread.Start(); } - public override void Poll() {} + public override void Poll() { + lock (errorLock) { + if (crashError != null) { + System.Exception error = crashError; + crashError = null; + throw new DFRemoteException(error); + } + } + } public override void Terminate() { finished = true; @@ -301,24 +325,32 @@ public override void Terminate() { private void RunForever() { while (!finished) { - connection.networkClient.suspend_game(); - lock (connection.viewInfoLock) { - connection.viewInfoCall.execute(null, out connection._netViewInfo); - } - lock (connection.unitListLock) { - connection.unitListCall.execute(null, out connection._netUnitList); - } - RemoteFortressReader.BlockList resultList; - lock (connection.blockRequest) { - connection.blockListCall.execute(connection.blockRequest, out resultList); - } - lock (connection.pendingBlocks) { - foreach (RemoteFortressReader.MapBlock block in resultList.map_blocks) { - connection.pendingBlocks.EnqueueAndDisplace(new DFCoord(block.map_x, block.map_y, block.map_z), block); + try { + connection.networkClient.suspend_game(); + lock (connection.viewInfoLock) { + connection.viewInfoCall.execute(null, out connection._netViewInfo); + } + lock (connection.unitListLock) { + connection.unitListCall.execute(null, out connection._netUnitList); + } + RemoteFortressReader.BlockList resultList; + lock (connection.blockRequest) { + connection.blockListCall.execute(connection.blockRequest, out resultList); + } + lock (connection.pendingBlocks) { + foreach (RemoteFortressReader.MapBlock block in resultList.map_blocks) { + connection.pendingBlocks.EnqueueAndDisplace(new DFCoord(block.map_x, block.map_y, block.map_z), block); + } + } + connection.networkClient.resume_game(); + Thread.Sleep(SLEEP_TIME); + } catch (System.Exception e) { + // For now, just pass on any exceptions and exit + lock (errorLock) { + crashError = e; + return; } } - connection.networkClient.resume_game(); - Thread.Sleep(SLEEP_TIME); } // finished connection.networkClient.disconnect(); From 49dc880a2cf300fa88e0b53dd9c41f0e5faec66c Mon Sep 17 00:00:00 2001 From: kazimuth Date: Tue, 19 May 2015 12:20:38 -0400 Subject: [PATCH 2/4] Ignore generated .apps on OS X --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index dd0bb9bf4..4141f4ad3 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ /*.booproj /TiletypeList.csv *.csv# +Armok Vision.app From beb13ac568518bc3321d0f919072842c87f5c7f3 Mon Sep 17 00:00:00 2001 From: kazimuth Date: Tue, 19 May 2015 14:10:12 -0400 Subject: [PATCH 3/4] README some more --- README.md | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 061c00460..34f36ace2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,47 @@ -armok-vision +Armok Vision ============ -A 3d realtime visualizer for Dwarf Fortress +[Forum thread](http://www.bay12forums.com/smf/index.php?topic=146473) | [Screenshots](http://imgur.com/a/bPmeo) + +A 3d realtime visualizer for Dwarf Fortress. + +## To Use + +1. Install Dwarf Fortress and a current DFHack. +2. Download Armok Vision from the forum thread. +3. Load into a fortress mode map. +4. Start up Armok Vision. +5. Enjoy! + +## To Contribute + +Want to help out? We love contributions! + +#### Bugs +If you've run into any bugs: [report them!](https://github.com/JapaMala/armok-vision/issues) (You'll need a [github account](https://github.com/).) Make sure to describe the issue in as much detail as you can, and to mention what system & Armok Vision version you're using. Also, check if what you're reporting has been reported before. + +#### Artists +If you're an artist and want to contribute 3D models, sounds, concept art: + +- There should be a folder called `StreamingAssets` somewhere around the armok vision executable (or inside, if you're on a mac.) If you edit the files inside and restart Armok Vision, it will use your modified assets. Be careful editing the .xml files, they're finnicky. You can post your edited resources in the forum thread and we can try to integrate them with the project. +- Alternatively, load things up in Unity and edit them there (see the following instructions). +- Check the [issues](https://github.com/JapaMala/armok-vision/issues); there may be something open about things that need prettifying. + +#### Developers +If you know how to code and want to hack on the engine: + +1. Install [Unity 5](http://unity3d.com/get-unity). (We're using the Personal Edition.) +2. `$ git clone --depth 1 https://github.com/JapaMala/armok-vision.git` (or without `--depth 1` if you want the full history, but it's pretty big). +3. Load the `armok-vision` folder in the Unity editor. +4. Hack around. Check out the [issues](https://github.com/JapaMala/armok-vision/issues) to find things that need fixing / ideas that could be implemented. +5. Submit a [pull request](https://github.com/JapaMala/armok-vision/pulls) with your changes! + +##### Structural Notes +(Some short notes for anyone getting started with the codebase.) + +- Armok Vision is an application built with the [Unity engine](https://unity3d.com/). It connects to the [remotefortressreader](https://github.com/DFHack/dfhack/blob/master/plugins/remotefortressreader.cpp) DFHack plugin over TCP and exchanges [protobuf-formatted messages](https://github.com/DFHack/dfhack/blob/master/plugins/proto/RemoteFortressReader.proto). (You don't need to be familiar with DFHack to work with Armok Vision.) +- On the Unity side, [Assets/RemoteClientDF](https://github.com/JapaMala/armok-vision/tree/master/Assets/RemoteClientDF) contains the generated C# protobuf files, as well as classes for managing the network connection. The script [Assets/MapGen/DFConnection.cs](https://github.com/JapaMala/armok-vision/blob/master/Assets/MapGen/DFConnection.cs) runs the connection on a separate thread and exposes data collected from DF. +- The script that actually manages the onscreen map is [Assets/MapGen/GameMap.cs](https://github.com/JapaMala/armok-vision/blob/master/Assets/MapGen/GameMap.cs), which stores the `GameObject`s representing different map chunks. It calls the scripts in [Assets/MapGen/Meshing](https://github.com/JapaMala/armok-vision/tree/master/Assets/MapGen/Meshing) to build the actual meshes (on separate threads). +- Most assets - textures, 3d models, sprites, etc. - are loaded at runtime from [Assets/StreamingAssets](https://github.com/JapaMala/armok-vision/tree/master/Assets/StreamingAssets), which is copied directly to folder containing the generated app. The script that handles this is [Assets/MapGen/ContentLoader.cs](https://github.com/JapaMala/armok-vision/blob/master/Assets/MapGen/ContentLoader.cs). + +There's a lot of other stuff but hopefully it'll be reasonably self-explanatory. Alternatively, you can ask in the forum thread, or the #dfhack IRC channel on freenode; somebody might be lurking who can help. From ac49935e068548929643e7177953f783db6b1535 Mon Sep 17 00:00:00 2001 From: kazimuth Date: Wed, 20 May 2015 18:09:20 -0400 Subject: [PATCH 4/4] Add basic banner and icon --- Assets/BasicBanner.png | 3 ++ Assets/BasicBanner.png.meta | 55 +++++++++++++++++++++++++++ Assets/BasicIcon.png | 3 ++ Assets/BasicIcon.png.meta | 55 +++++++++++++++++++++++++++ ProjectSettings/ProjectSettings.asset | 11 +++--- 5 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 Assets/BasicBanner.png create mode 100644 Assets/BasicBanner.png.meta create mode 100644 Assets/BasicIcon.png create mode 100644 Assets/BasicIcon.png.meta diff --git a/Assets/BasicBanner.png b/Assets/BasicBanner.png new file mode 100644 index 000000000..e34739ed4 --- /dev/null +++ b/Assets/BasicBanner.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c88710da82c7fbc897eb3320ef7e299da4080bf74f1733047fb51aa38a34541 +size 1129 diff --git a/Assets/BasicBanner.png.meta b/Assets/BasicBanner.png.meta new file mode 100644 index 000000000..09f42db75 --- /dev/null +++ b/Assets/BasicBanner.png.meta @@ -0,0 +1,55 @@ +fileFormatVersion: 2 +guid: c5438fb44cad84d79a3b9ae867451d83 +timeCreated: 1432160058 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: 5 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/BasicIcon.png b/Assets/BasicIcon.png new file mode 100644 index 000000000..f03fb8758 --- /dev/null +++ b/Assets/BasicIcon.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:10a8db4985a79ca4b9a4c38150b8c40e51eff18fc7a930f2d40435ee8500ed9b +size 5871 diff --git a/Assets/BasicIcon.png.meta b/Assets/BasicIcon.png.meta new file mode 100644 index 000000000..f4d404ab2 --- /dev/null +++ b/Assets/BasicIcon.png.meta @@ -0,0 +1,55 @@ +fileFormatVersion: 2 +guid: d57e1ad97b15e43a187111ec757683de +timeCreated: 1432156843 +licenseType: Free +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 8c006c05d..e0fdb69fe 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -48,7 +48,7 @@ PlayerSettings: submitAnalytics: 1 usePlayerLog: 1 bakeCollisionMeshes: 0 - forceSingleInstance: 0 + forceSingleInstance: 1 resizableWindow: 1 useMacAppStoreValidation: 0 gpuSkinning: 1 @@ -58,7 +58,7 @@ PlayerSettings: xboxEnableKinectAutoTracking: 0 xboxEnableFitness: 0 visibleInBackground: 0 - macFullscreenMode: 2 + macFullscreenMode: 1 d3d9FullscreenMode: 1 d3d11FullscreenMode: 1 xboxSpeechDB: 0 @@ -93,7 +93,7 @@ PlayerSettings: ForceSDCardPermission: 0 CreateWallpaper: 0 APKExpansionFiles: 0 - preloadShaders: 0 + preloadShaders: 1 StripUnusedMeshComponents: 0 iPhoneSdkVersion: 988 iPhoneTargetOSVersion: 22 @@ -133,11 +133,12 @@ PlayerSettings: height: 180 banner: {fileID: 0} androidGamepadSupportLevel: 0 - resolutionDialogBanner: {fileID: 0} + resolutionDialogBanner: {fileID: 2800000, guid: c5438fb44cad84d79a3b9ae867451d83, + type: 3} m_BuildTargetIcons: - m_BuildTarget: m_Icons: - - m_Icon: {fileID: 0} + - m_Icon: {fileID: 2800000, guid: d57e1ad97b15e43a187111ec757683de, type: 3} m_Size: 128 m_BuildTargetBatching: - m_BuildTarget: Standalone