All right, guys.
Welcome back.
How is it going?
This challenge was freaking hot.
Absolutely true.
If you have resolved this, congratulations.
You get your blue belt afterwards.
And if not, maybe you want to watch until a certain point.
When I provide you a hint, then you can go for this challenge once again.
So it's a very nice feeling if you can solve this challenge afterwards on your own and not just keep
watching it.
The complete solution.
So at least please try to solve it.
If you are not ready for this, absolutely no problem.
I will guide you through this right now.
All right.
So let's take a look into this together.
Okay, so here we are, the Ubuntu VM.
Let's have a look.
We go into apps and space ping.
And they combine in this challenge, we focus on this multiple shot, but then afterwards, you also
have to adjust the other pitches.
All right.
Sounds good.
Let's do it in this way then.
We are working on the same base over here.
Okay, let's have a look into this one.
Try the ski slopes.
That's the directory.
We want to open the APK.
All righty.
Systems player input system.
Here we go.
Now let's scroll down.
So this part is regarding to our player shot.
So we are creating here a player shot and we create another player shot.
Now we have to figure out what is really happening here because it's really important that we understand
what's going on here to solve this challenge.
So therefore, I pull out my graphic tablet and then we have a look into this together.
All right.
So I see you in a few moments.
Okay.
So I'm on my graphic tablet.
Let's have a look into this.
Here we have our spaceship and this one over here.
And normally, we we are shooting and only having a single shot.
So this one.
Okay.
We can also see those very accurate time delays
between each shot.
So let's have a look.
This is our allow case.
So we are allowed to shoot.
Next, we have this check, this shoot.
And and this time to shoot is less than equal.
Zero.
This means we are allowed to shoot.
Otherwise, we will increase this delay over here.
So this causes some delay.
And this part here allows us to shoot.
Okay.
So this one is clear.
Then we have this check.
This double shot has entity.
This means do we have a double shot?
Which means picking up a red coin gives us the possibility or gives us the ability to have a double
shot.
All right.
If this is not the case here, we have a single shot.
So this means the difference between a double and a single shot.
Are those lines?
These two lines provides us a double shot.
And this line over here provides us a single shot.
All right.
Afterwards, we we've got our blocking rate, which we can get rid of by replacing this number with
zero.
So our main instructions that makes the decision between a double and a single shot are these oops,
these over here.
And this one.
So let's focus on this.
Let's clean this up and have a look.
Okay.
So we need to investigate what's going on here, here and here.
Let's have a look.
The beginning seems to be the same.
Yes.
So until here.
Until here, we have exactly the same.
Then we've got a little bit of an indifference.
Okay.
So this is a very good starting point right now because there's just a little adjustment.
The only difference seems to be we have here position X -15 and here position X plus 15, and that's
all.
The rest seems to be equal.
Yes.
So this one here, this is the first parameter in this function.
And this one over here is also the first parameter in this function.
We just extend our parameter with X plus 15 and also X -15.
This makes the whole difference between a single and a double shot.
Nice.
Let's have a look into this.
Create player shot.
What happens there?
So let's see.
We double click on this one and then we are in here.
So here we are in the create player shot method.
Let's see, we have three parameters a word and let's call this P one.
We have a floating x, which is P two and we have float y, which is p three.
Okay.
Then we go into this method, we create a new entity and this one is thought in E.
So our P one is being used to create a new entity.
So this one here becomes our E.
All right, next, we are creating a new position object.
This one over here.
And then we assign X and Y to this position object.
So this one here, this is X, and this one over here is Y.
All right.
Let's have a look into this position object, because this is the most important part in our function
Y, because this one over here, this parameter, this makes it difference between having a single player
shot and having a double player shot.
Therefore, we need to keep track on what this parameter does or how is it being used because by modifying
this one, we achieve what we want to have.
So let's clean this up a little bit, okay?
And now let's have look into the position part.
So this one here.
All right, this is easy.
We've got just two values.
Two instance fields X and Y.
All right, so now let's keep track of this one.
Okay.
So this would be stored in position X.
Okay.
So what happens next?
Then we assign also the Y.
So we have used all of these three parameters now.
Then we have our entity.
This one.
This was our world entity.
Okay.
And we say entity edit add position.
So yeah, we do not know what this one does, but it seems to add something new at this position that's
provided over here.
This one, let's have a look into this e edit add and then position.
Okay, so this now looks very complicated.
Return.
Yeah, a lot of stuff.
We also may also have to figure out which of them is being used.
So let's get back.
We can close this one and here we can see we are only using one parameter.
This means we are using this one.
Yes, this one has two parameters.
So we definitely using this one.
Okay.
We can keep track of what's going on here.
We can investigate this.
But reverse engineering doesn't require often going that deep into stuff.
We just can take assumptions and see if we are correct on this one.
And if not, yeah, then we can dive into this and figure out what's going on right here.
But for now, this looks way too complicated.
So let's see.
Let's say we simply add a new yeah, a new entity, a new object at this position.
So let's assume it's exactly doing this.
This means we are adding a new object.
It and then this position
and this one has the position X or the instance fields X and Y.
Okay, next we've got some Sprite.
All right, then we've got Sprite name player shot and this sounds good.
Okay.
So it seems to assign a new Sprite name, which is player shot.
This sounds good because we want to create a player shot.
Okay.
And then we've got this Sprite player effects.
Okay.
We do not know what this one does, so we just skip this.
Then we have oh, this one sounds now good.
We have ADD Sprite and our Sprite is this one here.
Here we are adding this bright.
All right.
So here we have seen we are adding a new object at this position and here we have now add sprite.
So it seems like to add now our player shot Sprite.
I mean, so we have to reverse engineer this part right now.
So this is just a guess.
But regarding to our observation that this one creates a player shot and this is exactly what this one
sounds like.
It's yeah, I guess it's a well educated guess.
So here it seems to create a new here create a new player shot.
Okay, next we've got this velocity, so we do something with the speed, then we adjust the speed.
So this might be the speed.
How fast this player shot.
Yeah.
Is traveling over this map.
This might be also in super interesting value over here.
Maybe we can speed up our player shot even more.
This would be super amazing.
Right?
Okay, then we can see.
Okay.
We add also the speed now to our entity.
Okay.
Now it seems to make sense.
So we are creating a new player shot.
Then this.
Let me let me try to draw this once again.
There we go.
This looks like exactly the original player shot.
Right.
Okay.
I have to add the space ship.
There we go.
Okay.
So we are creating a new position of this player shot because it has to be drawn on this map somewhere.
This is this part over here, the position part.
Then we assign the sprite that it looks like a player shot.
This is the look of this player shot.
And now we adjust the speed to this player shot.
So how fast this player shot goes over the map.
Then we've got this regal bounce, this one with an eight OC.
Now we adjust the width and height of this player shot.
So for a second I was like, okay, I don't know what this means, but if we keep moving on in this
code, it makes sense.
All make sense.
I can be, of course, completely wrong on this.
Guess so.
I didn't take a look into all this function, but if you reverse engineer something, you will never
be finished if you go into every function step by step.
So in my opinion, it's better to get an overview of what's going on and then verify if our estimation
on what's going on is correct.
Okay, so then let's move on.
So this one seems to be.
This one seems to be the width and height of this object.
And then.
Offscreen remove sound player.
Oh, nice.
Here we can see we have also some sound.
So I guess it's looking.
Yeah, this should be the icon.
We also now have a sound on this object and we are returning it afterwards.
All right, this makes sense.
So this function is huge and it's even even more amazing than being huge.
Regarding to the Java part, it's not huge, but I have a feeling that in the smiley part this is ridiculous.
Large.
All righty.
So let's see, we create an entity and this takes quite a lot of effort.
We have to adjust everything on this object here.
We have to tell the position in our map.
So at this point, we have to tell how fast it travels over the map.
We also have to tell the size of this object.
So width and height and also a player sound and what it looks like.
The Sprite name.
Well, this is a lot of stuff, but this gives us also the power to adjust all of these values.
Isn't this nice?
I mean, adding the sound or changing the sound?
Yeah, that's boring, of course.
But maybe we can we can make this a little bit bigger.
So let's say we've got a player shot that looks like this, so therefore we can blast away three aliens
in one row with one single shot.
This would be also nice.
I haven't thought I looked into this right now.
I'm absolutely honest with you.
Otherwise, I have also included this in the video.
So hacking a game and smiley is so much fun because you will never finish in doing a lot of nice modifications
onto this.
Okay, but before I get too hyped up right now and yeah, try playing around with those objects itself,
let's get back on what was our original task?
So what we want to do is we want to add an multiplayer shot.
Okay, so this was our task and we can also see this has to be done in this one over here, create player
shot.
We have also figured out that this one is the key, the position X.
Now let's think about why this is the key.
I will clear the screen and then we talk about this one.
Okay.
So to understand this, let's draw our space planning application real quick.
So I take this little help to draw straight lines.
Okay, so here we have our player and here we have our aliens.
So the X position makes a difference between having a single and a double shot.
So to understand this, we have to observe our game really close and feel free to keep playing it once
again and try to make an observation on this one.
Try to figure out in which direction we can move our ship object over here.
So this one over here, how we can move with this one in our space ping application.
Okay.
So an important point in our app is we can only move this ship from right to left or from left to right,
but we cannot move it upwards.
So this direction is not possible.
And you know what this direction is?
The Y coordinate and this one is the X coordinate.
If we now take a look at this parameter again, it makes now a little bit more sense, right?
So if you want to create a player shot, we have to provide the position of this player shot this one
over here.
But this position, I mean, the y coordinate this one here, it only makes a difference where this
player's shot starts.
So if it starts here, for example, and let me clean this up, if it would start here or if you would
start directly here, for example.
So let's say we adjust this y coordinate, then our player shot would start far above from this ship.
Therefore, the spy coordinate is always bound to our ship that the shot gets created directly at our
ship.
Okay.
This makes sense.
And this is the reason why this one doesn't affect our player shot at all.
If he would modify this value.
Even if we have a player shot, all we would change is the position of this player shot.
So instead of starting here, the player shot would start here.
And also for the double shot, if he would have a double shot, then we would just adjust the position
of this double shot.
So this one here starts Wavefront up of the space pane application ship over here.
All right.
Therefore, the hate here, this one, this doesn't affect our double shot.
It just affects our position of this double shot.
So I guess I say this now 20 times again, but it's really important because it automatically leads
to our solution.
So if this one is not responsible for our double shot, it's the X value.
And we have already observed this.
Now why is the x value relevant for our double shot?
So the x value makes a decision where our player shot is going to be generated, and this means from
this one to this one.
So our whole screen here, if we have a single shot, our player shot is directly created at our ship.
But if we have a double shot, our player shot will be a little bit off from our ship.
So let's say our ship would be here then our double shot is a little bit off regarding to the single
shot over here.
All right.
So let's have a look into this.
We go into the player input system and this is exactly what we are seeing here.
So this one here is a single player shot.
We have our space ping application and now we create a new entity on our world.
So let me draw this once again a little bit more clean.
So we create a new entity on our world.
And here we also have some some aliens.
Okay?
And we create a new entity at the position X and the position Y.
And what we didn't reverse yet is that this position is bound to this player object here.
So let me maybe draw this in this way.
The position X and Y is bound to our player object here.
Okay, so now we are creating a single player shot directly in front of our player.
The player cannot move upwards.
So this one here is Y and this one here is X.
Okay.
This means if we have a double shot, this one over here, we are creating two player shots.
But if we would create two player shots at the exact same position here, it doesn't take effect.
Therefore, we are shifting them a little bit.
And this is exactly this one here.
Okay.
So if these are two objects at the same position, we do not see a difference because they are overlaid
on each other.
And this is the trick, how the double shot is being created.
We shift the position of both objects to the left and right so we can see this over here.
We have here the position of our player object, position X, and now we create a new player shot over
here.
This is our first player shot at this position, x -15.
So we take the position X, this one here -15.
This means we are at this position -15, and now we are creating this shot.
So it's a little bit off from our shape right now.
And we do this once again over here and this one here.
This is the second shot.
And this one gets now created at the position X plus 15.
This means now the second one is X plus 15.
So this is our x, this line and now we add plus 15 on this side.
So we create this player shot here.
Here we have -15.
All right.
And this is how the double player shot gets created by understanding and knowing this right now, we
can adjust this.
I will provide you now some additional hints.
But if these are enough for you right now, feel free and try to solve this challenge over here.
Otherwise, let's see what we have to do.
I'm not going to show you the code, just the the approach on Yeah.
What we need to do here.
Maybe first I clean this up a little bit.
Okay, so what do we need to do?
If you want to create a new player shot, we have to copy paste one of these, for example, this one
here.
So now if we only copy paste this one here, we will create a player shot at the exact same position
here.
Therefore we will not see the effect this means after copying this value, we also have to adjust this
one over here, this value, and we have to adjust it in a way regarding to an offset that it's not
being used on another player shot.
For example, if you say -30, then if we provide here instead of -15 on our new created player shot.
So we need to copy, paste this line and edit here.
And then we, we have, for example, -30, then we would create a new player shot at this position.
And we can also do this by copying, pasting this one, taking this value.
And here we had here we have to add, for example, plus 15 once again that we have a total of plus
30.
This means we are creating a player shot at plus 30.
And yeah, if you want to add an additional shot, we take this once again and we have to adjust 15
once again so that we have plus oops plus 45.
This means we are now at plus 45 and also the same over here, -45.
And we can do this over and over again.
The hard part on this challenge is this value over here.
So you can achieve this in different ways.
Of course, once again, what you can do is you can subtract the value twice from the register.
This is one solution.
You can also use an existing floating point number, for example, this one here, and use this in a
register and edit on this value over here.
Then you also achieve a different offset.
And if you add this twice or even more than yeah, the we've got our layout here.
Okay, so this is my hint regarding to this challenge, even after reversing it that far, it's the
super heart, believe me.
You have to figure out where this line of smiley code is, and then you have to copy all the instruction
regarding to this line.
I'm not sure how many these are.
Maybe three or four or only two, I don't know.
And are after copying this, we have to adjust this parameter over here that it gets subtracted once
again or that it has a different value.
To be honest, I'm absolutely happy if we achieve and let's say instead of an octa.
So it's okay if we achieve this with an a quatre, quatre, quattro with this amount of shots.
All right.
Okay.
So these amounts of shots are absolutely these are well enough to receive your bed afterwards.
But if you want to go to try hard mode.
Yeah, feel free to go for this one.
Okay.
So now you can pause and rewind this video.
I will move on with the solution of this one.
So let's see.
Okay.
So let's open the smiley file for this one.
And then yeah, we are trying to figure out where this one is.
So, so via opening.
Now it's important that we are opening the correct one.
So we are opening our space paint challenge decompile not just space playing decompile and then.
This is our modified version, right?
Yes.
And I don't want to lose this.
You know what?
Let's save this first.
So this is our space playing modified regarding to block and double shot
OC then APK Tool D.
And let's recompile it once again.
Okay.
By the way, if you have modified this one over here, the player shot, the double shot.
Sorry.
And you haven't adjusted this one over here.
You have to pick up a coin first until you get your cuatro octa pander shot, whatever you have adjusted
there.
All right.
Yes, of course.
You already know this, but I just want to mention it.
These are some mistakes that can occur.
Okay.
So let's see.
We are back here and let's open the smiley directory completely.
Then we are in the space paging systems player input system.
Okay.
We can also see the player input system has $1 one.
And also dollar fire state, which means these are inherited classes in that we have discussed about
this.
So yeah, this might be also a little bit confusing, but these two doesn't contain our our logic.
We are looking for our logic is directly in our player input system in this method over here.
Okay, so let's see what we are looking for.
Hmm.
We can look for this value over here.
Yes, I guess this one is not very often used.
Looks good.
So let's see.
We are looking for 15.0.
We've got this in the register v 11 directly at the beginning of this function.
This means we are referencing to the register v 11 in our huge function underneath.
So let's figure out where we do this.
Okay.
This looks good.
Yes.
Okay.
So here we are using this value, but we have assigned this at the top of this function.
So let's see if it does not get overwritten before.
Yes, we have three occurrences of this register and none instruction seems to override it.
Yes, we just use it in an sup also here in an ad.
And let's see, the beginning was the declaration.
Okay, so now we know this one is definitely holding our value 15 in the form of a float.
Alrighty.
So let's see what happens here.
Let's take this piece of code and get back on our graphic tablet because we definitely need to reverse
engineer all those lines that we understand what's going on.
So I see you in a few moments.
Okay, so here we add the graphic tablet.
Let's have a look into this.
Yes, of course, we have cut this a little bit off.
But this was regarding to the F condition.
So we can see we start at line 138.
So this is the decision if we have a double shot.
Okay.
But we are not interested in this one right now.
We are more interested in how to establish what gets created.
All right.
We know our V 11 is holding a certain value.
So this one here, we 11 let's write this over here.
And this is holding the value of 15.0 in float.
Okay, let's go then we've got I get object and we can see we have our P zero which is the this operator.
So let's mark it in this way.
And this, this operator is from this dot word.
So and this start.
But we are storing this value into v zero.
All right.
Next, let's see.
We've got I get once again, we are fetching the value in V six.
In this overview, we do not have the value of V six, but it's also not that important because we can
see v six is the position x on float, the affection, this value and storing it in v one which means
we are having here and yeah an instance field from the type position.
So we want this now let's mark this a little bit different from this type over here position dot x.
All righty then.
We are subtracting v 11 from v one and we are storing back the result in v one.
This means we have something like we want.
This equals v one minus v 11.
So we what is our exposition and now we are subtracting from our ex position v 11 and we 11 is our value
of 15 float.
This means right now we have our our spaceship which has X and Y, and now we are subtracting from this
let's, let's draw this imaginary line.
So now we are subtracting from this position -15.
Okay.
This is what now is being hold in.
We want.
All right then we have I get we are fetching now divide position.
We have seen that this one is not that relevant for us because we cannot move our ship up or downwards.
We can only move it from right to left.
Okay.
So this one is being stored in B to B to is now holding.
Hmm.
Yeah.
Let's nevertheless, let's take the same color.
So until now, everything is clear.
Now we call it invoke static on v zero.
We want and B to invoke static means we have no this object.
We have three parameters.
Let's see.
Those three parameters are here.
Yes.
So the first one is this one.
It's word.
Then we've got this one, which is a floating number and we've got this one over here, which is also
a floating number.
And we are returning back and entity.
Okay.
So to make this not as messy as the last one, let's simply use it in this way.
So we are calling entity factory create player shot over here.
All right.
This is what we are calling here.
And we are returning back an entity.
This means we create a shot.
Okay.
Our registers or parameters are V0 one and V two.
So this means this one.
Here is our first parameter and this one here is our second, but not this one.
And this one here is our second parameter.
And this one here is the third parameter because we subtract the value before we use it as a parameter
in there, let's draw this.
Here we are using V one and here we are subtracting a value from v one.
So we are providing an offset of this position to this function.
Okay then let's see what we have next.
Then we've got I get object.
So we are fetching another this object.
So P zero is our this object and we are fetching this dot world once again and we are putting this into
v zero.
By the way, we do not do anything with this return value over here yet.
So we are calling this static method, but we don't use this entity right now.
That's also pretty interesting.
Okay.
But back to this one.
So we zero is now the start word.
Okay, then we are fetching the position X once again.
So B six is being stored in v one and we can see over here and this one is our position x.
From type float.
So we one is holding position x OC then we are adding this is now adding so plus and this one here was
subtracting minus.
So we are adding now our value and register v 11 to this one OC.
So we want let's take or try to take the same color.
That's a little bit of but it's OC we want us now.
Our position X so it's we one plus we 11.
So we've got this yeah.
The reverse part of this right now.
So now we are going plus 15 in this direction here.
Okay.
So far, everything is clear.
We know what this one, this one and also this one is and this one.
Okay, now we are fetching the position why and we are storing it in V two.
Okay, so let's write it here in b two is now, but market us.
It's the instruction before V two is now position that y
okay.
So this is also clear and then we've got our inbox static here once again so we can now see this one
here is the same as this one here.
Okay, so invoke static, we are calling entity create player shot and we are calling it again on 0v1v2.
This means and this is our first parameter and this one here is our second parameter and this one here
is the third parameter.
So this means we are creating now a new player shot directly here.
So we have to clean this off.
And now we are creating a new player shot here, plus 15.
And then again, we do not do anything with the return value.
And this one here is regarding to time to shoot.
All right.
So our method ends here at this point.
Well, let's say our approach in creating a double shot, it starts right here and it ends over here.
So this is the part we need to focus.
Okay.
It seems to be a mess once again, but I hope you can follow on this one.
So let's play this even up a little bit further.
This means this one over here in this line, this line, this line, this line and this line and also
this line.
This is regarding to the left player shot.
And this line, this line, this line, this line and this line.
This is regarding to the right player shot.
And we can also see this as an identification of those line numbers over here.
Okay.
So if you want to create a new player shot, we have to copy paste this part over here and then we have
to modify this here.
We can do this by modifying or replacing the register B11 with another one.
For example, here we can see this floating number of 2.5.
This means we can create a new register just right before.
Let's call this me 12.
I'm not sure if B 12 is being used, but if you want to create a new floating point number 0.2.5, we
can use this value over here.
So by using this value over here and then changing the 11 to our newly created register, we 12.
This should work, but this has to be done on our copy it version of this one here.
So let me clean this up a little bit.
Okay.
So this is our job we need to do.
So if you still get an understanding what's going on right here, I'm super happy about this one.
I will now move on with this solution.
So feel free to pause and rewind if you want to try this on your own right now.
Otherwise, yeah.
Let's move on.