Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
more falafel please
Feb 26, 2005

forums poster

Aeka 2.0 posted:

I've tried. Its the dumbest thing ive ever encountered. So nothing is going to get done.

Yeah, this is super frustrating, and it's something I run into all the time. My best advice is to go to your lead (or contact if you're getting tasks directly from the client) and say "I can't do any more on this right now, so I need something else to work on until this is unblocked." Provide whatever documentation you need about the avenues you've explored to try to do the task without the information you need, and how you've tried to get the information, name names if you can. Make it clear you've done everything you can, and that this is on someone else to track down the information you need, and until you get it, this work cannot get done. I've been doing contract work like this for a decade, you just need to make sure that everyone up the chain from you knows that you've gone down every road you can, and now someone has to rattle some cages, or else the work won't get done.

Adbot
ADBOT LOVES YOU

more falafel please
Feb 26, 2005

forums poster

leper khan posted:

Define a list of actions the user can make. Have an event for each action. Trigger the event when a user configured key is pressed.

This. One layer further would be defining a list of input events (key down, key up, axis change) and a list of actions, and have a double-blind mapping between them. That helps when you want to support an input system that isn't what you originally planned (keyboard/mouse to controller, touch controls, etc).

Another thing to think about is different mappings: swapping the set of mappings based on what has input focus, gameplay vs. UI being the main use case.

more falafel please
Feb 26, 2005

forums poster

xgalaxy posted:

Interest thing I didn't know until yesterday:

Supergiant Games Hades was rewritten in C++ during the middle of early access from their C#/XNA code base they've been using since Bastion.
I thought that was a bold decision considering the game was out in early access for some time.

I had to do this in reverse once, take a game written in an in-house C++ engine with a lot of middleware and lua scripted gameplay that was written for Xbox360 and port it to C#/XNA to run on Windows Phone 7. Project budget was two programmers and eventually one tech artist, it took us 18 months. I learned a lot.

more falafel please
Feb 26, 2005

forums poster

Polio Vax Scene posted:

What did you end up doing as an alternative to the lua? I'm currently struggling to find a decent scripting interface for C#.

