@@ -112,6 +112,9 @@
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="Facepunch.Steamworks">
<HintPath>..\..\Facepunch.Steamworks-master\Facepunch.Steamworks\bin\Debug\net45\Facepunch.Steamworks.dll</HintPath>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib">
<HintPath>..\..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
@@ -176,6 +179,7 @@
<Compile Include="Ancora\TestGrammar.cs" />
<Compile Include="AssetManagement\IndexedTexture.cs" />
<Compile Include="AssetManagement\IndexedDecomposition.cs" />
<Compile Include="AssetManagement\ModMetaData.cs" />
<Compile Include="AssetManagement\TextureTool.cs" />
<Compile Include="AssetManagement\Palette.cs" />
<Compile Include="AssetManagement\MemoryTexture.cs" />
@@ -195,6 +199,7 @@
<Compile Include="AssetManagement\GameSave\OverworldFile.cs" />
<Compile Include="AssetManagement\AssetManager.cs" />
<Compile Include="AssetManagement\ModCompiler.cs" />
<Compile Include="AssetManagement\Steam\Steam.cs" />
<Compile Include="Components\AI\Buff.cs" />
<Compile Include="Components\AI\CharacterMode.cs" />
<Compile Include="Components\AI\CraftDetails.cs" />
@@ -881,9 +886,15 @@
<Compile Include="World\WorldTime.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="Facepunch.Steamworks.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="favicon.ico" />
<Content Include="Game.ico" />
<Content Include="GameThumbnail.png" />
<Content Include="steam_api.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="mod hooks.txt" />
<EmbeddedResource Include="version.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
Binary file not shown.
@@ -240,7 +240,9 @@ public class Settings
public bool AllowReporting = true;
public bool ZoomCameraTowardMouse = true;
public bool CameraFollowSurface = true;
public List<String> EnabledMods = new List<string>();
public String LocalModDirectory = "Mods";
public String SteamModDirectory = "C:/Program Files/Steam/steamapps/workshop/content/252390";
public List<Guid> EnabledMods = new List<Guid>();
public int MaxSaves = 15;
public bool EnableSlowMotion = false;
public int ConsoleTextSize = 2;
@@ -37,6 +37,7 @@
using DwarfCorp.Gui.Widgets;
using System.Linq;
using System;
using DwarfCorp.AssetManagement.Steam;

namespace DwarfCorp.GameStates
{
@@ -47,42 +48,36 @@ public class ManageModsState : GameState
{
private Gui.Root GuiRoot;
private bool HasChanges = false;
private Steam Steam;

public ManageModsState(DwarfGame game, GameStateManager stateManager) :
base(game, "ManageModsState", stateManager)
{
}

private List<string> DetectMods()
{
if (System.IO.Directory.Exists("Mods"))
return System.IO.Directory.EnumerateDirectories("Mods").Select(p => System.IO.Path.GetFileName(p)).ToList();
else
return new List<string>();
Steam = new Steam();
}

private class Mod
{
public bool Enabled = false;
public string Name;
public Widget LineItem;
public ModMetaData MetaData;
}

public override void OnEnter()
{
var availableMods = DetectMods();
var enabledMods = new List<String>(GameSettings.Default.EnabledMods);
foreach (var mod in GameSettings.Default.EnabledMods)
if (!availableMods.Contains(mod))
enabledMods.Remove(mod);
foreach (var mod in enabledMods)
availableMods.Remove(mod);
var availableMods = AssetManager.EnumerateInstalledMods().ToList();
var allMods = new List<Mod>();
allMods.AddRange(enabledMods.Select(m => new Mod { Enabled = true, Name = m }));
allMods.AddRange(availableMods.Select(m => new Mod { Enabled = false, Name = m }));



allMods.AddRange(availableMods.Where(m => GameSettings.Default.EnabledMods.Contains(m.Guid)).Select(m => new Mod
{
Enabled = true,
MetaData = m
}));
allMods.AddRange(availableMods.Where(m => !GameSettings.Default.EnabledMods.Contains(m.Guid)).Select(m => new Mod
{
Enabled = false,
MetaData = m
}));

DwarfGame.GumInputMapper.GetInputQueue();

GuiRoot = new Gui.Root(DwarfGame.GuiSkin);
@@ -93,7 +88,7 @@ public override void OnEnter()
float newWidth = System.Math.Min(System.Math.Max(screen.Width * scale, 640), screen.Width * scale);
float newHeight = System.Math.Min(System.Math.Max(screen.Height * scale, 480), screen.Height * scale);
Rectangle rect = new Rectangle((int)(screen.Width / 2 - newWidth / 2), (int)(screen.Height / 2 - newHeight / 2), (int)newWidth, (int)newHeight);
// CONSTRUCT GUI HERE...

var main = GuiRoot.RootItem.AddChild(new Gui.Widget
{
Rect = rect,
@@ -156,28 +151,66 @@ public override void OnEnter()

foreach (var mod in allMods)
{
var lineItem = GuiRoot.ConstructWidget(new CheckBox
var lineItem = GuiRoot.ConstructWidget(new Widget
{
MinimumSize = new Point(1, 32),
Background = new TileReference("basic", 0),
TextColor = new Vector4(0,0,0,1),
});

if (mod.MetaData.Source == ModSource.LocalDirectory)
{
var upload = lineItem.AddChild(new Button()
{
Text = "UPLOAD",
AutoLayout = AutoLayout.DockRight,
TextColor = new Vector4(0, 0, 0, 1),
OnClick = (sender, args) =>
{
try
{
Steam.CreateMod(mod.MetaData.Directory);
GuiRoot.ShowModalPopup(new Popup()
{
Text = "Successfully uploaded the mod to Steam."
});
}
catch (Exception exception)
{
GuiRoot.ShowModalPopup(new Popup()
{
MinimumSize = new Point(512, 256),
Text = exception.Message
});
}

}
});
}

var toggle = lineItem.AddChild(new CheckBox
{
MinimumSize = new Point(1, 32),
Text = mod.Name,
Text = mod.MetaData.Name,
Padding = new Margin(2,2,2,2),
Background = new TileReference("basic", 0),
InteriorMargin = new Margin(2,2,2,2),
ToggleOnTextClick = false

ToggleOnTextClick = false,
AutoLayout = AutoLayout.DockFill,
TextColor = new Vector4(0, 0, 0, 1),
}) as CheckBox;

lineItem.SilentSetCheckState(mod.Enabled);
lineItem.Tag = mod;
lineItem.OnCheckStateChange += (sender) =>
toggle.SilentSetCheckState(mod.Enabled);
toggle.Tag = mod;
toggle.OnCheckStateChange += (sender) =>
{
(sender.Tag as Mod).Enabled = (sender as CheckBox).CheckState;
HasChanges = true;
};

mod.LineItem = lineItem;

list.AddItem(lineItem);
list.AddItem(lineItem);
}

bottom.AddChild(new Gui.Widgets.Button
@@ -228,7 +261,6 @@ public override void OnEnter()

GuiRoot.RootItem.Layout();

// Must be true or Render will not be called.
IsInitialized = true;

base.OnEnter();
@@ -243,7 +275,7 @@ private void RebuildItems(WidgetListView View, List<Mod> Mods)

private void SaveList(List<Mod> Mods)
{
GameSettings.Default.EnabledMods = Mods.Where(m => m.Enabled).Select(m => m.Name).ToList();
GameSettings.Default.EnabledMods = Mods.Where(m => m.Enabled).Select(m => m.MetaData.Guid).ToList();
GameSettings.Save();
}

@@ -150,6 +150,13 @@ public String WordWrapString(String S, float GlyphWidthScale, float Width)
{
w.Append(c);
wordLength += (HasGlyph(c - ' ') ? GlyphSize(c - ' ').X : 0) * GlyphWidthScale;
if (wordLength > Width)
{
r.Append("\n");
r.Append(w);
w.Clear();
wordLength = 0;
}
}
}

@@ -14,9 +14,10 @@ public class Popup : Widget
public override void Construct()
{
//Set size and center on screen.
Rect = new Rectangle(0, 0, 256, 128);
Rect.X = (Root.RenderData.VirtualScreen.Width / 2) - 128;
Rect.Y = (Root.RenderData.VirtualScreen.Height / 2) - 32;
Rect = new Rectangle(0, 0, Math.Max(256, MinimumSize.X), Math.Max(128, MinimumSize.Y));
Rect.X = (Root.RenderData.VirtualScreen.Width / 2) - Rect.Width / 2;
Rect.Y = (Root.RenderData.VirtualScreen.Height / 2) - Rect.Height / 2;
WrapText = true;

Border = "border-fancy";

@@ -74,7 +74,8 @@ public static string CreatePath(params string[] args)
{
return String.Join(new String(DirChar, 1), args);
}


// Todo: KILL
public static char DirChar = Path.DirectorySeparatorChar;

}
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Facepunch.Steamworks" version="0.7.5" targetFramework="net40-client" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
<package id="SharpRaven" version="2.2.0" targetFramework="net45" />
<package id="SharpZipLib" version="0.86.0" targetFramework="net45" />
Binary file not shown.
@@ -0,0 +1,17 @@
# Auto detect text files and perform LF normalization
* text=auto

# Custom for Visual Studio
*.cs diff=csharp

# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
@@ -0,0 +1,76 @@
# Windows image file caches
Thumbs.db
ehthumbs.db

# Folder config file
Desktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msm
*.msp

# Windows shortcuts
*.lnk

# =========================
# Operating System Files
# =========================

# OSX
# =========================

.DS_Store
.AppleDouble
.LSOverride

# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
Facepunch.Steamworks.Test/bin/Debug/Facepunch.Steamworks.dll
*.pdb
Facepunch.Steamworks.Test/bin/Debug/Facepunch.Steamworks.Test.dll
*.suo
Facepunch.Steamworks.Test/bin/Debug/Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll
Facepunch.Steamworks.Test/bin/Release/Facepunch.Steamworks.dll
Facepunch.Steamworks.Test/bin/Release/Facepunch.Steamworks.Test.dll
Facepunch.Steamworks.Test/bin/Release/Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll
*.user
*.cache
*.idea
*.vscode
TestResults
obj
Facepunch.Steamworks/bin/Debug/Facepunch.Steamworks.Api.dll
Facepunch.Steamworks/bin/Debug/Facepunch.Steamworks.dll
Facepunch.Steamworks/bin/Release/Facepunch.Steamworks.dll
Facepunch.Steamworks/bin
*.opendb
*.db
Facepunch.Steamworks.dll
Facepunch.Steamworks.Test.dll
*UnitTestFramework.dll
mscorlib.dll
*.nlp
packages
Generator/bin
*.XML
.vs
@@ -0,0 +1,93 @@
using System;
using System.Text;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
public class Achievements
{
[TestMethod]
public void GetCount()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );

var gotStats = false;
client.Achievements.OnUpdated += () => { gotStats = true; };

while ( !gotStats )
{
client.Update();
}

Console.WriteLine( "Found " + client.Achievements.All.Length + " Achievements" );

Assert.AreNotEqual( 0, client.Achievements.All.Length );
}
}

[TestMethod]
public void GetNames()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );

var gotStats = false;
client.Achievements.OnUpdated += () => { gotStats = true; };

while ( !gotStats )
{
client.Update();
}

foreach( var ach in client.Achievements.All )
{
Assert.IsNotNull( ach.Id );

Console.WriteLine( " " + ach.Id );
Console.WriteLine( " - - " + ach.Name );
Console.WriteLine( " - - " + ach.Description );
Console.WriteLine( " - - " + ach.State );
Console.WriteLine( " - - " + ach.UnlockTime );
Console.WriteLine( " - - " + ach.GlobalUnlockedPercentage );

if ( ach.Icon != null )
{
Console.WriteLine( " - - " + ach.Icon.Width + " x " + ach.Icon.Height );
}

Console.WriteLine( "" );
}
}
}

[TestMethod]
public void Trigger()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );

var gotStats = false;
client.Achievements.OnUpdated += () => { gotStats = true; };

while ( !gotStats )
{
client.Update();
}

foreach ( var ach in client.Achievements.All )
{
ach.Trigger();
}
}
}

}
}
@@ -0,0 +1,65 @@
using System;
using System.Text;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
public class App
{
[TestMethod]
public void IsSubscribed()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Console.WriteLine("This test assumes you own Garry's Mod and not Charles III of Spain and the antiquity");

Assert.IsTrue( client.App.IsSubscribed( 4000 ) );
Assert.IsFalse( client.App.IsSubscribed( 590440 ));
}
}

[TestMethod]
public void IsInstalled()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Console.WriteLine("This test assumes you have Garry's Mod installed but not Charles III of Spain and the antiquity");

Assert.IsTrue(client.App.IsInstalled(4000));
Assert.IsFalse(client.App.IsInstalled(590440));
}
}

[TestMethod]
public void PurchaseTime()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Console.WriteLine("This test assumes you own Garry's Mod but not Charles III of Spain and the antiquity");

var gmodBuyTime = client.App.PurchaseTime( 4000 );
Assert.AreNotEqual( gmodBuyTime, DateTime.MinValue );

Console.WriteLine($"You bought Garry's Mod {gmodBuyTime}");

var otherBuyTime = client.App.PurchaseTime(590440);
Assert.AreEqual(otherBuyTime, DateTime.MinValue);
}
}

[TestMethod]
public void AppName()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var name = client.App.GetName( 4000 );
Console.WriteLine( name );
}
}

}
}
@@ -0,0 +1,187 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
public partial class Client
{
[TestMethod]
public void Init()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
}
}

[TestMethod]
public void Init_10()
{
for ( int i = 0; i < 10; i++ )
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
}

GC.Collect();
}
}

[TestMethod]
public void Name()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );

var username = client.Username;
Console.WriteLine( username );
Assert.IsNotNull( username );
}
}

[TestMethod]
public void SteamId()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );

var steamid = client.SteamId;
Console.WriteLine( steamid );
Assert.AreNotEqual( 0, steamid );
}
}

[TestMethod]
public void AuthSessionTicket()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var ticket = client.Auth.GetAuthSessionTicket();

Assert.IsTrue( ticket != null );
Assert.IsTrue( ticket.Handle != 0 );
Assert.IsTrue( ticket.Data.Length > 0 );

ticket.Cancel();

Assert.IsTrue( ticket.Handle == 0 );
}
}

[TestMethod]
public void Update()
{
var sw = new Stopwatch();
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue(client.IsValid);

for( int i=0; i<1024; i++ )
{
sw.Restart();
client.Update();
Console.WriteLine( $"{sw.Elapsed.TotalMilliseconds}ms" );

}
}
}

[TestMethod]
public void Subscribed()
{
var sw = new Stopwatch();
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
Assert.IsTrue(client.IsSubscribed);
}
}

[TestMethod]
public void Owner()
{
var sw = new Stopwatch();
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
Assert.AreEqual(client.OwnerSteamId, client.SteamId);
}
}

[TestMethod]
public void InstallFolder()
{
var sw = new Stopwatch();
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
Assert.IsTrue(client.InstallFolder.Exists);

Console.Write($"Install Folder: {client.InstallFolder}");
}
}

[TestMethod]
public void CurrentLanguage()
{
var sw = new Stopwatch();
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
Assert.IsTrue( client.CurrentLanguage != null );
Assert.IsTrue( client.CurrentLanguage.Length > 0 );

Console.Write( $"CurrentLanguage: {client.CurrentLanguage}" );
}
}

