Skip to content

Commit

Permalink
Merge pull request #640 from misternebula/dev
Browse files Browse the repository at this point in the history
0.30.2
  • Loading branch information
JohnCorby authored Aug 9, 2023
2 parents 8b5d7b3 + 42a0332 commit 4d8b128
Show file tree
Hide file tree
Showing 20 changed files with 232 additions and 89 deletions.
32 changes: 29 additions & 3 deletions APITestMod/IQSBAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,27 @@

public interface IQSBAPI
{
#region General

/// <summary>
/// If called, all players connected to YOUR hosted game must have this mod installed.
/// </summary>
void RegisterRequiredForAllPlayers(IModBehaviour mod);

/// <summary>
/// Returns if the current player is the host.
/// </summary>
bool GetIsHost();

/// <summary>
/// Returns if the current player is in multiplayer.
/// </summary>
bool GetIsInMultiplayer();

#endregion

#region Player

/// <summary>
/// Returns the player ID of the current player.
/// </summary>
Expand All @@ -22,23 +38,25 @@ public interface IQSBAPI

/// <summary>
/// Returns the list of IDs of all connected players.
///
/// The first player in the list is the host.
/// </summary>
uint[] GetPlayerIDs();

/// <summary>
/// Invoked when a player joins the game.
/// Invoked when any player (local or remote) joins the game.
/// </summary>
UnityEvent<uint> OnPlayerJoin();

/// <summary>
/// Invoked when a player leaves the game.
/// Invoked when any player (local or remote) leaves the game.
/// </summary>
UnityEvent<uint> OnPlayerLeave();

/// <summary>
/// Sets some arbitrary data for a given player.
/// </summary>
/// <typeparam name="T">The type of the data.</typeparam>
/// <typeparam name="T">The type of the data. If not serializable, data will not be synced.</typeparam>
/// <param name="playerId">The ID of the player.</param>
/// <param name="key">The unique key to access this data by.</param>
/// <param name="data">The data to set.</param>
Expand All @@ -53,8 +71,14 @@ public interface IQSBAPI
/// <returns>The data requested. If key is not valid, returns default.</returns>
T GetCustomData<T>(uint playerId, string key);

#endregion

#region Messaging

/// <summary>
/// Sends a message containing arbitrary data to every player.
///
/// Keep your messages under around 1100 bytes.
/// </summary>
/// <typeparam name="T">The type of the data being sent. This type must be serializable.</typeparam>
/// <param name="messageType">The unique key of the message.</param>
Expand All @@ -70,4 +94,6 @@ public interface IQSBAPI
/// <param name="messageType">The unique key of the message.</param>
/// <param name="handler">The action to be ran when the message is received. The uint is the player ID that sent the messsage.</param>
void RegisterHandler<T>(string messageType, Action<uint, T> handler);

#endregion
}
2 changes: 2 additions & 0 deletions QSB.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_USING/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/CASE_BLOCK_BRACES/@EntryValue">NEXT_LINE_SHIFTED_2</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=API/@EntryIndexedValue">API</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ID/@EntryIndexedValue">ID</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=QSB/@EntryIndexedValue">QSB</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UWP/@EntryIndexedValue">UWP</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
Expand Down
17 changes: 9 additions & 8 deletions QSB/API/AddonDataManager.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
using System;
using System.Collections.Generic;
using OWML.Common;
using QSB.Utility;

namespace QSB.API;

public static class AddonDataManager
{
private static readonly Dictionary<string, Action<uint, object>> _handlers = new();
private static readonly Dictionary<int, Action<uint, object>> _handlers = new();

public static void OnReceiveDataMessage(string messageType, object data, uint from)
public static void OnReceiveDataMessage(int hash, object data, uint from)
{
DebugLog.DebugWrite($"Received data message of message type \"{messageType}\" from {from}!");
if (!_handlers.TryGetValue(messageType, out var handler))
DebugLog.DebugWrite($"Received addon message of with hash {hash} from {from}!");
if (!_handlers.TryGetValue(hash, out var handler))
{
DebugLog.DebugWrite($"unknown addon message type with hash {hash}", MessageType.Error);
return;
}

handler(from, data);
}

public static void RegisterHandler<T>(string messageType, Action<uint, T> handler)
public static void RegisterHandler<T>(int hash, Action<uint, T> handler)
{
DebugLog.DebugWrite($"Registering handler for \"{messageType}\" with type of {typeof(T).Name}");
_handlers.Add(messageType, (from, data) => handler(from, (T)data));
DebugLog.DebugWrite($"Registering addon message handler for hash {hash} with type {typeof(T).Name}");
_handlers.Add(hash, (from, data) => handler(from, (T)data));
}
}
34 changes: 30 additions & 4 deletions QSB/API/IQSBAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,27 @@

