Last active
August 1, 2024 20:02
-
-
Save samsartor/a7ec457aca23a7f3f120 to your computer and use it in GitHub Desktop.
Code for simulating the elytra item in Minecraft
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* An accurate simulation of the elytra item as of Minecraft 15w41b | |
*/ | |
public class ElytraModel | |
{ | |
public int glideTime; | |
public int damageTaken; | |
public double posX; | |
public double posY; | |
public double posZ; | |
public double velX; | |
public double velY; | |
public double velZ; | |
/** | |
* Simulates a Minecraft tick (20 per second). | |
* The pitch and yaw are the look direction of the player. | |
*/ | |
public void tick(boolean isCreative, double yaw, double pitch) | |
{ | |
if (!isCreative && (this.glideTime + 1) % 20 == 0) | |
{ | |
this.damageTaken++; | |
} | |
//I did some simplifing of the folowing to reduce the number of negatives and trig functions | |
double yawcos = Math.cos(-yaw - Math.PI); | |
double yawsin = Math.sin(-yaw - Math.PI); | |
double pitchcos = Math.cos(pitch); | |
double pitchsin = Math.sin(pitch); | |
double lookX = yawsin * -pitchcos; | |
double lookY = -pitchsin; | |
double lookZ = yawcos * -pitchcos; | |
double hvel = Math.sqrt(velX * velX + velZ * velZ); | |
double hlook = pitchcos; //Math.sqrt(lookX * lookX + lookZ * lookZ) | |
double sqrpitchcos = pitchcos * pitchcos; //In MC this is multiplied by Math.min(1.0, Math.sqrt(lookX * lookX + lookY * lookY + lookZ * lookZ) / 0.4), don't ask me why, it should always =1 | |
//From here on, the code is identical to the code found in net.minecraft.entity.EntityLivingBase.moveEntityWithHeading(float, float) or rq.g(float, float) in obfuscated 15w41b | |
this.velY += -0.08 + sqrpitchcos * 0.06; | |
if (this.velY < 0 && hlook > 0) | |
{ | |
double yacc = this.velY * -0.1 * sqrpitchcos; | |
this.velY += yacc; | |
this.velX += lookX * yacc / hlook; | |
this.velZ += lookZ * yacc / hlook; | |
} | |
if (pitch < 0) | |
{ | |
double yacc = hvel * -pitchsin * 0.04; | |
this.velY += yacc * 3.5; | |
this.velX -= lookX * yacc / hlook; | |
this.velZ -= lookZ * yacc / hlook; | |
} | |
if (hlook > 0) | |
{ | |
this.velX += (lookX / hlook * hvel - this.velX) * 0.1; | |
this.velZ += (lookZ / hlook * hvel - this.velZ) * 0.1; | |
} | |
this.velX *= 0.99; | |
this.velY *= 0.98; | |
this.velZ *= 0.99; | |
this.posX += this.velX; | |
this.posY += this.velY; | |
this.posZ += this.velZ; | |
this.glideTime++; | |
} | |
/** | |
* Checks if the player is currently in a gliding state. | |
* As you can see, if the player is in creative, they will remain gliding even if on the ground. They will stop gliding once they move (but that functionality is not shown here). | |
*/ | |
public boolean isGliding(boolean isCreative, boolean isOnGround, float fallDistance) | |
{ | |
if (isCreative) | |
{ | |
return glideTime > 0; | |
} | |
else | |
{ | |
return !isOnGround && fallDistance >= 1.0f; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
BuildElytraData[pos_, vel_] := <|"time" -> 0, "pos" -> pos, | |
"vel" -> vel|> | |
BuildElytraData[] := BuildElytraData[{0, 0, 0}, {0, 0, 0}] | |
ElytraTick[dat_, \[Theta]_, \[Phi]_] := | |
Module[{out = dat, vel, pitchcos, pitchsin, sqrpitchcos, look, hvel, | |
hlook, yacc}, vel = dat[["vel"]]/20; pitchcos = Cos[\[Phi]]; | |
pitchsin = Sin[\[Phi]]; | |
look = {Sin[-\[Theta] - \[Pi]]*-pitchcos, -pitchsin, | |
Cos[-\[Theta] - \[Pi]]*-pitchcos}; | |
hvel = Sqrt[vel[[1]]*vel[[1]] + vel[[3]]*vel[[3]]]; | |
hlook = pitchcos; | |
sqrpitchcos = pitchcos*pitchcos; | |
vel[[2]] += -0.08 + sqrpitchcos*0.06; | |
If[vel[[2]] < 0 && hlook > 0, yacc = vel[[2]]*-0.1*sqrpitchcos; | |
vel[[2]] += yacc; vel[[1]] += look[[1]]*yacc/hlook; | |
vel[[3]] += look[[3]]*yacc/hlook]; | |
If[\[Phi] < 0 && hlook > 0, yacc = hvel*-pitchsin*0.04; | |
vel[[2]] += yacc*3.5; vel[[1]] -= look[[1]]*yacc/hlook; | |
vel[[3]] -= look[[3]]*yacc/hlook]; | |
If[hlook > 0, vel[[1]] += (look[[1]]/hlook*hvel - vel[[1]])*0.1; | |
vel[[3]] += (look[[3]]/hlook*hvel - vel[[3]])*0.1]; | |
vel *= {0.99, 0.98, 0.99}; out["pos"] += vel; out["vel"] = vel*20; | |
out["time"] += 1/20; out]; | |
ElytraSim[initdat_, \[Theta]f_, \[Phi]f_, time_] := | |
Module[{out = {initdat}, t, dat = initdat}, | |
While[dat[["time"]] <= time, t = dat[["time"]]; | |
dat = ElytraTick[dat, \[Theta]f[t], \[Phi]f[t]]; | |
AppendTo[out, dat]]; out] | |
PlotElytraFlight[datlist_, options_] := | |
Module[{points, x, y, z, rangeinfo, range, ranges}, | |
points = datlist[[All, "pos"]][[All, {1, 3, 2}]]; | |
rangeinfo = (range = MinMax[#]; | |
Join[range, {Mean[range], range[[2]] - range[[1]]}]) & /@ | |
Transpose[points]; | |
ListPointPlot3D @@ | |
Join[{points, BoxRatios -> (Max[#, 1] & /@ rangeinfo[[All, 4]]), | |
AxesLabel -> {"x", "z", "y"}}, options]] | |
FindFlightEq[initdat_, \[Theta]_, \[Phi]_, err_] := | |
Module[{lastdat, dat, con = True}, dat = initdat; | |
While[con, lastdat = dat; dat = ElytraTick[dat, \[Theta], \[Phi]]; | |
con = Max[Abs[dat[["vel"]] - lastdat[["vel"]]]] > err]; dat] | |
----------------------------------------------------------------------- | |
Examples | |
----------------------------------------------------------------------- | |
PlotElytraFlight[ElytraSim[BuildElytraData[{0, 0, 0}, {0, 0, 0}], 25 # Degree &, 70 Cos[#] Degree &, 20], {Filling -> Bottom, ImageSize -> Large}] | |
ListLinePlot[Transpose[Table[Join[{{1}, {1}}*180.*\[Phi]/\[Pi], Partition[FindFlightEq[BuildElytraData[], 0, \[Phi], 0.001][["vel"]][[{3, 2}]]*{1, -1}, 1], 2], {\[Phi], -\[Pi]/2, \[Pi]/2, \[Pi]/64}]], AxesLabel -> {"Pitch", None}, PlotLabel -> "Glide Velocity", ImageSize -> Large, PlotLegends -> {"x", "y"}] |
Can you update it for 1.16.3? I am pretty sure it changed a lot since then because it seems to be slower than normal
For mathematica, how would I code it so that I get a ListLinePlot of the xy position for a certain pitch over a time period. So it would map its changing poition for 5 seconds for a pitch of 5 degrees or so. This is what i had so far but i think im messing it up (Ive never used mathematica before)
ListLinePlot[Table[ElytraSim[BuildElytraData[], 0, 5, 5], {pos, 0, 100, 10}]]
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@zbot223 I don't think this code is at all usable code in a mod. It was just to help me reverse-engineer the elytra flight mechanics when the item was first released. I'm using "Model" in the statistical sense here.
It has been a while since I've worked on a mod but my understanding is that Minecraft now has a real 3D model format so you don't have to code the geometry any more. Have you looked at https://minecraft.gamepedia.com/Programs_and_editors/3D_modeling?