Palpatine was dead: to
begin with. There is no doubt whatever about that. His flailing body was flung down the open reactor shaft. Crackling with dark side power, he fell faster and faster until he hit a bridge far down the shaft, and burst like a bomb. Anakin and Luke felt the concussion even hundreds of meters away. And if that wasn't enough, he was killed twice, once by his former apprentice, and once by the terrorists who destroyed the planet-sized station that the pieces of his body were at rest upon. Anakin saw it, Luke saw it, we in the audience saw it.
There is no doubt that Palpatine was dead. This must be
distinctly understood, or nothing wonderful can come of the story I am
going to relate....
Wednesday, October 30, 2019
Wednesday, October 23, 2019
What makes a story?
"I wonder what they'll be like?" he mused. "Will they be nothing but wonderful engineers, with no art or philosophy?" --From Rescue Party by Arthur C. Clarke
Specialization is for insects --Attributed to Robert A. Heinlein
I might think of myself as an engineer (and by no means wonderful) but sometimes I think about art and philosophy as well. Today over lunch I was thinking about what makes a great story -- what makes a story entertaining to me? For instance, why do I like Star Wars? Is it the characters? Is it the message?
For me, the most entertaining part of the original trilogy was the Battle of Endor (which the Empire totally should have won, by the way. Ewoks?). Specifically the best part of that was the run to the Death Star core. Why? Great visuals. We got to see the intricate detail of the inside of a massive, complicated object. The interior of the Death Star is itself a work of art.
Similarly, the boarding and launch of USS Enterprise in Star Trek: The Motion(less) Picture is the best part of that film by far. The new Star Trek had its moments, but they were too fast and filmed in shaky-vision such that we never got a clean look at all of the great models. From the clips I have seen of Star Trek: Beyond, it looks like Starbase Yorktown was done right. It might be way too large and expensive to be practical, but it does look awesome.
So, why aren't all movies just spectacular visual effects?
Firstly, visual effects are not cheap. It is far cheaper per minute to put a bunch of actors on a sound stage and just record a play, compared to special effects.
Second, if we do, we end up with such works as Sonic Vision and The Mind's Eye. These are works of art in themselves, but there is still something missing. I don't think even I could watch Sonic Vision for two straight hours. I finally think I know what it is. It's consistency. In a well-constructed story, all the pieces just fit together. As long as it maintains consistency, the larger the story, the better. In such a story, you can understand what is going on. You can make predictions, and evaluate the actions of the characters. Did it make sense for Han Solo to do that? Did it make sense for Admiral Holdo to do that? Harry Potter seems consistent, and it maintained that through seven books.
A good consistent story, then it seems, must be well-planned from the start. A good story universe, must have a solid scaffold of ideas, and all new ideas added to it must remain consistent. The best ideas might expand the scaffold, but in a way that makes it stronger and able to hold even more ideas. The core of any good story universe is one good story.
So: Why did Admiral Holdo do that? It was a visually stunning 10 seconds, but how does it work as for consistency? In order for it to make sense, she must have had some idea that it could work -- not necessarily a sure thing, but at least a reasonable chance to be worth trading her life for. If hyperspace ramming works, then why isn't it always used?
Also, the Holdo Maneuver didn't even get a mission kill -- Supremacy was not destroyed, only damaged. It was not stopped, only slowed. It still was able to launch an invasion of Crait. She aimed for a wing, rather than the core.
Here are the facts as shown in The Last Jedi:
- Raddus was almost out of fuel -- it had enough for one jump, and no further fuel to travel through normal space.
- Admiral Holdo ordered the abandonment of Raddus with her alone staying aboard.
- She turned the ship to face Supremacy.
- The crew of Supremacy thought that Raddus was either trying to escape or was trying to block/stall to give the rest of the fleet a chance to escape.
- Just before Raddus jumped to hyperspace, the crew of Supremacy realized what Raddus was trying to do, and started to take action to counter, but they no longer had enough time to prevent it.
- Raddus jumped to hyperspace with its trajectory through the right wing of Supremacy. It isn't clear from the footage whether Raddus actually entered hyperspace, or just hit Supremacy at high speed in normal space. In any case, the right wing of Supremacy was sheared off, and at least four trailing ships were destroyed by debris from the collision.
- During Rogue One, Devastator jumps into Scarif orbit just as the rebel fleet is trying to flee. At least one GR75 (transport-class) ship hits Devastator's hull and is destroyed, and its pieces are just brushed off.
- In one of the Legends comic books, a squadron of three star destroyers drops out of hyperspace right on top of Executor. All three ships are smashed to atoms, and while Executor has to stop what it is doing, its shields brush the collision aside, such that the paint isn't even scratched.
We can enumerate all the possibilities, and dismiss each of them. The Holdo Maneuver is inconsistent with what has come before.
- Admiral Holdo is such a great military leader that this idea is original to her. In the twenty thousand year history of the galaxy, no one else has had this idea. We dismiss this because even a cursory study of either galactic or Earth history would have revealed many examples of ramming as a reasonable tactic. I have seen Youtube videos by one of the numberless online jabberers stating exactly this, before The Last Jedi was released, as an alternate way to destroy the Death Star, use an X-Wing in kamikaze mode.
- The shields of Supremacy should have been able to protect it from the collision, as seen in other hyperspace-shield interactions. Admiral Holdo should have known this and not even have attempted the ram.
- You can't just jump one X-wing to hyperspace and expect to destroy the Death Star -- a single X-wing isn't big enough. Anything bigger is supposedly too expensive. However, if just mass will do the trick, there is enough plain mass in the form of such things as asteroids to do cheaply.
- There is something special about Raddus which makes it uniquely qualified to ram. If this is the case, Raddus is just a machine, and any machine can be duplicated.
- The only theory which is not immediately dismissable is that there is something special about Supremacy, perhaps related to the hyperspace tracker. Admiral Holdo could not have successfully rammed any other ship. Even so, Holdo would have had to know how the hyperspace tracker worked, at least well enough to know that it created this vulnerability. Besides, one of the Incredible Cross Sections books contains text to the effect that hyperspace tracking was merely an algorithm, and the hyperspace tracker on Supremacy was merely a large computer facility.
Saturday, April 6, 2019
C++ Cleverness
Yukari was in some ways an amazing piece of code. It didn't actually drive the robot all that well, but of all the things in it, I am most proud of it's self-documentation. Each run of Yukari produced a file which recorded three things:
- Data packets showing what the robot was doing and what it was thinking
- An image of its code and any other files I thought needed attaching
- A description of how to parse the record file, partly in English, partly machine readable. With this description, anyone who had the file could in principle write a piece of code to parse the file.
I am redoing this code for the Loginator. While it is easy to just use the same logic that I used on Yukari, that code was inefficient. It did the following:
- The packet start function took a pointer to a string describing the packet, and each kind of fill function took a pointer to a string describing the field. This was nice because the documentation for each field in the code is right next to the actual code for it.
- The start function and each fill function called the writeDoc() function, which took care of documentaion. After that was finished, it wrote the field.
- The writeDoc() function kept track of apids which have already been documented. If this apid has already been documented, writeDoc() returns immediately. Otherwise it write a field description packet.
- In order to make this work, the actual packet data had to be stashed somewhere. If the packet was in the process of being documented, writeDoc() for a packet start set up pointers such that the packet being written went to this stash buffer, and writeDoc() got to create actual packets in the proper buffer.
What I have in mind is much more clever. It will see the compiler generate the core of the documentation packets at compile-time. These will then just be in ROM, which we have bucketloads of. I think this will involve template meta-programming and constexpr functions.
Each call to start and fill will be immediately followed by a template class instantiation. This class template will take as parameters the apid, the string description, and perhaps some other stuff (units, conversion, etc). The class will declare a couple of static constant member fields, which will result in them getting stuck in the .rodata section, or maybe a special section. Once it is someplace in the read-only image, the startup code will write out all the documentation in the same way that
The interface will look like this:
start(apid_blah,TTC(0)); template class packet_doc<apid_blah,0,"This packet records exactly how blah things are">;
fillu16(blah); template class packet_doc<apid_blah,t_u16,"This field records the blah level">;
It's not quite as clean as the old way, but it is purely a run-time thing. To begin with, we would have a template something like this:
template<int A, int T, const char* D>
class packet_doc {
static const int __attribute__ ((section(".packet_doc"))) apid=A;
static const int __attribute__ ((section(".packet_doc"))) fieldType=T;
static const char* __attribute__ ((section(".packet_doc"))) desc=D;
}
We could make things fancier by keeping track of the position in the packet using more advanced template metaprogramming.
Update:
Nope, defeated. While you can use an address as a template parameter, a string literal doesn't necessarily have an address on its own. You can set up a const array with a string literal in it, and use that as the template parameter, but that starts getting way too ugly. I'll do it the old way, and use the bottom of the stack for temporary space. It isn't secure, because what happens if the stack and this buffer collide, but I'm not going to worry about that.
Update:
Nope, defeated. While you can use an address as a template parameter, a string literal doesn't necessarily have an address on its own. You can set up a const array with a string literal in it, and use that as the template parameter, but that starts getting way too ugly. I'll do it the old way, and use the bottom of the stack for temporary space. It isn't secure, because what happens if the stack and this buffer collide, but I'm not going to worry about that.
Subscribe to:
Posts (Atom)