Godot 4 Tutorial - The Message Bus Pattern

แชร์
ฝัง
  • เผยแพร่เมื่อ 23 ม.ค. 2025

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

  • @donoteatmikezila
    @donoteatmikezila ปีที่แล้ว +32

    My man really rocking Windows 7 in the year of our lord 2023.

    • @gamegems7658
      @gamegems7658  ปีที่แล้ว +10

      I have some software that I used for a long time that wasn't compatible with 10, so I never upgraded.

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

      @@gamegems7658 just curious, what is that software?

    • @smbazi
      @smbazi 6 หลายเดือนก่อน +1

      First thing I noticed, best windows ever

  • @oliverkuss139
    @oliverkuss139 ปีที่แล้ว +48

    You should always add „if old_value == new_value: return“ to the beginning of all setters. Not only will it reduce unnecessary load, it will also automatically break circles between nodes that sync each other (like UI elements that reflect properties and that can also change the properties). This is also how the property changed signals in QML work.

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

      Indeed, and thanks for the reminder. I will most likely touch on this in my Volume Sliders tutorial, because it *is* an issue.

  • @jupitersky
    @jupitersky 4 หลายเดือนก่อน +2

    Fantastic tutorial. It conveys the bare minimum of information for understanding, then leaves. Nothing about syntax, or any of the detailed stuff I can find in the documentation, just the raw structure, basic workflow, and general design pointers. Thank you so much for making this!

    • @gamegems7658
      @gamegems7658  4 หลายเดือนก่อน +1

      You're very welcome!

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

    This is truly a gem.
    I think this problem with signals should be addressed by the Godot devs somewhere in the future.

    • @gamegems7658
      @gamegems7658  ปีที่แล้ว +20

      To be fair, it's not a signal problem. Passing object references around has been an issue for object-oriented programming since C++ was invented. It's why we have dozens of different patterns all solving the problem in different ways. Godot's signals are the subscriber pattern, same as they are in half-a-dozen other languages like C# or Java. Try adding an event handler to a button in Android from outside its containing class and you'll still need to walk the chain, same as you do in Godot.

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

    The best tutorial I have found on the concept. Simple and direct, and honest about it's shortcomings.

  • @AkaiKnight
    @AkaiKnight ปีที่แล้ว +13

    It's also useful for having a centralized place where you can control the flow of data for things like settings in your games menu.

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

      Good call! That'll be touched on in my next video on options sliders.

  • @Than.
    @Than. ปีที่แล้ว +5

    This channel is a gem

  • @WarrenMarshallBiz
    @WarrenMarshallBiz ปีที่แล้ว +9

    I LOVE this pattern, use it all the time, and will die on this hill. :) I previously worked with someone who swore up and down that it was bad programming and a terrible pattern. We don't work together anymore.

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

      Ain't nobody got time for that

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

      I don't think it's necessarily bad, but it can cause issues with debugging as your project scales if not used properly.

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

    Thank you for this video, I went through the documentation and didn't quite grasp the explanation but this helped me figure out what I was misunderstanding right away. I'm writing a visible checkpoint system where the on-body contact is supposed to update all other nodes of the same type to not be the primary one. A message bus is the perfect solution for getting them to all acknowledge their status without talking to each other.

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

      Glad it helped!

  • @Afreshio
    @Afreshio ปีที่แล้ว +13

    oh this channel seems promising

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

    I was considering implementing *exactly* this, and wanted to check if there is a trick somewhere I missed. Thanks for the video.

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

    This is great! I can tell this channel is going places!

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

    Thank you for this! I had no idea that I was already doing it back in the day in C# using static Actions as I have no idea about design patterns, but my main issue with that is there's no reliable way to disconnect an event.
    But it looks fantastic in Godot, as I also found out that signals get auto-disconnected when freeing a Node! I can't wait to try this out properly on my game :)

    • @gamegems7658
      @gamegems7658  ปีที่แล้ว

      The equivalent in C# is weak references, but I forget if delegates/events use them by default.

  • @blaaahization
    @blaaahization 11 หลายเดือนก่อน +2

    Thanks for the video! I would use constants instead of magic strings though, makes your life a lot easier.

    • @gamegems7658
      @gamegems7658  10 หลายเดือนก่อน +3

      If you're referring to the signal and function names, I accidentally used the 3.5 syntax instead of 4.0's out of habit. Some things just stick with you!

  • @ince55ant
    @ince55ant ปีที่แล้ว

    this is one of those videos that i should probably watch in a year. Godot still feels weird and new so cant really picture if this works best for what
    (currently researching different methods for bullet collision)

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

      Generally speaking, there's very little reason for a bullet collision to need to be handled in any way other than a simple _on_body_entered signal. You might want to check out the Message Bus pattern video for an easy way to handle signals to larger game systems beyond that.

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

    From there, maybe implement an event-driven architecture. Add to the message bus 3 signals "emitter", "timestamp or flag" and "payload" and broadcast to every nodes, then each node is free to register to specific emitters or publish an event. I don't remember the name or where i saw this pattern.
    For example a log node would store any events.

    • @valeriyatua
      @valeriyatua ปีที่แล้ว

      Close to the choreography

  • @albertpougnol7656
    @albertpougnol7656 ปีที่แล้ว

    wow a big thanks for this vidéo, i was struggle a lot for retrieve a signal from an instanced object and this workflow made the trick !

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

    Finally, I found a second person who uses this pattern!
    There are even more neat tricks you can do with this. For example, this is my menu overlay (the part that's there for every menu):
    func _ready():
    Bus.pause.connect(show)
    Bus.unpause.connect(hide)
    This is the AudioStream for the "bling!" when picking up stuff:
    func _ready():
    Bus.item_pickup.connect(_on_pickup)
    func _on_pickup(item, _player):
    position = item.position
    play()
    Very minimal code, no component needs to know anything about any other. the item pickup signal has plenty more consumers, none of them knows anything about any other.

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

      Great point about Singleton-based audio managers. Just about every professional project I've worked on - in either Godot or Unity - have made use of them.

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

    thank you, this is INCREDIBLY useful

  • @walkastray007
    @walkastray007 ปีที่แล้ว

    I found your channel recently and please never change how you explain or deliver the thoughts and ideas
    I like how you gave a problem and then explained how this pattern solves said problem.
    Also the length of the video. It was brief, yet comprehensive. I dont even have a use for this design pattern but I'll use it in my life for the sake of it!
    So many channels nowadays have really long explanations, or they overly edit their videos, or try to force memes where they dont work. I also find channels have pretty dull voices that suck the life out of me to listen to. You have the tone of a friend showing someone something cool!
    If you ever do make a game, or plan on making Devlogs, or plan on making a series on whatever, im really down!

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

      I make games professionally. As you can imagine, that monopolizes my programming time! I do have plans for a few in-depth series, so we'll see what happens.

    • @walkastray007
      @walkastray007 ปีที่แล้ว

      @@gamegems7658 take as long as you need! It's hard to find quality tutorials or explanations these days. But even if you managed to do 1 video a month I would still watch them. 😁

  • @brenocogu
    @brenocogu ปีที่แล้ว

    Thanks for the video, really helpful and didatic!
    In a note, perhaps the issue regarding a extense script with all events can be solved by breaking down each of the "Messeger" functionality in smaller batches
    "PlayerMesseger" - "EnemyMesseger" etc
    And then use the "Messeger" one to access those (just one auto-load).

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

      You're totally allowed to break up the Messenger into smaller bus objects for organizational purposes, and a lot of development teams do just that.

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

    Great video, perfect timing, just as I stated thinking about alert system in my stealth game)

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

    This is an great explanation. I thought signals were like radio broadcasts but I assume they are more like telephone wires connecting things.

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

      Signals are like radio broadcasts, but you have to "tune in" (IE, connect) to them for it to matter. Either analogy works. Just know that signals will only be processed by nodes that are connected and listening for them.

  • @Gureenu
    @Gureenu 11 หลายเดือนก่อน +1

    that windows 7 bar sent me back in time

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

    I have a problem with this. There are some nodes/scripts from where I can emit signals, but there are other that I cannot. Does someone could help me with this?

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

    Great alternative is using groups, so, for example, the player can check if its bullet raycast hit anything in the group "enemies" and if so, it can assume that the enemy implements a certain interface and call the hit function on that enemy. Personally I prefer keeping the UI in the player scene. That way level creation is just designing the map, dropping in the player and the enemies, and no need to connect any signals.

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

      Hitscan weapons definitely benefit from groups, yes. For level creation - and I have a video planned for this - I load levels/scenes into a "master" scene that never gets unloaded that also contains the UI.

    • @elverman
      @elverman ปีที่แล้ว

      @@gamegems7658 Why have a master scene with the UI? I mean, it seems more sensible to swap out as much as possible when changing scenes in case you have a sneaky memory leak somewhere. It's also simpler that way and it's easier to test individual levels. I try to keep the bare minimum in globals. Keeping the UI with the player scene also lets me have different player scenes for different maps, so I could easily have a 2D platforming map followed by a top-down racing map, for example. Inject some variety into the experience.

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

      Keep in mind that it depends on your architecture, but there are a lot of reasons to minimize what you unload, and if you provide default/bootstrap data for essentials like Autoloads, you can still test your scenes individually.
      The main reason I keep stuff in a singular master scene is to allow for things like loading screens and common UI - after all, your pause menu and such has to go somewhere, and if your scenes get large enough there'll be a noticeable hitch in your transition as the new assets load unless you mask it somehow.
      There are also other ways to assign the correct UI to a scene, like I explain in my NodePaths video. You can just drop the relevant UI into an exported variable.

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

    I use this pattern so much in my current project! is "message bus" a common name for the pattern or is it coined in this video? either way, I'm glad this video exists, because it really really cleans up my game's codebase. if I want to make a new UI element or something based on the general game state, it can be done super easily and completely decoupled from everything else.
    anyways, great video! subscribed :D

    • @gamegems7658
      @gamegems7658  ปีที่แล้ว +9

      I wish I could take credit for it, but the message bus pattern has been a part of networking concepts in computer science for probably longer than I've been alive... and I'm older than dirt.

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

      Can also be called Event Bus. But no, not coined in this video. There is a more elegant way to implement it than shown in this video, but I'm not sure if GDScript supports it tbh as I use C# in my Godot projects.

  • @en7622
    @en7622 ปีที่แล้ว

    I can actually follow along with what is happening! And that is saying something!

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

    One quick suggestion, make the event bus with signals using a custom resource; singletons/autoloads introduce tight coupling and cohesion.

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

      The odds of that ever actually being an issue in a commercial project is basically zero. Don't over-engineer for the sake of being clever.

  • @magefreak9356
    @magefreak9356 ปีที่แล้ว

    Great video. Short and sweet

  • @seyproductions
    @seyproductions ปีที่แล้ว

    Wow, this is pretty enlightening.

  • @perfectionbox
    @perfectionbox ปีที่แล้ว

    Neat, the C++ Mediator pattern in Godot.

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

    I have a question to ask, at 3:39 your health and ammo variables have code under where you have declared them, what exactly do those lines of codes do, and where should i use it? Its the first time i have seen something like that before
    Besides that, great video! I hope your channel grows bigger as it deserves to

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

      Those are setter methods. They're functions that get called whenever you assign a new value to a variable. In this case, we're using them to automatically fire a signal whenever we change that value, and that signal is what tells the UI to update.
      docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_basics.html#properties-setters-and-getters

  • @francescobigblak
    @francescobigblak ปีที่แล้ว

    Found It usefull! So i liked and subscribed

  • @Portitforward
    @Portitforward ปีที่แล้ว

    Subbed for the pub-sub. Thanks for the breakdown!

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

    personally I like to call my global event handler a "train" (because it deals with signals) instead of bus
    (I know, I know, bus is an ubiquitous name far outside game dev too....)

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

    My biggest issue with Godot is really node references.
    Where in Unity you can link nodes together in the inspector. And Unity makes a hard link so no matter where they component / game object is located in the tree. It's always accessible by its handle.
    This is how I've gotten used to doing things. But it also comes with its own set of issues.
    NodePath does something similar. But like you said. Change the scene and now everything is broken.
    Signalling looks like an ok workaround, but it is identical to BroadcastMesage in unity. Which is also classified as an anti pattern.
    Don't know what the grand idea is. Is there a secret I'm missing. Having nodes talk to each other seems to be discouraged?

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

      There's a lot to unpack here, but these are all great questions.
      Nodes are very much encouraged to talk to each other, which is why Godot implements the Observer pattern via Signals. "Call down, signal up" is a phrase you may have heard before. What it means is that a parent node should directly call the methods of its child, but the child should send signals upward along the node chain in order to not break encapsulation.
      The reason BroadcastMessage is an anti-pattern is because it sends the same message to EVERY object in the tree, and it's the object's responsibility to either handle it, or not. Neither a generic signal nor the Message Bus pattern does this; only nodes connected to the signal receive it, and it's the exact same thing as Unity's delegates or Java's event handlers.
      As for NodePaths, they do exactly what Unity's object references do... and it's funny, because both object references and Singletons - if my time in the trenches as a Unity developer is any indication, Unity devs LOVE 'em - were both widely considered bad practice back in the day, so there's that. Anyway, NodePaths are a bit misunderstood by typical/beginner Godot devs. If you export a variable of type NodePath, you can assign a node to it in the Inspector and *even if you move the node in the scene tree*, the reference won't break, same as in Unity. (I just tested it in 3.5 to make doubly sure before I posted this). The problem is, most Godot devs don't do that; they litter their code with dollar signs and work with hard-coded node paths.
      The reason I avoid such hard links is because I do a lot of dynamic spawning/instantiation in my projects and very often need to connect nodes via code, so object references rarely work for me. Like anything else in computer science, though, whether or not it's appropriate for you depends on the needs of your own project and your own preferences.
      So, in short, I think the "secret" is that you were laboring under some misinformation. That's OK, though; the Godot tutorial community is very incestuous and propagates a lot of bad practices because everyone copies one another. That's one of the reasons I'm here.
      Thanks for commenting!

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

      You're not supposed to use nodepaths, you're supposed to use [Export]/@export on your fields.

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

      Same thing. You need to export the node paths variables so that they're available in the inspector.
      I'm going to cover this in my next video, stay tuned!

    • @majorgnu
      @majorgnu ปีที่แล้ว

      Look up "Scene Unique Nodes" in the Godot documentation and see if that solves your woes with things breaking with changing scene structures.

  • @octagone.
    @octagone. 10 หลายเดือนก่อน

    in this case, i want the messenger to emit the signal when the enemy dies, how do i do that ? i have been trying to figure this out for 3 hours and nothing makes sense. cant i make the messenger receive a signal and then emit something else ? all i want to do is to add xp to an xp counter that the player has when a mob dies

    • @gamegems7658
      @gamegems7658  10 หลายเดือนก่อน +1

      You're complicating things by adding extra steps. The Messenger should not need to receive messages from other nodes. If you want to award XP when a mob dies, define a signal in the messenger called AWARD_XP(amount) and then in your mob script, emit that signal via Messenger.AWARD_XP.emit(amount). Other nodes can then connect to that signal to be notified that the XP is awarded, such as your XP tracker.

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

    Great video, ty!
    One question - is there any difference between placing this into autoload vs attaching it to a node in a main scene that is never unloaded?

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

      There are a few differences, yes. Autoloads are, as the name implies, automatically loaded, so you don't have to write any code to query the node and obtain a reference to it yourself. They're also always available by name, so any child node of your main scene can use them without needing either a reference to the node path of your top-level node or having to query it itself. You *can* do this yourself, as you describe, but it's easier and more convenient to let the engine handle it for you.

  • @Dudex11a
    @Dudex11a ปีที่แล้ว

    Aside from being more explicit, what's the difference between using Message Buses and Groups?

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

      The Message Bus is a centralized implementation of the Observer pattern, which is built in to Godot via signals. Groups simply allow you to grab a bunch of objects based on some tag or another.
      While they're functionally similar in that you can totally loop through all the objects in a group and call a particular method on them rather than fire a signal and expect the object to subscribe to it, as with everything else in computer science whether you need one or the other totally depends on your architecture. One difference is that connecting a signal allows you to define the signal's handler method explicitly, whereas using groups requires all of the objects in the group to implement the same method.
      Another difference is that in a distributed development environment, when more than one person is working on a project, signals allow scripts to be completely divorced from one another, whereas groups require one to know about the other in at least the most superficial sense. In the case of a solo developer, it totally comes down to preference.

    • @Dudex11a
      @Dudex11a ปีที่แล้ว

      ​@@gamegems7658 I really like your explanation here! When I said explicit earlier I was not think of the "allows you to define the signal's handler method explicitly" point. I might change some code I have from using Groups to a Message Bus because of how you explained it here. Thank you!

  • @DrNabeel20
    @DrNabeel20 ปีที่แล้ว

    this is amazing, thanks 🎉

  • @rremnar
    @rremnar ปีที่แล้ว

    I never thought of it this way, but I already do this in my project. I have a capsule object that dynamically changes its color and texture. When the player object collides with it, it an do a variety of things depending on the capsule type set by another event. To take care of this, I created a class in the script and set as a autoload, to handle these things as I needed to acces from other objects than just the player. The capsule script defines the signals and takes care of some of them itself. The level node handles some, the player node handles some, and other objects too. That way when the event happens, the signal is handled at the appropriate places, and sometimes more than 1 place and behavior for the same signal.

  • @LightningMcCream
    @LightningMcCream ปีที่แล้ว

    Its funny, i find myself gravitating to this pattern before I even knew the pattern existed.
    must be a multiplayer thing, who knows

  • @soirema
    @soirema ปีที่แล้ว

    this is just soo good its criminal o.O

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

    Nice pattern, but it does highlight the clash of Godot's philosophies;
    1. If something can exist in it's own scene, it should.
    2. Use Signals to communicate instead of hard coding a reference.
    This bugs me because when you have to connect a signal which is outside the immediate scene it effectively is a hard reference as you need to reference the node.

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

      It's not so much that you shouldn't hard-code references as it is that you should link them in ways that aren't dependent on the tree structure. I'm working on a video now that explains that in a bit more detail.

  • @skilletborne
    @skilletborne ปีที่แล้ว

    Based on what you said, is it not possible to have several message buses responsible for different parts of the game?
    Feels like that would be able to both give you some more general information about the signal and help organize your code.
    Really awesome tutorial, btw
    I knew I was going to need something like this, so having it confirmed to me what it is and how to implement it makes me feel just a little smarter for the noob I am

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

      You are definitely not limited to one Autoload, regardless of what you need them for. Breaking them up by function is definitely a good idea from an organizational standpoint.

    • @pythonxz
      @pythonxz ปีที่แล้ว

      ​@@gamegems7658Yeah, I think the advantage of breaking them up would help with debugging.

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

    This sounds like a singleton pattern

    • @gamegems7658
      @gamegems7658  ปีที่แล้ว +6

      That's correct. Autoload scripts are Godot's implementation of the Singleton pattern.

  • @niklu4038
    @niklu4038 ปีที่แล้ว

    cool, thanks!

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

    I defintely see the usefulness of this, but I'm also having difficulty wrapping my head around where the implementation, and where the functions go ^^; . Time for ore research.

    • @gamegems7658
      @gamegems7658  5 หลายเดือนก่อน +1

      The Message Bus itself is literally just an autoloaded Godot script, and you connect to its signals just as you would any other. It's done this way so that it doesn't *matter* where the functions go.

  • @akam9919
    @akam9919 ปีที่แล้ว

    are you still on the golden version of windows (7)?

    • @gamegems7658
      @gamegems7658  ปีที่แล้ว

      Yes, for the longest time I was using software that didn't run under 10 so I didn't upgrade.

  • @sslaxx
    @sslaxx ปีที่แล้ว

    Completely unrelated, but... Blue cup huh? Did you ever use AGS?

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

      Yes! I was active in the AGS community nearly 20 years ago. The logo is just a coincidence, though.

  • @Szmergolloth
    @Szmergolloth ปีที่แล้ว

    It looks really useful, thank you. But can you say something about performance of this way? I can force any scene to call a method in another scene just like another_scene.method(), or I can use your way. Which one have better performace result?

    • @gamegems7658
      @gamegems7658  ปีที่แล้ว +9

      I addressed the notion of directly calling other scenes' methods in the video when I mentioned that you could just walk back up the scene tree and find the nodes you needed manually. As your projects grow in complexity you'll find out the hard way why it's not a good idea. Regardless, this is not the part of your game where you need to care about performance. In fact, I'd go so far as to say that amateur programmers worry about performance *way* too much. If your game isn't causing framerate drops or stuttering then you don't need to care. And when you *do* need to care, I can guarantee you that the performance issues won't be in a one-shot method call or signal emission, it'll be somewhere in your game logic that's looping every frame.
      If I had to hazard a guess, though, I'd say performance would be about the same for either. You're still firing off a callback or directly calling a function either way, which is basically the same thing.

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

    2:07
    I spent 30 minutes trying to figure out WHY you changed "HELLO_WORLD" to "SAY_HELLO" only to realise only HELLO_WORLD works....

    • @gamegems7658
      @gamegems7658  10 หลายเดือนก่อน +2

      Yep, I'm guaranteed to notice at least one error in any video I make shortly after I upload it. I may also have accidentally used the old signal syntax at some point, as well.
      Regardless, the intent of this video is not to teach you how to connect or emit signals, it's to show you how to use them with autoloaded scripts.

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

      @@gamegems7658 Nah its still a GREAT vid just pointing it out for others.

  • @lucasabratti598
    @lucasabratti598 ปีที่แล้ว

    Is... is that... IS THAT WINDOWS 7?! 😍😍

    • @happygofishing
      @happygofishing ปีที่แล้ว

      Could be a Linux skin

    • @gamegems7658
      @gamegems7658  ปีที่แล้ว

      Only his hairdresser knows for sure...

  • @ritzenhauf
    @ritzenhauf ปีที่แล้ว

    This seems smart, but isn't working for me. I can only get one connection to receive for some reason, regardless where I test other connections. Completely flummoxed. v4.1.3