WP7 doesn't allow *any* native code, so we couldn't use libraries that weren't pure C#. We found a physics middleware that fit the bill (original engine used Bullet, and this was similar enough), but we didn't find a way to do the Lua runtime (there actually was a straight port of the Lua interpreter to C#, but it was ungodly slow and leaked references like a sieve, which means 100ms hitches more than 1x/second).

The good news was they had a strictly enforced Hungarian-style naming scheme for Lua scripts which meant I could use an awful lot of regex to get 90% of the Lua code translated to C# in a couple days, and then spent about a month fixing up everything else. I had also worked on the prequel to this game, so I was very familiar with the way their gameplay script system worked.

more falafel please
Feb 26, 2005

forums poster

leper khan posted:

Blend from where you are to where you're going. This will roughly look like the animations playing faster than you'd normally expect.

This. Alternatively, you can speed up the actual animations, but if your animation system isn't set up for that, it might be more work.

more falafel please
Feb 26, 2005

forums poster

Phigs posted:

That's a funny/weird example because for me, and I imagine anyone else who took the time to try and figure it out, it was incredibly easy to notice and I got it right away because I had to read the whole thing to know what was going on. It was only hard for you because your dumb human mind was like "yeah yeah I know this poo poo" and didn't bother to pay attention to the []. Like when you're editing your own writing and your mind just decides to helpfully add in the "the" you've left out of the sentence. :banjo:

I'd make fun, but the number of times I've done that with "const" instead of "[]" numbers in the hundreds

more falafel please
Feb 26, 2005

forums poster

LatwPIAT posted:

Good idea: I changed it from Trace Channel: Visibility to Trace Channel: Camera. That worked, thanks! (I just have no idea why, which terrifies me.)

It's been a while and I don't have an example UE4 project available, unfortunately -- the curse of contract work, but I do know some about this. You're on the right track in that there's something different about your shooting gallery Actors and your spawned enemy Actors that means they respond to different trace channels. If one of them is a Pawn subclass and the other isn't, that might explain it -- in general, Pawns are actors that have a controller, whether that's a PlayerController for a PlayerCharacter (which is a Pawn), an AIController for AI controlled pawns, or a custom one. Pawn is also one of the Object Types that can be included or excluded from a trace channel: https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/Physics/Collision/HowTo/AddCustomCollisionType/

I don't think you should need to add a custom collision type or a custom trace channel, but the question you need to answer is what's different about the two Actors that makes one of them respond to a Visibility trace and one of them not.

more falafel please
Feb 26, 2005

forums poster

Maintaining determinism isn't all that complicated if you start with it in mind, but retrofitting it in is very difficult.

more falafel please
Feb 26, 2005

forums poster

It's the same tricks pixel artists used to make sprites in a particular perspective, just in 3D.

more falafel please
Feb 26, 2005

forums poster

BabelFish posted:

Unreal's got systems for handling what you're looking for, though I don't know if their 'pixel streaming' system uses WebRTC and webasm under the hood.
https://docs.unrealengine.com/5.0/en-US/setting-up-dedicated-servers-in-unreal-engine/
https://docs.unrealengine.com/5.0/en-US/pixel-streaming-in-unreal-engine/

If OP is looking to support a lockstep/rollback networking model, UE4 doesn't do that out of box. UE4's networking is great, but it's very focused on a server-authoritative model. We've put rollback into UE4 for games before, but it's a big effort, probably more than a solo developer wants to take on.

more falafel please
Feb 26, 2005

forums poster

The answer is definitely "use a cloud service of some kind", and if you don't want to take on a whole separate project of writing a backend matchmaker, server controller, etc etc, then yeah, something like GameLift or Azure PlayFab is probably your best bet.

more falafel please
Feb 26, 2005

forums poster

Megafunk posted:

And yeah, in the new UE5 ECS (Mass) they opted to call systems Processors and components Fragments to avoid confusion. It's fairly similar to the early days of DOTS but it's already been used in their Matrix demo. It is designed to live alongside actors rather than replacing them if that assuages fears of the DOTS debacle.

Makes sense that they call them Processors and Fragments considering they already have long-standing things called Systems and Components.

more falafel please
Feb 26, 2005

forums poster

leper khan posted:

Lmao the off by one joke has been around since at least mid 2000s

Yeah, I was gonna say, I heard the off-by-one part way before I heard the cache invalidation part, if anything I always assumed that was the original joke

more falafel please
Feb 26, 2005

forums poster

lord funk posted:

Agreed with pretty much everything OOP related, and for sure it can work even for complex designs. I'm just really liking the workflow of components these days.

I'm trying hard to find the right balance between C++ blueprints and blueprint-blueprints. I love the idea of having an idea for a new enemy, and just whipping it up in its own blueprint. But as soon as I have to do any math in a blueprint I want to gouge my eyes out, so I head right over and make it in C++.

Raenir Salazar posted:

Gotta say, huge massive pain in the Aye! Whenever I need to figure out what's going on with code I'm looking at for the first time when some of it is hidden away behind Blueprints in the Editor :mad:

I'm coming at this from a AAA-ish standpoint, but my feeling is that Blueprint is great for simple logic and hooking up behaviors -- "when an AGamePawn enters this area, trigger this cinematic". It's also good for designers to prototype some functionality and quickly iterate on it. But as soon as there's "real" logic, or a piece of functionality being used in multiple places, or it's time to get it production ready, it's time to give that to a programmer to nativize.

more falafel please
Feb 26, 2005

forums poster

Rocko Bonaparte posted:

Is the norm for an Xbox One controller's in a menu to have A select and B to cancel the menu? I'm disregarding the menu button and looking at the diamond button quadrant or whatever they call it.

Yes, at least in NA (and increasingly everywhere). Same thing on PlayStation, Cross is select and circle cancel. In Japan it typically used to be reversed, and Sony would make you respect that, but I don't think they make you anymore.

Switch is A (east) select, B (south) cancel. But if you only care about PC, I'd say every controller should be treated like an Xbox controller.

I usually call them the "face buttons" and try to call them by cardinal direction, so on an Xbox controller it's A South, B East, Y North, X West.

more falafel please
Feb 26, 2005

forums poster

leper khan posted:

I should start calling buttons by their gravis gamepad color

On Mortal Kombat we referred to the face buttons as 1/2/3/4, corresponding to what they mapped to on an MK arcade machine (W/N/S/E). Another thing to learn, but it removes ambiguity.

The real answer of course is to call them O/Y/U/A

more falafel please
Feb 26, 2005

forums poster

leper khan posted:

Shameful.

USB HID spec clearly states that 0/1/2/3 correspond to S/E/W/N for the right cluster.

4/5/6/7 are L1/R1/L2/R2

https://w3c.github.io/gamepad/#remapping

I don't think I'm immediately aware of any controller that behaves this way.

Yeah, these were just #defines that mapped to the platform-specific button code. A good portion of the codebase and most of the standards were established well before USB was a thing.

more falafel please
Feb 26, 2005

forums poster

Purely anecdotal, but I've never heard of a situation where exporting to FBX and importing that FBX into another tool worked, without writing a custom FBX exporter and/or importer.

more falafel please
Feb 26, 2005

forums poster

I'm not sure you want to be using a lockstep model for a game that's going to be on mobile.

more falafel please
Feb 26, 2005

forums poster

This just reminded me of a bug from Mortal Kombat 2011 that probably would have shipped if I hadn't caught it randomly.

The game was lockstep, so basically the only data that was sent every frame was the controller input state. We were shipping on Xbox360 and PS3, both of which supported 16:9 but also 4:3, so you had to support 4:3.

I ran automated tests every night with desync detection turned on (basically, have "fenceposts" littered throughout the code that record __FILE__/__LINE__ into a buffer, optionally with a value. checksum that buffer every frame and send it on the wire to the other player, if your checksums are ever different, end the game and dump your log to a file where they can be diffed to (hopefully) figure out where you diverged). I'd run it on my 3 Xboxes and 3 PS3s, just going through matchmaking with each other and running AI vs AI matches, then I'd look to see if there were any dumps that weren't just from AI logic being nondeterministic (would have been nice to fix that but unnecessary). Two of my Xboxes and PS3s were hooked up to 16:9 TVs, the other set was just on a generic dell monitor from a few years back that was 4:3.

We had a function in character scripts called something like AmIOnTheLeft() which was used a lot to figure out mirroring stuff. I have no idea what the usage was here in this specific instance but it was used everywhere.

AmIOnTheLeft() for some reason did screenspace math to determine if you were on the left or not, which was almost always right, but one night I got a dump where one client said AmIOnTheLeft() was true and the other one said it was false, while the two characters were jumping past each other and switching sides.

Fix was to use the goddamn world space "tightrope" that both players were constrained to to trivially figure out if you were more than halfway along it.

more falafel please
Feb 26, 2005

forums poster

roomforthetuna posted:

Neat. I was being hyperbolic when I said 1Mb, but I genuinely did not expect over 900Mb. I would have more seriously thought maybe 50ish.

That presumably includes stuff like Engine/Source/ThirdParty, which means it's also all the source of asio, libcurl, libpng, libjpeg, zlib, dlmalloc, jemalloc, ICU, Ogg, Python, Python3, OpenSSL, etc, etc, etc. UnrealEngine is more akin to an operating system than most game engines.

more falafel please
Feb 26, 2005

forums poster

Nearly every Unreal game uses Wwise (and before Wwise became the standard, FMOD) so I'm sure it's just not a priority for Epic. Anything that doesn't ship in one of their games isn't going to be implemented in shippable quality, unfortunately.

more falafel please
Feb 26, 2005

forums poster

ZombieApostate posted:

If you make changes to C++ code while the editor is open, weird things can happen. Especially changes to header files. Sometimes it fails to replace dlls when you rebuild and then you're stuck until you close the editor, recompile in visual studio and then restart the editor. In theory, changes to cpp files are safe, but basically don't use the hot reload stuff. I think in UE5 it's even disabled by default.

That would be my best guess at what's happening.

I had one project where I was doing a lot of gameplay code, so iterating running in PIE a lot. Hot Reload magically worked, the only time it's ever worked for anyone, apparently, and it was a godsend. I used it all the time -- as long as you're not changing layout of classes/etc, it was amazing.

more falafel please
Feb 26, 2005

forums poster

IIRC from when I cared a lot more about the pedantic details of the standard, *foo and foo* are the same thing assuming it won't be parsed as the type pointer-to-foo.

That said, that's dumb as hell. Is that in UE4/5 source? whoops, saw FVector and assumed things

more falafel please fucked around with this message at 06:46 on Feb 15, 2023

more falafel please
Feb 26, 2005

forums poster

Raenir Salazar posted:

Rotation has weird gimble lock problems...

Unreal's dependence on FRotator still boggles my mind.

more falafel please
Feb 26, 2005

forums poster

Chillmatic posted:

Of course, but it's also important to cover fundamentals before delving into things you may or may not end up needing. That's why I've been talking about setting up even simple systems as generically as possible, so they're easier to grow and modify smoothly alongside the game you're working on.

When I was starting out, few things frustrated me as much as having to revisit some old system I'd made previously, and hitting a brick wall full of assumptions and magic numbers and hard casts and giant methods/classes and pretty much all the big bad smells.

Yeah, but just as annoying is the super overengineered perfectly abstract system where you have to hook up 17 objects, write some custom callbacks (but first define a new CallbackReceiver subclass), add two new global enums, and adjust the behavior of a state machine just to call a function. That stuff also gets super difficult to debug, profile, reason about, change, or document too.

I tend to prefer code/systems that are easier to delete if what I need it to do changes way too much from the original requirements/design.

more falafel please
Feb 26, 2005

forums poster

Rocko Bonaparte posted:

If my target is PC and (at-best/worst) console, would I worry about touch control for joystick and button-press-like inputs? I'm assuming that's only a phone thing unless I wanted to, hmmm, do something on a Switch?

Worry about that later. There can be touch controls on PC (and console, the PS4's touchpad for instance), but you shouldn't need to worry about it for now.

more falafel please
Feb 26, 2005

forums poster

TooMuchAbstraction posted:

My preference is to get memory allocations down to the point that an incremental GC can handle them between frames without creating lag. That's kind of like manual memory management, except that you don't have to worry about it 90% of the time because most code isn't doing enough allocations to matter.

I've worked on porting two different Unity games to console. On both of them, we had a senior engineer dedicated, for the entire 2 year project, to reducing mid-frame allocations (mostly strings). It's so, so, so much harder than manual memory management, because the environment is actively fighting you.

In UE3, we had the same problem. Eventually the engine tried to moved to reference counting for resources, but you had years of legacy code creating UObjects willy-nilly because it "you don't have to worry about it", and every UE3 project I worked on had a massive effort to remove allocations so that GC wouldn't run except on level load.

Using a GC language or environment for AAA games on anything but PC is a nonstarter.

more falafel please
Feb 26, 2005

forums poster

Raenir Salazar posted:

So there's something I'm not sure about groking from trying to make a static library, if I create a static library, and link it in Unreal, will Unreal now "know" about the types? How minimal can I get away with making a static library if all I want is to be able to use the types/objects defined/implemented by the library do I need any code at all?

I think you're having trouble with the difference between declarations and definitions in C++. A declaration tells the compiler "this symbol (name) is a function/class/variable that looks like this", so the compiler knows what to do with it. Some examples of declarations:

C++ code:
void foo(int x);

class Bar 
{
public:
	void baz();
private:
	float y;
};

typedef std::vector<Bar> VectorOfBars;
Most of the time, definitions will be in header files.

A definition of a function is the actual compiled code:
C++ code:
void foo(int x)
{
	std::cout << x << std::endl;
}

void Bar::baz()
{
	std::cout << "Bar::baz()" << std::endl;
}
Definitions are typically in .cpp files. A .cpp file is often referred to as a "translation unit" and is compiled individually. Translation units typically include a number of header files, which tell the compiler that there are symbols defined ~somewhere else~ that that translation unit is able to reference. This means that in a.cpp, you can #include b.h and call a function that's defined in b.cpp, because everything the compiler needs to know to generate the code that calls that function is in the declaration in b.h. When a.cpp is compiled, the compiler doesn't worry about where that function is, it just puts a placeholder in and assumes it'll be there somewhere.

A build process (via a Visual Studio project, a Makefile, or Unreal's UBT) has some list of .cpp files to compile. It invokes the compiler on each of those, individually, and generates an object file of compiled machine code that exports symbols (names). So, foo.cpp compiles to foo.o (or foo.obj, depending on the compiler), bar.cpp -> bar.o, etc. If the target of the build is a shared or dynamic library, the build tool then invokes a "librarian" or "archiver" or something to that effect, which basically just dumps all the compiled object files into one file that now exports a bunch of symbols. If the target of the build is an executable, the build tool invokes the linker, which takes as input all the object files and libraries that need to be linked into the executable. The linker finds all those references to symbols that are defined ~somewhere else~, looks at all the symbols that are exported by all the object files and libraries, and fixes up all the locations, so that calling foo() will call that actual function.

You're seeing undefined symbol errors from the linker, which means that in at least one translation unit, you promised that there would be some function (or variable) called foo, and then when everything got compiled and was ready to link together, there was nothing by that name to be found. This means that either: you're not compiling the .cpp files that define those symbols, or you're not linking them in to the plugin DLL, or the game executable target isn't linking against that plugin DLL.

more falafel please
Feb 26, 2005

forums poster

Rocko Bonaparte posted:

2. Having to fix a few incorrect lines of code in Unreal's own source before compiling successfully for the first time.

What did you have to fix? You generally shouldn't have to do that unless you're using a newer platform SDK than what's officially supported or something.

more falafel please
Feb 26, 2005

forums poster

TooMuchAbstraction posted:

If I wanted to be able to perfectly restore game state, I'd make a game where I manually control all relevant memory, and just serialize the memory block in its entirety, like emulator save states. Yes, this does mean doing pretty much everything by hand, instead of using an engine.

Lots of fighting games use a lockstep networking model with prediction and rollback: you send your input state to the other player every frame, assume that the other player's input for frame X is the same as it was for frame X-1, and when that input actually comes in, if I differs, roll back your game state to what it was before X and resimulate X, X+1, X+2, etc until you catch back up. This requires two things: a gameplay tick that can be run several times in a single frame's time slice, and a deterministic gameplay state that's small enough to store several copies of, so that two different machines running the game tick with the same inputs and same state produce the same output state.

more falafel please
Feb 26, 2005

forums poster

Rocko Bonaparte posted:

Unreal's coding standard using PascalCase for every variable name is really wild to me. I don't think I've ever seen that anywhere else before.

Wait til you learn what the F prefix in type names stands for.

more falafel please
Feb 26, 2005

forums poster

1) Yeah, that seems like a semantic difference between the POSIX/unix centric idea of the filesystem and the DOS/Windows idea. While Unreal is pretty good about being cross-platform friendly, its philosophy tends to skew to Windows-focused. In the UE3 days there were DWORDs and BYTEs all over the codebase.

2) I wouldn't be surprised if FPaths::ProjectDir() returns a path-style object (I don't have engine source in front of me at the moment), and i bet concatenating two paths works as expected. Looks like your/ChatGPT's code is concatenating the string literal to the path object, which I'm guessing just does string concat to support something like adding an extension to a filename.