public interface IQSBAPI
{
#region General

/// <summary>
/// If called, all players connected to YOUR hosted game must have this mod installed.
/// </summary>
void RegisterRequiredForAllPlayers(IModBehaviour mod);

/// <summary>
/// Returns if the current player is the host.
/// </summary>
bool GetIsHost();

/// <summary>
/// Returns if the current player is in multiplayer.
/// </summary>
bool GetIsInMultiplayer();

#endregion

#region Player

/// <summary>
/// Returns the player ID of the current player.
/// </summary>
Expand All @@ -22,23 +38,25 @@ public interface IQSBAPI

/// <summary>
/// Returns the list of IDs of all connected players.
///
/// The first player in the list is the host.
/// </summary>
uint[] GetPlayerIDs();

/// <summary>
/// Invoked when a player joins the game.
/// Invoked when any player (local or remote) joins the game.
/// </summary>
UnityEvent<uint> OnPlayerJoin();

/// <summary>
/// Invoked when a player leaves the game.
/// Invoked when any player (local or remote) leaves the game.
/// </summary>
UnityEvent<uint> OnPlayerLeave();

/// <summary>
/// Sets some arbitrary data for a given player.
/// </summary>
/// <typeparam name="T">The type of the data.</typeparam>
/// <typeparam name="T">The type of the data. If not serializable, data will not be synced.</typeparam>
/// <param name="playerId">The ID of the player.</param>
/// <param name="key">The unique key to access this data by.</param>
/// <param name="data">The data to set.</param>
Expand All @@ -52,9 +70,15 @@ public interface IQSBAPI
/// <param name="key">The unique key of the data you want to access.</param>
/// <returns>The data requested. If key is not valid, returns default.</returns>
T GetCustomData<T>(uint playerId, string key);


#endregion

#region Messaging

/// <summary>
/// Sends a message containing arbitrary data to every player.
///
/// Keep your messages under around 1100 bytes.
/// </summary>
/// <typeparam name="T">The type of the data being sent. This type must be serializable.</typeparam>
/// <param name="messageType">The unique key of the message.</param>
Expand All @@ -70,4 +94,6 @@ public interface IQSBAPI
/// <param name="messageType">The unique key of the message.</param>
/// <param name="handler">The action to be ran when the message is received. The uint is the player ID that sent the messsage.</param>
void RegisterHandler<T>(string messageType, Action<uint, T> handler);

#endregion
}
11 changes: 11 additions & 0 deletions QSB/API/Messages/AddonCustomDataSyncMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using QSB.Messaging;
using QSB.Player;
using QSB.Utility;

namespace QSB.API.Messages;

public class AddonCustomDataSyncMessage : QSBMessage<(uint playerId, string key, byte[] data)>
{
public AddonCustomDataSyncMessage(uint playerId, string key, object data) : base((playerId, key, data.ToBytes())) { }
public override void OnReceiveRemote() => QSBPlayerManager.GetPlayer(Data.playerId).SetCustomData(Data.key, Data.data.ToObject());
}
30 changes: 6 additions & 24 deletions QSB/API/Messages/AddonDataMessage.cs
Original file line number Diff line number Diff line change
@@ -1,29 +1,11 @@
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using QSB.Messaging;
using QSB.Messaging;
using QSB.Utility;

namespace QSB.API.Messages;

public class AddonDataMessage : QSBMessage<(string messageType, byte[] data, bool receiveLocally)>
public class AddonDataMessage : QSBMessage<(int hash, byte[] data, bool receiveLocally)>
{
public AddonDataMessage(string messageType, object data, bool receiveLocally) : base((messageType, Obj2Bytes(data), receiveLocally)) { }

private static byte[] Obj2Bytes(object obj)
{
using var ms = new MemoryStream();
var bf = new BinaryFormatter();
bf.Serialize(ms, obj);
var bytes = ms.ToArray();
return bytes;
}

private static object Bytes2Obj(byte[] bytes)
{
using var ms = new MemoryStream(bytes);
var bf = new BinaryFormatter();
var obj = bf.Deserialize(ms);
return obj;
}
public AddonDataMessage(int hash, object data, bool receiveLocally) : base((hash, data.ToBytes(), receiveLocally)) { }

public override void OnReceiveLocal()
{
Expand All @@ -35,7 +17,7 @@ public override void OnReceiveLocal()

public override void OnReceiveRemote()
{
var obj = Bytes2Obj(Data.data);
AddonDataManager.OnReceiveDataMessage(Data.messageType, obj, From);
var obj = Data.data.ToObject();
AddonDataManager.OnReceiveDataMessage(Data.hash, obj, From);
}
}
18 changes: 11 additions & 7 deletions QSB/API/QSBAPI.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using System;
using System.Linq;
using Mirror;
using OWML.Common;
using QSB.API.Messages;
using QSB.Messaging;
using QSB.Player;
using System;
using System.Linq;
using UnityEngine.Events;

namespace QSB.API;
Expand All @@ -16,22 +17,24 @@ public void RegisterRequiredForAllPlayers(IModBehaviour mod)
QSBCore.Addons.Add(uniqueName, mod);
}

