Skip to content

Commit

Permalink
Add input playback player emulation
Browse files Browse the repository at this point in the history
  • Loading branch information
jeickhoff committed Jul 5, 2023
1 parent 4cf7747 commit 0ba31e8
Show file tree
Hide file tree
Showing 23 changed files with 1,075 additions and 74 deletions.
4 changes: 2 additions & 2 deletions Assets/Scenes/AuthoringScene/AuthoringScene.unity
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,10 @@ MonoBehaviour:
seed: 43
initialAreas:
x: 10
y: 5
y: 2
z: 10
playerViewRange: 2
maxChunkSpawnsPerTick: 25
maxChunkSpawnsPerTick: 50
blocksPerAreaSide: 16
YBounds:
x: 0
Expand Down
89 changes: 88 additions & 1 deletion Assets/Scenes/MainScene.unity
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,92 @@ Transform:
m_Father: {fileID: 0}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &955198405
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 955198408}
- component: {fileID: 955198407}
- component: {fileID: 955198406}
- component: {fileID: 955198409}
m_Layer: 0
m_Name: PlayerEmulation
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &955198406
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 955198405}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1d8c509f1d3f4dcaab72eb2f27f779b7, type: 3}
m_Name:
m_EditorClassIdentifier:
inputFile: recordedInputs.csv
inputRecorder: {fileID: 955198409}
emulationType: 2
--- !u!114 &955198407
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 955198405}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c488ceaf592f44a9ad4be1e5dbf650bd, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!4 &955198408
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 955198405}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 7.3372736, y: 0.32767057, z: 12.821487}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 7
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &955198409
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 955198405}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 947bbf6d07a849f88ae34e79d6fb2f2e, type: 3}
m_Name:
m_EditorClassIdentifier:
m_StartRecordingWhenEnabled: 0
m_RecordFrames: 1
m_ReplayOnNewDevices: 0
m_SimulateOriginalTimingOnReplay: 1
m_RecordStateEventsOnly: 0
m_CaptureMemoryDefaultSize: 8388608
m_CaptureMemoryMaxSize: 41943040
m_DevicePath:
m_RecordButtonPath:
m_PlayButtonPath:
m_ChangeEvent:
m_PersistentCalls:
m_Calls: []
--- !u!1 &989023403
GameObject:
m_ObjectHideFlags: 0
Expand Down Expand Up @@ -766,7 +852,7 @@ Transform:
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 7
m_RootOrder: 8
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1577125370
GameObject:
Expand Down Expand Up @@ -812,6 +898,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 8bf58c69bf424fe194d229f05ce07072, type: 3}
m_Name:
m_EditorClassIdentifier:
editorArgs: -streaming_type host
--- !u!1 &2101193216
GameObject:
m_ObjectHideFlags: 0
Expand Down
10 changes: 7 additions & 3 deletions Assets/Scripts/CmdArgs.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Unity.Logging;
using Opencraft.Player.Emulated;
using Unity.Logging;
using Unity.NetCode;
using UnityEditor;
using UnityEngine;
Expand Down Expand Up @@ -42,8 +43,11 @@ public static StreamingRole ClientStreamingRole
public static StreamingRole ClientStreamingRole { get; set; } = DefaultStreamingRole;
#endif
public static bool DebugEnabled = false;


public static bool EmulationEnabled = false;
public static EmulationType emulationType = EmulationType.None;
public static int seed = -1;


// Client's streaming role for Multiplay
public enum StreamingRole
{
Expand Down
55 changes: 48 additions & 7 deletions Assets/Scripts/CmdArgsReader.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using Opencraft.Player.Emulated;
using UnityEngine;
#if UNITY_EDITOR
using ParrelSync;
Expand All @@ -8,10 +12,13 @@ namespace Opencraft
{
public class CmdArgsReader : MonoBehaviour
{
void Start()
public string editorArgs;

void OnEnable()
{
Debug.Log("Reading cmdargs");
var args = GetCommandlineArgs();
// Streaming type, only used on builds with a client, e.g. UNITY_SERVER undefined
// Multiplay streaming type, only used on builds with a client, e.g. UNITY_SERVER undefined
if (args.TryGetValue("-streaming_type", out string type))
{
switch (type)
Expand All @@ -31,27 +38,61 @@ void Start()
#if UNITY_EDITOR
Debug.Log($"Client streaming role is {CmdArgs.ClientStreamingRole} {CmdArgs.getPlayType()}");
#endif
// Debug flag, used for rendering outlines
if (args.TryGetValue("-debug", out string _))
{
CmdArgs.DebugEnabled = true;
}

// Emulation
if (args.TryGetValue("-emulation", out string emulationType))
{
CmdArgs.EmulationEnabled = true;
switch (emulationType)
{
case "playback":
CmdArgs.emulationType = EmulationType.InputPlayback;
break;
case "record":
CmdArgs.emulationType = EmulationType.RecordInput;
break;
case "behaviour":
default:
CmdArgs.emulationType = EmulationType.BehaviourProfile;
break;
}
}

// Seed
if (args.TryGetValue("-seed", out string seed))
{
MD5 md5Hasher = MD5.Create();
var hashed = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(seed));
var ivalue = BitConverter.ToInt32(hashed, 0);
CmdArgs.seed = ivalue;
}


}



private Dictionary<string, string> GetCommandlineArgs()
{
Dictionary<string, string> argDictionary = new Dictionary<string, string>();
string[] args = new[] { "" };
#if UNITY_EDITOR
// ParrelSync clones can have arguments passed to them in editor. The original project cannot.
// So, use ParrelSync clones to test streamed guests.
// todo add some sort of cmdline arg facade to original project
// ParrelSync clones can have arguments passed to them in the Clones Manager window
if (ClonesManager.IsClone())
{
// Get the custom arguments for this clone project.
args = ClonesManager.GetArgument().Split(' ');
} else {
// Otherwise, use arguments in this MonoBehaviour
args = editorArgs.Split(' ');
}
#else
args = System.Environment.GetCommandLineArgs();
args = System.Environment.GetCommandLineArgs();
#endif
for (int i = 0; i < args.Length; ++i)
{
Expand Down
104 changes: 53 additions & 51 deletions Assets/Scripts/Networking/NetCodeBootstrap.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Opencraft.Player.Emulated;
using Opencraft.Player.Multiplay;
using Unity.Entities;
using Unity.NetCode;
Expand Down Expand Up @@ -35,68 +36,68 @@ protected override void CreateDefaultClientServerWorlds()
{
if (CmdArgs.ClientStreamingRole == CmdArgs.StreamingRole.Guest)
{
CreateStreamClientWorld("StreamClientWorld");
// The guest world only needs Multiplay functionality
var systems = new List<Type> { typeof(MultiplayInitSystem), typeof(EmulationInitSystem) };
CreateClientWorld("StreamClientWorld", WorldFlags.Game, systems);
}
else
{
CreateClientWorld("ClientWorld");
var systems = DefaultWorldInitialization.GetAllSystems(WorldSystemFilterFlags.ClientSimulation |
WorldSystemFilterFlags.Presentation);
CreateClientWorld("ClientWorld", WorldFlags.GameClient, systems);
}

#if UNITY_EDITOR
var requestedNumThinClients = RequestedNumThinClients;
for (var i = 0; i < requestedNumThinClients; i++)
{
CreateThinClientWorld();
}
#endif
}
}

// Utility method for creating new stream clients worlds.
public static World CreateStreamClientWorld(string name)
/// <summary>
/// Utility method for creating new client worlds.
/// </summary>
/// <param name="name">The client world name</param>
/// <param name="flags">WorldFlags for the created world</param>
/// <param name="systems">List of systems the world will include</param>
/// <returns></returns>
public static World CreateClientWorld(string name, WorldFlags flags, IReadOnlyList<Type> systems)
{
#if UNITY_SERVER && !UNITY_EDITOR
throw new NotImplementedException();
#else
var world = new World(name, WorldFlags.Game);
// On Multiplay guest clients we don't really utilize any ECS-specific systems,
// so we use MultiplayInitSystem to start the relevant MonoBehaviours
var systems = new List<Type> { typeof(MultiplayInitSystem) };
var world = new World(name, flags);

DefaultWorldInitialization.AddSystemsToRootLevelSystemGroups(world, systems);

ScriptBehaviourUpdateOrder.AppendWorldToCurrentPlayerLoop(world);
#endif

if (World.DefaultGameObjectInjectionWorld == null)
World.DefaultGameObjectInjectionWorld = world;

return world;
#endif
}
}

// Custom network settings and driver initialize to specify network parameters
public class NetCodeDriverConstructor : INetworkStreamDriverConstructor
{
// Custom timeout time
private static readonly int s_DisconnectTimeout = 2000;

private NetworkSettings CreateNetworkSettings(int maxFrameTime = 0)
// Custom network settings and driver initialize to specify network parameters
public class NetCodeDriverConstructor : INetworkStreamDriverConstructor
{
var settings = new NetworkSettings();
settings.WithNetworkConfigParameters(
connectTimeoutMS: 1000,
disconnectTimeoutMS: s_DisconnectTimeout,
heartbeatTimeoutMS: s_DisconnectTimeout / 2,
fixedFrameTimeMS: 0,
maxFrameTimeMS: maxFrameTime);
settings.WithReliableStageParameters(windowSize: 32)
.WithFragmentationStageParameters(payloadCapacity: 16 * 1024);
return settings;
}
// Custom timeout time
private static readonly int s_DisconnectTimeout = 2000;

public void CreateClientDriver(World world, ref NetworkDriverStore driverStore, NetDebug netDebug)
{
var driverInstance = new NetworkDriverStore.NetworkDriverInstance();
private NetworkSettings CreateNetworkSettings(int maxFrameTime = 0)
{
var settings = new NetworkSettings();
settings.WithNetworkConfigParameters(
connectTimeoutMS: 1000,
disconnectTimeoutMS: s_DisconnectTimeout,
heartbeatTimeoutMS: s_DisconnectTimeout / 2,
fixedFrameTimeMS: 0,
maxFrameTimeMS: maxFrameTime);
settings.WithReliableStageParameters(windowSize: 32)
.WithFragmentationStageParameters(payloadCapacity: 16 * 1024);
return settings;
}

public void CreateClientDriver(World world, ref NetworkDriverStore driverStore, NetDebug netDebug)
{
var driverInstance = new NetworkDriverStore.NetworkDriverInstance();
#if UNITY_EDITOR || NETCODE_DEBUG
var settings = CreateNetworkSettings(100);
driverInstance.simulatorEnabled = NetworkSimulatorSettings.Enabled;
Expand All @@ -112,20 +113,21 @@ public void CreateClientDriver(World world, ref NetworkDriverStore driverStore,
DefaultDriverBuilder.CreateClientPipelines(ref driverInstance);
}
#else
var settings = CreateNetworkSettings();
driverInstance.driver = NetworkDriver.Create(new UDPNetworkInterface(), settings);
DefaultDriverBuilder.CreateClientPipelines(ref driverInstance);
var settings = CreateNetworkSettings();
driverInstance.driver = NetworkDriver.Create(new UDPNetworkInterface(), settings);
DefaultDriverBuilder.CreateClientPipelines(ref driverInstance);
#endif
driverStore.RegisterDriver(TransportType.Socket, driverInstance);
}
driverStore.RegisterDriver(TransportType.Socket, driverInstance);
}

public void CreateServerDriver(World world, ref NetworkDriverStore driverStore, NetDebug netDebug)
{
var settings = CreateNetworkSettings();
var driverInstance = new NetworkDriverStore.NetworkDriverInstance();
driverInstance.driver = NetworkDriver.Create(new UDPNetworkInterface(), settings);
DefaultDriverBuilder.CreateServerPipelines(ref driverInstance);
driverStore.RegisterDriver(TransportType.Socket, driverInstance);
public void CreateServerDriver(World world, ref NetworkDriverStore driverStore, NetDebug netDebug)
{
var settings = CreateNetworkSettings();
var driverInstance = new NetworkDriverStore.NetworkDriverInstance();
driverInstance.driver = NetworkDriver.Create(new UDPNetworkInterface(), settings);
DefaultDriverBuilder.CreateServerPipelines(ref driverInstance);
driverStore.RegisterDriver(TransportType.Socket, driverInstance);
}
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions Assets/Scripts/Player/Emulated.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 0ba31e8

Please sign in to comment.