3) Actually writing code is a pretty small part of my job. I'm not confident LLMs will be able to do that consistently well for quite a while, but even if they do: you still, largely speaking, wrote that program. You wrote it in a different language with a buggy transpiler, but you still had to tell it what to do, it just knew the API reference, sorta.

more falafel please
Feb 26, 2005

forums poster

Kaedric posted:

Yes, I would agree and say that probably one of the more important areas this would help (meaning: a good place to actually bother doing it) would be in multiplayer netcode, where every bit is a cost in literal money and/or bandwidth.

It depends a lot on your packet frequency and how big your average packet is. Back in the day to pass cert on Xbox, you needed to be "playable" on 64kbps, 100ms average latency, 1% average packet loss (IIRC). "Playable" was pretty vague, but that was always the target. On a couple games I worked on where we ran lockstep between two peers at 60fps, sending a tiny packet every frame, bandwidth was dominated by Ethernet/IP/UDP headers. Cutting a few bits from the payload wouldn't make a noticeable difference.

more falafel please
Feb 26, 2005

forums poster

The universities are selling the idea that if they pay the tuition, they get a degree that gets them a job, so I kind of understand where the kids are coming from. The school is treating their relationship as purely transactional, it's hard to expect the students to feel differently.

more falafel please
Feb 26, 2005