public bool GetIsHost() => QSBCore.IsHost;
public bool GetIsInMultiplayer() => QSBCore.IsInMultiplayer;

public uint GetLocalPlayerID() => QSBPlayerManager.LocalPlayerId;
public string GetPlayerName(uint playerId) => QSBPlayerManager.GetPlayer(playerId).Name;
public uint[] GetPlayerIDs() => QSBPlayerManager.PlayerList.Select(x => x.PlayerId).ToArray();

public UnityEvent<uint> OnPlayerJoin() => QSBAPIEvents.OnPlayerJoinEvent;

public UnityEvent<uint> OnPlayerLeave() => QSBAPIEvents.OnPlayerLeaveEvent;

public void SetCustomData<T>(uint playerId, string key, T data) => QSBPlayerManager.GetPlayer(playerId).SetCustomData(key, data);
public T GetCustomData<T>(uint playerId, string key) => QSBPlayerManager.GetPlayer(playerId).GetCustomData<T>(key);

public void SendMessage<T>(string messageType, T data, uint to = uint.MaxValue, bool receiveLocally = false)
=> new AddonDataMessage(messageType, data, receiveLocally) {To = to} .Send();
=> new AddonDataMessage(messageType.GetStableHashCode(), data, receiveLocally) { To = to }.Send();

public void RegisterHandler<T>(string messageType, Action<uint, T> handler)
=> AddonDataManager.RegisterHandler(messageType, handler);
=> AddonDataManager.RegisterHandler(messageType.GetStableHashCode(), handler);
}

internal static class QSBAPIEvents
Expand All @@ -43,6 +46,7 @@ static QSBAPIEvents()
}

internal class PlayerEvent : UnityEvent<uint> { }
internal static PlayerEvent OnPlayerJoinEvent = new PlayerEvent();
internal static PlayerEvent OnPlayerLeaveEvent = new PlayerEvent();

internal static readonly PlayerEvent OnPlayerJoinEvent = new();
internal static readonly PlayerEvent OnPlayerLeaveEvent = new();
}
5 changes: 4 additions & 1 deletion QSB/DeathSync/RespawnOnDeath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,10 @@ private void ResetPlayerComponents()
var sectorList = PlayerTransformSync.LocalInstance.SectorDetector.SectorList;
if (sectorList.All(x => x.Type != Sector.Name.TimberHearth))
{
// stops sectors from breaking when you die on TH??
// Spooky scary legacy code?
// Original comment was "stops sectors from breaking when you die on TH??"
// I think dying on TH used to break all the sectors. Something about you not technically re-entering TH when dying inside it.
// I commented out these lines, and everything seemed fine. But I'm not gonna touch them just in case. :P
Locator.GetPlayerSectorDetector().RemoveFromAllSectors();
Locator.GetPlayerCameraDetector().GetComponent<AudioDetector>().DeactivateAllVolumes(0f);
}
Expand Down
2 changes: 2 additions & 0 deletions QSB/Menus/MenuManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,7 @@ private void Host(bool newMultiplayerSave)
}
LoadGame(PlayerData.GetWarpedToTheEye());
// wait until scene load and then wait until Start has ran
Delay.RunWhen(() => TimeLoop._initialized, QSBNetworkManager.singleton.StartHost);
};

Expand All @@ -655,6 +656,7 @@ private void Host(bool newMultiplayerSave)
else
{
LoadGame(PlayerData.GetWarpedToTheEye());
// wait until scene load and then wait until Start has ran
Delay.RunWhen(() => TimeLoop._initialized, QSBNetworkManager.singleton.StartHost);
}
}
Expand Down
Loading

0 comments on commit 4d8b128

Please sign in to comment.