Persistent Data - How to save your game states and settings | Unite Now 2020

แชร์
ฝัง
  • เผยแพร่เมื่อ 27 ต.ค. 2024

ความคิดเห็น • 132

  • @ian_snyder
    @ian_snyder 4 ปีที่แล้ว +43

    These videos always come up right AFTER I spent days banging my head against an issue 😂 I like to tell myself I learned a lot in the process 😜

  • @stesproject
    @stesproject 4 ปีที่แล้ว +21

    I really needed a video like this 3 years ago, when I started using Unity. I remember I struggled a lot to build a save/load system for my game. After watching the video I'm happy to see I've done a good job. I developed a pretty similar system :)

  • @gagang4286
    @gagang4286 4 ปีที่แล้ว +7

    I was just finding the best ways to save my app data and then this video comes in. Looking forward to use Json to do so for now.

  • @Bletzkarn
    @Bletzkarn 4 ปีที่แล้ว +11

    One of the better tutorials I've seen on Unity channel. I think these generalised tutorials make for very strong content.

  • @clarkmeyer7211
    @clarkmeyer7211 3 ปีที่แล้ว +7

    players prefs is exactly self explanatory though. you use it for your preferences such as volume, sensitivity, keybinds etc. things that don't have any game breaking impact if edited.

  • @Xenobicus
    @Xenobicus 4 ปีที่แล้ว +2

    Great content covering the options and explanations/reasoning to help choose the correct route- Please keep making content like this.. and consider zooming in on the code for easier readability in the video for future tutorials. Thank you!

  • @aldigangster123
    @aldigangster123 4 ปีที่แล้ว +8

    I really appreciate the effort and Saving / Serialization is definitely something Unity should put out more tutorials. But this one failed to deliver any knowledge imo. Even as someone with basic knowledge of JSON serialization, this was horrible to follow or understand. Long breaks without speech while silently commenting out code. No explanation of each function, or its lines. FileManager? I've seen much better explanations from random TH-camrs and would expect a lot more from Unity. Sorry if this is a bit harsh.

    • @nathanielguggenheim5522
      @nathanielguggenheim5522 4 ปีที่แล้ว

      I would like to have mention the drawbacks. This does not work on spawned enemies. Everything saved must come with the scene.
      Also if the scene changes in case of a patch, this solution breaks. Consider a new enemy is in the patch. He will probably get the id of the enemy right after him and so on. All saved data on and after this enemy will be corrupted. And now imagine enemies with different data. Crash.
      As long as there is no way to produce an unique Id taking more information into account (e.g. spawn position, time, whatever) data cannot be reproduced in case anything changes (scene).

  • @ZacharyAghaizu
    @ZacharyAghaizu 3 ปีที่แล้ว

    great timing! was convinced to buy the easy save and it's nice

  • @dmitrypriadko4409
    @dmitrypriadko4409 2 ปีที่แล้ว

    Just what I needed! Thanks! And the guy should not be so nervous) Great job!

  • @512Squared
    @512Squared 2 ปีที่แล้ว

    Really enjoyed your presentation, clarity and explanations. Really pulled all the stuff I've been reading and watching together. 👍🍻

  • @stefan429
    @stefan429 4 ปีที่แล้ว +1

    Very nice :) not many vids covering my preferred ways to save

  • @dryrunhd
    @dryrunhd 2 ปีที่แล้ว +2

    Great video. So then in the scenario where we have a game and we're keeping important player data on a remote server, and we're heeding the advice of not trusting anything the game client says, what's the right way to do user auth such that they're reliably retrieving their own save data?

  • @Ziplock9000
    @Ziplock9000 3 ปีที่แล้ว +8

    4:40 If your registry is being corrupted, you have much bigger problems that saving to files won't fix.

  • @coolkidllama1483
    @coolkidllama1483 หลายเดือนก่อน

    this video is great, but i would like to see a video of someone using these things starting from a blank project and start with variable data, then go up the list. like a name and ID system that saves the stuff would be nice.

  • @gegenton3953
    @gegenton3953 4 ปีที่แล้ว

    I would appreciate more content on server side saving as in "actual implementation". JSON and PlayerPrefs are both relatively easy to understand while server side saving requires some more thinking ahead. Expecially mobile integration would be interesting, e. g. for offline states of the player.
    Thanks for that overview, though! Great presentation!

    • @gegenton3953
      @gegenton3953 4 ปีที่แล้ว

      @@bronsonzgeb5651 Thanks for the detailed answer! I guess I'll have to have a look at the server docs more properly then ;) Was thinking about an off the shelf solution for android using the PlayStore built-in options, but maybe that doesn't even exist? At least now I have some starting points, thanks!

    • @gegenton3953
      @gegenton3953 4 ปีที่แล้ว

      @@bronsonzgeb5651 I kinda am, yes. Just some simple systems that are cheat-proof. E. g. running a small game look (Tetris, Snake, etc.) locally but saving the (high-)score directly on the server. The score itself can savely be stored, I'm sure, but is it generated safely enough to prevent cheating? These kind of things currently grind my gears ;) Looking forward to more content of yours on persistent data, then :)

    • @gegenton3953
      @gegenton3953 4 ปีที่แล้ว

      @@bronsonzgeb5651 Well, that's a great idea. In my special case I can think of some parameters right away ;) Thanks a ton!

  • @Gers217
    @Gers217 4 ปีที่แล้ว +1

    I'm a simple man I saw Vscode and I give a like to the video

  • @512Squared
    @512Squared 2 ปีที่แล้ว +1

    There are some complaints in this thread about things not being clear, of pieces missing - if you have any questions, just reply and I can answer them. I got this working just fine.

    • @beneuser1220
      @beneuser1220 2 ปีที่แล้ว

      I have the problem, that I don't know how to set up the UUID for my enemies. How did you do that?

    • @512Squared
      @512Squared 2 ปีที่แล้ว

      @@beneuser1220 attach this script to all your enemies:
      ​using​ ​UnityEngine​;
      ​[​ExecuteAlways​]
      ​public​ ​class​ ​GenerateGUID​ : ​MonoBehaviour
      ​{
      ​ [​SerializeField​]
      ​ ​private​ ​string​ ​_gUID​ ​=​ ​"​"​;
      ​ ​public​ ​string​ ​GUID​ { ​get​ ​=>​ ​_gUID​; ​set​ ​=>​ ​_gUID​ ​=​ ​value​; }
      ​ ​private​ ​void​ ​OnValidate​()
      ​ {
      ​ ​//​ Only populate in the editor
      ​ ​if​ (​!​Application​.​IsPlaying​(​gameObject​))
      ​ {
      ​ ​//​ Ensure the object has a guaranteed unique id
      ​ ​if​ (​_gUID​ ​==​ ​"​"​)
      ​ {
      ​ ​//​Assign GUID
      ​ ​_gUID​ ​=​ ​System​.​Guid​.​NewGuid​().​ToString​();
      ​ }
      ​ }
      ​ }

    • @512Squared
      @512Squared 2 ปีที่แล้ว +1

      @@beneuser1220 you can then set up a GUID string field in your main enemy class and retrieve the GUID by putting this in your Start:
      private string _enemyGuid;
      void Start()
      {
      _enemyGuid = GetComponent().GUID;
      }

    • @512Squared
      @512Squared 2 ปีที่แล้ว

      @@beneuser1220 You can be call you GUID variable UUID if you want, makes no difference, idea is the same. GUID is generally understood to be Microsoft's implementation of UUID, though there can be subtle differences in GUID standard Vs RFC4122 UUID, but not anything you need to think about.
      Let me know if you got this working - you'll need to either call the Save and Load methods via Awake, Start or OnDestroy, or via UI buttons, depending on your preference and game style.

    • @512Squared
      @512Squared 2 ปีที่แล้ว

      @@beneuser1220 Just remember that a prefab will be given the same GUID if you don't unpack it first. If you are instantiating via a prefab, you can assign the GUID at that point through script. I also use a button (Odin.Inspector) in the Inspector for resetting the GUID when I unpack the prefab. If you don't have Odin, you could create your own custom drawer for this - shouldn't be too difficult.

  • @mrp0001
    @mrp0001 4 ปีที่แล้ว +15

    Should have had timestamps

    • @mrp0001
      @mrp0001 4 ปีที่แล้ว

      @@bronsonzgeb5651 oh, great!

  • @KalechippsDev
    @KalechippsDev 2 ปีที่แล้ว

    Awesome tutorial, practical and succinct. Thanks!

  • @afrakes4510
    @afrakes4510 3 ปีที่แล้ว

    a bit complicated for a noob. I wish you would have used a more clear cut example for the unityJson. It was helpful to get a good understanding of how it works, but im finding it difficult to apply it while learning to code. nicely done, just above my head. intermediate+

  • @mintydog06
    @mintydog06 4 ปีที่แล้ว +3

    Maybe it's just me, but I couldn't really follow the JSON example. I can't see what files/classes you are looking at and how they are connected.

  • @page0809
    @page0809 3 ปีที่แล้ว

    Awesome tutorial on save data! Thank you!

  • @XnecromungerX
    @XnecromungerX 3 ปีที่แล้ว

    Thank you so much for making this video

  • @yudnai5577
    @yudnai5577 2 ปีที่แล้ว +1

    how did you Create the Uuid? i see you use it in many places. did you build it by yourself or with unity build in class?

    • @usz1444
      @usz1444 2 ปีที่แล้ว

      it's built-in C#. string guid = System.Guid.NewGuid().ToString(); (using System;)

  • @hungnong3760
    @hungnong3760 3 ปีที่แล้ว +1

    thankiu this is what i need

  • @spotonmusic7554
    @spotonmusic7554 4 ปีที่แล้ว +3

    What's inside the FileManager class? He didn't mention it.

    • @spotonmusic7554
      @spotonmusic7554 4 ปีที่แล้ว

      @@bronsonzgeb5651 ok, thanks a lot.

  • @StarkTech47
    @StarkTech47 3 ปีที่แล้ว

    Very strong save system, it's a pleasure to follow the different steps but for the Uuid, how did you do to make them persistent. I have been working on it for many days and I don't find a way to do it.

  • @salmanalsaffar8040
    @salmanalsaffar8040 2 ปีที่แล้ว +1

    the problem with jsonutillty that if you updated a value in will update all the other values in the json file

  • @ooDEFENDERoo
    @ooDEFENDERoo 4 ปีที่แล้ว +1

    Thank you so much!

  • @yudnai5577
    @yudnai5577 2 ปีที่แล้ว

    Unity should buy easy save like they did with Bolt.!!! saving a lot of problems for people using the engine.

  • @Paanch_Tanmatra_Studio
    @Paanch_Tanmatra_Studio 3 ปีที่แล้ว +4

    Amazing tutorial.
    I also have a save system playlist series.
    It covers from player-pref to Firebase.
    I am currently editing the video with NodeJS as the back-end server for saving data.
    Any feedback on it will be really helpful.

  • @RedstoneinventeArmoredGuy
    @RedstoneinventeArmoredGuy 3 ปีที่แล้ว +1

    what is the LoadFromFile ? What data type is it? Cannot access it

  • @gokayakcay7093
    @gokayakcay7093 3 ปีที่แล้ว +5

    Am I the only one who don't have filemanager in Unity ??

    • @QvsTheWorld
      @QvsTheWorld 3 ปีที่แล้ว +2

      It's a custom class with 2 static methods, WriteToFile and LoadFromFile. He starts his explanation at 17:25 .
      Here is what it looks like.
      public class FileManager {
      public static bool WriteToFile(string a_filename, string a_filecontent) {
      var fullPath = Path.Combine(Application.persistentDataPath, a_filename);
      try {
      File.WriteAllText(fullPath, a_filecontent);
      return true;
      } catch (Exception e) {
      Debug.LogError("Fail to write to " + fullPath + " exception:" + e);
      }
      return false;
      }
      public static bool LoadFromFile(string a_filename, out string result) {
      var fullPath = Path.Combine(Application.persistentDataPath, a_filename);
      try {
      result = File.ReadAllText(fullPath);
      return true;
      } catch (Exception e) {
      Debug.LogError("Fail to read from " + fullPath + " exception:" + e);
      result = "";
      return false;
      }
      }
      }

    • @carrotcat5940
      @carrotcat5940 2 ปีที่แล้ว +1

      @@QvsTheWorld hippity hoppety that code is now my property

  • @jamescampbell1622
    @jamescampbell1622 2 ปีที่แล้ว +3

    To understand this tutorial, you must already know 90% of what he's attempting to explain. Does not write or explain why or how most things work. Shows snippets of code with no references on what makes them work. Hopefully this helps the more advanced pupils.

  • @GUYX10
    @GUYX10 2 ปีที่แล้ว +1

    found this very unclear. basicly what i got from this tutorial was "copy paste my code dont worry how to works".

  • @Gmania999
    @Gmania999 4 ปีที่แล้ว +1

    Please tell me the name of your color theme (VS), looks nice to my eyes.
    By the way, why not store data at the binary level? Using Protobuf.Serialize() ? like a
    [ProtoBuf.ProtoContract]
    public struct Data
    {
    [ProtoBuf.ProtoMember(1)]
    public string UUID;
    [ProtoBuf.ProtoMember(2)]
    public int M_Data1;
    [ProtoBuf.ProtoMember(3)]
    public int M_Data2;
    }
    This will improve the performance of the game, you can also put the UUID in the file name.

    • @Gmania999
      @Gmania999 4 ปีที่แล้ว

      @@bronsonzgeb5651 Thanks!

  • @greggalloway6410
    @greggalloway6410 3 ปีที่แล้ว

    Was this edited to cut out the time Unity is saving/reloadind when hitting play? I'm just wondering if I'm missing a setting that'll save me hours of my life.

  • @donnewcomb3547
    @donnewcomb3547 2 ปีที่แล้ว

    Thank you great video! question? how would you load Json data between scenes? I made a start menu, but as soon as I load my scene from, the menu I created, I receive compiler errors. however if I load the same data staring from the scene I'm trying to load, instead of the menu scene, it works perfectly???
    I would appreciate some help upstanding this, but regardless. thank you for a wonderful tutorial

  • @gilleswalther5964
    @gilleswalther5964 4 ปีที่แล้ว

    Very helpful thanks

  • @Ziplock9000
    @Ziplock9000 3 ปีที่แล้ว

    JSON compact? It's an ASCII or Unicode representation of simple types that uses a lot more space

  • @faiz7180
    @faiz7180 3 ปีที่แล้ว

    How to save the data after adding new features to my game? Like when users download an update from playstore and then keep users old data. Is the method shown in this video work?

  • @Talha-hg4sl
    @Talha-hg4sl 3 ปีที่แล้ว

    How to save data on server load pls make a video on this or any guidance

  • @divyanthj
    @divyanthj 4 ปีที่แล้ว +1

    Where is FileManager? where do I import it from?

    • @albertmontagutcasero2129
      @albertmontagutcasero2129 4 ปีที่แล้ว +2

      FileManager of the video is a class that the teacher has coded. He explains how at min 17:27. It is not from the engine namespaces.

    • @albertmontagutcasero2129
      @albertmontagutcasero2129 4 ปีที่แล้ว

      @@bronsonzgeb5651 Thank you for requesting the links, for sure it will be helpful! Congratz on the video!

  • @alex_steed8472
    @alex_steed8472 4 ปีที่แล้ว +1

    Is there any advantages to using sqllite? I have lots of data. Mostly structured.

    • @pt8306
      @pt8306 4 ปีที่แล้ว +2

      JSON is a tree structure, SQL is a flat table structure. If your data is more tabular in nature (like how some RPGs have a lot of flat tables for things like XP gains), you might have an easier time using sqlite. If you want objects to take care of themselves, JSON can easily store all their information in the same structure as your C# class, which is very nice. If you instead want a very centralised data model where everything needs to have lightning-fast access to a centralised data store, sqlite is the way to go.

  • @duckriddle3340
    @duckriddle3340 2 หลายเดือนก่อน

    Both asset store links leads to Easy Save :(

  • @joaohudsonlacerdaoliveira5253
    @joaohudsonlacerdaoliveira5253 4 ปีที่แล้ว +1

    Wouldn't serializing in binary be another good option?

    • @duramirez
      @duramirez 2 ปีที่แล้ว

      É basicamente o que eu faço, criei uma biblioteca minha mesmo que salva tudo em uma cadeia de bytes organizados hehehe Consome muito menos espaço em disco porque não tem overhead né.

  • @mjaada
    @mjaada 4 ปีที่แล้ว +8

    or another alternative on lootboxes, don't add them at all!

  • @cydu
    @cydu 2 ปีที่แล้ว

    Error with Path and File does not exist in the current content

  • @nathanielguggenheim5522
    @nathanielguggenheim5522 4 ปีที่แล้ว

    As far as I've read, there is no way to produce an unique Id. So you can also just register all enemies in a list in Awake() and save this list. If an enemy was Destroyed, the list entry is null, so you save a 'Destroyed' information for that index. So your uuID saves no purpose.
    But both solutions cannot handle spawned enemies. All you can save here must come with the scene. Any ideas of how to address this problem?

  • @pt8306
    @pt8306 4 ปีที่แล้ว +1

    How am I supposed to give every savable object in my game a UUID that is always the same every time the game is loaded? I can't just assign a UUID in the constructor and I don't want to have to assign it one in the inspector. They need to have a consistent UUID so when I save/load their data it's associated with the correct entity.

    • @saniel2748
      @saniel2748 4 ปีที่แล้ว

      You could do
      [SerializeField] string uuid = System.Guid.NewGuid().ToString(); in class as default value, so every time it'll set new guid, which is not likely to overlap. I did it myself, seems to work

    • @pt8306
      @pt8306 4 ปีที่แล้ว

      @@saniel2748 I guess. Can I use [HideInInspector] too since I don't want it to be seen by my artists?

    • @saniel2748
      @saniel2748 4 ปีที่แล้ว +1

      @@pt8306 i would recommend making your own attribute because HideInInspector is not visible even in debug view
      But technically yes, you can

    • @pt8306
      @pt8306 4 ปีที่แล้ว

      @@saniel2748 how can I detect debug mode in my editor script?

    • @saniel2748
      @saniel2748 4 ปีที่แล้ว

      @@pt8306 I mean switching the inspector to debug view

  • @evenprime1658
    @evenprime1658 3 ปีที่แล้ว

    so i use json to save data but i made a encryption system to encrypt the keys using some sketchy algorithm imade.. is it safe or is it easily reversable because its json

    • @donkeykong315
      @donkeykong315 11 หลายเดือนก่อน

      Any data on a player's computer should be considered as accessible/modifiable by the player.

  • @simpson6700
    @simpson6700 3 ปีที่แล้ว

    i just want to know how to change the save location... as a player i hate it when games save in appdata.

  • @skorm043
    @skorm043 4 ปีที่แล้ว

    what about using scriptable objects for saving game data?

  • @MohammadFaizanKhanJ
    @MohammadFaizanKhanJ 4 ปีที่แล้ว

    I was thinking playerprefs save data into file in data folder of the build.

  • @Gurem
    @Gurem 2 ปีที่แล้ว

    How to save animation data so the player can load mid attack animation

  • @oliverwigren163
    @oliverwigren163 3 ปีที่แล้ว

    how do you access/find the savedata.dat file on mac?

  • @ohj6878
    @ohj6878 2 ปีที่แล้ว

    What is "FileManager" please
    its doesn't exist and callback an error

    • @usz1444
      @usz1444 2 ปีที่แล้ว

      this tutorial is weirdly cut but what you want is in 17:30 and 17:55. just create new class FileManager and add these 2 methods

    • @ohj6878
      @ohj6878 2 ปีที่แล้ว

      @@usz1444 thx but still some value that are unsigned even in this class .. "Path" and "File" in 17,30 doesn't exist

    • @cydu
      @cydu 2 ปีที่แล้ว

      @@ohj6878 Same error

  • @insidiousmaximus
    @insidiousmaximus 2 ปีที่แล้ว +2

    this is some kind of spaghetti tutorial so many things not explained uncommenting all this code from earlier, no mention of interfaces, gameviewconroller etc, you dont teach people like that, you demonstrate with the most simple example to outline the flow. Then build complexity on top of that. This is a mess.

  • @ElDonitazz
    @ElDonitazz 3 ปีที่แล้ว

    I'll be the one making Unity related videos yelling, rainbows and explosions. Mark that down.

  • @ThatRazzy
    @ThatRazzy 2 ปีที่แล้ว

    Does anyone know how to delete the JSON save data upon starting a new game?

    • @donkeykong315
      @donkeykong315 11 หลายเดือนก่อน

      You could just save an empty file on the same filepath.

  • @trod146
    @trod146 4 ปีที่แล้ว

    Why do so many people from Unity whisper at points in these videos?...

  • @IronFreee
    @IronFreee 4 ปีที่แล้ว +1

    Player Prefs is really dirty in windows, it will write data in the registry. Just make a Json (or XML) in any case.
    Why dictionary can't be serialized?
    For Assets (Item sprites...), the best way to do it is to put them in the "Resources" folder and name them with an ID system. Then check if they exist when loading your data to avoid error. It's very error prone, but it's easy and Unity offers no solution.

    • @IronFreee
      @IronFreee 4 ปีที่แล้ว

      @@bronsonzgeb5651 Thank you for the tip, I will try that. It sound good :D (Will be easier to maintain)

  • @ayan3789
    @ayan3789 4 ปีที่แล้ว

    Unity please make tutorials for ragdolls!

    • @pt8306
      @pt8306 4 ปีที่แล้ว

      Turn off IsKinematic on your model, make sure it has a rigidbody. Ragdolls should work fine

    • @ayan3789
      @ayan3789 4 ปีที่แล้ว

      @@pt8306 ragdoll movement?

    • @pt8306
      @pt8306 4 ปีที่แล้ว

      Why is your ragdoll moving?

    • @ayan3789
      @ayan3789 4 ปีที่แล้ว

      @@pt8306 ragdoll movement and balance scripts, i cant find any good tutorials

    • @pt8306
      @pt8306 4 ปีที่แล้ว

      @@ayan3789 Normally you don't want to balance ragdolls. Instead you want to set them to kinematic movement and control them directly (with no physics), then "trigger" ragdolling by letting the rigidbody take over

  • @evilmind5178
    @evilmind5178 2 ปีที่แล้ว

    So you still use hungarian notation.... well.

  • @brunopinheirobrazil5352
    @brunopinheirobrazil5352 4 ปีที่แล้ว

    Is it okay for us to only use PlayerPrefs to save data? Or we could lose it somehow?

    • @mrp0001
      @mrp0001 4 ปีที่แล้ว +1

      It's not really good, involves a lot of strings and has other issues.

  • @Lurkness
    @Lurkness 2 ปีที่แล้ว +5

    Horrific tutorial, find another video. Uncommenting out code surrounded by unrelated functions looks bad. Hearing every small sound and keystroke is bad. What really blows me away is you make a reference to custom code, and explain it AT THE END OF THE SECTION. I don't think there's a nice way to put how inept that is. You breeze right past introducing FileManager to the extent I rewatched this thing from the start a few times to see if you included it, instead it was 17 minutes in. Random comments had to point this out.
    Please delist this, it should not be a top result from google.

  • @sillygoose8037
    @sillygoose8037 2 ปีที่แล้ว

    Nice content.

  • @duramirez
    @duramirez 2 ปีที่แล้ว +1

    I don't know if you are eating something or if it's gum, but it is super annoying and distracting. >_

  • @ohj6878
    @ohj6878 2 ปีที่แล้ว +1

    the guy who did the same tuto in 2014 was far far better than this one this tuto is bad he do anything
    only show an already filled game its bad

  • @junpinox1574
    @junpinox1574 2 ปีที่แล้ว

    honestly couldnt finish the video. 7 minutes in and there was just too much smacking/swallowing/mouth noises.

  • @thomlaurent
    @thomlaurent 3 ปีที่แล้ว

    With the length of the video I hope I would have learned something.
    It could be shrinked down to 10 minutes with montage or maybe 5 minutes if rushed.

  • @_g_r_m_
    @_g_r_m_ 3 ปีที่แล้ว +2

    that's probably one of the worst tutorials ever made

  • @Lurkness
    @Lurkness 24 วันที่ผ่านมา

    Update. This awful developer no longer works at unity and went on to make the most beginner game I've ever seen. No wonder this engine and company fell through, this guy was making their tools.

  • @Jake-yy9fg
    @Jake-yy9fg 3 ปีที่แล้ว

    it doesn't even explain how to implement playerprefs so this is a total waste of time.

  • @Athomield3D
    @Athomield3D 4 ปีที่แล้ว

    Binaryformatter (ie binary files) work for me

  • @marshallwyatterb
    @marshallwyatterb 11 หลายเดือนก่อน

    this was a very poor tutorial. someone should redo this using the actual example files

  • @vaultt309
    @vaultt309 ปีที่แล้ว +1

    This is deadAss some "draw the rest of the owl" bullshit

  • @eysn
    @eysn 3 ปีที่แล้ว

    That mouth ASMR is really distracting when you have good headphones.
    Edit: 7 minutes in and I'm clawing at my face.