[TestMethod]
public void AvailableLanguages()
{
var sw = new Stopwatch();
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
Assert.IsTrue( client.AvailableLanguages != null );
Assert.IsTrue( client.AvailableLanguages.Length > 0 );

foreach ( var lang in client.AvailableLanguages )
{
Console.Write( $"AvailableLanguages: {lang}" );
}

}
}

[TestMethod]
public void Cybercafe()
{
var sw = new Stopwatch();
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
Assert.IsFalse(client.IsCybercafe);
}
}

[TestMethod]
public void LowViolence()
{
var sw = new Stopwatch();
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
Assert.IsFalse(client.IsLowViolence);
}
}
}
}
@@ -0,0 +1,124 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;

namespace Facepunch.Steamworks.Test
{
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
[TestClass]
public class Friends
{
[TestMethod]
public void FriendList()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );

client.Friends.Refresh();

Assert.IsNotNull( client.Friends.All );

foreach ( var friend in client.Friends.All )
{
Console.WriteLine( "{0}: {1} (Friend:{2}) (Blocked:{3})", friend.Id, friend.Name, friend.IsFriend, friend.IsBlocked );

Assert.IsNotNull(friend.GetAvatar( Steamworks.Friends.AvatarSize.Medium ));
}
}
}

[TestMethod]
public void FriendListWithoutRefresh()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );

foreach ( var friend in client.Friends.All )
{
Console.WriteLine( "{0}: {1} (Friend:{2}) (Blocked:{3})", friend.Id, friend.Name, friend.IsFriend, friend.IsBlocked );
}
}
}

[TestMethod]
public void Avatar()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );

ulong id = (ulong)( 76561197960279927 + (new Random().Next() % 10000));
bool passed = false;

client.Friends.GetAvatar( Steamworks.Friends.AvatarSize.Medium, id, ( avatar) =>
{
if ( avatar == null )
{
Console.WriteLine( "No Avatar" );
}
else
{
Assert.AreEqual( avatar.Width, 64 );
Assert.AreEqual( avatar.Height, 64 );
Assert.AreEqual( avatar.Data.Length, avatar.Width * avatar.Height * 4 );

DrawImage( avatar );
}
passed = true;
});

while (passed == false )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}
}
}

[TestMethod]
public void CachedAvatar()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);

var friend = client.Friends.All.First();

var image = client.Friends.GetCachedAvatar( Steamworks.Friends.AvatarSize.Medium, friend.Id );

if (image != null)
{
Assert.AreEqual(image.Width, 64);
Assert.AreEqual(image.Height, 64);
Assert.AreEqual(image.Data.Length, image.Width * image.Height * 4);
}
}
}

public static void DrawImage( Image img )
{
var grad = " -:+#";

for ( int y = 0; y<img.Height; y++ )
{
var str = "";

for ( int x = 0; x < img.Width; x++ )
{
var p = img.GetPixel( x, y );

var brightness = 1 - ((float)(p.r + p.g + p.b) / (255.0f * 3.0f));
var c = (int) ((grad.Length) * brightness);
if ( c > 3 ) c = 3;
str += grad[c];

}

Console.WriteLine( str );
}
}
}
}
@@ -0,0 +1,295 @@
using System;
using System.Diagnostics;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;

namespace Facepunch.Steamworks.Test
{
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
[TestClass]
public class Inventory
{
[TestMethod]
public void InventoryDefinitions()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
while ( client.Inventory.Definitions == null )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}

Assert.IsNotNull( client.Inventory.Definitions );
Assert.AreNotEqual( 0, client.Inventory.Definitions.Length );

foreach ( var i in client.Inventory.Definitions.Where( x => x.PriceCategory != "" ) )
{
Console.WriteLine( "{0}: {1} ({2})", i.Id, i.Name, i.Type );
Console.WriteLine( " itemshortname: {0}", i.GetStringProperty( "itemshortname" ) );
Console.WriteLine( " workshopdownload: {0}", i.GetStringProperty( "workshopdownload" ) );
Console.WriteLine( " IconUrl: {0}", i.IconUrl );
Console.WriteLine( " IconLargeUrl: {0}", i.IconLargeUrl );
Console.WriteLine( " PriceRaw: {0}", i.PriceCategory );
Console.WriteLine( " PriceDollars: {0}", i.PriceDollars );
}
}
}

[TestMethod]
public void InventoryDefinitionExchange()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
while ( client.Inventory.Definitions == null )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}

Assert.IsNotNull( client.Inventory.Definitions );
Assert.AreNotEqual( 0, client.Inventory.Definitions.Length );

foreach ( var i in client.Inventory.Definitions )
{
if ( i.Recipes == null ) continue;

Console.WriteLine( "Ways To Create " + i.Name );

foreach ( var r in i.Recipes )
{
Console.WriteLine( " " + string.Join( ", ", r.Ingredients.Select( x => x.Count + " x " + x.Definition.Name ) ) );
}
}
}
}

[TestMethod]
public void InventoryDefinitionIngredients()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
while ( client.Inventory.Definitions == null )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}

Assert.IsNotNull( client.Inventory.Definitions );
Assert.AreNotEqual( 0, client.Inventory.Definitions.Length );

foreach ( var i in client.Inventory.Definitions )
{
if ( i.IngredientFor == null ) continue;

Console.WriteLine( i.Name + " Can Be Used to Make" );

foreach ( var r in i.IngredientFor )
{
Console.WriteLine( " " + r.Result.Name );
}
}
}
}

[TestMethod]
public void InventoryItemList()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
while ( client.Inventory.Definitions == null )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}

bool CallbackCalled = false;

// OnUpdate hsould be called when we receive a list of our items
client.Inventory.OnUpdate = () => { CallbackCalled = true; };

// tell steam to download the items
client.Inventory.Refresh();

// Wait for the items
var timeout = Stopwatch.StartNew();
while ( client.Inventory.Items == null )
{
client.Update();
System.Threading.Thread.Sleep( 1000 );

if ( timeout.Elapsed.TotalSeconds > 10 )
break;
}

// make sure callback was called
Assert.IsTrue( CallbackCalled );

// Make sure items are valid
foreach ( var item in client.Inventory.Items )
{
Assert.IsNotNull( item );
Assert.IsNotNull( item.Definition );

Console.WriteLine( item.Definition.Name + " - " + item.Id );
}
}
}

[TestMethod]
public void InventoryItemProperties()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
while ( true )
{
client.Update();

if (client.Inventory.Items == null) continue;

foreach (var item in client.Inventory.Items)
{
Console.WriteLine($"{item.Id} ({item.Definition.Name})");

foreach (var property in item.Properties)
{
Console.WriteLine($" {property.Key} = {property.Value}");
}

Console.WriteLine("");
}

return;
}
}
}

[TestMethod]
public void Deserialize()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
while ( client.Inventory.Definitions == null )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}

Assert.IsTrue( client.IsValid );
Assert.IsNotNull(client.Inventory.Definitions);
Assert.AreNotEqual(0, client.Inventory.Definitions.Length);

client.Inventory.Refresh();

var stopwatch = Stopwatch.StartNew();

//
// Block until we have the items
//
while ( client.Inventory.SerializedItems == null )
{
client.Update();

if (stopwatch.Elapsed.Seconds > 10)
throw new System.Exception("Getting SerializedItems took too long");
}

Assert.IsNotNull( client.Inventory.SerializedItems );
Assert.IsTrue( client.Inventory.SerializedItems.Length > 4 );