forums poster

leper khan posted:

counterpoint, managed languages are bad because you have the same or similar problems while lacking some of the tools to deal with them and people who dont understand you need to manage memory carefully anyway

i'd take C where people around me know they need to care vs C# where people around me pretend they dont any day

more falafel please
Feb 26, 2005

forums poster

TooMuchAbstraction posted:

As someone who actually shipped a pretty large game in C# on Unity, "thinking about performance" and micro-managing memory are absolutely not the same thing. You want to know what was murdering my performance in the game? It was poo poo like:

- logging too much
- making a copy of every ship for each instance of that ship in the mission
- calculating firing angles for each gun on each ship during mission loading, even though I then throw out that data because I have it precalculated and stored in the ship data
- rendering dynamic HUD textures (for the radar) every frame instead of on alternating frames (nobody notices if the radar is 15 or 30 FPS instead of 60)
- performing physics checks for every projectile every frame (instead of doing it on alternating frames and only for projectiles that are close to their targets)
- regenerating displayed strings even when the text doesn't change
- having trees on the terrain

Yes, there are a few cases where I added pooling. Almost universally, these cases were "I want there to be a technically infinite number of this thing in the game, but instantiating new ones causes lag, so I'll pre-instantiate the number I need and then enable/disable them as required".

Somewhat more common was me cutting down on allocations by creating a static data container (list or dictionary or whatever) that is only used by one function, so that that function can avoid calling `new`.

In absolutely 0% of cases did I even briefly consider stepping outside of C#'s memory management.

All of my performance improvements were identified by using a profiler. I did not worry about performance for the first ~year of development, because my priority was shipping the game and features count more for that than performance does.

(also, Zelda: Ocarina of Time runs at 20FPS at best and people love that game, the occasional FPS hitch is not the end of the world)

Have you tried putting your game on console? I've worked on two ports of Unity games to console, and literally 75% of the engineering effort has been spent on memory management, because GC is murder for a realtime application, and the original devs just don't think about it at all, because "it's managed, you don't have to worry about it"

Adbot
ADBOT LOVES YOU

more falafel please
Feb 26, 2005

forums poster

KillHour posted:

There's a fundamental difference between using "memory management" to refer to "Creating and destroying a new array every frame is inefficient" and "You need to keep track of where this pointer goes or you could end up dereferencing to somewhere you're not supposed to be and crash the application in the best case."

It takes more work to fight against a managed environment, especially for stuff like string allocations, than it does to just do it correctly.

I don't know how to say this any clearer: nearly every memory management pitfall in C/C++ is also a problem in managed environments, and it's more difficult to solve them in a managed environment.

But please, make your AAA game in Unity and then try to put it on console, us contractors need work.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply