Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add simple player simulation, fix terrain block search #2

Merged
merged 12 commits into from
Feb 20, 2024
Merged
Prev Previous commit
Next Next commit
Reduce simulated player memory usage, fix statistics collection
  • Loading branch information
JerritEic committed Dec 19, 2023
commit ce435d999c316b5f7fef9924533f2cb8f41b6c96
3 changes: 1 addition & 2 deletions Assets/Scenes/MainScene.unity
Original file line number Diff line number Diff line change
Expand Up @@ -476,8 +476,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 7670ed7fdc2d435abe14606c6942102a, type: 3}
m_Name:
m_EditorClassIdentifier:
editorArgs: -playType SimulatedClient -emulationType Simulation -userID 1 -numSimulatedPlayers
2 -duration 20
editorArgs: -userID 1
useDeploymentConfig: 0
deploymentConfig: "{\n\t\"nodes\":[\n\t\t{\n\t\t\t\"nodeID\":0,\n\t\t\t\"nodeIP\":\"\",\n\t\t\t\"worldConfigs\":[\n\t\t\t\t{\n\t\t\t\t\t\"worldName\":
\"GameServer\",\n\t\t\t\t\t\"worldType\":\"Server\",\n\t\t\t\t\t\"initializationMode\":\"Connect\",\n\t\t\t\t\t\"multiplayStreamingRoles\":\"Disabled\",\n\t\t\t\t\t\"serverNodeID\":0,\n\t\t\t\t\t\"streamingNodeID\":-1,\n\t\t\t\t\t\"numThinClients\":0,\n\t\t\t\t\t\"services\":[],\n\t\t\t\t\t\"serviceFilterType\":\"Includes\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"worldName\":
Expand Down
63 changes: 41 additions & 22 deletions Assets/Scripts/Player/Emulation/PlayerSimulationSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,21 @@ public partial struct PlayerSimulationSystem : ISystem
// If we encounter unloaded chunks, wait an amount of ticks for them to load
private static readonly int _ticksToWait = 60; // e.g. roughly 1 second at 60 tps
private int _waitingTicks;


// Flag for when we encounter an unloaded chunk
private bool _notLoaded;


// Determines how we pick the target locations
private SimulationBehaviour _chosenBehaviour;


// World metadata used to compute a pseudo-random seed
private FixedString128Bytes _worldName;

// Reusable A* collections
private NativeHashSet<int3> _visited;
private NativeHashMap<int3, int3> _previousNode;
private NativePriorityQueue<int3> _toVisit;

public void OnCreate(ref SystemState state)
{
if (ApplicationConfig.EmulationType != EmulationType.Simulation)
Expand Down Expand Up @@ -165,6 +173,12 @@ public void OnCreate(ref SystemState state)
_notLoaded = false;

_chosenBehaviour = GameConfig.PlayerSimulationBehaviour.Value;

_visited = new NativeHashSet<int3>(64, Allocator.Persistent);

_previousNode = new NativeHashMap<int3, int3>(64, Allocator.Persistent);

_toVisit = new NativePriorityQueue<int3>(64, Allocator.Persistent);
}

public void OnDestroy(ref SystemState state)
Expand All @@ -178,6 +192,9 @@ public void OnDestroy(ref SystemState state)
_belowOffsets.Dispose();
_aboveOffsets.Dispose();
_playerOffsets.Dispose();
_visited.Dispose();
_previousNode.Dispose();
_toVisit.Dispose();
}

[BurstCompile]
Expand Down Expand Up @@ -495,6 +512,8 @@ private bool FindTargetPosFixedDirection(int3 playerPos, int attempt, out int3 t
/// <returns>True if a target position was found</returns>
private bool FindTargetPosBoundedRandom(int3 playerPos, int attempt, out int3 target)
{
target = int3.zero;

int startSeed = _simulationSeed + attempt;
// Find local bounds within a wider bounding area
int maxOffset = 10;
Expand All @@ -516,13 +535,12 @@ private bool FindTargetPosBoundedRandom(int3 playerPos, int attempt, out int3 ta
int xVal = negXBound + NoiseUtilities.FastFloor(randVal1 * rangeX);
int zVal = negZBound + NoiseUtilities.FastFloor(randVal2 * rangeZ);
int3 startingTarget = new int3(xVal, playerPos.y, zVal);

//Debug.Log($"+x {posXBound} -x {negXBound} +z {posZBound} -z {negZBound} rv1 {randVal1} rv2 {randVal2}");

if (startingTarget.Equals(playerPos))
return false;

if (FindAvailablePos(startingTarget, out target))
return true;

target = int3.zero;
return false;
}

Expand Down Expand Up @@ -557,19 +575,20 @@ private bool FindAvailablePos( int3 start, out int3 target)
/// <returns>True if a path could be found. The resulting path is stored in _path.</returns>
private bool AStar(int3 start, int3 end)
{
NativeHashSet<int3> visited = new NativeHashSet<int3>(32, Allocator.Temp);
_visited.Clear();

_previousNode.Clear();

NativeHashMap<int3, int3> previousNode = new NativeHashMap<int3, int3>(32, Allocator.Temp);
_toVisit.Clear();

NativePriorityQueue<int3> toVisit = new NativePriorityQueue<int3>(32, Allocator.Temp);
int baseCost = DistanceSquared(start, end);
toVisit.Enqueue(start, baseCost);
_toVisit.Enqueue(start, baseCost);


while (toVisit.Length > 0)
while (_toVisit.Length > 0)
{
int3 current = toVisit.Dequeue(out int priority);
visited.Add(current);
int3 current = _toVisit.Dequeue(out int priority);
_visited.Add(current);

double distance = Distance(current, end);

Expand All @@ -586,7 +605,7 @@ private bool AStar(int3 start, int3 end)
float3 centerOffset = new float3(0.5f, 0, 0.5f);
int3 next = current;
//var sb = new StringBuilder($"PATH: ");
while (previousNode.ContainsKey(next))
while (_previousNode.ContainsKey(next))
{
float3 floatPos = next;

Expand All @@ -595,7 +614,7 @@ private bool AStar(int3 start, int3 end)
TerrainUtilities.DebugDrawTerrainBlock(in floatPos, Color.yellow, 6.0f);
//sb.Append($"[{next.x},{next.y},{next.z}]<-");

next = previousNode[next];
next = _previousNode[next];
}
//_path.Add(start + centerOffset );
//Debug.Log(sb.ToString());
Expand All @@ -615,20 +634,20 @@ private bool AStar(int3 start, int3 end)

foreach (int3 neighbor in _walkable)
{
if (visited.Contains(neighbor))
if (_visited.Contains(neighbor))
{
continue;
}

var nCost = priority + 1 + DistanceSquared(neighbor, end);
if (!toVisit.Contains(neighbor, out var nPriority))
if (!_toVisit.Contains(neighbor, out var nPriority))
{
toVisit.Enqueue(neighbor, nCost);
previousNode[neighbor] = current;
_toVisit.Enqueue(neighbor, nCost);
_previousNode[neighbor] = current;
} else if (nPriority > nCost)
{
toVisit.UpdatePriority(neighbor, nCost);
previousNode[neighbor] = current;
_toVisit.UpdatePriority(neighbor, nCost);
_previousNode[neighbor] = current;
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions Assets/Scripts/Player/PlayerMovementSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ partial struct PlayerMovementSystem : ISystem

public void OnCreate(ref SystemState state)
{
if (state.WorldUnmanaged.IsSimulatedClient())
{
state.Enabled = false;
return;
}
state.RequireForUpdate<TerrainSpawner>();
state.RequireForUpdate<NetworkTime>();
state.RequireForUpdate<PolkaDOTS.Player>();
Expand Down
2 changes: 1 addition & 1 deletion Assets/Scripts/Rendering/DebugRenderSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Opencraft.Rendering
{
[RequireMatchingQueriesForUpdate]
[UpdateInGroup(typeof(PresentationSystemGroup))]
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation, WorldSystemFilterFlags.Editor)]
[WorldSystemFilter(WorldSystemFilterFlags.Presentation, WorldSystemFilterFlags.Editor)]
[BurstCompile]
// Draws bounding boxing on terrain area borders, only in the editor.
public partial struct DebugRenderSystem : ISystem
Expand Down
2 changes: 1 addition & 1 deletion Assets/Scripts/Rendering/HighlightSelectedBlockSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace Opencraft.Rendering
{
[UpdateInGroup(typeof(SimulationSystemGroup))]
[UpdateAfter(typeof(PlayerSelectedBlockSystem))]
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
[WorldSystemFilter(WorldSystemFilterFlags.Presentation)]
[BurstCompile]

public partial struct HighlightSelectedBlockSystem : ISystem
Expand Down
9 changes: 8 additions & 1 deletion Assets/Scripts/Rendering/TerrainRenderInitSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
using Unity.Entities;
using Unity.Entities.Graphics;
using Unity.Mathematics;
using Unity.NetCode;
using Unity.Rendering;
using UnityEngine;

namespace Opencraft.Rendering
{
// Adds components to TerrainArea entities on client side for meshing and rendering purposes
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
[WorldSystemFilter(WorldSystemFilterFlags.Presentation)]
[UpdateInGroup(typeof(InitializationSystemGroup))]
[UpdateAfter(typeof(TerrainNeighborSystem))]
public partial class TerrainRenderInitSystem : SystemBase
Expand All @@ -20,6 +21,12 @@ public partial class TerrainRenderInitSystem : SystemBase

protected override void OnCreate()
{
/*if (World.IsSimulatedClient())
{
Enabled = false;
return;
}*/

RequireForUpdate<TerrainArea>();
RequireForUpdate<MaterialBank>();
RequireForUpdate<NewSpawn>();
Expand Down
31 changes: 26 additions & 5 deletions Assets/Scripts/Statistics/GameStatistics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@ namespace Opencraft.Statistics
/// </summary>
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation | WorldSystemFilterFlags.ClientSimulation)]
[UpdateAfter(typeof(NetworkReceiveSystemGroup))]
[UniqueSystem]
public partial struct StatisticsSystem : ISystem
{
private EntityQuery _terrainAreaQuery;
private EntityQuery _playerQuery;
private bool first;

public void OnCreate(ref SystemState state)
{
_terrainAreaQuery = state.EntityManager.CreateEntityQuery(typeof(TerrainArea));
_playerQuery = state.EntityManager.CreateEntityQuery(typeof(PolkaDOTS.Player));
first = true;
}

Expand All @@ -37,18 +40,28 @@ public void OnUpdate(ref SystemState state)
PolkaDOTS.Statistics.StatisticsWriter writer = PolkaDOTS.Statistics.StatisticsWriterInstance.instance;
writer.AddStatisticRecorder("Number of Terrain Areas (Client)", ProfilerCategory.Scripts);
writer.AddStatisticRecorder("Number of Terrain Areas (Server)", ProfilerCategory.Scripts);
writer.AddStatisticRecorder("Number of Players (Client)", ProfilerCategory.Scripts);
writer.AddStatisticRecorder("Number of Players (Server)", ProfilerCategory.Scripts);
}
first = false;
}
// Record terrain area data
var terrainCount = _terrainAreaQuery.CalculateEntityCount();
var playerCount = _playerQuery.CalculateEntityCount();
if (state.WorldUnmanaged.IsClient())
{
GameStatistics.NumTerrainAreasClient.Value = terrainCount;
if(state.WorldUnmanaged.IsServer())
GameStatistics.NumPlayersClient.Value = playerCount;
}

if (state.WorldUnmanaged.IsServer())
{
GameStatistics.NumTerrainAreasServer.Value = terrainCount;



GameStatistics.NumPlayersServer.Value = playerCount;
}



}
}

Expand All @@ -65,6 +78,12 @@ public class GameStatistics
public const string NumTerrainAreasServerName = "Number of Terrain Areas (Server)";
public static readonly ProfilerCounterValue<int> NumTerrainAreasServer =
new ProfilerCounterValue<int>(GameStatisticsCategory, NumTerrainAreasServerName, ProfilerMarkerDataUnit.Count);
public const string NumPlayersClientName = "Number of Players (Client)";
public static readonly ProfilerCounterValue<int> NumPlayersClient =
new ProfilerCounterValue<int>(GameStatisticsCategory, NumPlayersClientName, ProfilerMarkerDataUnit.Count);
public const string NumPlayersServerName = "Number of Players (Server)";
public static readonly ProfilerCounterValue<int> NumPlayersServer =
new ProfilerCounterValue<int>(GameStatisticsCategory, NumPlayersServerName, ProfilerMarkerDataUnit.Count);

}
#if UNITY_EDITOR
Expand All @@ -75,7 +94,9 @@ public class GameProfilerModule : ProfilerModule
static readonly ProfilerCounterDescriptor[] k_Counters = new ProfilerCounterDescriptor[]
{
new ProfilerCounterDescriptor(GameStatistics.NumTerrainAreasClientName, GameStatistics.GameStatisticsCategory),
new ProfilerCounterDescriptor(GameStatistics.NumTerrainAreasServerName, GameStatistics.GameStatisticsCategory)
new ProfilerCounterDescriptor(GameStatistics.NumTerrainAreasServerName, GameStatistics.GameStatisticsCategory),
new ProfilerCounterDescriptor(GameStatistics.NumPlayersClientName, GameStatistics.GameStatisticsCategory),
new ProfilerCounterDescriptor(GameStatistics.NumPlayersServerName, GameStatistics.GameStatisticsCategory)
};

// Ensure that both ProfilerCategory.Scripts and ProfilerCategory.Memory categories are enabled when our module is active.
Expand Down
4 changes: 2 additions & 2 deletions Assets/Scripts/Terrain/Authoring/TerrainAreaAuthoring.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,14 @@ public struct TerrainBlocks : IBufferElementData
[GhostField] public BlockType type;
}

[InternalBufferCapacity(512)]
[InternalBufferCapacity(256)]
// The buffer component to store heightmap column min
public struct TerrainColMinY : IBufferElementData
{
[GhostField] public byte minY;
}

[InternalBufferCapacity(512)]
[InternalBufferCapacity(256)]
// The buffer component to store heightmap column max
public struct TerrainColMaxY : IBufferElementData
{
Expand Down
2 changes: 1 addition & 1 deletion Packages/PolkaDOTS