Oberon_Command

Members
  • Content count

    4119
  • Joined

  • Last visited

Community Reputation

6103 Excellent

About Oberon_Command

  • Rank
    Contributor

Personal Information

  • Interests
    Design
    Programming
  1. Cant find how to do this asm code in c++...

    What is this function trying to accomplish, exactly? edit: Never mind, read the comment above it.
  2. How to learn from Quake source code

    No, we do not all agree. Windows without DirectX is still very much usable. In fact, the parts of DirectX that aren't Direct3D are deprecated, so really "DirectX" nowadays means "Direct3D". I don't know of anyone using DirectInput, DirectSound was replaced with XAudio2 which is theoretically succeeded by WASAPI, and DirectMusic doesn't even have complete documentation available anymore! Even if we didn't have Direct3D, we'd have OpenGL, Vulkan, and Mantle (on AMD cards). And this is just talking about hardware access APIs - never mind the support for multicore computing and virtual memory and bigger address spaces and other such nice things. Using a 32 (now 64-bit, for the most part) OS confers advantages beyond merely those provided by DirectX. I'm a little fuzzy on what you think DOS does better, because from where I'm standing, running Windows 10 in November 2017, it does nothing better. I'm furthermore not sold on the relevance of this discussion to Quake, apart from "Quake originally used DOS" - which is true, but also meaningless, since it's been ported to multiple OSs since then, including Windows (twice!).
  3. How to learn from Quake source code

    We have the tools now. We shouldn't keep around practices that are built around obsolete development paradigms. We certainly shouldn't teach them to beginners. There is no such thing as "holy" code. There are no perfect codebases. That's just the nature of software "engineering." I would never tell a beginner that any particular codebase represents the canonical way to structure and implement a game. There is no such thing. I would go so far as to suggest that anyone who tells you they have a perfect codebase is selling you something. If such a thing even existed, it certainly wouldn't be from the mid-'90s. It has been 20 years since Quake came out. Approaches that were optimal then are no longer optimal on modern hardware, for modern games. Our understanding of what constitutes "good design" has evolved considerably. I strongly doubt anybody would write a modern game the way Quake was written. There may well be instances where I could recommend that a beginner look over a part of a larger codebase for inspiration or as a reference for implementing a particular algorithm. I struggle to think of any specific example of such offhand and I definitely wouldn't recommend an entire codebase as an example. I recall encountering someone on the GDNet chat who structured their code in a complex, boilerplate-y way (for what they were doing) who when asked why they chose that approach, said "that's how Unreal/CryEngine does it." That's not an attitude I want to encourage. Broadly-speaking, I would agree that beginners should start off by learning to solve problems, but we should also actively discourage bad habits from forming while they're still learning. Overuse of global state (or use of any global state, depending on whom you ask) is widely considered to be a bad habit. So are deep inheritance hierarchies and the use of inheritance for code reuse, which are widely caricatured features of a lot of late '90s codebases.
  4. How to learn from Quake source code

    I've read that post before and I stand by my points counter to the practice of excessive inlining on the grounds that it doesn't scale all that well and can obscure where things happen when navigating the code. It's worth noting that this post is from 2007, with an addendum from 2014 - quite some time after Quake shipped and still some time before C++'11 and C++'14 went mainstream. Quite a few of the points he makes actually have nothing to do with code inlining per se - they're more to do with architectural choices. The example he used was an aerospace thing, as well, and I'm not confident that what works for aerospace would work all that well for games. For perspective, a few months ago I spotted a function that was multiple thousands of lines long that went something like this: void foo() { // 500 lines switch (thing) { case a: // 30 lines follow break; case b: // 1000 lines follow break; case c: // 300 lines break; case d: // 10 lines break; default: // 150 lines break; } // 30 lines } I ended up extracting each of the case blocks into their own functions because following what was happening when was proving too difficult, even though it had little to do with my current task at hand. Carmack's email on inlining would seem to agree that this is a good idea, actually:
  5. How to learn from Quake source code

    "Harder to read" is quite subjective. Having worked on code written this way, and having refactored said code to use multiple smaller functions, I find it much easier to follow the code blocks when they were shorter. It is claimed that large, monolithic functions are better because they don't introduce unnecessary boilerplate, which is true - but this ignores the fact that the "boilerplate" can be hugely useful when actually navigating the code after the fact - which is important because on large legacy projects we tend to spend more time navigating code than actually writing it. The cost of writing the boilerplate is negligible over the lifetime of the project and in the case of simply breaking a function out into multiple functions, does not generally contribute to code bloat if it is done at the proper granularity level, unlike certain other kinds of boilerplate that do little more than add layers of abstraction. Breaking a monolithic function into smaller functions is a transformation that adds value in the long term. Modern languages also allow us to make "local functions" - in C++, through the use of local lambdas with captures. One can contain any "clutter" that results from breaking a monolithic function down into sub-functions within the monolithic function itself, rather than polluting the local namespace with external functions, so that particular argument (which I know wasn't mentioned here, but I've heard it argued) doesn't really need to apply anymore. I fundamentally disagree. Commented out code is, at best, an inferior way to duplicate the functionality of your version control system, and outright misleading at worst. Pray tell, do you actually maintain your commented out code through refactorings and bug fixes, "just in case"? If you really need that code back, you can just go back through your version control's commit/checkin history for the file that contained it. In my experience, chances are good that if you need the same functionality again later, the context will have changed sufficiently that the original code would not work as written, anyway. I'd also argue that leaving commented code around "just in case it's useful" could contribute to perpetuating a culture of copy-and-paste programming, which I feel most of us can agree is not a culture conducive to producing maintainable code. "Good code" has come to mean all of what you've said plus "code that can be maintained long term without your successors wanting to shoot you in the face." Does the Quake engine meet that specification? If your code works, is efficient, and bug-free, but difficult to navigate and modify without breaking stuff, you have not written "good" code. You have at best written "throwaway code that gets the job done." In a world where the industry is moving towards "games as a service" and where at the very least, most major games get patched, extra content, or even outright sequels using the same codebase, I would say that throwaway code of any sort is no longer acceptable. I confess I've been forced to write throwaway code to solve a problem at the last minute like I imagine most programmers have, but I felt really dirty doing it and was constantly aware of how terrible it was that I was doing it. edit: I was going to say something on the subject of global state and how it can hurt you in an increasingly parallel world, but others have made that argument in the past and I don't think we need to rehash it for the nth time. Having maintained large C++ codebases where global state was the standard way of doing things, even in a single threaded environment they've caused me more pain than I felt they were worth.
  6. Is Phil Fish a Jerk?

    So you're okay with game developers getting death threats and having their lives potentially destroyed when they piss off internet trolls? And it's the fault of the game developers that they're receiving the death threats, and the people sending them are not culpable at all? I really don't see how this isn't victim blaming. In case you couldn't tell, I am strongly of the opinion that we shouldn't endorse toxic behavior in our culture or our players'. Blaming game developers for being on the receiving end of toxicity, rather than condemning that toxicity, constitutes an implicit endorsement of toxic behavior. It frankly frightens me a little that people who hang out in a game developer forum seem to think that the kind of hate Fish received is okay, or that Fish is culpable for his treatment...
  7. Is Phil Fish a Jerk?

    In other words, an insecure person shouldn't show themselves to the public because they might piss someone off enough that the person they pissed off sends them death threats? That's... still victim blaming. I mean, are you really trying to say that that Phil Fish is the aggressor, and the trolls who sent him death threats are the victims?
  8. Is Phil Fish a Jerk?

    It sounds to me like you already made up your mind on the subject of Phil Fish before you made this thread.
  9. use of shared_ptr

    That is part of the purpose of unique_ptr.
  10. use of shared_ptr

    shared_ptr alone is not a silver bullet. There are a few ways that using it can go wrong and lead to leaks and performance issues. Circular references (where you have two objects that refer to each other with a shared_ptr) are an example of that. Mitigating cases like that constitutes "memory management" to some degree. If you're working in C++ you are going to have to deal with memory management even if you're using smart pointers, mainly in the form of ownership semantics. Now, shared_ptr is intended to be used in cases where ownership is shared, hence the name. Is shared ownership really what you want here? If only one object (the scene list) will ever have ownership of the scenes, then you can represent that in code using a unique_ptr, is a smart pointer template that enforces the idea that only one object at a time can own the memory that it points to. You can use references or raw pointers if you need objects to refer to memory they don't own and unique_ptrs to refer to the memory if the objects do own.
  11. Bit of a sidebar, but I'm curious as to why are you trying to do this in the first place? First of all, this isn't actually ECS, because a fundamental aspect of ECS is that composition is done at run-time. What you have here is a complicated way to use multiple inheritance to make compile-time composition happen. The problems you're running into are one of the many reasons we don't generally use multiple inheritance. What does this approach give you over plain old composition (which we normally prefer over inheritance) or plain old multiple inheritance for that matter?
  12. Getter + dirty flag + "mutable"

    If getResult is only called once, why even bother caching the value?
  13. I was hoping I wouldn't have to ride the Linux horse, but...

    The community editions are free. I don't know if the PSP SDK will work with those versions, however.
  14. Blank Programmer.

    If you're really that worried about losing sales as a result of the bad press surrounding Unity, then you don't have to actually tell people you made it in Unity. Get the professional version that hides/lets you change the splash screen and have people who work on your game with you sign an NDA saying that they won't talk about the tech used to build your game. Many developers do this, anyway, even when they're using their own custom engines or even well-known technology and engines. One should not generally let public opinion dictate technical decisions like engine choice. Technical issues should dictate technical decisions.
  15. C++ IO approach in engine/framework

    One thing to be aware of with this approach is that even if the code itself doesn't care where the data is coming from, you as the programmer debugging the code probably will at some point. Debugging problems that appear only for specific assets is incredibly frustrating when you have no way to trace a particular piece of data back to its source asset. You may want to consider having at least some kind of debugging-only system that lets you do that.