(3dc4135ce) v0.9.5.1
This commit is contained in:
@@ -36,10 +36,13 @@ namespace Facepunch.Steamworks
|
||||
internal Client client;
|
||||
private byte[] buffer = new byte[1024 * 128];
|
||||
|
||||
public Dictionary<ulong, Action> OnRichPresenceUpdateCallbacks;
|
||||
|
||||
internal Friends( Client c )
|
||||
{
|
||||
client = c;
|
||||
|
||||
client.RegisterCallback<FriendRichPresenceUpdate_t>(OnRichPresenceUpdate);
|
||||
client.RegisterCallback<AvatarImageLoaded_t>( OnAvatarImageLoaded );
|
||||
client.RegisterCallback<PersonaStateChange_t>( OnPersonaStateChange );
|
||||
client.RegisterCallback<GameRichPresenceJoinRequested_t>( OnGameJoinRequested );
|
||||
@@ -149,6 +152,33 @@ namespace Facepunch.Steamworks
|
||||
}
|
||||
}
|
||||
|
||||
public void SetRichPresenceUpdateCallback(ulong steamId, Action callback)
|
||||
{
|
||||
if (callback != null)
|
||||
{
|
||||
if (OnRichPresenceUpdateCallbacks == null)
|
||||
{
|
||||
OnRichPresenceUpdateCallbacks = new Dictionary<ulong, Action>();
|
||||
}
|
||||
if (!OnRichPresenceUpdateCallbacks.ContainsKey(steamId))
|
||||
{
|
||||
OnRichPresenceUpdateCallbacks.Add(steamId, callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnRichPresenceUpdateCallbacks[steamId] = callback;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (OnRichPresenceUpdateCallbacks == null) { return; }
|
||||
if (OnRichPresenceUpdateCallbacks.ContainsKey(steamId))
|
||||
{
|
||||
OnRichPresenceUpdateCallbacks.Remove(steamId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns only friends
|
||||
/// </summary>
|
||||
@@ -392,5 +422,14 @@ namespace Facepunch.Steamworks
|
||||
LoadAvatarForSteamId( data.SteamID );
|
||||
}
|
||||
|
||||
private void OnRichPresenceUpdate( FriendRichPresenceUpdate_t data )
|
||||
{
|
||||
if (OnRichPresenceUpdateCallbacks == null) { return; }
|
||||
if (OnRichPresenceUpdateCallbacks.ContainsKey(data.SteamIDFriend))
|
||||
{
|
||||
OnRichPresenceUpdateCallbacks[data.SteamIDFriend]?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using SteamNative;
|
||||
|
||||
|
||||
//TODO: this entire file is the main reason why we need to update this library
|
||||
namespace Facepunch.Steamworks
|
||||
{
|
||||
public partial class LobbyList : IDisposable
|
||||
@@ -12,6 +14,8 @@ namespace Facepunch.Steamworks
|
||||
//The list of retrieved lobbies
|
||||
public List<Lobby> Lobbies { get; private set; }
|
||||
|
||||
public Dictionary<ulong, Action<Lobby>> ManualLobbyDataCallbacks { get; private set; }
|
||||
|
||||
//True when all the possible lobbies have had their data updated
|
||||
//if the number of lobbies is now equal to the initial request number, we've found all lobbies
|
||||
public bool Finished { get; private set; }
|
||||
@@ -21,9 +25,13 @@ namespace Facepunch.Steamworks
|
||||
|
||||
internal LobbyList(Client client)
|
||||
{
|
||||
client.RegisterCallback<SteamNative.LobbyDataUpdate_t>(OnLobbyDataUpdated);
|
||||
|
||||
this.client = client;
|
||||
Lobbies = new List<Lobby>();
|
||||
requests = new List<ulong>();
|
||||
|
||||
ManualLobbyDataCallbacks = new Dictionary<ulong, Action<Lobby>>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -77,7 +85,6 @@ namespace Facepunch.Steamworks
|
||||
|
||||
}
|
||||
|
||||
bool registeredLobbyDataUpdated = false;
|
||||
void OnLobbyList(LobbyMatchList_t callback, bool error)
|
||||
{
|
||||
if (error) return;
|
||||
@@ -107,11 +114,6 @@ namespace Facepunch.Steamworks
|
||||
{
|
||||
//else we need to get the info for the missing lobby
|
||||
client.native.matchmaking.RequestLobbyData(lobby);
|
||||
if (!registeredLobbyDataUpdated)
|
||||
{
|
||||
client.RegisterCallback<SteamNative.LobbyDataUpdate_t>(OnLobbyDataUpdated);
|
||||
registeredLobbyDataUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -135,24 +137,72 @@ namespace Facepunch.Steamworks
|
||||
{
|
||||
if (callback.Success == 1) //1 if success, 0 if failure
|
||||
{
|
||||
if (ManualLobbyDataCallbacks.ContainsKey(callback.SteamIDLobby))
|
||||
{
|
||||
ManualLobbyDataCallbacks[callback.SteamIDLobby]?.Invoke(Lobby.FromSteam(client, callback.SteamIDLobby));
|
||||
}
|
||||
|
||||
//find the lobby that has been updated
|
||||
Lobby lobby = Lobbies.Find(x => x != null && x.LobbyID == callback.SteamIDLobby);
|
||||
|
||||
//if this lobby isn't yet in the list of lobbies, we know that we should add it
|
||||
if (lobby == null)
|
||||
{
|
||||
lobby = Lobby.FromSteam(client, callback.SteamIDLobby);
|
||||
Lobbies.Add(lobby);
|
||||
checkFinished();
|
||||
if (requests.Contains(callback.SteamIDLobby))
|
||||
{
|
||||
lobby = Lobby.FromSteam(client, callback.SteamIDLobby);
|
||||
Lobbies.Add(lobby);
|
||||
checkFinished();
|
||||
}
|
||||
}
|
||||
|
||||
//otherwise lobby data in general was updated and you should listen to see what changed
|
||||
if (OnLobbiesUpdated != null) { OnLobbiesUpdated(); }
|
||||
if (requests.Contains(callback.SteamIDLobby))
|
||||
{
|
||||
OnLobbiesUpdated?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Action OnLobbiesUpdated;
|
||||
|
||||
public Lobby GetLobbyFromID(ulong lobbyId)
|
||||
{
|
||||
return Lobby.FromSteam(client, lobbyId);
|
||||
}
|
||||
|
||||
public void RequestLobbyData(ulong lobby)
|
||||
{
|
||||
client.native.matchmaking.RequestLobbyData(lobby);
|
||||
}
|
||||
|
||||
public void SetManualLobbyDataCallback(ulong steamId, Action<Lobby> callback)
|
||||
{
|
||||
if (callback != null)
|
||||
{
|
||||
if (ManualLobbyDataCallbacks == null)
|
||||
{
|
||||
ManualLobbyDataCallbacks = new Dictionary<ulong, Action<Lobby>>();
|
||||
}
|
||||
if (!ManualLobbyDataCallbacks.ContainsKey(steamId))
|
||||
{
|
||||
ManualLobbyDataCallbacks.Add(steamId, callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
ManualLobbyDataCallbacks[steamId] = callback;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ManualLobbyDataCallbacks == null) { return; }
|
||||
if (ManualLobbyDataCallbacks.ContainsKey(steamId))
|
||||
{
|
||||
ManualLobbyDataCallbacks.Remove(steamId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
client = null;
|
||||
|
||||
@@ -1,12 +1,349 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using SteamNative;
|
||||
|
||||
namespace Facepunch.Steamworks
|
||||
{
|
||||
//ISteamMatchmakingRulesResponse & ISteamMatchmakingPlayersResponse taken from:
|
||||
// https://github.com/rlabrecque/Steamworks.NET/blob/master/Plugins/Steamworks.NET/ISteamMatchmakingResponses.cs
|
||||
|
||||
/**
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2019 Riley Labrecque
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
**/
|
||||
public class ISteamMatchmakingPingResponse
|
||||
{
|
||||
// Server has responded successfully and has updated data
|
||||
public delegate void ServerResponded(ServerList.Server server);
|
||||
|
||||
// Server failed to respond to the ping request
|
||||
public delegate void ServerFailedToRespond();
|
||||
|
||||
private VTable m_VTable;
|
||||
private IntPtr m_pVTable;
|
||||
private GCHandle m_pGCHandle;
|
||||
private ServerResponded m_ServerResponded;
|
||||
private ServerFailedToRespond m_ServerFailedToRespond;
|
||||
private Client client;
|
||||
|
||||
public ISteamMatchmakingPingResponse(Client c, ServerResponded onServerResponded, ServerFailedToRespond onServerFailedToRespond)
|
||||
{
|
||||
if (onServerResponded == null || onServerFailedToRespond == null)
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
client = c;
|
||||
m_ServerResponded = onServerResponded;
|
||||
m_ServerFailedToRespond = onServerFailedToRespond;
|
||||
|
||||
m_VTable = new VTable()
|
||||
{
|
||||
m_VTServerResponded = InternalOnServerResponded,
|
||||
m_VTServerFailedToRespond = InternalOnServerFailedToRespond,
|
||||
};
|
||||
m_pVTable = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(VTable)));
|
||||
Marshal.StructureToPtr(m_VTable, m_pVTable, false);
|
||||
|
||||
m_pGCHandle = GCHandle.Alloc(m_pVTable, GCHandleType.Pinned);
|
||||
}
|
||||
|
||||
~ISteamMatchmakingPingResponse()
|
||||
{
|
||||
if (m_pVTable != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(m_pVTable);
|
||||
}
|
||||
|
||||
if (m_pGCHandle.IsAllocated)
|
||||
{
|
||||
m_pGCHandle.Free();
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
private delegate void InternalServerResponded(IntPtr thisptr, gameserveritem_t server);
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
private delegate void InternalServerFailedToRespond(IntPtr thisptr);
|
||||
private void InternalOnServerResponded(IntPtr thisptr, gameserveritem_t serverItem)
|
||||
{
|
||||
m_ServerResponded(ServerList.Server.FromSteam(client, serverItem));
|
||||
}
|
||||
private void InternalOnServerFailedToRespond(IntPtr thisptr)
|
||||
{
|
||||
m_ServerFailedToRespond();
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private class VTable
|
||||
{
|
||||
[NonSerialized]
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)]
|
||||
public InternalServerResponded m_VTServerResponded;
|
||||
|
||||
[NonSerialized]
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)]
|
||||
public InternalServerFailedToRespond m_VTServerFailedToRespond;
|
||||
}
|
||||
|
||||
public static explicit operator System.IntPtr(ISteamMatchmakingPingResponse that)
|
||||
{
|
||||
return that.m_pGCHandle.AddrOfPinnedObject();
|
||||
}
|
||||
};
|
||||
|
||||
public class ISteamMatchmakingRulesResponse
|
||||
{
|
||||
// Got data on a rule on the server -- you'll get one of these per rule defined on
|
||||
// the server you are querying
|
||||
public delegate void RulesResponded(string pchRule, string pchValue);
|
||||
|
||||
// The server failed to respond to the request for rule details
|
||||
public delegate void RulesFailedToRespond();
|
||||
|
||||
// The server has finished responding to the rule details request
|
||||
// (ie, you won't get anymore RulesResponded callbacks)
|
||||
public delegate void RulesRefreshComplete();
|
||||
|
||||
private VTable m_VTable;
|
||||
private IntPtr m_pVTable;
|
||||
private GCHandle m_pGCHandle;
|
||||
private RulesResponded m_RulesResponded;
|
||||
private RulesFailedToRespond m_RulesFailedToRespond;
|
||||
private RulesRefreshComplete m_RulesRefreshComplete;
|
||||
|
||||
public ISteamMatchmakingRulesResponse(RulesResponded onRulesResponded, RulesFailedToRespond onRulesFailedToRespond, RulesRefreshComplete onRulesRefreshComplete)
|
||||
{
|
||||
if (onRulesResponded == null || onRulesFailedToRespond == null || onRulesRefreshComplete == null)
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
m_RulesResponded = onRulesResponded;
|
||||
m_RulesFailedToRespond = onRulesFailedToRespond;
|
||||
m_RulesRefreshComplete = onRulesRefreshComplete;
|
||||
|
||||
m_VTable = new VTable()
|
||||
{
|
||||
m_VTRulesResponded = InternalOnRulesResponded,
|
||||
m_VTRulesFailedToRespond = InternalOnRulesFailedToRespond,
|
||||
m_VTRulesRefreshComplete = InternalOnRulesRefreshComplete
|
||||
};
|
||||
m_pVTable = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(VTable)));
|
||||
Marshal.StructureToPtr(m_VTable, m_pVTable, false);
|
||||
|
||||
m_pGCHandle = GCHandle.Alloc(m_pVTable, GCHandleType.Pinned);
|
||||
}
|
||||
|
||||
~ISteamMatchmakingRulesResponse()
|
||||
{
|
||||
if (m_pVTable != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(m_pVTable);
|
||||
}
|
||||
|
||||
if (m_pGCHandle.IsAllocated)
|
||||
{
|
||||
m_pGCHandle.Free();
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
public delegate void InternalRulesResponded(IntPtr thisptr, IntPtr pchRule, IntPtr pchValue);
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
public delegate void InternalRulesFailedToRespond(IntPtr thisptr);
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
public delegate void InternalRulesRefreshComplete(IntPtr thisptr);
|
||||
private void InternalOnRulesResponded(IntPtr thisptr, IntPtr pchRule, IntPtr pchValue)
|
||||
{
|
||||
List<byte> bytes = new List<byte>();
|
||||
IntPtr seekPointer = pchRule;
|
||||
byte b = Marshal.ReadByte(seekPointer);
|
||||
while (b != 0)
|
||||
{
|
||||
bytes.Add(b);
|
||||
seekPointer = (IntPtr)(seekPointer.ToInt64() + sizeof(byte));
|
||||
b = Marshal.ReadByte(seekPointer);
|
||||
}
|
||||
|
||||
string pchRuleDecoded = Encoding.UTF8.GetString(bytes.ToArray());
|
||||
|
||||
bytes.Clear();
|
||||
seekPointer = pchValue;
|
||||
b = Marshal.ReadByte(seekPointer);
|
||||
while (b != 0)
|
||||
{
|
||||
bytes.Add(b);
|
||||
seekPointer = (IntPtr)(seekPointer.ToInt64() + sizeof(byte));
|
||||
b = Marshal.ReadByte(seekPointer);
|
||||
}
|
||||
|
||||
string pchValueDecoded = Encoding.UTF8.GetString(bytes.ToArray());
|
||||
|
||||
m_RulesResponded(pchRuleDecoded, pchValueDecoded);
|
||||
}
|
||||
private void InternalOnRulesFailedToRespond(IntPtr thisptr)
|
||||
{
|
||||
m_RulesFailedToRespond();
|
||||
}
|
||||
private void InternalOnRulesRefreshComplete(IntPtr thisptr)
|
||||
{
|
||||
m_RulesRefreshComplete();
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private class VTable
|
||||
{
|
||||
[NonSerialized]
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)]
|
||||
public InternalRulesResponded m_VTRulesResponded;
|
||||
|
||||
[NonSerialized]
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)]
|
||||
public InternalRulesFailedToRespond m_VTRulesFailedToRespond;
|
||||
|
||||
[NonSerialized]
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)]
|
||||
public InternalRulesRefreshComplete m_VTRulesRefreshComplete;
|
||||
}
|
||||
|
||||
public static explicit operator System.IntPtr(ISteamMatchmakingRulesResponse that)
|
||||
{
|
||||
return that.m_pGCHandle.AddrOfPinnedObject();
|
||||
}
|
||||
};
|
||||
|
||||
public class ISteamMatchmakingPlayersResponse
|
||||
{
|
||||
// Got data on a new player on the server -- you'll get this callback once per player
|
||||
// on the server which you have requested player data on.
|
||||
public delegate void AddPlayerToList(string pchName, int nScore, float flTimePlayed);
|
||||
|
||||
// The server failed to respond to the request for player details
|
||||
public delegate void PlayersFailedToRespond();
|
||||
|
||||
// The server has finished responding to the player details request
|
||||
// (ie, you won't get anymore AddPlayerToList callbacks)
|
||||
public delegate void PlayersRefreshComplete();
|
||||
|
||||
private VTable m_VTable;
|
||||
private IntPtr m_pVTable;
|
||||
private GCHandle m_pGCHandle;
|
||||
private AddPlayerToList m_AddPlayerToList;
|
||||
private PlayersFailedToRespond m_PlayersFailedToRespond;
|
||||
private PlayersRefreshComplete m_PlayersRefreshComplete;
|
||||
|
||||
public ISteamMatchmakingPlayersResponse(AddPlayerToList onAddPlayerToList, PlayersFailedToRespond onPlayersFailedToRespond, PlayersRefreshComplete onPlayersRefreshComplete)
|
||||
{
|
||||
if (onAddPlayerToList == null || onPlayersFailedToRespond == null || onPlayersRefreshComplete == null)
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
m_AddPlayerToList = onAddPlayerToList;
|
||||
m_PlayersFailedToRespond = onPlayersFailedToRespond;
|
||||
m_PlayersRefreshComplete = onPlayersRefreshComplete;
|
||||
|
||||
m_VTable = new VTable()
|
||||
{
|
||||
m_VTAddPlayerToList = InternalOnAddPlayerToList,
|
||||
m_VTPlayersFailedToRespond = InternalOnPlayersFailedToRespond,
|
||||
m_VTPlayersRefreshComplete = InternalOnPlayersRefreshComplete
|
||||
};
|
||||
m_pVTable = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(VTable)));
|
||||
Marshal.StructureToPtr(m_VTable, m_pVTable, false);
|
||||
|
||||
m_pGCHandle = GCHandle.Alloc(m_pVTable, GCHandleType.Pinned);
|
||||
}
|
||||
|
||||
~ISteamMatchmakingPlayersResponse()
|
||||
{
|
||||
if (m_pVTable != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(m_pVTable);
|
||||
}
|
||||
|
||||
if (m_pGCHandle.IsAllocated)
|
||||
{
|
||||
m_pGCHandle.Free();
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
public delegate void InternalAddPlayerToList(IntPtr thisptr, IntPtr pchName, int nScore, float flTimePlayed);
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
public delegate void InternalPlayersFailedToRespond(IntPtr thisptr);
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
public delegate void InternalPlayersRefreshComplete(IntPtr thisptr);
|
||||
private void InternalOnAddPlayerToList(IntPtr thisptr, IntPtr pchName, int nScore, float flTimePlayed)
|
||||
{
|
||||
List<byte> bytes = new List<byte>();
|
||||
IntPtr seekPointer = pchName;
|
||||
byte b = Marshal.ReadByte(seekPointer);
|
||||
while (b != 0)
|
||||
{
|
||||
bytes.Add(b);
|
||||
seekPointer = (IntPtr)(seekPointer.ToInt64() + sizeof(byte));
|
||||
b = Marshal.ReadByte(seekPointer);
|
||||
}
|
||||
|
||||
string pchNameDecoded = Encoding.UTF8.GetString(bytes.ToArray());
|
||||
|
||||
m_AddPlayerToList(pchNameDecoded, nScore, flTimePlayed);
|
||||
}
|
||||
private void InternalOnPlayersFailedToRespond(IntPtr thisptr)
|
||||
{
|
||||
m_PlayersFailedToRespond();
|
||||
}
|
||||
private void InternalOnPlayersRefreshComplete(IntPtr thisptr)
|
||||
{
|
||||
m_PlayersRefreshComplete();
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private class VTable
|
||||
{
|
||||
[NonSerialized]
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)]
|
||||
public InternalAddPlayerToList m_VTAddPlayerToList;
|
||||
|
||||
[NonSerialized]
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)]
|
||||
public InternalPlayersFailedToRespond m_VTPlayersFailedToRespond;
|
||||
|
||||
[NonSerialized]
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)]
|
||||
public InternalPlayersRefreshComplete m_VTPlayersRefreshComplete;
|
||||
}
|
||||
|
||||
public static explicit operator System.IntPtr(ISteamMatchmakingPlayersResponse that)
|
||||
{
|
||||
return that.m_pGCHandle.AddrOfPinnedObject();
|
||||
}
|
||||
};
|
||||
|
||||
public partial class ServerList : IDisposable
|
||||
{
|
||||
internal Client client;
|
||||
@@ -124,7 +461,20 @@ namespace Facepunch.Steamworks
|
||||
public string value;
|
||||
}
|
||||
|
||||
public void CancelHQuery(int query)
|
||||
{
|
||||
client.native.servers.CancelServerQuery((HServerQuery)query);
|
||||
}
|
||||
|
||||
public int HQueryPing(ISteamMatchmakingPingResponse response, IPAddress ip, int port)
|
||||
{
|
||||
return client.native.servers.PingServer(ip.IpToInt32(), (ushort)port, (IntPtr)response).Value;
|
||||
}
|
||||
|
||||
public int HQueryServerRules(ISteamMatchmakingRulesResponse response, IPAddress ip, int queryPort)
|
||||
{
|
||||
return client.native.servers.ServerRules(ip.IpToInt32(), (ushort)queryPort, (IntPtr)response).Value;
|
||||
}
|
||||
|
||||
public Request Internet( Filter filter = null )
|
||||
{
|
||||
|
||||
@@ -85,21 +85,30 @@ namespace Facepunch.Steamworks
|
||||
|
||||
unsafe void RunInternal()
|
||||
{
|
||||
string queryType = "";
|
||||
if ( FileId.Count != 0 )
|
||||
{
|
||||
var fileArray = FileId.Select( x => (SteamNative.PublishedFileId_t)x ).ToArray();
|
||||
_resultsRemain = fileArray.Length;
|
||||
|
||||
Handle = workshop.ugc.CreateQueryUGCDetailsRequest( fileArray );
|
||||
queryType = "DetailsRequest";
|
||||
}
|
||||
else if ( UserId.HasValue )
|
||||
{
|
||||
uint accountId = (uint)( UserId.Value & 0xFFFFFFFFul );
|
||||
Handle = workshop.ugc.CreateQueryUserUGCRequest( accountId, (SteamNative.UserUGCList)( int)UserQueryType, (SteamNative.UGCMatchingUGCType)( int)QueryType, SteamNative.UserUGCListSortOrder.LastUpdatedDesc, UploaderAppId, AppId, (uint)_resultPage + 1 );
|
||||
queryType = "UserRequest";
|
||||
}
|
||||
else
|
||||
{
|
||||
Handle = workshop.ugc.CreateQueryAllUGCRequest( (SteamNative.UGCQuery)(int)Order, (SteamNative.UGCMatchingUGCType)(int)QueryType, UploaderAppId, AppId, (uint)_resultPage + 1 );
|
||||
queryType = "AllRequest";
|
||||
}
|
||||
|
||||
if (Handle == 0xfffffffffffffffful)
|
||||
{
|
||||
throw new Exception("Steam UGC "+queryType+" Query Handle invalid!");
|
||||
}
|
||||
|
||||
if ( !string.IsNullOrEmpty( SearchText ) )
|
||||
@@ -246,7 +255,7 @@ namespace Facepunch.Steamworks
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// ReleaseQueryUGCRequest
|
||||
workshop.ugc.ReleaseQueryUGCRequest(Handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+50
-84
@@ -520,8 +520,9 @@ namespace Microsoft.Xna.Framework.Graphics
|
||||
if (_d3dContext != null)
|
||||
_d3dContext.Dispose();
|
||||
|
||||
// Windows requires BGRA support out of DX.
|
||||
var creationFlags = SharpDX.Direct3D11.DeviceCreationFlags.BgraSupport;
|
||||
// Windows requires BGRA support out of DX. (...what)
|
||||
// Barotrauma doesn't tho
|
||||
var creationFlags = SharpDX.Direct3D11.DeviceCreationFlags.None;//.BgraSupport;
|
||||
|
||||
if (GraphicsAdapter.UseDebugLayers)
|
||||
{
|
||||
@@ -545,14 +546,14 @@ namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
featureLevels = new[]
|
||||
{
|
||||
// For the Reach profile, first try use the highest supported 9_X feature level
|
||||
FeatureLevel.Level_9_3,
|
||||
FeatureLevel.Level_9_2,
|
||||
FeatureLevel.Level_9_1,
|
||||
// If level 9 is not supported, then just use the highest supported level
|
||||
// Try using the highest supported level
|
||||
FeatureLevel.Level_11_0,
|
||||
FeatureLevel.Level_10_1,
|
||||
FeatureLevel.Level_10_0,
|
||||
// Then try using the highest supported 9_X feature level
|
||||
FeatureLevel.Level_9_3,
|
||||
FeatureLevel.Level_9_2,
|
||||
FeatureLevel.Level_9_1,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -583,7 +584,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
||||
_d3dDevice = defaultDevice.QueryInterface<SharpDX.Direct3D11.Device>();
|
||||
}
|
||||
|
||||
// Get Direct3D 11.1 context
|
||||
// Get Direct3D 11 context
|
||||
_d3dContext = _d3dDevice.ImmediateContext.QueryInterface<SharpDX.Direct3D11.DeviceContext>();
|
||||
|
||||
// Create a new instance of GraphicsDebug because we support it on Windows platforms.
|
||||
@@ -600,24 +601,6 @@ namespace Microsoft.Xna.Framework.Graphics
|
||||
_swapChain.SetFullscreenState(false, null);
|
||||
}
|
||||
|
||||
internal void ResizeTargets()
|
||||
{
|
||||
var format = SharpDXHelper.ToFormat(PresentationParameters.BackBufferFormat);
|
||||
var descr = new ModeDescription
|
||||
{
|
||||
Format = format,
|
||||
#if WINRT
|
||||
Scaling = DisplayModeScaling.Stretched,
|
||||
#else
|
||||
Scaling = DisplayModeScaling.Unspecified,
|
||||
#endif
|
||||
Width = PresentationParameters.BackBufferWidth,
|
||||
Height = PresentationParameters.BackBufferHeight,
|
||||
};
|
||||
|
||||
_swapChain.ResizeTarget(ref descr);
|
||||
}
|
||||
|
||||
internal void GetModeSwitchedSize(out int width, out int height)
|
||||
{
|
||||
Output output = null;
|
||||
@@ -717,76 +700,59 @@ namespace Microsoft.Xna.Framework.Graphics
|
||||
format,
|
||||
PresentationParameters.MultiSampleCount);
|
||||
|
||||
// If the swap chain already exists... update it.
|
||||
if (false && _swapChain != null
|
||||
// check if multisampling hasn't changed
|
||||
&& _swapChain.Description.SampleDescription.Count == multisampleDesc.Count
|
||||
&& _swapChain.Description.SampleDescription.Quality == multisampleDesc.Quality)
|
||||
// Create a new swap chain.
|
||||
var wasFullScreen = false;
|
||||
// Dispose of old swap chain if exists
|
||||
if (_swapChain != null)
|
||||
{
|
||||
_swapChain.ResizeBuffers(2,
|
||||
PresentationParameters.BackBufferWidth,
|
||||
PresentationParameters.BackBufferHeight,
|
||||
format,
|
||||
SwapChainFlags.AllowModeSwitch);
|
||||
wasFullScreen = _swapChain.IsFullScreen;
|
||||
// Before releasing a swap chain, first switch to windowed mode
|
||||
_swapChain.SetFullscreenState(false, null);
|
||||
_swapChain.Dispose();
|
||||
}
|
||||
|
||||
// Otherwise, create a new swap chain.
|
||||
else
|
||||
// SwapChain description
|
||||
var desc = new SharpDX.DXGI.SwapChainDescription()
|
||||
{
|
||||
var wasFullScreen = false;
|
||||
// Dispose of old swap chain if exists
|
||||
if (_swapChain != null)
|
||||
ModeDescription =
|
||||
{
|
||||
wasFullScreen = _swapChain.IsFullScreen;
|
||||
// Before releasing a swap chain, first switch to windowed mode
|
||||
_swapChain.SetFullscreenState(false, null);
|
||||
_swapChain.Dispose();
|
||||
}
|
||||
|
||||
// SwapChain description
|
||||
var desc = new SharpDX.DXGI.SwapChainDescription()
|
||||
{
|
||||
ModeDescription =
|
||||
{
|
||||
Format = format,
|
||||
Format = format,
|
||||
#if WINDOWS_UAP
|
||||
Scaling = DisplayModeScaling.Stretched,
|
||||
Scaling = DisplayModeScaling.Stretched,
|
||||
#else
|
||||
Scaling = DisplayModeScaling.Unspecified,
|
||||
Scaling = DisplayModeScaling.Unspecified,
|
||||
#endif
|
||||
Width = PresentationParameters.BackBufferWidth,
|
||||
Height = PresentationParameters.BackBufferHeight,
|
||||
},
|
||||
Width = PresentationParameters.BackBufferWidth,
|
||||
Height = PresentationParameters.BackBufferHeight,
|
||||
},
|
||||
|
||||
OutputHandle = PresentationParameters.DeviceWindowHandle,
|
||||
SampleDescription = multisampleDesc,
|
||||
Usage = SharpDX.DXGI.Usage.RenderTargetOutput,
|
||||
BufferCount = 2,
|
||||
SwapEffect = SharpDXHelper.ToSwapEffect(PresentationParameters.PresentationInterval),
|
||||
IsWindowed = true,
|
||||
Flags = SwapChainFlags.AllowModeSwitch
|
||||
};
|
||||
OutputHandle = PresentationParameters.DeviceWindowHandle,
|
||||
SampleDescription = multisampleDesc,
|
||||
Usage = SharpDX.DXGI.Usage.RenderTargetOutput,
|
||||
BufferCount = 2,
|
||||
SwapEffect = SharpDXHelper.ToSwapEffect(PresentationParameters.PresentationInterval),
|
||||
IsWindowed = true
|
||||
};
|
||||
|
||||
// Once the desired swap chain description is configured, it must be created on the same adapter as our D3D Device
|
||||
// Once the desired swap chain description is configured, it must be created on the same adapter as our D3D Device
|
||||
|
||||
// First, retrieve the underlying DXGI Device from the D3D Device.
|
||||
// Creates the swap chain
|
||||
using (var dxgiDevice = _d3dDevice.QueryInterface<SharpDX.DXGI.Device1>())
|
||||
using (var dxgiAdapter = dxgiDevice.Adapter)
|
||||
using (var dxgiFactory = dxgiAdapter.GetParent<SharpDX.DXGI.Factory1>())
|
||||
{
|
||||
_swapChain = new SwapChain(dxgiFactory, dxgiDevice, desc);
|
||||
RefreshAdapter();
|
||||
dxgiFactory.MakeWindowAssociation(PresentationParameters.DeviceWindowHandle, WindowAssociationFlags.IgnoreAll);
|
||||
// To reduce latency, ensure that DXGI does not queue more than one frame at a time.
|
||||
// Docs: https://msdn.microsoft.com/en-us/library/windows/desktop/ff471334(v=vs.85).aspx
|
||||
dxgiDevice.MaximumFrameLatency = 1;
|
||||
}
|
||||
// Preserve full screen state, after swap chain is re-created
|
||||
if (PresentationParameters.HardwareModeSwitch
|
||||
&& wasFullScreen)
|
||||
SetHardwareFullscreen();
|
||||
// First, retrieve the underlying DXGI Device from the D3D Device.
|
||||
// Creates the swap chain
|
||||
using (var dxgiDevice = _d3dDevice.QueryInterface<SharpDX.DXGI.Device1>())
|
||||
using (var dxgiAdapter = dxgiDevice.Adapter)
|
||||
using (var dxgiFactory = dxgiAdapter.GetParent<SharpDX.DXGI.Factory1>())
|
||||
{
|
||||
_swapChain = new SwapChain(dxgiFactory, dxgiDevice, desc);
|
||||
RefreshAdapter();
|
||||
dxgiFactory.MakeWindowAssociation(PresentationParameters.DeviceWindowHandle, WindowAssociationFlags.IgnoreAll);
|
||||
// To reduce latency, ensure that DXGI does not queue more than one frame at a time.
|
||||
// Docs: https://msdn.microsoft.com/en-us/library/windows/desktop/ff471334(v=vs.85).aspx
|
||||
dxgiDevice.MaximumFrameLatency = 1;
|
||||
}
|
||||
// Preserve full screen state, after swap chain is re-created
|
||||
if (PresentationParameters.HardwareModeSwitch
|
||||
&& wasFullScreen)
|
||||
SetHardwareFullscreen();
|
||||
|
||||
// Obtain the backbuffer for this window which will be the final 3D rendertarget.
|
||||
Point targetSize;
|
||||
|
||||
@@ -72,7 +72,10 @@ namespace Microsoft.Xna.Framework.Graphics
|
||||
var subresourceIndex = CalculateSubresourceIndex(0, level);
|
||||
var d3dContext = GraphicsDevice._d3dContext;
|
||||
lock (d3dContext)
|
||||
{
|
||||
d3dContext.UpdateSubresource(GetTexture(), subresourceIndex, region, dataPtr, GetPitch(w), 0);
|
||||
d3dContext.GenerateMips(GetShaderResourceView());
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -390,6 +393,12 @@ namespace Microsoft.Xna.Framework.Graphics
|
||||
if (_shared)
|
||||
desc.OptionFlags |= ResourceOptionFlags.Shared;
|
||||
|
||||
if (_mipmap)
|
||||
{
|
||||
desc.OptionFlags |= ResourceOptionFlags.GenerateMipMaps;
|
||||
desc.BindFlags |= BindFlags.RenderTarget;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
internal override Resource CreateTexture()
|
||||
@@ -403,6 +412,30 @@ namespace Microsoft.Xna.Framework.Graphics
|
||||
return new SharpDX.Direct3D11.Texture2D(GraphicsDevice._d3dDevice, desc);
|
||||
}
|
||||
|
||||
protected override ShaderResourceView CreateShaderResourceView()
|
||||
{
|
||||
var texDesc = GetTexture2DDescription();
|
||||
if (_mipmap)
|
||||
{
|
||||
ShaderResourceViewDescription resViewDesc = new ShaderResourceViewDescription()
|
||||
{
|
||||
Format = texDesc.Format,
|
||||
Dimension = SharpDX.Direct3D.ShaderResourceViewDimension.Texture2D,
|
||||
Texture2D = new ShaderResourceViewDescription.Texture2DResource()
|
||||
{
|
||||
MostDetailedMip = 0,
|
||||
MipLevels = texDesc.MipLevels
|
||||
}
|
||||
};
|
||||
|
||||
return new SharpDX.Direct3D11.ShaderResourceView(GraphicsDevice._d3dDevice, GetTexture(), resViewDesc);
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.CreateShaderResourceView();
|
||||
}
|
||||
}
|
||||
|
||||
protected internal virtual SampleDescription CreateSampleDescription()
|
||||
{
|
||||
return new SampleDescription(1, 0);
|
||||
|
||||
@@ -118,6 +118,12 @@ namespace Microsoft.Xna.Framework.Graphics
|
||||
}
|
||||
GraphicsExtensions.CheckGLError();
|
||||
|
||||
if (CurrentPlatform.OS != OS.MacOSX)
|
||||
{
|
||||
GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
|
||||
GraphicsExtensions.CheckGLError();
|
||||
}
|
||||
|
||||
#if !ANDROID
|
||||
// Required to make sure that any texture uploads on a thread are completed
|
||||
// before the main thread tries to use the texture.
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
public static class MessageBox
|
||||
{
|
||||
[Flags]
|
||||
public enum Flags : uint
|
||||
{
|
||||
Error = 0x00000010,
|
||||
Warning = 0x00000020,
|
||||
Information = 0x00000040
|
||||
}
|
||||
|
||||
public static void Show(Flags flags, string title, string message, GameWindow window = null)
|
||||
{
|
||||
Sdl.ShowSimpleMessageBox((uint)flags, title, message, window?.Handle ?? IntPtr.Zero);
|
||||
}
|
||||
|
||||
public static void ShowWrapped(Flags flags, string title, string message, int charsPerLine = 60, GameWindow window = null)
|
||||
{
|
||||
string[] split = message.Split(' ');
|
||||
if (split.Length > 0)
|
||||
{
|
||||
message = split[0];
|
||||
string currLine = message;
|
||||
for (int i = 1; i < split.Length; i++)
|
||||
{
|
||||
currLine += " " + split[i];
|
||||
if (currLine.Length > charsPerLine)
|
||||
{
|
||||
currLine = split[i];
|
||||
message += "\n" + split[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
message += " " + split[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Show(flags, title, message, window);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>none</DebugType>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<OutputPath>..\..\DesktopGL\</OutputPath>
|
||||
<IntermediateOutputPath>obj\Linux\AnyCPU\Release</IntermediateOutputPath>
|
||||
<DocumentationFile>..\..\DesktopGL\MonoGame.Framework.xml</DocumentationFile>
|
||||
@@ -38,6 +38,7 @@
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
@@ -45,6 +46,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Clipboard.cs" />
|
||||
<Compile Include="MessageBox.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.DesktopGL.cs">
|
||||
<Platforms>WindowsGL,Linux</Platforms>
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
<Compile Include="Input\KeyboardUtil.SDL.cs" />
|
||||
<Compile Include="Input\Mouse.SDL.cs" />
|
||||
<Compile Include="Input\MouseCursor.SDL.cs" />
|
||||
<Compile Include="MessageBox.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.Windows.cs">
|
||||
<Platforms>Windows</Platforms>
|
||||
|
||||
@@ -255,12 +255,26 @@ internal static class Sdl
|
||||
|
||||
public static void SetClipboardText(string text)
|
||||
{
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(text);
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(text+"\0");
|
||||
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||
GetError(SDL_SetClipboardText(handle.AddrOfPinnedObject()));
|
||||
handle.Free();
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate int d_sdl_showsimplemessagebox(uint flags, IntPtr title, IntPtr msg, IntPtr window);
|
||||
public static d_sdl_showsimplemessagebox SDL_ShowSimpleMessageBox = FuncLoader.LoadFunction<d_sdl_showsimplemessagebox>(NativeLibrary, "SDL_ShowSimpleMessageBox");
|
||||
public static void ShowSimpleMessageBox(uint flags, string title, string message, IntPtr window)
|
||||
{
|
||||
byte[] bytesTitle = Encoding.UTF8.GetBytes(title + "\0");
|
||||
GCHandle handleTitle = GCHandle.Alloc(bytesTitle, GCHandleType.Pinned);
|
||||
byte[] bytesMessage = Encoding.UTF8.GetBytes(message + "\0");
|
||||
GCHandle handleMessage = GCHandle.Alloc(bytesMessage, GCHandleType.Pinned);
|
||||
GetError(SDL_ShowSimpleMessageBox(flags, handleTitle.AddrOfPinnedObject(), handleMessage.AddrOfPinnedObject(), window));
|
||||
handleTitle.Free();
|
||||
handleMessage.Free();
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate IntPtr d_sdl_gethint(string name);
|
||||
public static d_sdl_gethint SDL_GetHint = FuncLoader.LoadFunction<d_sdl_gethint>(NativeLibrary, "SDL_GetHint");
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user