admanbunionize your workplaceSeattle, WARegistered Userregular
but jokes aside I don't think you're going to unfuck this pig by understanding how Ruby/Rails works. Rails doesn't do this. You need to domain-specific knowledge of the people who've worked with this. Aside from that I would start with the scripts, figure out how to modify them to get a thing that you need, and then figure out what the scripts are doing to see if you can get from there to a less fucknuts way of working with this database.
Oh also one of my first tasks is to produce a data diagram describing all of this!
But yeah good to confirm this is more of a them thing than a Ruby thing. Not that I have a problem learning Ruby, but it's more a matter of learning what they're doing to interact with this stuff and how they've approached solving problems.
Also I downloaded DBVisualizer and found that a little more helpful than Postico for a database that I'm brand-new to while also using an OS I haven't used in years. It has some easy GUI ways to explore table relationships that I appreciate since there doesn't seem to be a person who really knows the database/design choices all that well. It got me going well enough to grab half the info for a task I have. The other half is apparently in a separate Discourse database? So that'll be fun to learn how to interact with.
Truly weird to go from a place that was comparatively a lot less staffed and capable in many ways but did have a very competent DBA and several good data engineers to a place with a way bigger dev team but also somehow I'm the first person who knows more than basic SQL.
Also today I finally just gave up on using this Dell USB-C hub thing they sent. It actually caused my computer to bluescreen multiple times this morning, in addition to randomly losing power somehow and requiring me to plug and unplug it to get it working. Just a spectacularly cursed piece of technology.
ButtersA glass of some milksRegistered Userregular
Who has two thumbs and spent the better part of today investigating a program created in a 20-year-old and very much obsolete function block diagram software only to find out the reason the system wasn't working is because a replacement part (a servo drive) was sent to the customer without being commissioned first?
Who has two thumbs and spent the better part of today investigating a program created in a 20-year-old and very much obsolete function block diagram software only to find out the reason the system wasn't working is because a replacement part (a servo drive) was sent to the customer without being commissioned first?
I spent the better part of two days collapsing a like 20 projects solution in visual studio down to 1. There was no reason for the segmented project approach, just how the app (everything was a library) changed over the past 15 years, but for some reason visual studio was barfing on the 20 projects today and I couldn't figure out why (build/clean weren't working and no errors were given, just.. nothing happened).
As soon as I collapsed it down to one logical project and converted all the namespaces it seems to work better than it ever did, so small victories I guess.
I'm still bugged by the lack of build/clean not working, but I'll take it.
not a doctor, not a lawyer, examples I use may not be fully researched so don't take out of context plz, don't @ me
Apparently this really only makes sense if you worked at Google around 2010 and would be privy to the issues discussed in the video.
Maybe so, but "I am going to quit my job. My next job will be making your vital organs universally accessible and useful." is a phrase Ima stick in the old memory banks for later usage...
Yeah I'm definitely getting the impression that these folks kind of put together the database without totally knowing what they were doing.
Like while discussing it with me they said that it may not be possible to get stuff out via SQL and... it's definitely stuff that should be possible. Easy, even! I just need to know how to walk from the eventID on table A to the userID on table C, but they seemed to not really get how to do that except by writing Ruby scripts. And the thing about some of the IDs being accessible only in Ruby really confounded me, because why even do that? Like why not have the table you know PokemonTypes with ID | Name in the database with everything else? I wasn't certain if it was just a normal part of building the DB this way, since I've never worked with Ruby.
I'll speak further with the person who handled these requests prior to me to figure out what the heck they've been doing to handle this, but I'm happy to have some confirmation that it's actually just very weird. I'm really not much of a DBA, I've mostly worked within databases administered by other folks, but this is really making me want to take the time to learn more so I can avoid... all this.
Edit: Oh and to clarify the other places they store data are not all related to Ruby, they're external databases acting as backends for different but related things using totally distinct formats. They suggested I might want to make a Ruby script to loop through and pull out every individual record I was interested in if there was information in those that I needed to match to information in the main DB...
what you have here is not a database, it's an ancient curse
Yeah, were they just querying all the different backends and just doing everything in memory or something? Or were they writing back to the other backends, while segregating out the db it touches from the data it uses from the other ones?
I'm still learning how things work at the new place but I think I have a better handle on it... though like I said I'm coming from a place that had a very old-school physical servers & MS SQL Server setup and still getting a grip on the new place so I'm probably not totally correct about how this works.
So they've got an app database on Heroku with most of the user/app info, then they have various other databases that were made to support specific features at one time or another basically independently. Like there's a Discourse setup that's totally separate, but has IDs that can be used to link back to the app database.
So part of the confusion is that I'm used to interacting with a database via SQL primarily, with maybe some Powershell if necessary to do something weird. These folks seem to generally avoid SQL at all costs. This means the data I'm working with has both got some odd design features like the text arrays becoming numeric columns and the people who work with it are like "oh I don't think you can do that without [some weird Ruby thing]". Having worked with it for a bit longer, I'm less intimidated because it is in fact an okay database to work with even if it's a annoyingly auto-generated in some ways.
Now, I still need to get all the credentials to work with all the rest of the stuff but at least I kinda get it now. Like someone walked me through how they had answered some previous ad-hoc questions, by just running rails on the Heroku dev environment and copy-pasting in some Ruby that also had all the SQL.
Work is very weird. I'm constantly ping-ponging between thinking I don't understand something because I lack expertise and thinking I don't understand something because it's silly.
Also, particularly fun thing: I'm actually in charge of figuring out how to get all of the disparate elements here to be a unified Data Lake! The new buzzword! My initial thought is to just use AWS's Lake Formation because we've already got some stuff on AWS and it seems plausible that with the setup we have this could be something where I just plug in some connection info and then fiddle with Glue jobs to make any transformations needed. Has anyone had any experiences with Lake Formation? I'm basically finding AWS documentation and then really bad blog posts that are like "WOW! Why You Need a Data Lake" and then are just paraphrases of AWS documentation.
OK , I have a dilemma and need some help trying to code my way out of a wet paper bag.
As an exercise I'm making a sector based 2.5D engine and I'm borrowing heavily from this YouTube video to help. I'm slowly making my way though it, and taking it bit by bit to understand what is going on... I do have some impediments and need some help.
1) I failed basic algebra in college. My math skills are... not great. Recently I've been learning a little trig with the help of Khan Academy, but I mostly learn rotations in terms of Tau as it SO MUCH EASIER
2) For as long as I remember, C pointers are just... awful. I don't understand why I keep half-learning them and then just gets wrecked in my brain. Funny thing. I can do pointers in assembly in my sleep. I know what they are and what thy do. I don't know. There is just something so intrinsically bullshit about how C presents pointer operations.
So my goal. Use the engine from the YouTube channel to load a Duke Nukem 3D level. It is possible, as they are both sector based. I have a 1:1 correlation between the data in the Duke "Build" engine and the data used in the YouTube Tutorial
However the structs that hold the data is massively different and accessing them is... Difficult
At the core of the problem is the MovePlayer() function (he talks about it here on the YouTube video)
As he says. the main function of MovePlayer() to check the player's movement, determine if they are still in the same sector, and update the player sector if a sector line is crossed. The update the player position.
Now, for the most part I get this! Well except the nuances of the two "const struct" pointer things, but I get the jist.
He's making a single sector (object?) based on the sector the player is in.
Then an array of vertex[].x and vertex[].y (Like I said, this part is a little black magic for me.
The next part I get
Then for every "wall" see if there is a sector behind it and if there isn't (neighbors[] = -1) then skip
If there is a sector, check between it's beginning and end vertex and see if we crossed the line into the next sector
If we have, then update the player sector.
Then update the actual player position.
Now the problem is that the above code assumes that sectors are in this kind of a struct.
static struct sector
{
float floor, ceil;
struct xy { float x,y; } *vertex; // Each vertex has an x and y coordinate
signed char *neighbors; // Each edge may have a corresponding neighboring sector (-1 if no sector is there)
unsigned npoints; // How many vertexes there are
} *sectors = NULL;
He has pointers and structs in stucts with pointers and I'm not parsing this real hot.
The (relevant) duke "Build" level has the sector in two parts, and much easier to understand. (I'm removed the data for the sector not relevant here)
//The sector
typedef struct
{
short wallptr; //index to first wall of sector
short wallnum; //number of walls in sector
} sectortype;
sectortype sector[1024];
//The walls
typedef struct
{
long x, y; //Coordinate of left side of wall, get right side from next wall's left side
short point2 //Index to next wall on the right (always in the same sector)
short nextwall //Index to wall on other side of wall (-1 if there is no sector)
short nextsector //Index to sector on other side of wall (-1 if there is no sector)
} walltype;
walltype wall[8192];
So you can see the data is all there I need, but I can't quite figure out how to fit the round peg into the square hole.
I like the "Build data" because it's all arrays, but it gets really unwieldy when I set it up in this (very wrong) way
Then I also have no idea how to "step through" all of the walls
float px = player.where.x;
float py = player.where.y;
int currentSector = player.sector;
short wallCount = sector[currentSector].wallnum;
short currentWall = sector[currentSector].wallptr;
short currentSectorBackside = wall[currentWall].nextsector;
short nextPoint = currentSectorBackside = wall[currentWall].point2;
long vertex1X = wall[currentWall].x;
long vertex1Y = wall[currentWall].y;
long vertex2X = wall[nextPoint].x;
long vertex2Y = wall[nextPoint].y;
I'm sure there is a better way than this..
Apologies if this was too long.
Now the problem is that the above code assumes that sectors are in this kind of a struct.
static struct sector
{
float floor, ceil;
struct xy { float x,y; } *vertex; // Each vertex has an x and y coordinate
signed char *neighbors; // Each edge may have a corresponding neighboring sector (-1 if no sector is there)
unsigned npoints; // How many vertexes there are
}
I'm not knowledgeable about C, but this appears to be declaring an anonymous struct and then saying "vertex" is a pointer of the type of this anonymous struct. So as I understand it, it would be equivalent to something like:
typedef struct
{
float x;
float y;
} Coordinate;
static struct sector
{
float floor, ceil;
Coordinate *vertex; // vertex is a pointer of type Coordinate which is a struct with two floating point values. It will point to a Coordinate object/struct
signed char *neighbors;
unsigned npoints;
}
TelMarine on
3ds: 4983-4935-4575
0
Options
OrcaAlso known as EspressosaurusWrexRegistered Userregular
edited November 2021
There's some real weirdness, at least coming at this completely blind, to the construction you're working against.
static struct sector
{
float floor, ceil;
struct xy { float x,y; } *vertex; // Each vertex has an x and y coordinate
signed char *neighbors; // Each edge may have a corresponding neighboring sector (-1 if no sector is there)
unsigned npoints; // How many vertexes there are
} *sectors = NULL;
What's jumping out at me here is that you need to allocate or assign a vertex array for each structure, instead of making them values of the structure (or using e.g. a vector because C). The use of an unsigned char pointer for the neighbors with a sentinel value of -1 has me just scratching my head--at that point why not just use NULL as the sentinel value for no neighbors? Anyway, point is you've got pointer types to deal with where they appear to just be value types in the load data, which means you're going to need to allocate members and arrays to fill them, and then do the required housekeeping.
Where things look like you're going to have trouble is you're going to need to traverse wall and build up a list of all neighbors for each sector, allocate, and assign it to neighbors. And then of course when that changes you're going to need to deallocate it. You likely will need to use the Build data as the input for a datastructure more suitable for your implementation rather than loading it directly.
The structures you're using right now strike me as using pointers quite, err, pointlessly, but presumably there's a reason for it that isn't obvious given a single forum post.
You can't use null as a sentinel because that's an array. You could use 0 but presumably 0 is a valid value here as it likely just indexes the list of sectors
There are some number of sectors, each sector has some number of point, neighbour pairs
They're separated because that produces a more compact serialization and it's likely that those are just pointing into the file that was read
So I'm not insane and that that this is a wierd-ass way to put together a struct. That makes me feel better...
Yea, the file format used to generate the level was weird
So good news. I leared the difference between a -> and a .
-> accesses a struct member via a pointer
. accesses a struct member via the struct variable
Using that tool, I found how how to "borrow" data using a new struct pointing to the loaded data.
It works, but I'm not super happy with it. First IntersectBox() and PointSide() are macros (Because the original programmer couldn't use templates in C) I may need to make these actual functions and just watch what I pass to them. Another thing that bug me is that the "build" data uses coordinates of long integers and I use floats (my units are equivalent to meters) , the scale is WAY different and the Y axis is, weirdly, upside down. So I may need to do some scaling and flipping when I load the level in my coordinate system.
Re: upside-down Y, there's a number of current coordinate/display systems (I AM LOOKING AT YOU, APPLE) where 0,0 is actually top left. It's exactly as annoying as you think it would be.
Edit: That is to say "not too surprised there's more of those from the beforetime".
dporowski on
0
Options
Ear3nd1lEärendil the Mariner, father of ElrondRegistered Userregular
0,0 in CSS positioning is the top left, but that makes sense since it's the start of the document.
Y-up views the screen as the +x,+y quadrant with the origin in the bottom-left corner
Y-down views the screen as the hardware does with address 0 being the top-left pixel and increasing addresses going down the screen
Most computer things end up Y-down but with enough math you can do it either way.
Well, I have my sectors all good (for the most part) now I have to do.... scaling.
I like the duke "build" map because it's map is so simple. Doom's Wads are too complicated and I don't have to worry about nodes, linedefs, sidedefs etc etc.. and I get a level editor for free! (As long as I'm not using any of the duke code and only following the map spec, I have a clear copyright too The "YouTube" engine is CC0, so I guess it's my engine now. Public domain is really rad!)
Now here comes the fun part.. Scaling.
My engine came with units in.. feet(!) and I'm going to convert that to meters. It's coordinate system is Y+ = North, X+ = east, and Z+ = Up. Angles are in terms of Tau (2*pi, counter-clockwise)
In build, 1 meter = 512 units, and it's units are Y- = North, X+ = east, an Z- = up. Oh and the Z axis is a different scale then the X and Y (8,192 units per meter). Angles are 0-2047 units, clockwise)
The angle conversion is done and I already flip and scale the Z axis on load, however, when flipping the Y axis, my sector math breaks down because the sector line crossing algorithm assumes the sector vertexes are clockwise. I'll make due with my levels being flipped.
Y-up views the screen as the +x,+y quadrant with the origin in the bottom-left corner
Y-down views the screen as the hardware does with address 0 being the top-left pixel and increasing addresses going down the screen
Most computer things end up Y-down but with enough math you can do it either way.
This does not make it not-annoying. :P
CSS? I get that, very sensible. Phones and TVs? No. Bad. Bad bad bad, go to the box and feel shame. Don't even start me on the Android ecosystem and its inability to decide which end of a device is "up"...
dporowski on
0
Options
OrcaAlso known as EspressosaurusWrexRegistered Userregular
Y-up views the screen as the +x,+y quadrant with the origin in the bottom-left corner
Y-down views the screen as the hardware does with address 0 being the top-left pixel and increasing addresses going down the screen
Most computer things end up Y-down but with enough math you can do it either way.
This does not make it not-annoying. :P
CSS? I get that, very sensible. Phones and TVs? No. Bad. Bad bad bad, go to the box and feel shame. Don't even start me on the Android ecosystem and its inability to decide which end of a device is "up"...
Boy have I got bad news for you about how displays are typically scanned out
Orca on
+2
Options
Ear3nd1lEärendil the Mariner, father of ElrondRegistered Userregular
Years ago, I had to work with iTextSharp, which is a .NET PDF creation library. The first few hours of working on it were rather confusing because nothing was ending up where I thought it would on the page. It was then that I realized that it was Y-up. I was a little annoyed at first because I had spent many years to this point working Y-down in CSS. But then I recalled back to my first two years of school when I was going through a phase where I wanted to be an architect. AutoCAD uses Y-up, as do most applications of that type because drawings on paper always used the typical mathematical graphing coordinates. Once I got that through my head, working Y-up was easy.
0
Options
gavindelThe reason all your softwareis brokenRegistered Userregular
Big change: No errors, boss.
Me and everybody else: I don't believe you.
Big change: okay fine I hid the problem in another castle
ABSTRACT
The received wisdom suggests that Unix’s unusual combination of fork() and exec() for process creation was an
inspired design. In this paper, we argue that fork was a clever
hack for machines and programs of the 1970s that has long
outlived its usefulness and is now a liability. We catalog the
ways in which fork is a terrible abstraction for the modern programmer to use, describe how it compromises OS
implementations, and propose alternatives.
As the designers and implementers of operating systems,
we should acknowledge that fork’s continued existence as
a first-class OS primitive holds back systems research, and
deprecate it. As educators, we should teach fork as a historical artifact, and not the first process creation mechanism
students encounter.
Yeah fork is unimportant in a world where you have threads and a proper OS
fork + exec is strictly more work for the kernel to do, requires CoW be implemented for private memory (or more strictly implying that private memory does not exist) and makes more exotic memory management like user mode paging difficult-to-impossible. This also makes it extremely difficult to maintain a total memory commit size. linux is an OS that can give the user more memory than it can actually make available
It is however very simple both in concept and execution
OrcaAlso known as EspressosaurusWrexRegistered Userregular
Coming from embedded land, the entire idea of the out of memory killer is completely bonkers to me, but there's no better way when the execution model is fork + exec + copy-on-write and you can't simply have a memory request fail to allocate. Unless you're going to start killing processes in the order forked or something.
Well for most programs the only response to allocation failure is to die anyway. Zero people are catching the error if std::vector throws for example
But it does mean that if you allocate memory some other process can die for you instead!
It's Very Fun to deal with this in the chrome process model. At least that's designed such that only one process actually cannot be respawned but there's just endless bugs coming in about flickering screens and crashed renderers that were just "well you tried to show a 4000x3000 image and you can't do that"
I don't think you can check everything with C++ unless every allocation is new (std::nothrow) or is a placement new and you never use any library functions that could allocate anything. The compiler can assume that default throwing new never returns null
Coming from embedded land, the entire idea of the out of memory killer is completely bonkers to me, but there's no better way when the execution model is fork + exec + copy-on-write and you can't simply have a memory request fail to allocate. Unless you're going to start killing processes in the order forked or something.
I feel like in embedded land though this is kind of what you want though? Complex real-time systems can have dynamic resource constraints (and should be designed to fail gracefully) - something like this is what saved the Apollo 11 landing for example, keeping the main landing process alive when the system was overtaxed.
0
Options
OrcaAlso known as EspressosaurusWrexRegistered Userregular
I don't think you can check everything with C++ unless every allocation is new (std::nothrow) or is a placement new and you never use any library functions that could allocate anything. The compiler can assume that default throwing new never returns null
When you don't have a heap, everything is placement new (objects) or statically allocated (buffers used for placement new, buffers used for stacks, never use static objects). And yes, only a subset of the standard library is available. Particularly off limits are the container classes except std::array and std::tuple.
Coming from embedded land, the entire idea of the out of memory killer is completely bonkers to me, but there's no better way when the execution model is fork + exec + copy-on-write and you can't simply have a memory request fail to allocate. Unless you're going to start killing processes in the order forked or something.
I feel like in embedded land though this is kind of what you want though? Complex real-time systems can have dynamic resource constraints (and should be designed to fail gracefully) - something like this is what saved the Apollo 11 landing for example, keeping the main landing process alive when the system was overtaxed.
Absolutely not.
If you have dynamically allocated resources, they need to be carefully constrained so you don't end up with heap fragmentation and out of memory when you're talking desired uptimes of > 1 year. The easiest answer is either to only allocate on the heap up front on boot and never allocate again after that, or to just link against C standard library instead of the C++ standard library and remove all uses of malloc.
How is "kill random processes" failing gracefully?
For the use case you're describing, that process needs to be at a higher priority than other competing processes so it can advance even if the other processes are poorly behaved. Preferably on a dedicated MCU rather than a shared CPU as well, if practical. Sharing CPU time for safety-critical processes is ill-advised. In an ideal world, the firmware is either only involved in enabling a hardware interlock (for sequencing purposes) or is running on a dedicated MCU with extremely simple logic where the disassembly has been checked for correctness. I don't want firmware anywhere near safety-critical stuff if I have a choice. Bake that shit into the ASIC!
Ah yes, well if you don't have a heap then you can't fail any allocations!
That's exactly part of the thinking behind that design choice. When you have hard realtime guarantees to make, limited RAM, and uptime guarantees to meet, sometimes you gotta make tradeoffs.
In an application, a failed allocation is probably a sign the system is overtaxed and your app dying is the correct thing to have happen.
Does anyone have any recommendations for online courses/classes for programing for kids? There is a little one (7) in my life that is super interested in coding and wants to learn more.
Does anyone have any recommendations for online courses/classes for programing for kids? There is a little one (7) in my life that is super interested in coding and wants to learn more.
Posts
Good luck, and god be with you.
For a couple of peer bonuses I would be happy to explain the subtle jokes.
But yeah good to confirm this is more of a them thing than a Ruby thing. Not that I have a problem learning Ruby, but it's more a matter of learning what they're doing to interact with this stuff and how they've approached solving problems.
Also I downloaded DBVisualizer and found that a little more helpful than Postico for a database that I'm brand-new to while also using an OS I haven't used in years. It has some easy GUI ways to explore table relationships that I appreciate since there doesn't seem to be a person who really knows the database/design choices all that well. It got me going well enough to grab half the info for a task I have. The other half is apparently in a separate Discourse database? So that'll be fun to learn how to interact with.
Truly weird to go from a place that was comparatively a lot less staffed and capable in many ways but did have a very competent DBA and several good data engineers to a place with a way bigger dev team but also somehow I'm the first person who knows more than basic SQL.
Also today I finally just gave up on using this Dell USB-C hub thing they sent. It actually caused my computer to bluescreen multiple times this morning, in addition to randomly losing power somehow and requiring me to plug and unplug it to get it working. Just a spectacularly cursed piece of technology.
This guy! This poor motherfucker right here!
lol. lmao
As soon as I collapsed it down to one logical project and converted all the namespaces it seems to work better than it ever did, so small victories I guess.
I'm still bugged by the lack of build/clean not working, but I'll take it.
Maybe so, but "I am going to quit my job. My next job will be making your vital organs universally accessible and useful." is a phrase Ima stick in the old memory banks for later usage...
Yeah, were they just querying all the different backends and just doing everything in memory or something? Or were they writing back to the other backends, while segregating out the db it touches from the data it uses from the other ones?
So they've got an app database on Heroku with most of the user/app info, then they have various other databases that were made to support specific features at one time or another basically independently. Like there's a Discourse setup that's totally separate, but has IDs that can be used to link back to the app database.
So part of the confusion is that I'm used to interacting with a database via SQL primarily, with maybe some Powershell if necessary to do something weird. These folks seem to generally avoid SQL at all costs. This means the data I'm working with has both got some odd design features like the text arrays becoming numeric columns and the people who work with it are like "oh I don't think you can do that without [some weird Ruby thing]". Having worked with it for a bit longer, I'm less intimidated because it is in fact an okay database to work with even if it's a annoyingly auto-generated in some ways.
Now, I still need to get all the credentials to work with all the rest of the stuff but at least I kinda get it now. Like someone walked me through how they had answered some previous ad-hoc questions, by just running rails on the Heroku dev environment and copy-pasting in some Ruby that also had all the SQL.
Work is very weird. I'm constantly ping-ponging between thinking I don't understand something because I lack expertise and thinking I don't understand something because it's silly.
Also, particularly fun thing: I'm actually in charge of figuring out how to get all of the disparate elements here to be a unified Data Lake! The new buzzword! My initial thought is to just use AWS's Lake Formation because we've already got some stuff on AWS and it seems plausible that with the setup we have this could be something where I just plug in some connection info and then fiddle with Glue jobs to make any transformations needed. Has anyone had any experiences with Lake Formation? I'm basically finding AWS documentation and then really bad blog posts that are like "WOW! Why You Need a Data Lake" and then are just paraphrases of AWS documentation.
As an exercise I'm making a sector based 2.5D engine and I'm borrowing heavily from this YouTube video to help. I'm slowly making my way though it, and taking it bit by bit to understand what is going on... I do have some impediments and need some help.
1) I failed basic algebra in college. My math skills are... not great. Recently I've been learning a little trig with the help of Khan Academy, but I mostly learn rotations in terms of Tau as it SO MUCH EASIER
2) For as long as I remember, C pointers are just... awful. I don't understand why I keep half-learning them and then just gets wrecked in my brain. Funny thing. I can do pointers in assembly in my sleep. I know what they are and what thy do. I don't know. There is just something so intrinsically bullshit about how C presents pointer operations.
So my goal. Use the engine from the YouTube channel to load a Duke Nukem 3D level. It is possible, as they are both sector based. I have a 1:1 correlation between the data in the Duke "Build" engine and the data used in the YouTube Tutorial
However the structs that hold the data is massively different and accessing them is... Difficult
At the core of the problem is the MovePlayer() function (he talks about it here on the YouTube video)
As he says. the main function of MovePlayer() to check the player's movement, determine if they are still in the same sector, and update the player sector if a sector line is crossed. The update the player position.
Here is the function.
Now, for the most part I get this! Well except the nuances of the two "const struct" pointer things, but I get the jist.
He's making a single sector (object?) based on the sector the player is in.
Then an array of vertex[].x and vertex[].y (Like I said, this part is a little black magic for me.
The next part I get
Then for every "wall" see if there is a sector behind it and if there isn't (neighbors[] = -1) then skip
If there is a sector, check between it's beginning and end vertex and see if we crossed the line into the next sector
If we have, then update the player sector.
Then update the actual player position.
Now the problem is that the above code assumes that sectors are in this kind of a struct.
He has pointers and structs in stucts with pointers and I'm not parsing this real hot.
The (relevant) duke "Build" level has the sector in two parts, and much easier to understand. (I'm removed the data for the sector not relevant here)
So you can see the data is all there I need, but I can't quite figure out how to fit the round peg into the square hole.
I like the "Build data" because it's all arrays, but it gets really unwieldy when I set it up in this (very wrong) way
Then I also have no idea how to "step through" all of the walls
float px = player.where.x;
float py = player.where.y;
int currentSector = player.sector;
short wallCount = sector[currentSector].wallnum;
short currentWall = sector[currentSector].wallptr;
short currentSectorBackside = wall[currentWall].nextsector;
short nextPoint = currentSectorBackside = wall[currentWall].point2;
long vertex1X = wall[currentWall].x;
long vertex1Y = wall[currentWall].y;
long vertex2X = wall[nextPoint].x;
long vertex2Y = wall[nextPoint].y;
I'm sure there is a better way than this..
Apologies if this was too long.
I'm not knowledgeable about C, but this appears to be declaring an anonymous struct and then saying "vertex" is a pointer of the type of this anonymous struct. So as I understand it, it would be equivalent to something like:
What's jumping out at me here is that you need to allocate or assign a vertex array for each structure, instead of making them values of the structure (or using e.g. a vector because C). The use of an unsigned char pointer for the neighbors with a sentinel value of -1 has me just scratching my head--at that point why not just use NULL as the sentinel value for no neighbors? Anyway, point is you've got pointer types to deal with where they appear to just be value types in the load data, which means you're going to need to allocate members and arrays to fill them, and then do the required housekeeping.
Where things look like you're going to have trouble is you're going to need to traverse wall and build up a list of all neighbors for each sector, allocate, and assign it to neighbors. And then of course when that changes you're going to need to deallocate it. You likely will need to use the Build data as the input for a datastructure more suitable for your implementation rather than loading it directly.
The structures you're using right now strike me as using pointers quite, err, pointlessly, but presumably there's a reason for it that isn't obvious given a single forum post.
There are some number of sectors, each sector has some number of point, neighbour pairs
They're separated because that produces a more compact serialization and it's likely that those are just pointing into the file that was read
Yea, the file format used to generate the level was weird
So good news. I leared the difference between a -> and a .
-> accesses a struct member via a pointer
. accesses a struct member via the struct variable
Using that tool, I found how how to "borrow" data using a new struct pointing to the loaded data.
It works, but I'm not super happy with it. First IntersectBox() and PointSide() are macros (Because the original programmer couldn't use templates in C) I may need to make these actual functions and just watch what I pass to them. Another thing that bug me is that the "build" data uses coordinates of long integers and I use floats (my units are equivalent to meters) , the scale is WAY different and the Y axis is, weirdly, upside down. So I may need to do some scaling and flipping when I load the level in my coordinate system.
Works a treat though!
Edit: That is to say "not too surprised there's more of those from the beforetime".
Y-down views the screen as the hardware does with address 0 being the top-left pixel and increasing addresses going down the screen
Most computer things end up Y-down but with enough math you can do it either way.
I like the duke "build" map because it's map is so simple. Doom's Wads are too complicated and I don't have to worry about nodes, linedefs, sidedefs etc etc.. and I get a level editor for free! (As long as I'm not using any of the duke code and only following the map spec, I have a clear copyright too The "YouTube" engine is CC0, so I guess it's my engine now. Public domain is really rad!)
Now here comes the fun part.. Scaling.
My engine came with units in.. feet(!) and I'm going to convert that to meters. It's coordinate system is Y+ = North, X+ = east, and Z+ = Up. Angles are in terms of Tau (2*pi, counter-clockwise)
In build, 1 meter = 512 units, and it's units are Y- = North, X+ = east, an Z- = up. Oh and the Z axis is a different scale then the X and Y (8,192 units per meter). Angles are 0-2047 units, clockwise)
The angle conversion is done and I already flip and scale the Z axis on load, however, when flipping the Y axis, my sector math breaks down because the sector line crossing algorithm assumes the sector vertexes are clockwise. I'll make due with my levels being flipped.
I think GameMaker studio does that too.
This does not make it not-annoying. :P
CSS? I get that, very sensible. Phones and TVs? No. Bad. Bad bad bad, go to the box and feel shame. Don't even start me on the Android ecosystem and its inability to decide which end of a device is "up"...
Boy have I got bad news for you about how displays are typically scanned out
Me and everybody else: I don't believe you.
Big change: okay fine I hid the problem in another castle
django: not even once
fork + exec is strictly more work for the kernel to do, requires CoW be implemented for private memory (or more strictly implying that private memory does not exist) and makes more exotic memory management like user mode paging difficult-to-impossible. This also makes it extremely difficult to maintain a total memory commit size. linux is an OS that can give the user more memory than it can actually make available
It is however very simple both in concept and execution
But it does mean that if you allocate memory some other process can die for you instead!
It's Very Fun to deal with this in the chrome process model. At least that's designed such that only one process actually cannot be respawned but there's just endless bugs coming in about flickering screens and crashed renderers that were just "well you tried to show a 4000x3000 image and you can't do that"
I mean, in my world, that's a problem!
Because yes, I do check for failure on every malloc (in C) and in C++ since we don't have exceptions, we do not use the heap!
I feel like in embedded land though this is kind of what you want though? Complex real-time systems can have dynamic resource constraints (and should be designed to fail gracefully) - something like this is what saved the Apollo 11 landing for example, keeping the main landing process alive when the system was overtaxed.
When you don't have a heap, everything is placement new (objects) or statically allocated (buffers used for placement new, buffers used for stacks, never use static objects). And yes, only a subset of the standard library is available. Particularly off limits are the container classes except std::array and std::tuple.
Absolutely not.
If you have dynamically allocated resources, they need to be carefully constrained so you don't end up with heap fragmentation and out of memory when you're talking desired uptimes of > 1 year. The easiest answer is either to only allocate on the heap up front on boot and never allocate again after that, or to just link against C standard library instead of the C++ standard library and remove all uses of malloc.
How is "kill random processes" failing gracefully?
For the use case you're describing, that process needs to be at a higher priority than other competing processes so it can advance even if the other processes are poorly behaved. Preferably on a dedicated MCU rather than a shared CPU as well, if practical. Sharing CPU time for safety-critical processes is ill-advised. In an ideal world, the firmware is either only involved in enabling a hardware interlock (for sequencing purposes) or is running on a dedicated MCU with extremely simple logic where the disassembly has been checked for correctness. I don't want firmware anywhere near safety-critical stuff if I have a choice. Bake that shit into the ASIC!
That's exactly part of the thinking behind that design choice. When you have hard realtime guarantees to make, limited RAM, and uptime guarantees to meet, sometimes you gotta make tradeoffs.
In an application, a failed allocation is probably a sign the system is overtaxed and your app dying is the correct thing to have happen.
https://blockly.games/
https://studio.code.org/courses
https://www.kodable.com/
https://codecombat.com/
https://lightbot.com/
Not really "learning" so much as creating:
https://www.stencyl.com/