using ( var server = new Facepunch.Steamworks.Server( 252490, new ServerInit( "rust", "Rust" ) ) )
{
server.LogOnAnonymous();
Assert.IsTrue( server.IsValid );

var result = server.Inventory.Deserialize( client.Inventory.SerializedItems );

stopwatch = Stopwatch.StartNew();

while (result.IsPending)
{
server.Update();

if (stopwatch.Elapsed.Seconds > 10)
throw new System.Exception("result took too long");
}

Assert.IsFalse( result.IsPending );
Assert.IsNotNull( result.Items );

foreach ( var item in result.Items )
{
Console.WriteLine( "Item: {0} ({1})", item.Id, item.DefinitionId );
Console.WriteLine( "Item: {0} ({1})", item.Id, item.DefinitionId );
}
}
}
}

[TestMethod]
public void PurchaseItems()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
while ( client.Inventory.Definitions == null )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}

Assert.IsNotNull(client.Inventory.Definitions);
Assert.AreNotEqual(0, client.Inventory.Definitions.Length);

while ( client.Inventory.Currency == null )
{
client.Update();
}

var shoppingList = client.Inventory.DefinitionsWithPrices.Take(2).ToArray();
bool waitingForCallback = true;

if ( !client.Inventory.StartPurchase(shoppingList, ( order, tran ) =>
{
Console.WriteLine($"Order: {order}, Transaction {tran}");
waitingForCallback = false;

} ) )
{
throw new Exception("Couldn't Buy!");
}

while ( waitingForCallback )
{
client.Update();
}
}
}

[TestMethod]
public void ListPrices()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
while ( client.Inventory.Definitions == null )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}

Assert.IsNotNull(client.Inventory.Definitions);
Assert.AreNotEqual(0, client.Inventory.Definitions.Length);

while (client.Inventory.Currency == null)
{
client.Update();
}

foreach ( var i in client.Inventory.Definitions.Where( x => x.LocalPrice > 0 ) )
{
Console.WriteLine( $" {i.Name} - {i.LocalPriceFormatted} ({client.Inventory.Currency})" );
}
}
}
}
}
@@ -0,0 +1,277 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
public class Leaderboard
{
[TestMethod]
public void GetLeaderboard()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var board = client.GetLeaderboard( "TestLeaderboard", Steamworks.Client.LeaderboardSortMethod.Ascending, Steamworks.Client.LeaderboardDisplayType.Numeric );

var time = Stopwatch.StartNew();
while ( !board.IsValid )
{
Thread.Sleep( 10 );
client.Update();

if (time.Elapsed.TotalSeconds > 10 )
{
throw new Exception("board.IsValid took too long");
}
}

Assert.IsTrue( board.IsValid );
Assert.IsFalse( board.IsError );
Assert.IsNotNull( board.Name );

Console.WriteLine( $"Board name is \"{board.Name}\"" );
Console.WriteLine( $"Board has \"{board.TotalEntries}\" entries" );

board.AddScore( true, 86275309, 7, 8, 9 );

board.FetchScores( Steamworks.Leaderboard.RequestType.Global, 0, 20 );

time = Stopwatch.StartNew();
while ( board.IsQuerying )
{
Thread.Sleep( 10 );
client.Update();

if (time.Elapsed.TotalSeconds > 10)
{
throw new Exception("board.IsQuerying took too long");
}
}

Assert.IsFalse( board.IsError );
Assert.IsNotNull( board.Results );

foreach ( var entry in board.Results )
{
Console.WriteLine( $"{entry.GlobalRank}: {entry.SteamId} ({entry.Name}) with {entry.Score}" );

if ( entry.SubScores != null )
Console.WriteLine( " - " + string.Join( ";", entry.SubScores.Select( x => x.ToString() ).ToArray() ) );
}
}
}

[TestMethod]
public void GetLeaderboardCallback()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var board = client.GetLeaderboard( "TestLeaderboard", Steamworks.Client.LeaderboardSortMethod.Ascending, Steamworks.Client.LeaderboardDisplayType.Numeric );

var time = Stopwatch.StartNew();
while ( !board.IsValid )
{
Thread.Sleep( 10 );
client.Update();

if (time.Elapsed.TotalSeconds > 10)
{
throw new Exception("board.IsValid took too long");
}
}

Assert.IsTrue( board.IsValid );
Assert.IsFalse( board.IsError );
Assert.IsNotNull( board.Name );

board.AddScore( true, 86275309, 7, 8, 9 );

var done = false;

board.FetchScores( Steamworks.Leaderboard.RequestType.Global, 0, 20, results =>
{
foreach ( var entry in results )
{
Console.WriteLine( $"{entry.GlobalRank}: {entry.SteamId} ({entry.Name}) with {entry.Score}" );

if ( entry.SubScores != null )
Console.WriteLine( " - " + string.Join( ";", entry.SubScores.Select( x => x.ToString() ).ToArray() ) );
}

done = true;
}, error => Assert.Fail( error.ToString() ) );

while ( !done )
{
Thread.Sleep( 10 );
client.Update();
}
}
}

[TestMethod]
public void AddScores()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var board = client.GetLeaderboard( "TestLeaderboard", Steamworks.Client.LeaderboardSortMethod.Ascending, Steamworks.Client.LeaderboardDisplayType.Numeric );

var time = Stopwatch.StartNew();
while (!board.IsValid)
{
Thread.Sleep(10);
client.Update();

if (time.Elapsed.TotalSeconds > 10)
{
throw new Exception("board.IsValid took too long");
}
}

Assert.IsTrue( board.IsValid );
Assert.IsFalse( board.IsError );

board.AddScore( true, 1234 );

Thread.Sleep( 10 );
client.Update();

board.AddScore( true, 34566 );

Thread.Sleep( 10 );
client.Update();

board.AddScore( true, 86275309, 7, 8, 9, 7, 4, 7, 98, 24, 5, 76, 124, 6 );

Thread.Sleep( 10 );
client.Update();

board.AddScore( false, 86275309, 7, 8, 9, 7, 4, 7, 98, 24, 5, 76, 124, 6 );

Thread.Sleep( 10 );
client.Update();
}
}

[TestMethod]
public void AddScoresCallback()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var board = client.GetLeaderboard( "TestLeaderboard", Steamworks.Client.LeaderboardSortMethod.Ascending, Steamworks.Client.LeaderboardDisplayType.Numeric );

var time = Stopwatch.StartNew();
while (!board.IsValid)
{
Thread.Sleep(10);
client.Update();

if ( board.IsError )
{
throw new Exception( "Board is Error" );
}

if (time.Elapsed.TotalSeconds > 10)
{
throw new Exception("board.IsValid took too long");
}
}

Assert.IsTrue( board.IsValid );
Assert.IsFalse( board.IsError );

var done = false;

const int score = 5678;

board.AddScore( false, score, null, result =>
{
Assert.IsTrue( result.ScoreChanged );
Assert.AreEqual( result.Score, score );

done = true;
}, error => Assert.Fail( error.ToString() ) );

while ( !done )
{
Thread.Sleep( 10 );
client.Update();
}
}
}

[TestMethod]
public void AddFileAttachment()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var board = client.GetLeaderboard( "TestLeaderboard", Steamworks.Client.LeaderboardSortMethod.Ascending, Steamworks.Client.LeaderboardDisplayType.Numeric );

var time = Stopwatch.StartNew();
while (!board.IsValid)
{
Thread.Sleep(10);
client.Update();

if (time.Elapsed.TotalSeconds > 10)
{
throw new Exception("board.IsValid took too long");
}
}

Assert.IsTrue( board.IsValid );
Assert.IsFalse( board.IsError );

var done = false;

const int score = 5678;
const string attachment = "Hello world!";

var file = client.RemoteStorage.CreateFile( "score/example.txt" );
file.WriteAllText( attachment );

Assert.IsTrue( board.AddScore( false, score, null, result =>
{
Assert.IsTrue( result.ScoreChanged );

Assert.IsTrue( board.AttachRemoteFile( file, () =>
{
done = true;
}, error => Assert.Fail( error.ToString() ) ) );
}, error => Assert.Fail( error.ToString() ) ) );

while ( !done )
{
Thread.Sleep( 10 );
client.Update();
}

done = false;

Assert.IsTrue( board.FetchScores( Steamworks.Leaderboard.RequestType.GlobalAroundUser, 0, 0, entries =>
{
Assert.AreEqual( 1, entries.Length );
Assert.IsNotNull( entries[0].AttachedFile );

Assert.IsTrue( entries[0].AttachedFile.Download( () =>
{
Assert.AreEqual( attachment, entries[0].AttachedFile.ReadAllText() );

done = true;
}, error => Assert.Fail( error.ToString() ) ) );
}, error => Assert.Fail( error.ToString() ) ) );

while ( !done )
{
Thread.Sleep( 10 );
client.Update();
}
}
}
}
}
@@ -0,0 +1,390 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Facepunch.Steamworks;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem("steam_api.dll")]
[DeploymentItem("steam_api64.dll")]
public class Lobby
{
[TestMethod]
public void CreateLobby()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);

client.Lobby.Create(Steamworks.Lobby.Type.Public, 10);

client.Lobby.OnLobbyCreated = (success) =>
{
Assert.IsTrue(success);
Assert.IsTrue(client.Lobby.IsValid);
Console.WriteLine("lobby created: " + client.Lobby.CurrentLobby);
Console.WriteLine($"Owner: {client.Lobby.Owner}");
Console.WriteLine($"Max Members: {client.Lobby.MaxMembers}");
Console.WriteLine($"Num Members: {client.Lobby.NumMembers}");
client.Lobby.Leave();
};

var sw = Stopwatch.StartNew();

while (sw.Elapsed.TotalSeconds < 3)
{
client.Update();
System.Threading.Thread.Sleep(10);
}

}
}

[TestMethod]
public void GetCreatedLobbyData()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);

client.Lobby.Create(Steamworks.Lobby.Type.Public, 10);

client.Lobby.OnLobbyCreated = (success) =>
{
Assert.IsTrue(success);
Assert.IsTrue(client.Lobby.IsValid);
Console.WriteLine("lobby created: " + client.Lobby.CurrentLobby);
foreach (KeyValuePair<string, string> data in client.Lobby.CurrentLobbyData.GetAllData())
{
if (data.Key == "appid")
{
Assert.IsTrue(data.Value == "252490");
}
Console.WriteLine($"{data.Key} {data.Value}");
}
client.Lobby.Leave();
};

var sw = Stopwatch.StartNew();

while (sw.Elapsed.TotalSeconds < 3)
{
client.Update();
System.Threading.Thread.Sleep(10);
}

}
}

[TestMethod]
public void UpdateLobbyData()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);

client.Lobby.Create(Steamworks.Lobby.Type.Public, 10);

client.Lobby.OnLobbyCreated = (success) =>
{
Assert.IsTrue(success);
Assert.IsTrue(client.Lobby.IsValid);
Console.WriteLine("lobby created: " + client.Lobby.CurrentLobby);

client.Lobby.Name = "My Updated Lobby Name";
client.Lobby.CurrentLobbyData.SetData("testkey", "testvalue");
client.Lobby.LobbyType = Steamworks.Lobby.Type.Private;
client.Lobby.MaxMembers = 5;
client.Lobby.Joinable = false;

foreach (KeyValuePair<string, string> data in client.Lobby.CurrentLobbyData.GetAllData())
{
if (data.Key == "appid")
{
Assert.IsTrue(data.Value == "252490");
}

if (data.Key == "testkey")
{
Assert.IsTrue(data.Value == "testvalue");
}

if (data.Key == "lobbytype")
{
Assert.IsTrue(data.Value == Steamworks.Lobby.Type.Private.ToString());
}

Console.WriteLine($"{data.Key} {data.Value}");
}



};


client.Lobby.OnLobbyDataUpdated = () =>
{
Console.WriteLine("lobby data updated");
Console.WriteLine(client.Lobby.MaxMembers);
Console.WriteLine(client.Lobby.Joinable);
};



var sw = Stopwatch.StartNew();

while (sw.Elapsed.TotalSeconds < 3)
{
client.Update();
System.Threading.Thread.Sleep(10);
}

client.Lobby.Leave();

}
}

[TestMethod]
public void RefreshLobbyList()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);

client.Lobby.OnLobbyCreated = (success) =>
{
Assert.IsTrue(success);
Assert.IsTrue(client.Lobby.IsValid);
Console.WriteLine("lobby created: " + client.Lobby.CurrentLobby);
client.LobbyList.Refresh();
};

client.LobbyList.OnLobbiesUpdated = () =>
{
Console.WriteLine("lobbies updating");
if (client.LobbyList.Finished)
{
Console.WriteLine("lobbies finished updating");
Console.WriteLine($"found {client.LobbyList.Lobbies.Count} lobbies");

foreach (LobbyList.Lobby lobby in client.LobbyList.Lobbies)
{
Console.WriteLine($"Found Lobby: {lobby.Name}");
}

client.Lobby.Leave();

}

};

client.Lobby.Create(Steamworks.Lobby.Type.Public, 10);

var sw = Stopwatch.StartNew();

while (sw.Elapsed.TotalSeconds < 3)
{
client.Update();
System.Threading.Thread.Sleep(10);
}

}
}

[TestMethod]
public void RefreshLobbyListWithFilter()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);

client.Lobby.OnLobbyCreated = (success) =>
{
Assert.IsTrue(success);
Assert.IsTrue(client.Lobby.IsValid);
Console.WriteLine("lobby created: " + client.Lobby.CurrentLobby);
client.Lobby.CurrentLobbyData.SetData("testkey", "testvalue");
};

client.Lobby.OnLobbyDataUpdated = () =>
{
var filter = new LobbyList.Filter();
filter.StringFilters.Add("testkey", "testvalue");
client.LobbyList.Refresh(filter);
};

client.LobbyList.OnLobbiesUpdated = () =>
{
Console.WriteLine("lobbies updating");
if (client.LobbyList.Finished)
{
Console.WriteLine("lobbies finished updating");
Console.WriteLine($"found {client.LobbyList.Lobbies.Count} lobbies");

foreach (LobbyList.Lobby lobby in client.LobbyList.Lobbies)
{
Console.WriteLine($"Found Lobby: {lobby.Name}");
}

}

};

client.Lobby.Create(Steamworks.Lobby.Type.Public, 10);

var sw = Stopwatch.StartNew();

while (sw.Elapsed.TotalSeconds < 5)
{
client.Update();
System.Threading.Thread.Sleep(10);
}

client.Lobby.Leave();

}
}

[TestMethod]
public void RefreshLobbyListWithFilterAndGetLobbyDataFromListLobby()
{
using (var client = new Facepunch.Steamworks.Client(755870))
{
Assert.IsTrue(client.IsValid);

client.Lobby.OnLobbyCreated = (success) =>
{
Assert.IsTrue(success);
Assert.IsTrue(client.Lobby.IsValid);
Console.WriteLine("lobby created: " + client.Lobby.CurrentLobby);
client.Lobby.CurrentLobbyData.SetData("testkey", "testvalue");
};

client.Lobby.OnLobbyDataUpdated = () =>
{
var filter = new LobbyList.Filter();
filter.StringFilters.Add("testkey", "testvalue");
client.LobbyList.Refresh(filter);
};

client.LobbyList.OnLobbiesUpdated = () =>
{
Console.WriteLine("lobbies updating");
if (client.LobbyList.Finished)
{
Console.WriteLine("lobbies finished updating");
Console.WriteLine($"found {client.LobbyList.Lobbies.Count} lobbies");

foreach (LobbyList.Lobby lobby in client.LobbyList.Lobbies)
{
foreach (var pair in lobby.GetAllData())
{
Console.WriteLine(string.Format("Key: {0,-36} Value: {1}", pair.Key, pair.Value));
}
}
}
};

client.Lobby.Create(Steamworks.Lobby.Type.Public, 10);

var sw = Stopwatch.StartNew();

while (sw.Elapsed.TotalSeconds < 5)
{
client.Update();
System.Threading.Thread.Sleep(10);
}

client.Lobby.Leave();

}
}

[TestMethod]
public void SendChatMessage()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
string testString = "Hello, World";

client.Lobby.OnLobbyCreated = (success) =>
{
Assert.IsTrue(success);
Assert.IsTrue(client.Lobby.IsValid);
Console.WriteLine("lobby created: " + client.Lobby.CurrentLobby);
client.Lobby.CurrentLobbyData.SetData("testkey", "testvalue");
client.Lobby.SendChatMessage(testString);
};

client.Lobby.OnChatMessageRecieved = (steamID, bytes, length) =>
{
string message = Encoding.UTF8.GetString(bytes, 0, length);
Console.WriteLine("message recieved");
Assert.IsTrue(message == testString);
};

client.Lobby.OnChatStringRecieved = (steamID, message) =>
{
Console.WriteLine("message recieved");
Assert.IsTrue(message == testString);
};

client.Lobby.Create(Steamworks.Lobby.Type.Public, 10);

var sw = Stopwatch.StartNew();

while (sw.Elapsed.TotalSeconds < 5)
{
client.Update();
System.Threading.Thread.Sleep(10);
}

client.Lobby.Leave();

}
}

[TestMethod]
public void SetGetUserMetadata()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);

client.Lobby.OnLobbyCreated = (success) =>
{
Assert.IsTrue(success);
Assert.IsTrue(client.Lobby.IsValid);
Console.WriteLine("lobby created: " + client.Lobby.CurrentLobby);
client.Lobby.SetMemberData("testkey", "testvalue");
};

client.Lobby.OnLobbyMemberDataUpdated = (steamID) =>
{
string name = client.Friends.GetName(steamID);
Console.WriteLine(name + " updated data");
Assert.IsTrue(client.Lobby.GetMemberData(steamID, "testkey") == "testvalue");
Console.WriteLine("testkey is now: " + client.Lobby.GetMemberData(steamID, "testkey"));
};

client.Lobby.Create(Steamworks.Lobby.Type.Public, 10);

var sw = Stopwatch.StartNew();

while (sw.Elapsed.TotalSeconds < 5)
{
client.Update();
System.Threading.Thread.Sleep(10);
}

client.Lobby.Leave();

}
}

}
}
@@ -0,0 +1,115 @@
using System;
using System.Diagnostics;
using System.Text;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
public partial class Networking
{
[TestMethod]
public void PeerToPeerSend()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var TestString = "This string will be transformed to bytes, sent over the Steam P2P network, then converted back to a string.";
var OutputReceived = false;
var data = Encoding.UTF8.GetBytes( TestString );

//
// Enable listening on this channel
//
client.Networking.SetListenChannel( 0, true );

client.Networking.OnP2PData = ( steamid, bytes, length, channel ) =>
{
var str = Encoding.UTF8.GetString( bytes, 0, length );
Assert.AreEqual( str, TestString );
Assert.AreEqual( steamid, client.SteamId );
OutputReceived = true;

Console.WriteLine( "Got: " + str );
};

client.Networking.OnIncomingConnection = ( steamid ) =>
{
Console.WriteLine( "Incoming P2P Connection: " + steamid );
return true;
};

client.Networking.OnConnectionFailed = ( steamid, error ) =>
{
Console.WriteLine( "Connection Error: " + steamid + " - " + error );
};

client.Networking.SendP2PPacket( client.SteamId, data, data.Length );

while( true )
{
Thread.Sleep( 10 );
client.Update();

if ( OutputReceived )
break;
}
}
}

[TestMethod]
public void PeerToPeerFailure()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var TestString = "This string will be transformed to bytes, sent over the Steam P2P network, then converted back to a string.";
var TimeoutReceived = false;
var data = Encoding.UTF8.GetBytes( TestString );

client.Networking.OnIncomingConnection = ( steamid ) =>
{
Console.WriteLine( "Incoming P2P Connection: " + steamid );

return true;
};

client.Networking.OnConnectionFailed = ( steamid, error ) =>
{
Console.WriteLine( "Connection Error: " + steamid + " - " + error );
TimeoutReceived = true;
};

ulong rand = (ulong) new Random().Next( 1024 * 16 );

// Send to an invalid, not listening steamid
if ( !client.Networking.SendP2PPacket( client.SteamId + rand, data, data.Length ) )
{
Console.WriteLine( "Couldn't send packet" );
return;
}

var sw = Stopwatch.StartNew();

while ( true )
{
Thread.Sleep( 10 );
client.Update();

//
// Timout is usually around 15 seconds
//
if ( TimeoutReceived )
break;

if ( sw.Elapsed.TotalSeconds > 30 )
{
Assert.Fail( "Didn't time out" );
}
}
}
}

}
}
@@ -0,0 +1,86 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
public class RemoteStorage
{
[TestMethod]
public void GetQuota()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
ulong total = client.RemoteStorage.QuotaTotal;
var available = client.RemoteStorage.QuotaRemaining;

Console.WriteLine( $"Total quota: {total} bytes" );
Console.WriteLine( $"Available: {available} bytes" );
}
}

[TestMethod]
public void WriteFile()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var file = client.RemoteStorage.CreateFile( "test.txt" );

const string text = "Hello world!";

file.WriteAllText( text );

Assert.IsTrue( file.Exists );

var read = file.ReadAllText();
Assert.AreEqual( text, read );
}
}

[TestMethod]
public void ReadText()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var text = client.RemoteStorage.ReadString( "test.txt" );

Assert.IsNotNull( text );
Assert.AreEqual( text, "Hello world!" );
}
}

[TestMethod]
public void WriteText()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var result = client.RemoteStorage.WriteString( "test.txt", "Hello world!" );
Assert.IsTrue( result );
}
}

[TestMethod]
public void WriteFiles()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
for ( var i = 0; i < 10; ++i )
{
client.RemoteStorage
.CreateFile( $"test_{i}/example.txt" )
.WriteAllText( Guid.NewGuid().ToString() );
}

Console.WriteLine( $"File count: {client.RemoteStorage.FileCount}" );

foreach ( var file in client.RemoteStorage.Files )
{
DateTime t = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(file.FileTimestamp);
Console.WriteLine( $"- {file.FileName} ({file.SizeInBytes} bytes), modified {t:O}" );
}
}
}
}
}
@@ -0,0 +1,57 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
public class RichPresence
{
[TestMethod]
public void MissingKeyIsNull()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var key = client.User.GetRichPresence( "Missing Key" );
Assert.IsNull( key );
}
}

[TestMethod]
public void ReadBackSetKey()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var success = client.User.SetRichPresence( "One", "Two" );
Assert.IsTrue( success );

var value = client.User.GetRichPresence( "One" );
Assert.IsNotNull( value );
Assert.AreEqual( value, "Two" );
}
}

[TestMethod]
public void ClearingKeys()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var success = client.User.SetRichPresence( "One", "Two" );
Assert.IsTrue( success );

var value = client.User.GetRichPresence( "One" );
Assert.IsNotNull( value );
Assert.AreEqual( value, "Two" );

client.User.ClearRichPresence();

value = client.User.GetRichPresence( "One" );
Assert.IsNull( value );
}
}
}
}
@@ -0,0 +1,154 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Facepunch.Steamworks.Test
{
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
[DeploymentItem( "tier0_s.dll" )]
[DeploymentItem( "vstdlib_s.dll" )]
[DeploymentItem( "steamclient.dll" )]
[DeploymentItem( "tier0_s64.dll" )]
[DeploymentItem( "vstdlib_s64.dll" )]
[DeploymentItem( "steamclient64.dll" )]
[TestClass]
public partial class Server
{
[TestMethod]
public void Init()
{
var serverInit = new ServerInit( "rust", "Rust" );
serverInit.GamePort = 28015;
serverInit.Secure = true;
serverInit.QueryPort = 28016;

using ( var server = new Facepunch.Steamworks.Server( 252490, serverInit ) )
{
server.ServerName = "My Test Server";
server.LogOnAnonymous();

Assert.IsTrue( server.IsValid );
}
}

[TestMethod]
public void PublicIp()
{
using ( var server = new Facepunch.Steamworks.Server( 252490, new ServerInit( "rust", "Rust" ) ) )
{
server.LogOnAnonymous();

Assert.IsTrue( server.IsValid );

while ( true )
{
var ip = server.PublicIp;

if ( ip == null )
{
System.Threading.Thread.Sleep( 100 );
server.Update();
continue;
}

Assert.IsNotNull( ip );
Console.WriteLine( ip.ToString() );
break;
}

}
}

[TestMethod]
public void AuthCallback()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
var ticket = client.Auth.GetAuthSessionTicket();
var ticketBinary = ticket.Data;

using ( var server = new Facepunch.Steamworks.Server( 252490, new ServerInit( "rust", "Rust" ) ) )
{
server.LogOnAnonymous();

Assert.IsTrue( server.IsValid );

var auth = server.Auth;

var Authed = false;

server.Auth.OnAuthChange = ( steamid, ownerid, status ) =>
{
Authed = status == ServerAuth.Status.OK;

Assert.AreEqual( steamid, client.SteamId );
Assert.AreEqual( steamid, ownerid );

Console.WriteLine( "steamid: {0}", steamid );
Console.WriteLine( "ownerid: {0}", ownerid );
Console.WriteLine( "status: {0}", status );
};

for ( int i = 0; i < 16; i++ )
{
System.Threading.Thread.Sleep( 10 );
GC.Collect();
server.Update();
GC.Collect();
client.Update();
GC.Collect();
}

GC.Collect();
if ( !server.Auth.StartSession( ticketBinary, client.SteamId ) )
{
Assert.Fail( "Start Session returned false" );
}
GC.Collect();

//
// Server should receive a ServerAuth.Status.OK
// message via the OnAuthChange callback
//

for ( int i = 0; i< 100; i++ )
{
GC.Collect();
System.Threading.Thread.Sleep( 100 );
GC.Collect();
server.Update();
client.Update();

if ( Authed )
break;
}

Assert.IsTrue( Authed );

//
// Client cancels ticket
//
ticket.Cancel();

//
// Server should receive a ticket cancelled message
//

for ( int i = 0; i < 100; i++ )
{
System.Threading.Thread.Sleep( 100 );
server.Update();
client.Update();

if ( !Authed )
break;
}

Assert.IsTrue( !Authed );

}
}
}
}
}
@@ -0,0 +1,42 @@
using System;
using System.Text;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Facepunch.Steamworks.Test
{
public partial class Server
{
[TestMethod]
public void StatsGet()
{
using ( var server = new Facepunch.Steamworks.Server( 252490, new ServerInit( "rust", "Rust" ) ) )
{
Assert.IsTrue( server.IsValid );
server.LogOnAnonymous();

ulong MySteamId = 76561197960279927;

bool GotStats = false;

server.Stats.Refresh( MySteamId, (steamid, success) =>
{
GotStats = true;
Assert.IsTrue( success );

var deathsInCallback = server.Stats.GetInt( MySteamId, "deaths", -1 );
Console.WriteLine( "deathsInCallback: {0}", deathsInCallback );
Assert.IsTrue( deathsInCallback > 0 );
} );


server.UpdateWhile( () => !GotStats );

var deaths = server.Stats.GetInt( MySteamId, "deaths", -1 );
Console.WriteLine( "deathsInCallback: {0}", deaths );
Assert.IsTrue( deaths > 0 );
}
}

}
}

Large diffs are not rendered by default.

@@ -0,0 +1,73 @@
using System;
using System.Text;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
public class Stats
{
[TestMethod]
public void UpdateStats()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
client.Stats.UpdateStats();
}
}

[TestMethod]
public void UpdateSUpdateGlobalStatstats()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
client.Stats.UpdateGlobalStats( 1 );
client.Stats.UpdateGlobalStats( 3 );
client.Stats.UpdateGlobalStats( 7 );
}
}

[TestMethod]
public void GetClientFloat()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var v = client.Stats.GetFloat( "deaths" );
Console.WriteLine( v );
}
}

[TestMethod]
public void GetClientInt()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var v = client.Stats.GetInt( "deaths" );
Console.WriteLine( v );
}
}

[TestMethod]
public void GetGlobalFloat()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var v = client.Stats.GetGlobalFloat( "deaths" );
Console.WriteLine( v );
}
}

[TestMethod]
public void GetGlobalInt()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var v = client.Stats.GetGlobalInt( "deaths" );
Console.WriteLine( v );
}
}
}
}
@@ -0,0 +1,124 @@
using System;
using System.Diagnostics;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Facepunch.Steamworks.Test
{
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
[TestClass]
public class Voice
{
static readonly MemoryStream decompressStream = new MemoryStream();

[TestMethod]
public void GetVoice()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
int unCompressed = 0;
int compressed = 0;

client.Voice.OnCompressedData = ( buffer, length ) =>
{
compressed += length;

if ( !client.Voice.Decompress( buffer, length, decompressStream ) )
{
Assert.Fail( "Decompress returned false" );
}
};

client.Voice.OnUncompressedData = ( buffer, length ) =>
{
unCompressed += length;
};

client.Voice.WantsRecording = true;

var sw = Stopwatch.StartNew();

while ( sw.Elapsed.TotalSeconds < 3 )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}

Assert.AreNotEqual( unCompressed, 0 );
Assert.AreNotEqual( compressed, 0 );

// Should really be > 0 if the mic was getting audio
Console.WriteLine( "unCompressed: {0}", unCompressed );
Console.WriteLine( "compressed: {0}", compressed );
}
}

[TestMethod]
public void CompressedOnly()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
int compressed = 0;

client.Voice.OnCompressedData = ( buffer, length ) =>
{
compressed += length;
};

client.Voice.WantsRecording = true;

var sw = Stopwatch.StartNew();

while ( sw.Elapsed.TotalSeconds < 3 )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}

Assert.AreNotEqual( compressed, 0 );
Console.WriteLine( "compressed: {0}", compressed );
}
}

[TestMethod]
public void UnCompressedOnly()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
int unCompressed = 0;

client.Voice.OnUncompressedData = ( buffer, length ) =>
{
unCompressed += length;
};

client.Voice.WantsRecording = true;

var sw = Stopwatch.StartNew();

while ( sw.Elapsed.TotalSeconds < 3 )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}

Assert.AreNotEqual( unCompressed, 0 );

// Should really be > 0 if the mic was getting audio
Console.WriteLine( "unCompressed: {0}", unCompressed );

}
}

[TestMethod]
public void OptimalSampleRate()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var rate = client.Voice.OptimalSampleRate;
Assert.AreNotEqual( rate, 0 );
}
}
}
}

Large diffs are not rendered by default.

@@ -0,0 +1,151 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{3F6183AD-D966-44F2-A6EB-42E61E591B49}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Facepunch.Steamworks.Test</RootNamespace>
<AssemblyName>Facepunch.Steamworks.Test</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.9.0.2-beta1\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
</ItemGroup>
<Choose>
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework">
<Private>False</Private>
</Reference>
</ItemGroup>
</Otherwise>
</Choose>
<ItemGroup>
<Compile Include="Client\AchievementsTest.cs" />
<Compile Include="Client\ClientTest.cs" />
<Compile Include="Client\LobbyTest.cs" />
<Compile Include="Client\RichPresenceTest.cs" />
<Compile Include="Client\LeaderboardTest.cs" />
<Compile Include="Client\AppTest.cs" />
<Compile Include="Client\RemoteStorageTest.cs" />
<Compile Include="Client\VoiceTest.cs" />
<Compile Include="Client\InventoryTest.cs" />
<Compile Include="Client\WorkshopTest.cs" />
<Compile Include="Client\NetworkingTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Client\FriendsTest.cs" />
<Compile Include="Client\Server\ServerTest.cs" />
<Compile Include="Client\Server\StatsTest.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="Client\ServerlistTest.cs" />
<Compile Include="Client\StatsTest.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Facepunch.Steamworks\Facepunch.Steamworks.csproj">
<Project>{91962664-eb42-472a-94c8-c4ffeb44cc4b}</Project>
<Name>Facepunch.Steamworks</Name>
</ProjectReference>
</ItemGroup>
<Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
</ItemGroup>
</When>
</Choose>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle( "Facepunch.Steamworks.Test" )]
[assembly: AssemblyDescription( "" )]
[assembly: AssemblyConfiguration( "" )]
[assembly: AssemblyCompany( "" )]
[assembly: AssemblyProduct( "Facepunch.Steamworks.Test" )]
[assembly: AssemblyCopyright( "Copyright © 2016" )]
[assembly: AssemblyTrademark( "" )]
[assembly: AssemblyCulture( "" )]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible( false )]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid( "3f6183ad-d966-44f2-a6eb-42e61e591b49" )]

// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion( "1.0.0.0" )]
[assembly: AssemblyFileVersion( "1.0.0.0" )]
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="9.0.2-beta1" targetFramework="net452" />
</packages>
@@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.12
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Facepunch.Steamworks", "Facepunch.Steamworks\Facepunch.Steamworks.csproj", "{91962664-EB42-472A-94C8-C4FFEB44CC4B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Facepunch.Steamworks.Test", "Facepunch.Steamworks.Test\Facepunch.Steamworks.Test.csproj", "{3F6183AD-D966-44F2-A6EB-42E61E591B49}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Generator", "Generator\Generator.csproj", "{B7225D11-2AAA-49D6-AE93-A73696EA35FE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{91962664-EB42-472A-94C8-C4FFEB44CC4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91962664-EB42-472A-94C8-C4FFEB44CC4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91962664-EB42-472A-94C8-C4FFEB44CC4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91962664-EB42-472A-94C8-C4FFEB44CC4B}.Release|Any CPU.Build.0 = Release|Any CPU
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Release|Any CPU.Build.0 = Release|Any CPU
{B7225D11-2AAA-49D6-AE93-A73696EA35FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B7225D11-2AAA-49D6-AE93-A73696EA35FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B7225D11-2AAA-49D6-AE93-A73696EA35FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B7225D11-2AAA-49D6-AE93-A73696EA35FE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {506FC2EC-38D1-45E2-BAE8-D61584162F7D}
EndGlobalSection
EndGlobal
@@ -0,0 +1,219 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Facepunch.Steamworks.Interop;

namespace Facepunch.Steamworks
{
/// <summary>
/// Implements shared functionality between Steamworks.Client and Steamworks.Server
/// </summary>
public class BaseSteamworks : IDisposable
{
/// <summary>
/// Current running program's AppId
/// </summary>
public uint AppId { get; internal set; }

public Networking Networking { get; internal set; }
public Inventory Inventory { get; internal set; }
public Workshop Workshop { get; internal set; }

internal event Action OnUpdate;

internal Interop.NativeInterface native;

private List<SteamNative.CallbackHandle> CallbackHandles = new List<SteamNative.CallbackHandle>();
private List<SteamNative.CallResult> CallResults = new List<SteamNative.CallResult>();
protected bool disposed = false;


protected BaseSteamworks( uint appId )
{
AppId = appId;

//
// No need for the "steam_appid.txt" file any more
//
System.Environment.SetEnvironmentVariable("SteamAppId", AppId.ToString());
System.Environment.SetEnvironmentVariable("SteamGameId", AppId.ToString());
}

~BaseSteamworks()
{
Dispose();
}

public virtual void Dispose()
{
if ( disposed ) return;

Callbacks.Clear();

foreach ( var h in CallbackHandles )
{
h.Dispose();
}
CallbackHandles.Clear();

foreach ( var h in CallResults )
{
h.Dispose();
}
CallResults.Clear();

if ( Workshop != null )
{
Workshop.Dispose();
Workshop = null;
}

if ( Inventory != null )
{
Inventory.Dispose();
Inventory = null;
}

if ( Networking != null )
{
Networking.Dispose();
Networking = null;
}

if ( native != null )
{
native.Dispose();
native = null;
}

System.Environment.SetEnvironmentVariable("SteamAppId", null );
System.Environment.SetEnvironmentVariable("SteamGameId", null );
disposed = true;
}

protected void SetupCommonInterfaces()
{
Networking = new Steamworks.Networking( this, native.networking );
Inventory = new Steamworks.Inventory( this, native.inventory, IsGameServer );
Workshop = new Steamworks.Workshop( this, native.ugc, native.remoteStorage );
}

/// <summary>
/// Returns true if this instance has initialized properly.
/// If this returns false you should Dispose and throw an error.
/// </summary>
public bool IsValid
{
get { return native != null; }
}


internal virtual bool IsGameServer { get { return false; } }

internal void RegisterCallbackHandle( SteamNative.CallbackHandle handle )
{
CallbackHandles.Add( handle );
}

internal void RegisterCallResult( SteamNative.CallResult handle )
{
CallResults.Add( handle );
}

internal void UnregisterCallResult( SteamNative.CallResult handle )
{
CallResults.Remove( handle );
}

public virtual void Update()
{
Networking.Update();

RunUpdateCallbacks();
}

/// <summary>
/// This gets called automatically in Update. Only call it manually if you know why you're doing it.
/// </summary>
public void RunUpdateCallbacks()
{
if ( OnUpdate != null )
OnUpdate();

for( int i=0; i < CallResults.Count; i++ )
{
CallResults[i].Try();
}

//
// The SourceServerQuery's happen in another thread, so we
// query them to see if they're finished, and if so post a callback
// in our main thread. This will all suck less once we have async.
//
Facepunch.Steamworks.SourceServerQuery.Cycle();
}

/// <summary>
/// Run Update until func returns false.
/// This will cause your program to lock up until it finishes.
/// This is useful for things like tests or command line utilities etc.
/// </summary>
public void UpdateWhile( Func<bool> func )
{
const int sleepMs = 1;

while ( func() )
{
Update();
#if NET_CORE
System.Threading.Tasks.Task.Delay( sleepMs ).Wait();
#else
System.Threading.Thread.Sleep( sleepMs );
#endif
}
}

/// <summary>
/// Debug function, called for every callback. Only really used to confirm that callbacks are working properly.
/// </summary>
public Action<object> OnAnyCallback;

Dictionary<Type, List<Action<object>>> Callbacks = new Dictionary<Type, List<Action<object>>>();

internal List<Action<object>> CallbackList( Type T )
{
List<Action<object>> list = null;

if ( !Callbacks.TryGetValue( T, out list ) )
{
list = new List<Action<object>>();
Callbacks[T] = list;
}

return list;
}

internal void OnCallback<T>( T data )
{
var list = CallbackList( typeof( T ) );

foreach ( var i in list )
{
i( data );
}

if ( OnAnyCallback != null )
{
OnAnyCallback.Invoke( data );
}
}

internal void RegisterCallback<T>( Action<T> func )
{
var list = CallbackList( typeof( T ) );
list.Add( ( o ) => func( (T) o ) );
}

}
}