unity error
This commit is contained in:
@@ -75,6 +75,14 @@ public class Logger
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Writable Logs folder next to match log files (creates if missing).</summary>
|
||||||
|
public static string GetLogsDirectory()
|
||||||
|
{
|
||||||
|
string dir = Path.Combine(ApplicationDirectory, "Logs");
|
||||||
|
EnsureDirectoryExists(dir);
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
public static void SetFilePath(string path){
|
public static void SetFilePath(string path){
|
||||||
instance.LogFilePath= path;
|
instance.LogFilePath= path;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
+148
-64
@@ -1,65 +1,149 @@
|
|||||||
Logger initiated at 7/19/2026 12:08:23 PM
|
Logger initiated at 7/29/2026 1:21:58 PM
|
||||||
|
|
||||||
[7/19/2026 12:08:23 PM] Cupid settings updated
|
[7/29/2026 1:21:58 PM] Cupid settings updated
|
||||||
[7/19/2026 12:08:23 PM] Cupid settings updated
|
[7/29/2026 1:21:58 PM] Cupid settings updated
|
||||||
[7/19/2026 12:08:25 PM] Starting matchmake as warlock2
|
[7/29/2026 1:22:00 PM] Starting matchmake as warlock
|
||||||
[7/19/2026 12:08:53 PM] Still waiting: {"ok":true,"entry_fee":21,"rc_prize":34,"for_red":{"Players":[{"Name":"warlock2","LastSeen":1784443133384,"UserId":3,"l10_wins":4,"l10_losses":4}],"GameName":"soccar","Port":26143,"InitTime":1784443133384,"entry_fee":21,"match_id":450,"rc_prize":34,"your_team":"red"},"for_blue":null}
|
[7/29/2026 1:22:02 PM] Got into a room
|
||||||
[7/19/2026 12:08:54 PM] Got into a room
|
[7/29/2026 1:22:02 PM] {"ok":true,"entry_fee":21,"rc_prize":34,"for_red":{"Players":[{"Name":"choel","LastSeen":1785311520437,"UserId":9,"l10_wins":7,"l10_losses":0},{"Name":"warlock","LastSeen":1785311520886,"UserId":2,"l10_wins":8,"l10_losses":2}],"GameName":"soccar","Port":26815,"InitTime":1785311520437,"entry_fee":21,"match_id":535,"instance_started":true,"rc_prize":34,"your_team":"red"},"for_blue":{"Players":[{"Name":"choel","LastSeen":1785311520437,"UserId":9,"l10_wins":7,"l10_losses":0},{"Name":"warlock","LastSeen":1785311520886,"UserId":2,"l10_wins":8,"l10_losses":2}],"GameName":"soccar","Port":26815,"InitTime":1785311520437,"entry_fee":21,"match_id":535,"instance_started":true,"rc_prize":34,"your_team":"blue"}}
|
||||||
[7/19/2026 12:08:54 PM] {"ok":true,"entry_fee":21,"rc_prize":34,"for_red":{"Players":[{"Name":"warlock2","LastSeen":1784443134684,"UserId":3,"l10_wins":4,"l10_losses":4},{"Name":"Malik gaming","LastSeen":1784443134377,"UserId":96,"l10_wins":0,"l10_losses":5}],"GameName":"soccar","Port":26143,"InitTime":1784443133384,"entry_fee":21,"match_id":450,"instance_started":true,"rc_prize":34,"your_team":"red"},"for_blue":{"Players":[{"Name":"warlock2","LastSeen":1784443134684,"UserId":3,"l10_wins":4,"l10_losses":4},{"Name":"Malik gaming","LastSeen":1784443134377,"UserId":96,"l10_wins":0,"l10_losses":5}],"GameName":"soccar","Port":26143,"InitTime":1784443133384,"entry_fee":21,"match_id":450,"instance_started":true,"rc_prize":34,"your_team":"blue"}}
|
[7/29/2026 1:22:02 PM] Configured dedicated match reporting for match id 535 with secret 38516e39d3406225b7c3015a66e5d25c54e9b2024c0755212122bdcea3e3a328 and internal api base https://kkapi.playpoolstudios.com
|
||||||
[7/19/2026 12:08:54 PM] Configured dedicated match reporting for match id 450 with secret 38516e39d3406225b7c3015a66e5d25c54e9b2024c0755212122bdcea3e3a328 and internal api base https://kkapi.playpoolstudios.com
|
[7/29/2026 1:22:02 PM] Setting cupid to load game scene
|
||||||
[7/19/2026 12:08:54 PM] Setting cupid to load game scene
|
[7/29/2026 1:22:02 PM] Loading game scene
|
||||||
[7/19/2026 12:08:54 PM] Loading game scene
|
[7/29/2026 1:22:07 PM] Starting client at $kkapi.playpoolstudios.com:26815
|
||||||
[7/19/2026 12:08:59 PM] Starting client at $kkapi.playpoolstudios.com:26143
|
[7/29/2026 1:22:07 PM] Client connected
|
||||||
[7/19/2026 12:08:59 PM] Client connected
|
[7/29/2026 1:22:14 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:09:06 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:22:19 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:09:24 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:22:26 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:09:35 PM] Score changed from 0 to 1
|
[7/29/2026 1:22:30 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:09:38 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:22:34 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:09:51 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:22:37 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:09:56 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:22:44 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:10:11 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:22:48 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:10:17 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:22:53 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:10:27 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:22:57 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:10:42 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:23:01 PM] Score changed from 0 to 1
|
||||||
[7/19/2026 12:10:48 PM] Score changed from 0 to 1
|
[7/29/2026 1:23:04 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:10:51 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:23:11 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:11:06 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:23:19 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:11:12 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:23:24 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:11:19 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:23:30 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:11:27 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:23:35 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:11:42 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:23:42 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:11:48 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:23:46 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:11:59 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:23:55 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:12:12 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:23:59 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:12:27 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:24:07 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:12:31 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:24:10 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:12:46 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:24:19 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:12:56 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:24:24 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:13:05 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:24:30 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:13:12 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:24:36 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:13:27 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:24:44 PM] Score changed from 1 to 2
|
||||||
[7/19/2026 12:13:36 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:24:48 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:13:38 PM] Score changed from 1 to 2
|
[7/29/2026 1:24:52 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:13:41 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:24:58 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:13:47 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:25:04 PM] Score changed from 0 to 1
|
||||||
[7/19/2026 12:14:02 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:25:07 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:14:11 PM] Score changed from 1 to 2
|
[7/29/2026 1:25:16 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:14:14 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:25:18 PM] Score changed from 1 to 2
|
||||||
[7/19/2026 12:14:29 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:25:21 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:14:42 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:25:27 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:14:47 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:25:34 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:14:53 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:25:40 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:15:00 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:25:45 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:15:15 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:25:56 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:15:25 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:26:00 PM] Score changed from 2 to 3
|
||||||
[7/19/2026 12:15:40 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:26:11 PM] Configured dedicated match reporting for match id 536 with secret 38516e39d3406225b7c3015a66e5d25c54e9b2024c0755212122bdcea3e3a328 and internal api base https://kkapi.playpoolstudios.com
|
||||||
[7/19/2026 12:15:45 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:26:11 PM] Client disconnected
|
||||||
[7/19/2026 12:16:00 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:26:15 PM] Starting client at $kkapi.playpoolstudios.com:26172
|
||||||
[7/19/2026 12:16:05 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:26:15 PM] Client connected
|
||||||
[7/19/2026 12:16:20 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:26:20 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:16:27 PM] Selected team changed from Red to Blue
|
[7/29/2026 1:26:25 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:16:42 PM] Selected team changed from Blue to Red
|
[7/29/2026 1:26:33 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:16:43 PM] Score changed from 2 to 3
|
[7/29/2026 1:26:37 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:16:50 PM] Client disconnected
|
[7/29/2026 1:26:48 PM] Selected team changed from Red to Blue
|
||||||
[7/19/2026 12:16:55 PM] Cupid settings updated
|
[7/29/2026 1:26:56 PM] Selected team changed from Blue to Red
|
||||||
[7/19/2026 12:16:55 PM] Cupid settings updated
|
[7/29/2026 1:27:03 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:27:09 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:27:14 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:27:24 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:27:32 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:27:37 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:27:45 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:27:49 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:27:55 PM] Score changed from 0 to 1
|
||||||
|
[7/29/2026 1:27:58 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:28:02 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:28:08 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:28:15 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:28:23 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:28:28 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:28:35 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:28:39 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:28:52 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:28:55 PM] Score changed from 0 to 1
|
||||||
|
[7/29/2026 1:28:58 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:29:06 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:29:14 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:29:18 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:29:23 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:29:32 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:29:36 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:29:42 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:29:46 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:29:52 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:29:56 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:30:11 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:30:16 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:30:21 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:30:27 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:30:30 PM] Score changed from 1 to 2
|
||||||
|
[7/29/2026 1:30:33 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:30:40 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:30:45 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:30:50 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:30:55 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:31:01 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:31:03 PM] Score changed from 2 to 3
|
||||||
|
[7/29/2026 1:31:24 PM] Configured dedicated match reporting for match id 537 with secret 38516e39d3406225b7c3015a66e5d25c54e9b2024c0755212122bdcea3e3a328 and internal api base https://kkapi.playpoolstudios.com
|
||||||
|
[7/29/2026 1:31:24 PM] Client disconnected
|
||||||
|
[7/29/2026 1:31:28 PM] Starting client at $kkapi.playpoolstudios.com:26149
|
||||||
|
[7/29/2026 1:31:28 PM] Client connected
|
||||||
|
[7/29/2026 1:31:33 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:31:37 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:31:41 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:31:45 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:31:50 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:31:54 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:32:05 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:32:12 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:32:18 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:32:25 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:32:32 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:32:38 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:32:44 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:32:56 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:33:04 PM] Score changed from 0 to 1
|
||||||
|
[7/29/2026 1:33:07 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:33:16 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:33:22 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:33:31 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:33:40 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:33:43 PM] Score changed from 0 to 1
|
||||||
|
[7/29/2026 1:33:46 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:33:52 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:33:58 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:34:04 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:34:11 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:34:16 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:34:22 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:34:30 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:34:34 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:34:39 PM] Score changed from 1 to 2
|
||||||
|
[7/29/2026 1:34:42 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:34:47 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:34:54 PM] Selected team changed from Red to Blue
|
||||||
|
[7/29/2026 1:34:58 PM] Selected team changed from Blue to Red
|
||||||
|
[7/29/2026 1:35:12 PM] Score changed from 2 to 3
|
||||||
|
[7/29/2026 1:35:21 PM] Client disconnected
|
||||||
|
[7/29/2026 1:35:23 PM] Cupid settings updated
|
||||||
|
[7/29/2026 1:35:23 PM] Cupid settings updated
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d5d4b6e75e17172409ca64a1f41951a1
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -4421,7 +4421,7 @@ MonoBehaviour:
|
|||||||
m_OnCullStateChanged:
|
m_OnCullStateChanged:
|
||||||
m_PersistentCalls:
|
m_PersistentCalls:
|
||||||
m_Calls: []
|
m_Calls: []
|
||||||
m_Sprite: {fileID: 21300000, guid: 4297fad7619e3e8459accb93d1731a2c, type: 3}
|
m_Sprite: {fileID: 21300000, guid: 91a97bd203e9c8341b3cafd71fe62ef9, type: 3}
|
||||||
m_Type: 0
|
m_Type: 0
|
||||||
m_PreserveAspect: 0
|
m_PreserveAspect: 0
|
||||||
m_FillCenter: 1
|
m_FillCenter: 1
|
||||||
@@ -4636,7 +4636,7 @@ MonoBehaviour:
|
|||||||
preview: 0
|
preview: 0
|
||||||
isPlaying: 1
|
isPlaying: 1
|
||||||
loop: 1
|
loop: 1
|
||||||
currentFrame: 57
|
currentFrame: 76
|
||||||
--- !u!1 &239916595
|
--- !u!1 &239916595
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|||||||
+1941
-14
File diff suppressed because it is too large
Load Diff
@@ -96,10 +96,14 @@ public class Ball : NetworkBehaviour
|
|||||||
|
|
||||||
if(collision.collider.CompareTag("wall")){
|
if(collision.collider.CompareTag("wall")){
|
||||||
AudioManager.instance.PlayWallHit(vol);
|
AudioManager.instance.PlayWallHit(vol);
|
||||||
|
if (isServer)
|
||||||
|
ReplayRecorder.RecordHit("ball_wall", vol, this);
|
||||||
RpcWallHitAudio(vol);
|
RpcWallHitAudio(vol);
|
||||||
}
|
}
|
||||||
else if(collision.collider.CompareTag("Puck")){
|
else if(collision.collider.CompareTag("Puck")){
|
||||||
AudioManager.instance.PlayBallHit(vol);
|
AudioManager.instance.PlayBallHit(vol);
|
||||||
|
if (isServer)
|
||||||
|
ReplayRecorder.RecordHit("ball_puck", vol, this);
|
||||||
RpcBallHitAudio(vol);
|
RpcBallHitAudio(vol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ public class GameManager : NetworkBehaviour
|
|||||||
bool _dedicatedReportedRedJoin;
|
bool _dedicatedReportedRedJoin;
|
||||||
bool _dedicatedReportedBlueJoin;
|
bool _dedicatedReportedBlueJoin;
|
||||||
bool _dedicatedReportedGameOver;
|
bool _dedicatedReportedGameOver;
|
||||||
|
bool _replayRecordingStarted;
|
||||||
|
|
||||||
public static Action<Team> OnTeamChanged;
|
public static Action<Team> OnTeamChanged;
|
||||||
public static bool isMoving{
|
public static bool isMoving{
|
||||||
@@ -575,6 +576,14 @@ public class GameManager : NetworkBehaviour
|
|||||||
Logger.Log("Game started On Server");
|
Logger.Log("Game started On Server");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Host practice (tutorial) and dedicated matches both record once NetworkServer is ready.
|
||||||
|
// Retry until StartRecording succeeds — StartHost can lag one frame behind gameStarted.
|
||||||
|
if (gameStarted && !_replayRecordingStarted && NetworkServer.active)
|
||||||
|
{
|
||||||
|
if (ReplayRecorder.StartRecording(DedicatedMatchId, this))
|
||||||
|
_replayRecordingStarted = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateLocalTurnTimerBeep();
|
UpdateLocalTurnTimerBeep();
|
||||||
@@ -736,6 +745,7 @@ public class GameManager : NetworkBehaviour
|
|||||||
if(hitCounter == 1){
|
if(hitCounter == 1){
|
||||||
//kickoff goal
|
//kickoff goal
|
||||||
Logger.Log("Kickoff goal");
|
Logger.Log("Kickoff goal");
|
||||||
|
ReplayRecorder.RecordGoal(concedingTeam, redScore, blueScore, kickoff: true);
|
||||||
SetKickoffTeam(concedingTeam);
|
SetKickoffTeam(concedingTeam);
|
||||||
StartCoroutine(CoroutineOnGoal(team,true));//true = Kickoff goal, reset only the ball
|
StartCoroutine(CoroutineOnGoal(team,true));//true = Kickoff goal, reset only the ball
|
||||||
hitCounter = 0;
|
hitCounter = 0;
|
||||||
@@ -754,16 +764,19 @@ public class GameManager : NetworkBehaviour
|
|||||||
Logger.Log($"Red goal scored, red score is now {redScore}");
|
Logger.Log($"Red goal scored, red score is now {redScore}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReplayRecorder.RecordGoal(concedingTeam, redScore, blueScore, kickoff: false);
|
||||||
SetKickoffTeam(concedingTeam);
|
SetKickoffTeam(concedingTeam);
|
||||||
|
|
||||||
|
|
||||||
if(blueScore >= 3){
|
if(blueScore >= 3){
|
||||||
isGameEnded = true;
|
isGameEnded = true;
|
||||||
|
ReplayRecorder.StopAndFlush();
|
||||||
ReportDedicatedMatchGameOver(Team.Blue);
|
ReportDedicatedMatchGameOver(Team.Blue);
|
||||||
RpcGameOver(Team.Blue);
|
RpcGameOver(Team.Blue);
|
||||||
gameOver(Team.Blue);
|
gameOver(Team.Blue);
|
||||||
}else if(redScore >= 3){
|
}else if(redScore >= 3){
|
||||||
isGameEnded = true;
|
isGameEnded = true;
|
||||||
|
ReplayRecorder.StopAndFlush();
|
||||||
ReportDedicatedMatchGameOver(Team.Red);
|
ReportDedicatedMatchGameOver(Team.Red);
|
||||||
RpcGameOver(Team.Red);
|
RpcGameOver(Team.Red);
|
||||||
gameOver(Team.Red);
|
gameOver(Team.Red);
|
||||||
@@ -963,6 +976,7 @@ public class GameManager : NetworkBehaviour
|
|||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator CoroutineReset(bool kickoff = false){
|
IEnumerator CoroutineReset(bool kickoff = false){
|
||||||
|
ReplayRecorder.RecordReset(kickoff);
|
||||||
float resetDuration = 0.5f;
|
float resetDuration = 0.5f;
|
||||||
if(!kickoff){
|
if(!kickoff){
|
||||||
foreach(Puck puck in pucks){
|
foreach(Puck puck in pucks){
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ public class MainMenuManager : MonoBehaviour
|
|||||||
public GameObject gameModesScreen;
|
public GameObject gameModesScreen;
|
||||||
public GameObject dummyBuyScreen;
|
public GameObject dummyBuyScreen;
|
||||||
public GameObject withdrawalScreen;
|
public GameObject withdrawalScreen;
|
||||||
|
public GameObject settingsScreen;
|
||||||
|
|
||||||
[Header("Play")]
|
[Header("Play")]
|
||||||
public Button btnPlay;
|
public Button btnPlay;
|
||||||
public Button btnTutorial;
|
public Button btnTutorial;
|
||||||
@@ -338,6 +340,7 @@ public class MainMenuManager : MonoBehaviour
|
|||||||
gameModesScreen.SetActive(false);
|
gameModesScreen.SetActive(false);
|
||||||
dummyBuyScreen.SetActive(false);
|
dummyBuyScreen.SetActive(false);
|
||||||
withdrawalScreen.SetActive(false);
|
withdrawalScreen.SetActive(false);
|
||||||
|
settingsScreen.SetActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ShowGameModesScreen(){
|
public void ShowGameModesScreen(){
|
||||||
@@ -346,6 +349,7 @@ public class MainMenuManager : MonoBehaviour
|
|||||||
gameModesScreen.SetActive(true);
|
gameModesScreen.SetActive(true);
|
||||||
dummyBuyScreen.SetActive(false);
|
dummyBuyScreen.SetActive(false);
|
||||||
withdrawalScreen.SetActive(false);
|
withdrawalScreen.SetActive(false);
|
||||||
|
settingsScreen.SetActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ShowDummyBuyScreen(){
|
public void ShowDummyBuyScreen(){
|
||||||
@@ -354,6 +358,7 @@ public class MainMenuManager : MonoBehaviour
|
|||||||
gameModesScreen.SetActive(false);
|
gameModesScreen.SetActive(false);
|
||||||
dummyBuyScreen.SetActive(true);
|
dummyBuyScreen.SetActive(true);
|
||||||
withdrawalScreen.SetActive(false);
|
withdrawalScreen.SetActive(false);
|
||||||
|
settingsScreen.SetActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ShowWithdrawalScreen(){
|
public void ShowWithdrawalScreen(){
|
||||||
@@ -362,7 +367,17 @@ public class MainMenuManager : MonoBehaviour
|
|||||||
gameModesScreen.SetActive(false);
|
gameModesScreen.SetActive(false);
|
||||||
dummyBuyScreen.SetActive(false);
|
dummyBuyScreen.SetActive(false);
|
||||||
withdrawalScreen.SetActive(true);
|
withdrawalScreen.SetActive(true);
|
||||||
|
settingsScreen.SetActive(false);
|
||||||
UpdateWithdrawalStatus();
|
UpdateWithdrawalStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ShowSettingsScreen(){
|
||||||
|
statsPanel.SetActive(false);
|
||||||
|
mainMenuScreen.SetActive(false);
|
||||||
|
gameModesScreen.SetActive(false);
|
||||||
|
dummyBuyScreen.SetActive(false);
|
||||||
|
withdrawalScreen.SetActive(false);
|
||||||
|
settingsScreen.SetActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ public class NetManager : NetworkManager
|
|||||||
{
|
{
|
||||||
Application.logMessageReceived -= ForwardMirrorServerLogToLogger;
|
Application.logMessageReceived -= ForwardMirrorServerLogToLogger;
|
||||||
|
|
||||||
|
ReplayRecorder.StopAndFlush();
|
||||||
GameManager.ReportDedicatedMatchRoomClosed();
|
GameManager.ReportDedicatedMatchRoomClosed();
|
||||||
base.OnStopServer();
|
base.OnStopServer();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ public class Puck : NetworkBehaviour
|
|||||||
if (AudioManager.instance != null){
|
if (AudioManager.instance != null){
|
||||||
AudioManager.instance.PlayPuckHit(vol);
|
AudioManager.instance.PlayPuckHit(vol);
|
||||||
if(isServer){
|
if(isServer){
|
||||||
|
ReplayRecorder.RecordHit("puck_puck", vol, this);
|
||||||
RpcPuckHitAudio(vol);
|
RpcPuckHitAudio(vol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9cff4a867ddc05341bf42777b654509a
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,291 @@
|
|||||||
|
# Match Replay JSON Format
|
||||||
|
|
||||||
|
Guide for implementing the admin-panel replay viewer. Files are written by the Unity dedicated server (and practice host) to disk only.
|
||||||
|
|
||||||
|
## Where files live
|
||||||
|
|
||||||
|
Written next to the match log with the **same basename**, only the extension differs:
|
||||||
|
|
||||||
|
```
|
||||||
|
{ApplicationDirectory}/Logs/{matchId}.txt ← match log
|
||||||
|
{ApplicationDirectory}/Logs/{matchId}.json ← replay
|
||||||
|
```
|
||||||
|
|
||||||
|
| Match type | `matchId` | Example pair |
|
||||||
|
|------------|-----------|--------------|
|
||||||
|
| Ranked / dedicated | Positive matchmaker id | `Logs/228.txt` + `Logs/228.json` |
|
||||||
|
| Practice / tutorial | Negative unix timestamp | `Logs/-1769539200.txt` + `Logs/-1769539200.json` |
|
||||||
|
|
||||||
|
Admin panel: given a log at `Logs/{id}.txt`, load `Logs/{id}.json` beside it.
|
||||||
|
|
||||||
|
## Top-level object
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"matchId": 228,
|
||||||
|
"isPractice": false,
|
||||||
|
"fixedDeltaTime": 0.02,
|
||||||
|
"duration": 184.32,
|
||||||
|
"entities": [ /* ... */ ],
|
||||||
|
"frames": [ /* ... */ ],
|
||||||
|
"events": [ /* ... */ ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `version` | int | Schema version. Currently `1`. |
|
||||||
|
| `matchId` | int | Match id (positive = ranked, negative = practice). |
|
||||||
|
| `isPractice` | bool | `true` for localhost practice / tutorial host. |
|
||||||
|
| `fixedDeltaTime` | float | Physics step used while recording (typically `0.02` → ~50 Hz). |
|
||||||
|
| `duration` | float | Length of the recording in seconds (`t` of last sample / end). |
|
||||||
|
| `entities` | array | Ball + pucks. Order defines pose array indices in every frame. |
|
||||||
|
| `frames` | array | Time-ordered pose samples (~every FixedUpdate). |
|
||||||
|
| `events` | array | Time-ordered discrete events (hits, goals, resets). |
|
||||||
|
|
||||||
|
Time `t` everywhere is **seconds since recording start** (match start), not wall-clock UTC.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Entities
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "id": 0, "type": "ball", "team": "" }
|
||||||
|
{ "id": 1, "type": "puck", "team": "Red" }
|
||||||
|
{ "id": 2, "type": "puck", "team": "Blue" }
|
||||||
|
```
|
||||||
|
|
||||||
|
| Field | Type | Values |
|
||||||
|
|-------|------|--------|
|
||||||
|
| `id` | int | Stable index `0 .. N-1`. Matches array index in each frame’s `x`/`y`/`vx`/`vy`. |
|
||||||
|
| `type` | string | `"ball"` or `"puck"` |
|
||||||
|
| `team` | string | `"Red"`, `"Blue"`, or `""` for ball |
|
||||||
|
|
||||||
|
Entity list is fixed for the whole file. **Index `i` in a frame’s pose arrays always refers to `entities[i]`.**
|
||||||
|
|
||||||
|
Typical order: ball first, then pucks sorted by team then spawn position.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Frames (motion samples)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"t": 12.40,
|
||||||
|
"x": [0.0, 1.2, -0.5],
|
||||||
|
"y": [0.1, -0.3, 2.0],
|
||||||
|
"vx": [0.0, 3.1, -1.0],
|
||||||
|
"vy": [0.2, 0.0, 0.5]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `t` | float | Sample time in seconds (monotonic, increasing). |
|
||||||
|
| `x`, `y` | float[] | World position per entity (Unity 2D world units). |
|
||||||
|
| `vx`, `vy` | float[] | Linear velocity per entity at that sample (world units / second). |
|
||||||
|
|
||||||
|
- Array length always equals `entities.length`.
|
||||||
|
- Samples are dense (~`1 / fixedDeltaTime` Hz). Do **not** treat them as render frames.
|
||||||
|
|
||||||
|
### Coordinate system
|
||||||
|
|
||||||
|
Unity 2D world space:
|
||||||
|
|
||||||
|
- Origin at field center
|
||||||
|
- `+X` right, `+Y` up (as in Unity)
|
||||||
|
- Scale matches the in-game pitch (see game `fieldSize` / art for admin canvas mapping)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Events
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "t": 12.4, "type": "hit", "kind": "ball_wall", "vol": 0.6, "id": 0, "team": "", "redScore": 0, "blueScore": 0, "kickoff": false }
|
||||||
|
{ "t": 30.1, "type": "goal", "kind": "", "vol": 0, "id": -1, "team": "Blue", "redScore": 1, "blueScore": 0, "kickoff": false }
|
||||||
|
{ "t": 32.2, "type": "reset", "kind": "", "vol": 0, "id": -1, "team": "", "redScore": 0, "blueScore": 0, "kickoff": false }
|
||||||
|
```
|
||||||
|
|
||||||
|
All event objects share the same fields (Unity `JsonUtility` shape). Unused fields are empty / zero / `-1`.
|
||||||
|
|
||||||
|
| Field | Used by | Description |
|
||||||
|
|-------|---------|-------------|
|
||||||
|
| `t` | all | Event time in seconds. |
|
||||||
|
| `type` | all | `"hit"` \| `"goal"` \| `"reset"` |
|
||||||
|
| `kind` | `hit` | `"puck_puck"` \| `"ball_puck"` \| `"ball_wall"` |
|
||||||
|
| `vol` | `hit` | SFX volume `0..1` (from relative impact speed). |
|
||||||
|
| `id` | `hit` | Entity id involved (spatial cue). `-1` if unknown. |
|
||||||
|
| `team` | `goal` | **Conceding** side / goal owner (`"Red"` or `"Blue"`). The other team scored. |
|
||||||
|
| `redScore` | `goal` | Score after this goal. |
|
||||||
|
| `blueScore` | `goal` | Score after this goal. |
|
||||||
|
| `kickoff` | `goal`, `reset` | Kickoff-goal / kickoff-style reset when `true`. |
|
||||||
|
|
||||||
|
### Event semantics
|
||||||
|
|
||||||
|
| `type` | Meaning for the viewer |
|
||||||
|
|--------|-------------------------|
|
||||||
|
| `hit` | Play collision SFX at `vol`. Optional: flash near entity `id`. |
|
||||||
|
| `goal` | Goal scored against `team`. Update scoreboard to `redScore`/`blueScore`. Play goal SFX. **Discontinuity** — do not interpolate motion across this time. |
|
||||||
|
| `reset` | Pieces are lerping / teleporting back. **Discontinuity** — snap poses; do not blend across. |
|
||||||
|
|
||||||
|
First-to-3 wins; a completed match usually ends shortly after a goal that makes a score `3`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Playback contract (required for smooth motion)
|
||||||
|
|
||||||
|
Recording is FixedUpdate (~50 Hz). Snapping happens if the viewer steps sample-by-sample without blending. Follow this:
|
||||||
|
|
||||||
|
### 1. Drive time with wall clock
|
||||||
|
|
||||||
|
```text
|
||||||
|
playbackTime += (deltaMs / 1000) * playbackSpeed
|
||||||
|
playbackTime = clamp(playbackTime, 0, duration)
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `requestAnimationFrame` (or equivalent). Do **not** advance one JSON frame per rAF tick.
|
||||||
|
|
||||||
|
### 2. Interpolate poses between samples
|
||||||
|
|
||||||
|
Binary-search `frames` for neighbors where:
|
||||||
|
|
||||||
|
```text
|
||||||
|
frames[i].t <= playbackTime < frames[i+1].t
|
||||||
|
```
|
||||||
|
|
||||||
|
Then for each entity index `e`:
|
||||||
|
|
||||||
|
**Minimum (good):** linear lerp of `x`/`y`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
u = (playbackTime - t0) / (t1 - t0)
|
||||||
|
x = lerp(x0[e], x1[e], u)
|
||||||
|
y = lerp(y0[e], y1[e], u)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Recommended (smooth under acceleration):** cubic Hermite using velocities:
|
||||||
|
|
||||||
|
```text
|
||||||
|
dt = t1 - t0
|
||||||
|
u = (playbackTime - t0) / dt
|
||||||
|
u2 = u*u
|
||||||
|
u3 = u2*u
|
||||||
|
|
||||||
|
h00 = 2*u3 - 3*u2 + 1
|
||||||
|
h10 = u3 - 2*u2 + u
|
||||||
|
h01 = -2*u3 + 3*u2
|
||||||
|
h11 = u3 - u2
|
||||||
|
|
||||||
|
x = h00*x0 + h10*dt*vx0 + h01*x1 + h11*dt*vx1
|
||||||
|
y = h00*y0 + h10*dt*vy0 + h01*y1 + h11*dt*vy1
|
||||||
|
```
|
||||||
|
|
||||||
|
(Same for each entity index.)
|
||||||
|
|
||||||
|
### 3. Snap across discontinuities
|
||||||
|
|
||||||
|
Treat every `goal` and `reset` event as a cut:
|
||||||
|
|
||||||
|
- When `playbackTime` crosses that event’s `t`, **do not** interpolate from the previous sample across the cut.
|
||||||
|
- Seek to the frame at or immediately after `t` and snap positions.
|
||||||
|
|
||||||
|
Practical approach: build a sorted list of discontinuity times from events where `type === "goal" || type === "reset"`. If `t0` and `t1` straddle a discontinuity, snap to the post-cut sample instead of lerping.
|
||||||
|
|
||||||
|
### 4. Fire events once when crossed
|
||||||
|
|
||||||
|
Keep `lastEventIndex` (or last fired `t`). When `playbackTime` advances past an event’s `t`, fire it once:
|
||||||
|
|
||||||
|
- `hit` → SFX by `kind` / `vol`
|
||||||
|
- `goal` → score UI + goal audio
|
||||||
|
- `reset` → optional reset cue (usually silent)
|
||||||
|
|
||||||
|
On seek / scrub: reset event cursor; either skip SFX or replay only from the new time forward.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Suggested viewer pipeline
|
||||||
|
|
||||||
|
```text
|
||||||
|
Load JSON
|
||||||
|
→ map entities to sprites (ball / red pucks / blue pucks)
|
||||||
|
→ sort events by t (already ordered, but verify)
|
||||||
|
→ each animation frame:
|
||||||
|
advance playbackTime
|
||||||
|
resolve poses (Hermite + discontinuity snaps)
|
||||||
|
draw entities
|
||||||
|
dispatch newly crossed events
|
||||||
|
```
|
||||||
|
|
||||||
|
### Seeking / scrubbing
|
||||||
|
|
||||||
|
1. Set `playbackTime` to the scrub value.
|
||||||
|
2. Find the nearest frame (or interpolate as above).
|
||||||
|
3. Recompute score from the last `goal` event with `t <= playbackTime` (else `0–0`).
|
||||||
|
4. Reset the event-fire cursor to that time so SFX don’t spam.
|
||||||
|
|
||||||
|
### Scoreboard without scrubbing
|
||||||
|
|
||||||
|
Start at `0–0`. On each `goal` event, set scores from that event’s `redScore` / `blueScore`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Minimal TypeScript types
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export interface ReplayFile {
|
||||||
|
version: number;
|
||||||
|
matchId: number;
|
||||||
|
isPractice: boolean;
|
||||||
|
fixedDeltaTime: number;
|
||||||
|
duration: number;
|
||||||
|
entities: ReplayEntity[];
|
||||||
|
frames: ReplayFrame[];
|
||||||
|
events: ReplayEvent[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ReplayEntity {
|
||||||
|
id: number;
|
||||||
|
type: "ball" | "puck" | string;
|
||||||
|
team: "Red" | "Blue" | "" | string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ReplayFrame {
|
||||||
|
t: number;
|
||||||
|
x: number[];
|
||||||
|
y: number[];
|
||||||
|
vx: number[];
|
||||||
|
vy: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ReplayEvent {
|
||||||
|
t: number;
|
||||||
|
type: "hit" | "goal" | "reset" | string;
|
||||||
|
kind: "puck_puck" | "ball_puck" | "ball_wall" | "" | string;
|
||||||
|
vol: number;
|
||||||
|
id: number; // entity id, or -1
|
||||||
|
team: "Red" | "Blue" | "" | string; // conceding team on goal
|
||||||
|
redScore: number;
|
||||||
|
blueScore: number;
|
||||||
|
kickoff: boolean;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Checklist for a correct viewer
|
||||||
|
|
||||||
|
- [ ] Time driven by real elapsed time × speed, not frame index
|
||||||
|
- [ ] Poses interpolated between samples (Hermite preferred)
|
||||||
|
- [ ] No interpolation across `goal` / `reset`
|
||||||
|
- [ ] Entity index `i` always matches `entities[i]`
|
||||||
|
- [ ] Hit SFX use `kind` + `vol`
|
||||||
|
- [ ] Goal `team` means **conceding** side
|
||||||
|
- [ ] Practice files filtered via `isPractice` or negative `matchId`
|
||||||
|
|
||||||
|
## Out of scope (not in the JSON)
|
||||||
|
|
||||||
|
- Player names / user ids (use matchmaker / match API by `matchId` for ranked games)
|
||||||
|
- Camera / UI layout
|
||||||
|
- Launch aim lines / turn timer
|
||||||
|
- Network latency or client prediction
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8cced32e9b154814b99db72a5ae58c70
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a1b2c3d4e5f60718293a4b5c6d7e8f90
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Replay JSON DTOs for admin-panel playback.
|
||||||
|
/// Playback contract:
|
||||||
|
/// 1. Advance playbackTime with real time (scaled).
|
||||||
|
/// 2. Binary-search frames by t; Hermite-interpolate x/y using vx/vy between neighbors.
|
||||||
|
/// 3. On reset/goal events (discontinuities): snap to the sample at/after t — do not blend across.
|
||||||
|
/// 4. Fire SFX on hit/goal when playbackTime crosses event t.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public class ReplayFile
|
||||||
|
{
|
||||||
|
public int version = 1;
|
||||||
|
public int matchId;
|
||||||
|
/// <summary>True for localhost practice / tutorial host matches (no dedicated matchmaker id).</summary>
|
||||||
|
public bool isPractice;
|
||||||
|
public float fixedDeltaTime;
|
||||||
|
public float duration;
|
||||||
|
public ReplayEntity[] entities;
|
||||||
|
public ReplayFrame[] frames;
|
||||||
|
public ReplayEvent[] events;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class ReplayEntity
|
||||||
|
{
|
||||||
|
public int id;
|
||||||
|
/// <summary>"ball" or "puck"</summary>
|
||||||
|
public string type;
|
||||||
|
/// <summary>"Red", "Blue", or empty for ball</summary>
|
||||||
|
public string team;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class ReplayFrame
|
||||||
|
{
|
||||||
|
public float t;
|
||||||
|
public float[] x;
|
||||||
|
public float[] y;
|
||||||
|
public float[] vx;
|
||||||
|
public float[] vy;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class ReplayEvent
|
||||||
|
{
|
||||||
|
public float t;
|
||||||
|
/// <summary>"hit", "goal", or "reset"</summary>
|
||||||
|
public string type;
|
||||||
|
/// <summary>For hits: "puck_puck", "ball_puck", or "ball_wall"</summary>
|
||||||
|
public string kind;
|
||||||
|
public float vol;
|
||||||
|
/// <summary>Entity id for spatial cueing; -1 when N/A</summary>
|
||||||
|
public int id = -1;
|
||||||
|
/// <summary>For goals: conceding team ("Red"/"Blue")</summary>
|
||||||
|
public string team;
|
||||||
|
public int redScore;
|
||||||
|
public int blueScore;
|
||||||
|
public bool kickoff;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b2c3d4e5f60718293a4b5c6d7e8f901a
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,301 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using Mirror;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Server-only match recorder. Samples poses every FixedUpdate; flushes JSON to disk on stop.
|
||||||
|
/// Admin playback must interpolate by time (Hermite using velocity) — never snap one FixedUpdate sample per render frame.
|
||||||
|
/// </summary>
|
||||||
|
public class ReplayRecorder : MonoBehaviour
|
||||||
|
{
|
||||||
|
public static ReplayRecorder Instance { get; private set; }
|
||||||
|
|
||||||
|
public static bool IsRecording => Instance != null && Instance._recording && !Instance._flushed;
|
||||||
|
|
||||||
|
bool _recording;
|
||||||
|
bool _flushed;
|
||||||
|
int _matchId;
|
||||||
|
bool _isPractice;
|
||||||
|
float _startFixedTime;
|
||||||
|
float _duration;
|
||||||
|
|
||||||
|
readonly List<ReplayEntity> _entities = new List<ReplayEntity>();
|
||||||
|
readonly List<Rigidbody2D> _bodies = new List<Rigidbody2D>();
|
||||||
|
readonly Dictionary<int, int> _instanceIdToEntityId = new Dictionary<int, int>();
|
||||||
|
readonly List<ReplayFrame> _frames = new List<ReplayFrame>();
|
||||||
|
readonly List<ReplayEvent> _events = new List<ReplayEvent>();
|
||||||
|
|
||||||
|
/// <returns>True if recording started (or already recording this session).</returns>
|
||||||
|
public static bool StartRecording(int matchId, GameManager gm)
|
||||||
|
{
|
||||||
|
if (!NetworkServer.active || gm == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Instance == null)
|
||||||
|
{
|
||||||
|
var go = new GameObject("ReplayRecorder");
|
||||||
|
DontDestroyOnLoad(go);
|
||||||
|
Instance = go.AddComponent<ReplayRecorder>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Instance.Begin(matchId, gm);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void StopAndFlush()
|
||||||
|
{
|
||||||
|
if (Instance != null)
|
||||||
|
Instance.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RecordHit(string kind, float vol, Component source)
|
||||||
|
{
|
||||||
|
if (!IsRecording)
|
||||||
|
return;
|
||||||
|
Instance.AddHit(kind, vol, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RecordGoal(Team concedingTeam, int redScore, int blueScore, bool kickoff)
|
||||||
|
{
|
||||||
|
if (!IsRecording)
|
||||||
|
return;
|
||||||
|
Instance.AddEvent(new ReplayEvent
|
||||||
|
{
|
||||||
|
t = Instance.CurrentT(),
|
||||||
|
type = "goal",
|
||||||
|
kind = "",
|
||||||
|
vol = 0f,
|
||||||
|
id = -1,
|
||||||
|
team = concedingTeam.ToString(),
|
||||||
|
redScore = redScore,
|
||||||
|
blueScore = blueScore,
|
||||||
|
kickoff = kickoff
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RecordReset(bool kickoff)
|
||||||
|
{
|
||||||
|
if (!IsRecording)
|
||||||
|
return;
|
||||||
|
Instance.AddEvent(new ReplayEvent
|
||||||
|
{
|
||||||
|
t = Instance.CurrentT(),
|
||||||
|
type = "reset",
|
||||||
|
kind = "",
|
||||||
|
vol = 0f,
|
||||||
|
id = -1,
|
||||||
|
team = "",
|
||||||
|
redScore = 0,
|
||||||
|
blueScore = 0,
|
||||||
|
kickoff = kickoff
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryGetEntityId(Component source, out int entityId)
|
||||||
|
{
|
||||||
|
entityId = -1;
|
||||||
|
if (Instance == null || source == null)
|
||||||
|
return false;
|
||||||
|
return Instance._instanceIdToEntityId.TryGetValue(source.gameObject.GetInstanceID(), out entityId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Begin(int matchId, GameManager gm)
|
||||||
|
{
|
||||||
|
if (_recording && !_flushed)
|
||||||
|
Flush();
|
||||||
|
|
||||||
|
// Practice / tutorial host uses DedicatedMatchId 0 — mint a unique id so files don't overwrite.
|
||||||
|
_isPractice = matchId <= 0 || GameTutorialManager.tutorialModeEnabled;
|
||||||
|
if (matchId <= 0)
|
||||||
|
matchId = GeneratePracticeMatchId();
|
||||||
|
|
||||||
|
_matchId = matchId;
|
||||||
|
_recording = true;
|
||||||
|
_flushed = false;
|
||||||
|
_startFixedTime = Time.fixedTime;
|
||||||
|
_duration = 0f;
|
||||||
|
_entities.Clear();
|
||||||
|
_bodies.Clear();
|
||||||
|
_instanceIdToEntityId.Clear();
|
||||||
|
_frames.Clear();
|
||||||
|
_events.Clear();
|
||||||
|
|
||||||
|
// Keep log + replay siblings: Logs/{matchId}.txt and Logs/{matchId}.json
|
||||||
|
if (_isPractice)
|
||||||
|
Logger.SetFileName(_matchId.ToString());
|
||||||
|
|
||||||
|
BuildEntities(gm);
|
||||||
|
string mode = _isPractice ? "practice" : "match";
|
||||||
|
Logger.Log($"ReplayRecorder started ({mode}) id {_matchId} with {_entities.Count} entities");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Negative unix timestamp so practice ids never collide with positive matchmaker ids.</summary>
|
||||||
|
static int GeneratePracticeMatchId()
|
||||||
|
{
|
||||||
|
long unix = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||||
|
if (unix > int.MaxValue)
|
||||||
|
unix %= int.MaxValue;
|
||||||
|
int id = -(int)unix;
|
||||||
|
return id == 0 ? -1 : id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildEntities(GameManager gm)
|
||||||
|
{
|
||||||
|
if (gm.ball != null)
|
||||||
|
{
|
||||||
|
RegisterEntity(gm.ball.gameObject, gm.ball, "ball", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
var sorted = new List<Puck>(gm.pucks);
|
||||||
|
sorted.Sort((a, b) =>
|
||||||
|
{
|
||||||
|
int teamCmp = a.team.CompareTo(b.team);
|
||||||
|
if (teamCmp != 0)
|
||||||
|
return teamCmp;
|
||||||
|
int xCmp = a.transform.position.x.CompareTo(b.transform.position.x);
|
||||||
|
if (xCmp != 0)
|
||||||
|
return xCmp;
|
||||||
|
return a.transform.position.y.CompareTo(b.transform.position.y);
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (Puck puck in sorted)
|
||||||
|
{
|
||||||
|
if (puck == null || puck.rb == null)
|
||||||
|
continue;
|
||||||
|
RegisterEntity(puck.gameObject, puck.rb, "puck", puck.team.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterEntity(GameObject go, Rigidbody2D rb, string type, string team)
|
||||||
|
{
|
||||||
|
int id = _entities.Count;
|
||||||
|
_entities.Add(new ReplayEntity { id = id, type = type, team = team ?? "" });
|
||||||
|
_bodies.Add(rb);
|
||||||
|
_instanceIdToEntityId[go.GetInstanceID()] = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
float CurrentT() => Time.fixedTime - _startFixedTime;
|
||||||
|
|
||||||
|
void FixedUpdate()
|
||||||
|
{
|
||||||
|
if (!_recording || _flushed || !NetworkServer.active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int n = _bodies.Count;
|
||||||
|
if (n == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var frame = new ReplayFrame
|
||||||
|
{
|
||||||
|
t = CurrentT(),
|
||||||
|
x = new float[n],
|
||||||
|
y = new float[n],
|
||||||
|
vx = new float[n],
|
||||||
|
vy = new float[n]
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
Rigidbody2D rb = _bodies[i];
|
||||||
|
if (rb == null)
|
||||||
|
continue;
|
||||||
|
Vector2 pos = rb.position;
|
||||||
|
Vector2 vel = rb.linearVelocity;
|
||||||
|
frame.x[i] = pos.x;
|
||||||
|
frame.y[i] = pos.y;
|
||||||
|
frame.vx[i] = vel.x;
|
||||||
|
frame.vy[i] = vel.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
_duration = frame.t;
|
||||||
|
_frames.Add(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddHit(string kind, float vol, Component source)
|
||||||
|
{
|
||||||
|
int entityId = -1;
|
||||||
|
if (source != null)
|
||||||
|
_instanceIdToEntityId.TryGetValue(source.gameObject.GetInstanceID(), out entityId);
|
||||||
|
|
||||||
|
AddEvent(new ReplayEvent
|
||||||
|
{
|
||||||
|
t = CurrentT(),
|
||||||
|
type = "hit",
|
||||||
|
kind = kind ?? "",
|
||||||
|
vol = vol,
|
||||||
|
id = entityId,
|
||||||
|
team = "",
|
||||||
|
redScore = 0,
|
||||||
|
blueScore = 0,
|
||||||
|
kickoff = false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddEvent(ReplayEvent ev)
|
||||||
|
{
|
||||||
|
_events.Add(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Flush()
|
||||||
|
{
|
||||||
|
if (!_recording || _flushed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_flushed = true;
|
||||||
|
_recording = false;
|
||||||
|
_duration = Mathf.Max(_duration, CurrentT());
|
||||||
|
|
||||||
|
var file = new ReplayFile
|
||||||
|
{
|
||||||
|
version = 1,
|
||||||
|
matchId = _matchId,
|
||||||
|
isPractice = _isPractice,
|
||||||
|
fixedDeltaTime = Time.fixedDeltaTime,
|
||||||
|
duration = _duration,
|
||||||
|
entities = _entities.ToArray(),
|
||||||
|
frames = _frames.ToArray(),
|
||||||
|
events = _events.ToArray()
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string path = ResolveReplayFilePath();
|
||||||
|
string json = JsonUtility.ToJson(file);
|
||||||
|
File.WriteAllText(path, json);
|
||||||
|
Logger.Log($"ReplayRecorder wrote {path} ({_frames.Count} frames, {_events.Count} events, duration {_duration:F2}s)");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Log("ReplayRecorder flush failed: " + e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Same directory and basename as the match log, extension <c>.json</c>
|
||||||
|
/// (e.g. <c>Logs/228.txt</c> → <c>Logs/228.json</c>).
|
||||||
|
/// </summary>
|
||||||
|
string ResolveReplayFilePath()
|
||||||
|
{
|
||||||
|
string expectedName = _matchId.ToString();
|
||||||
|
string logPath = Logger.instance != null ? Logger.instance.LogFilePath : null;
|
||||||
|
if (!string.IsNullOrEmpty(logPath))
|
||||||
|
{
|
||||||
|
string logBase = Path.GetFileNameWithoutExtension(logPath);
|
||||||
|
if (logBase == expectedName)
|
||||||
|
return Path.ChangeExtension(logPath, ".json");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Path.Combine(Logger.GetLogsDirectory(), expectedName + ".json");
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnDestroy()
|
||||||
|
{
|
||||||
|
if (Instance == this)
|
||||||
|
{
|
||||||
|
Flush();
|
||||||
|
Instance = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c3d4e5f60718293a4b5c6d7e8f901a2b
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -19,6 +19,7 @@ public class FrameAnimator : MonoBehaviour
|
|||||||
bool m_previewPlaying = false;
|
bool m_previewPlaying = false;
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
double m_lastEditorTime = 0d;
|
double m_lastEditorTime = 0d;
|
||||||
|
bool m_editorHooked;
|
||||||
#endif
|
#endif
|
||||||
Image m_img;
|
Image m_img;
|
||||||
Image img {
|
Image img {
|
||||||
@@ -42,19 +43,19 @@ public class FrameAnimator : MonoBehaviour
|
|||||||
void OnEnable()
|
void OnEnable()
|
||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
if (!Application.isPlaying)
|
// Never hook editor updates during play-mode enter/exit — QueuePlayerLoopUpdate
|
||||||
{
|
// + isPlaying serialized true can infinite-reload Temp/__Backupscenes.
|
||||||
m_lastEditorTime = EditorApplication.timeSinceStartup;
|
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
|
||||||
EditorApplication.update -= OnEditorUpdate;
|
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
||||||
EditorApplication.update += OnEditorUpdate;
|
TryHookEditorUpdate();
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnDisable()
|
void OnDisable()
|
||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
EditorApplication.update -= OnEditorUpdate;
|
UnhookEditorUpdate();
|
||||||
|
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
void Start()
|
void Start()
|
||||||
@@ -80,23 +81,71 @@ public class FrameAnimator : MonoBehaviour
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
void OnEditorUpdate()
|
void OnPlayModeStateChanged(PlayModeStateChange state)
|
||||||
{
|
{
|
||||||
if (Application.isPlaying || this == null || !isActiveAndEnabled)
|
if (state == PlayModeStateChange.ExitingEditMode ||
|
||||||
|
state == PlayModeStateChange.EnteredPlayMode ||
|
||||||
|
state == PlayModeStateChange.ExitingPlayMode)
|
||||||
{
|
{
|
||||||
|
m_previewPlaying = false;
|
||||||
|
UnhookEditorUpdate();
|
||||||
|
}
|
||||||
|
else if (state == PlayModeStateChange.EnteredEditMode)
|
||||||
|
{
|
||||||
|
TryHookEditorUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TryHookEditorUpdate()
|
||||||
|
{
|
||||||
|
if (Application.isPlaying || EditorApplication.isPlayingOrWillChangePlaymode)
|
||||||
|
{
|
||||||
|
UnhookEditorUpdate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_editorHooked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_lastEditorTime = EditorApplication.timeSinceStartup;
|
||||||
|
EditorApplication.update += OnEditorUpdate;
|
||||||
|
m_editorHooked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnhookEditorUpdate()
|
||||||
|
{
|
||||||
|
if (!m_editorHooked)
|
||||||
|
return;
|
||||||
|
EditorApplication.update -= OnEditorUpdate;
|
||||||
|
m_editorHooked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnEditorUpdate()
|
||||||
|
{
|
||||||
|
if (Application.isPlaying ||
|
||||||
|
EditorApplication.isPlayingOrWillChangePlaymode ||
|
||||||
|
this == null ||
|
||||||
|
!isActiveAndEnabled)
|
||||||
|
{
|
||||||
|
UnhookEditorUpdate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Edit-mode animation is preview-only. Ignoring serialized isPlaying prevents
|
||||||
|
// permanent editor loops when isPlaying was left true in the scene.
|
||||||
|
if (!m_previewPlaying)
|
||||||
|
return;
|
||||||
|
|
||||||
double now = EditorApplication.timeSinceStartup;
|
double now = EditorApplication.timeSinceStartup;
|
||||||
float dt = (float)(now - m_lastEditorTime);
|
float dt = (float)(now - m_lastEditorTime);
|
||||||
m_lastEditorTime = now;
|
m_lastEditorTime = now;
|
||||||
|
|
||||||
if (dt <= 0f)
|
if (dt <= 0f)
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
|
int frameBefore = currentFrame;
|
||||||
TickAnimation(dt);
|
TickAnimation(dt);
|
||||||
|
if (currentFrame != frameBefore || m_previewPlaying)
|
||||||
EditorApplication.QueuePlayerLoopUpdate();
|
EditorApplication.QueuePlayerLoopUpdate();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -108,7 +157,9 @@ public class FrameAnimator : MonoBehaviour
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool shouldAnimate = m_previewPlaying || isPlaying;
|
bool shouldAnimate = Application.isPlaying
|
||||||
|
? (m_previewPlaying || isPlaying)
|
||||||
|
: m_previewPlaying;
|
||||||
if (!shouldAnimate)
|
if (!shouldAnimate)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|||||||
+2
-2
@@ -10,7 +10,7 @@ MonoBehaviour:
|
|||||||
m_Enabled: 1
|
m_Enabled: 1
|
||||||
m_EditorHideFlags: 0
|
m_EditorHideFlags: 0
|
||||||
m_Script: {fileID: 15003, guid: 0000000000000000e000000000000000, type: 0}
|
m_Script: {fileID: 15003, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
m_Name: "New Android\u2122 Profile"
|
m_Name: Android
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
m_AssetVersion: 1
|
m_AssetVersion: 1
|
||||||
m_BuildTarget: 13
|
m_BuildTarget: 13
|
||||||
@@ -23,7 +23,7 @@ MonoBehaviour:
|
|||||||
- m_enabled: 1
|
- m_enabled: 1
|
||||||
m_path: Assets/Scenes/MainMenu.unity
|
m_path: Assets/Scenes/MainMenu.unity
|
||||||
- m_enabled: 1
|
- m_enabled: 1
|
||||||
m_path: Assets/Scenes/Proto.unity
|
m_path: Assets/Scenes/Game.unity
|
||||||
m_ScriptingDefines: []
|
m_ScriptingDefines: []
|
||||||
m_PlayerSettingsYaml:
|
m_PlayerSettingsYaml:
|
||||||
m_Settings:
|
m_Settings:
|
||||||
+1
-1
@@ -10,7 +10,7 @@ MonoBehaviour:
|
|||||||
m_Enabled: 1
|
m_Enabled: 1
|
||||||
m_EditorHideFlags: 0
|
m_EditorHideFlags: 0
|
||||||
m_Script: {fileID: 15003, guid: 0000000000000000e000000000000000, type: 0}
|
m_Script: {fileID: 15003, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
m_Name: New Linux Server Profile 1
|
m_Name: Server
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
m_AssetVersion: 1
|
m_AssetVersion: 1
|
||||||
m_BuildTarget: 24
|
m_BuildTarget: 24
|
||||||
Reference in New Issue
Block a user