Skip to content

Commit

Permalink
Merge pull request #159 from Centurion-Creative-Connect/bug/player-co…
Browse files Browse the repository at this point in the history
…unter-desync

Fix wrong team count when multiple colliders were intersecting
  • Loading branch information
DerpyNewbie authored Feb 28, 2024
2 parents a2c6a8a + 27cc0f1 commit ce03650
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -236,25 +236,25 @@ MonoBehaviour:
Data:
- Name: $k
Entry: 1
Data: _playersInArea
Data: _playersInAreaDict
- Name: $v
Entry: 7
Data: 15|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: _playersInArea
Data: _playersInAreaDict
- Name: <UserType>k__BackingField
Entry: 7
Data: 16|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: CenturionCC.System.Player.PlayerBase[], CenturionCC.System
Data: VRC.SDK3.Data.DataDictionary, VRCSDK3
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 9
Data: 13
Data: 16
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
Expand Down
65 changes: 47 additions & 18 deletions Packages/org.centurioncc.system/Runtime/Utils/AreaPlayerCounter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,28 @@
using JetBrains.Annotations;
using UdonSharp;
using UnityEngine;
using VRC.SDK3.Data;
using VRC.SDKBase;

namespace CenturionCC.System.Utils
{
[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
public class AreaPlayerCounter : PlayerManagerCallbackBase
{
private const int MinTeamId = 0;
private const int MaxTeamId = short.MaxValue;

[SerializeField] [HideInInspector] [NewbieInject]
private PlayerManager playerManager;
private int _eventCallbackCount;

private UdonSharpBehaviour[] _eventCallbacks = new UdonSharpBehaviour[0];

private PlayerBase[] _playersInArea = new PlayerBase[0];
private DataDictionary _playersInAreaDict = new DataDictionary();

[PublicAPI]
public int TotalPlayerCount => _playersInArea.Length;
public int TotalPlayerCount => _playersInAreaDict.Count;
[PublicAPI]
public int[] TeamPlayerCount { get; private set; } = new int[short.MaxValue];
public int[] TeamPlayerCount { get; private set; } = new int[MaxTeamId];

private void Start()
{
Expand All @@ -45,21 +48,27 @@ public void Recount()
{
TeamPlayerCount = new int[short.MaxValue];

foreach (var player in _playersInArea)
if (player != null)
IncrementTeamCount(player.TeamId);
var playersInArea = _playersInAreaDict.GetKeys().ToArray();
foreach (var player in playersInArea)
IncrementTeamCount(((PlayerBase)player.Reference).TeamId);
}

[PublicAPI]
public PlayerBase[] GetPlayersInArea()
{
return _playersInArea;
// Reconstruct PlayerBase array based on DataDictionary keys because it's easier to use
var playersInAreaTokens = _playersInAreaDict.GetKeys().ToArray();
var playerBaseArr = new PlayerBase[playersInAreaTokens.Length];
for (var i = 0; i < playerBaseArr.Length; i++)
playerBaseArr[i] = (PlayerBase)playersInAreaTokens[i].Reference;

return playerBaseArr;
}

[PublicAPI]
public void GetPlayerCount(out int allPlayersCount, out int redPlayerCount, out int yellowPlayerCount)
{
allPlayersCount = _playersInArea.Length;
allPlayersCount = _playersInAreaDict.Count;
redPlayerCount = TeamPlayerCount[1];
yellowPlayerCount = TeamPlayerCount[2];
}
Expand All @@ -71,8 +80,16 @@ public override void OnPlayerTriggerEnter(VRCPlayerApi player)
var playerBase = playerManager.GetPlayerById(player.playerId);
if (playerBase == null) return;

_playersInArea = _playersInArea.AddAsSet(playerBase);
IncrementTeamCount(playerBase.TeamId);
var key = new DataToken(playerBase);
if (!_playersInAreaDict.ContainsKey(key))
{
// For the first time player enters collider
_playersInAreaDict.Add(key, 0);
IncrementTeamCount(playerBase.TeamId);
}

var triggerCount = _playersInAreaDict[key].Int + 1;
_playersInAreaDict[key] = triggerCount;
}

public override void OnPlayerTriggerExit(VRCPlayerApi player)
Expand All @@ -82,35 +99,47 @@ public override void OnPlayerTriggerExit(VRCPlayerApi player)
var playerBase = playerManager.GetPlayerById(player.playerId);
if (playerBase == null) return;

_playersInArea = _playersInArea.RemoveItem(playerBase);
DecrementTeamCount(playerBase.TeamId);
var key = new DataToken(playerBase);
if (!_playersInAreaDict.ContainsKey(key)) return;

var triggerCount = _playersInAreaDict[key].Int - 1;
if (triggerCount <= 0)
{
// For the last time player exits collider
_playersInAreaDict.Remove(key);
DecrementTeamCount(playerBase.TeamId);
}
else
{
_playersInAreaDict[key] = triggerCount;
}
}

public override void OnTeamChanged(PlayerBase player, int oldTeam)
{
if (!_playersInArea.ContainsItem(player)) return;
if (!_playersInAreaDict.ContainsKey(player)) return;

DecrementTeamCount(oldTeam);
IncrementTeamCount(player.TeamId);
}

public override void OnPlayerChanged(PlayerBase player, int oldId, int newId)
{
if (!_playersInArea.ContainsItem(player)) return;
if (!_playersInAreaDict.ContainsKey(player)) return;

_playersInArea = _playersInArea.RemoveItem(player);
_playersInAreaDict.Remove(player);
DecrementTeamCount(player.TeamId);
}

private void DecrementTeamCount(int id)
{
if (id >= 0 && id <= 255) --TeamPlayerCount[id];
if (id >= MinTeamId && id <= MaxTeamId) --TeamPlayerCount[id];
Invoke_CountChanged();
}

private void IncrementTeamCount(int id)
{
if (id >= 0 && id <= 255) ++TeamPlayerCount[id];
if (id >= MinTeamId && id <= MaxTeamId) ++TeamPlayerCount[id];
Invoke_CountChanged();
}

Expand Down

0 comments on commit ce03650

Please sign in to comment.