better flight
This commit is contained in:
parent
182aabd032
commit
e23d2a3da1
|
@ -4,8 +4,9 @@ import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
public record FlightAbility(boolean allowed, int timeLeft, ResourceKey<Level> dimension, Vec3 origin, double radius) {
|
/**
|
||||||
public static FlightAbility deny() {
|
* @param timeLeft sentinel of -1 for infinite
|
||||||
return new FlightAbility(false, 0, Level.OVERWORLD, Vec3.ZERO, 0);
|
* @param radius sentinel of negative for infinite
|
||||||
}
|
*/
|
||||||
|
public record FlightAbility(int timeLeft, ResourceKey<Level> dimension, Vec3 origin, double radius) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,55 +7,73 @@ import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
|
||||||
import at.petrak.hexcasting.api.casting.getPlayer
|
import at.petrak.hexcasting.api.casting.getPlayer
|
||||||
import at.petrak.hexcasting.api.casting.getPositiveDouble
|
import at.petrak.hexcasting.api.casting.getPositiveDouble
|
||||||
import at.petrak.hexcasting.api.casting.iota.Iota
|
import at.petrak.hexcasting.api.casting.iota.Iota
|
||||||
|
import at.petrak.hexcasting.api.misc.FrozenColorizer
|
||||||
import at.petrak.hexcasting.api.misc.MediaConstants
|
import at.petrak.hexcasting.api.misc.MediaConstants
|
||||||
import at.petrak.hexcasting.api.player.FlightAbility
|
import at.petrak.hexcasting.api.player.FlightAbility
|
||||||
|
import at.petrak.hexcasting.common.lib.HexItems
|
||||||
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
||||||
|
import net.minecraft.Util
|
||||||
import net.minecraft.server.level.ServerLevel
|
import net.minecraft.server.level.ServerLevel
|
||||||
import net.minecraft.server.level.ServerPlayer
|
import net.minecraft.server.level.ServerPlayer
|
||||||
import net.minecraft.world.entity.LivingEntity
|
import net.minecraft.util.Mth
|
||||||
|
import net.minecraft.world.item.DyeColor
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraft.world.phys.Vec3
|
import net.minecraft.world.phys.Vec3
|
||||||
|
import kotlin.math.max
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
object OpFlight : SpellAction {
|
class OpFlight(val type: Type) : SpellAction {
|
||||||
override val argc = 3
|
override val argc = 2
|
||||||
override fun execute(
|
override fun execute(
|
||||||
args: List<Iota>,
|
args: List<Iota>,
|
||||||
ctx: CastingEnvironment
|
ctx: CastingEnvironment
|
||||||
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
|
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
|
||||||
val target = args.getPlayer(0, argc)
|
val target = args.getPlayer(0, argc)
|
||||||
val timeRaw = args.getPositiveDouble(1, argc)
|
val theArg = args.getPositiveDouble(1, argc)
|
||||||
val radiusRaw = args.getPositiveDouble(2, argc)
|
|
||||||
ctx.assertEntityInRange(target)
|
ctx.assertEntityInRange(target)
|
||||||
|
|
||||||
|
val cost = when (this.type) {
|
||||||
|
Type.LimitRange -> theArg * MediaConstants.DUST_UNIT
|
||||||
|
// A minute of flight should cost a charged crystal?
|
||||||
|
Type.LimitTime -> theArg / 60.0 * MediaConstants.CRYSTAL_UNIT
|
||||||
|
}.roundToInt()
|
||||||
|
|
||||||
// Convert to ticks
|
// Convert to ticks
|
||||||
val time = (timeRaw * 20.0).roundToInt()
|
|
||||||
return Triple(
|
return Triple(
|
||||||
Spell(target, time, radiusRaw, ctx.position),
|
Spell(this.type, target, theArg),
|
||||||
(MediaConstants.DUST_UNIT * 0.25 * (timeRaw * radiusRaw + 1.0)).roundToInt(),
|
cost,
|
||||||
listOf(ParticleSpray(target.position(), Vec3(0.0, 2.0, 0.0), 0.0, 0.1))
|
listOf(ParticleSpray(target.position(), Vec3(0.0, 2.0, 0.0), 0.0, 0.1))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Spell(val target: ServerPlayer, val time: Int, val radius: Double, val origin: Vec3) : RenderedSpell {
|
enum class Type {
|
||||||
|
LimitRange,
|
||||||
|
LimitTime;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Spell(val type: Type, val target: ServerPlayer, val theArg: Double) : RenderedSpell {
|
||||||
override fun cast(ctx: CastingEnvironment) {
|
override fun cast(ctx: CastingEnvironment) {
|
||||||
if (target.abilities.mayfly) {
|
if (target.abilities.mayfly) {
|
||||||
// Don't accidentally clobber someone else's flight
|
// Don't accidentally clobber someone else's flight
|
||||||
|
// TODO make this a mishap?
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
IXplatAbstractions.INSTANCE.setFlight(
|
val dim = target.level.dimension()
|
||||||
target,
|
val origin = target.position()
|
||||||
FlightAbility(
|
|
||||||
true,
|
val flight = when (this.type) {
|
||||||
time,
|
Type.LimitRange -> FlightAbility(-1, dim, origin, theArg)
|
||||||
target.level.dimension(),
|
Type.LimitTime -> FlightAbility((theArg * 20.0).roundToInt(), dim, origin, -1.0)
|
||||||
origin,
|
}
|
||||||
radius
|
|
||||||
)
|
IXplatAbstractions.INSTANCE.setFlight(target, flight)
|
||||||
)
|
|
||||||
|
|
||||||
target.abilities.mayfly = true
|
target.abilities.mayfly = true
|
||||||
target.abilities.flying = true
|
target.abilities.flying = true
|
||||||
|
// On fabric it only seems to make them actually fly once every other time so let's try this
|
||||||
|
target.onUpdateAbilities()
|
||||||
target.onUpdateAbilities()
|
target.onUpdateAbilities()
|
||||||
// Launch the player into the air to really emphasize the flight
|
// Launch the player into the air to really emphasize the flight
|
||||||
target.push(0.0, 1.0, 0.0)
|
target.push(0.0, 1.0, 0.0)
|
||||||
|
@ -63,48 +81,111 @@ object OpFlight : SpellAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun tickDownFlight(entity: LivingEntity) {
|
|
||||||
if (entity !is ServerPlayer) return
|
|
||||||
|
|
||||||
val flight = IXplatAbstractions.INSTANCE.getFlight(entity)
|
companion object {
|
||||||
|
// danger particles up to 1 block from the edge
|
||||||
|
private val DIST_DANGER_THRESHOLD = 2.0
|
||||||
|
|
||||||
if (flight.allowed) {
|
// danger particles up to 7 seconds from the limit
|
||||||
val flightTime = flight.timeLeft - 1
|
private val TIME_DANGER_THRESHOLD = 7.0 * 20.0
|
||||||
if (flightTime < 0 || flight.origin.distanceToSqr(entity.position()) > flight.radius * flight.radius || flight.dimension != entity.level.dimension()) {
|
|
||||||
if (!entity.isOnGround) {
|
|
||||||
entity.fallDistance = 1_000_000f
|
|
||||||
}
|
|
||||||
IXplatAbstractions.INSTANCE.setFlight(entity, FlightAbility.deny())
|
|
||||||
|
|
||||||
if (!entity.isCreative && !entity.isSpectator) {
|
@JvmStatic
|
||||||
val abilities = entity.abilities
|
fun tickAllPlayers(world: ServerLevel) {
|
||||||
abilities.flying = false
|
for (player in world.players()) {
|
||||||
abilities.mayfly = false
|
tickDownFlight(player)
|
||||||
entity.onUpdateAbilities()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!entity.abilities.mayfly) {
|
|
||||||
entity.abilities.mayfly = true
|
|
||||||
entity.onUpdateAbilities()
|
|
||||||
}
|
|
||||||
IXplatAbstractions.INSTANCE.setFlight(
|
|
||||||
entity,
|
|
||||||
FlightAbility(
|
|
||||||
true,
|
|
||||||
flightTime,
|
|
||||||
flight.dimension,
|
|
||||||
flight.origin,
|
|
||||||
flight.radius
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
@JvmStatic
|
||||||
|
fun tickDownFlight(player: ServerPlayer) {
|
||||||
|
val flight = IXplatAbstractions.INSTANCE.getFlight(player)
|
||||||
|
|
||||||
fun tickAllPlayers(world: ServerLevel) {
|
if (flight != null) {
|
||||||
for (player in world.players()) {
|
val danger = getDanger(player, flight)
|
||||||
tickDownFlight(player)
|
if (danger >= 1.0) {
|
||||||
|
IXplatAbstractions.INSTANCE.setFlight(player, null)
|
||||||
|
// stop shin smashing bonke
|
||||||
|
|
||||||
|
if (!player.isCreative && !player.isSpectator) {
|
||||||
|
val abilities = player.abilities
|
||||||
|
abilities.flying = false
|
||||||
|
abilities.mayfly = false
|
||||||
|
player.onUpdateAbilities()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!player.abilities.mayfly) {
|
||||||
|
player.abilities.mayfly = true
|
||||||
|
player.onUpdateAbilities()
|
||||||
|
}
|
||||||
|
val time2 = if (flight.timeLeft >= 0) {
|
||||||
|
flight.timeLeft - 1
|
||||||
|
} else {
|
||||||
|
flight.timeLeft
|
||||||
|
}
|
||||||
|
IXplatAbstractions.INSTANCE.setFlight(
|
||||||
|
player,
|
||||||
|
FlightAbility(
|
||||||
|
time2,
|
||||||
|
flight.dimension,
|
||||||
|
flight.origin,
|
||||||
|
flight.radius
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val particleCount = 5
|
||||||
|
val dangerParticleCount = (particleCount * danger).roundToInt()
|
||||||
|
val okParticleCount = particleCount - dangerParticleCount
|
||||||
|
val oneDangerParticleCount = Mth.ceil(dangerParticleCount / 2.0)
|
||||||
|
val color = IXplatAbstractions.INSTANCE.getColorizer(player)
|
||||||
|
|
||||||
|
// TODO: have the particles go in the opposite direction of the velocity?
|
||||||
|
ParticleSpray(player.position(), Vec3(0.0, -0.4, 0.0), Math.PI / 4.0, 0.4, count = okParticleCount)
|
||||||
|
.sprayParticles(player.getLevel(), color)
|
||||||
|
val dangerSpray = ParticleSpray(player.position(), Vec3(0.0, -0.2, 0.0), Math.PI * 0.75, 0.3, count = 0)
|
||||||
|
dangerSpray.copy(count = oneDangerParticleCount)
|
||||||
|
.sprayParticles(player.getLevel(), FrozenColorizer(ItemStack(HexItems.DYE_COLORIZERS[DyeColor.BLACK]!!), Util.NIL_UUID))
|
||||||
|
dangerSpray.copy(count = oneDangerParticleCount)
|
||||||
|
.sprayParticles(player.getLevel(), FrozenColorizer(ItemStack(HexItems.DYE_COLORIZERS[DyeColor.RED]!!), Util.NIL_UUID))
|
||||||
|
|
||||||
|
if (danger >= 0.95) {
|
||||||
|
val superDangerSpray = ParticleSpray(player.position(), Vec3(0.0, 1.0, 0.0), Math.PI, 0.4, count = 10)
|
||||||
|
superDangerSpray.sprayParticles(player.getLevel(), FrozenColorizer(ItemStack(HexItems.DYE_COLORIZERS[DyeColor.RED]!!), Util.NIL_UUID))
|
||||||
|
superDangerSpray.sprayParticles(player.getLevel(), FrozenColorizer(ItemStack(HexItems.DYE_COLORIZERS[DyeColor.BLACK]!!), Util.NIL_UUID))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a number from 0 (totally fine) to 1 (danger will robinson, stop the flight)
|
||||||
|
// it's a double for particle reason
|
||||||
|
private fun getDanger(player: ServerPlayer, flight: FlightAbility): Double {
|
||||||
|
val radiusDanger = if (flight.radius >= 0.0) {
|
||||||
|
if (player.level.dimension() != flight.dimension) {
|
||||||
|
1.0
|
||||||
|
} else {
|
||||||
|
// Limit it only in X/Z
|
||||||
|
val posXZ = Vec3(player.x, 0.0, player.z)
|
||||||
|
val originXZ = Vec3(flight.origin.x, 0.0, flight.origin.z)
|
||||||
|
val dist = posXZ.distanceTo(originXZ)
|
||||||
|
val distFromEdge = flight.radius - dist
|
||||||
|
if (distFromEdge >= DIST_DANGER_THRESHOLD) {
|
||||||
|
0.0
|
||||||
|
} else if (dist > flight.radius) {
|
||||||
|
1.0
|
||||||
|
} else {
|
||||||
|
1.0 - (distFromEdge / DIST_DANGER_THRESHOLD)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else 0.0
|
||||||
|
val timeDanger = if (flight.timeLeft >= 0) {
|
||||||
|
if (flight.timeLeft >= TIME_DANGER_THRESHOLD) {
|
||||||
|
0.0
|
||||||
|
} else {
|
||||||
|
val timeDanger = TIME_DANGER_THRESHOLD - flight.timeLeft
|
||||||
|
timeDanger / TIME_DANGER_THRESHOLD
|
||||||
|
}
|
||||||
|
} else 0.0
|
||||||
|
return max(radiusDanger, timeDanger)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -345,8 +345,17 @@ public class HexActions {
|
||||||
|
|
||||||
public static final ActionRegistryEntry LIGHTNING = make("lightning",
|
public static final ActionRegistryEntry LIGHTNING = make("lightning",
|
||||||
new ActionRegistryEntry(HexPattern.fromAngles("waadwawdaaweewq", HexDir.EAST), OpLightning.INSTANCE));
|
new ActionRegistryEntry(HexPattern.fromAngles("waadwawdaaweewq", HexDir.EAST), OpLightning.INSTANCE));
|
||||||
|
// TODO: turn this into elytra flight
|
||||||
public static final ActionRegistryEntry FLIGHT = make("flight",
|
public static final ActionRegistryEntry FLIGHT = make("flight",
|
||||||
new ActionRegistryEntry(HexPattern.fromAngles("eawwaeawawaa", HexDir.NORTH_WEST), OpFlight.INSTANCE));
|
new ActionRegistryEntry(HexPattern.fromAngles("eawwaeawawaa", HexDir.NORTH_WEST), OpLightning.INSTANCE));
|
||||||
|
|
||||||
|
public static final ActionRegistryEntry FLIGHT$RANGE = make("flight/range",
|
||||||
|
new ActionRegistryEntry(HexPattern.fromAngles("awawaawq", HexDir.SOUTH_WEST),
|
||||||
|
new OpFlight(OpFlight.Type.LimitRange)));
|
||||||
|
public static final ActionRegistryEntry FLIGHT$TIME = make("flight/time",
|
||||||
|
new ActionRegistryEntry(HexPattern.fromAngles("dwdwdewq", HexDir.NORTH_EAST),
|
||||||
|
new OpFlight(OpFlight.Type.LimitTime)));
|
||||||
|
|
||||||
public static final ActionRegistryEntry CREATE_LAVA = make("create_lava",
|
public static final ActionRegistryEntry CREATE_LAVA = make("create_lava",
|
||||||
new ActionRegistryEntry(HexPattern.fromAngles("eaqawqadaqd", HexDir.EAST), new OpCreateFluid(
|
new ActionRegistryEntry(HexPattern.fromAngles("eaqawqadaqd", HexDir.EAST), new OpCreateFluid(
|
||||||
MediaConstants.CRYSTAL_UNIT,
|
MediaConstants.CRYSTAL_UNIT,
|
||||||
|
|
|
@ -77,7 +77,7 @@ public interface IXplatAbstractions {
|
||||||
|
|
||||||
void setSentinel(Player target, Sentinel sentinel);
|
void setSentinel(Player target, Sentinel sentinel);
|
||||||
|
|
||||||
void setFlight(ServerPlayer target, FlightAbility flight);
|
void setFlight(ServerPlayer target, @Nullable FlightAbility flight);
|
||||||
|
|
||||||
void setHarness(ServerPlayer target, @Nullable CastingHarness harness);
|
void setHarness(ServerPlayer target, @Nullable CastingHarness harness);
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ public interface IXplatAbstractions {
|
||||||
|
|
||||||
boolean isBrainswept(Mob mob);
|
boolean isBrainswept(Mob mob);
|
||||||
|
|
||||||
FlightAbility getFlight(ServerPlayer player);
|
@Nullable FlightAbility getFlight(ServerPlayer player);
|
||||||
|
|
||||||
FrozenColorizer getColorizer(Player player);
|
FrozenColorizer getColorizer(Player player);
|
||||||
|
|
||||||
|
|
|
@ -8,23 +8,26 @@ import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public class CCFlight implements Component {
|
public class CCFlight implements Component {
|
||||||
public static final String
|
public static final String
|
||||||
TAG_ALLOWED = "allowed",
|
TAG_ALLOWED = "allowed", // Fake: use this as a null sentinel
|
||||||
TAG_TIME_LEFT = "time_left",
|
TAG_TIME_LEFT = "time_left",
|
||||||
TAG_DIMENSION = "dimension",
|
TAG_DIMENSION = "dimension",
|
||||||
TAG_ORIGIN = "origin",
|
TAG_ORIGIN = "origin",
|
||||||
TAG_RADIUS = "radius";
|
TAG_RADIUS = "radius";
|
||||||
|
|
||||||
private final ServerPlayer owner;
|
private final ServerPlayer owner;
|
||||||
private FlightAbility flight = FlightAbility.deny();
|
@Nullable
|
||||||
|
private FlightAbility flight = null;
|
||||||
|
|
||||||
public CCFlight(ServerPlayer owner) {
|
public CCFlight(ServerPlayer owner) {
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public FlightAbility getFlight() {
|
public FlightAbility getFlight() {
|
||||||
return flight;
|
return flight;
|
||||||
}
|
}
|
||||||
|
@ -37,21 +40,21 @@ public class CCFlight implements Component {
|
||||||
public void readFromNbt(CompoundTag tag) {
|
public void readFromNbt(CompoundTag tag) {
|
||||||
var allowed = tag.getBoolean(TAG_ALLOWED);
|
var allowed = tag.getBoolean(TAG_ALLOWED);
|
||||||
if (!allowed) {
|
if (!allowed) {
|
||||||
this.flight = FlightAbility.deny();
|
this.flight = null;
|
||||||
} else {
|
} else {
|
||||||
var timeLeft = tag.getInt(TAG_TIME_LEFT);
|
var timeLeft = tag.getInt(TAG_TIME_LEFT);
|
||||||
var dim = ResourceKey.create(Registry.DIMENSION_REGISTRY,
|
var dim = ResourceKey.create(Registry.DIMENSION_REGISTRY,
|
||||||
new ResourceLocation(tag.getString(TAG_DIMENSION)));
|
new ResourceLocation(tag.getString(TAG_DIMENSION)));
|
||||||
var origin = HexUtils.vecFromNBT(tag.getLongArray(TAG_ORIGIN));
|
var origin = HexUtils.vecFromNBT(tag.getLongArray(TAG_ORIGIN));
|
||||||
var radius = tag.getDouble(TAG_RADIUS);
|
var radius = tag.getDouble(TAG_RADIUS);
|
||||||
this.flight = new FlightAbility(true, timeLeft, dim, origin, radius);
|
this.flight = new FlightAbility(timeLeft, dim, origin, radius);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeToNbt(CompoundTag tag) {
|
public void writeToNbt(CompoundTag tag) {
|
||||||
tag.putBoolean(TAG_ALLOWED, this.flight.allowed());
|
tag.putBoolean(TAG_ALLOWED, this.flight != null);
|
||||||
if (this.flight.allowed()) {
|
if (this.flight != null) {
|
||||||
tag.putInt(TAG_TIME_LEFT, this.flight.timeLeft());
|
tag.putInt(TAG_TIME_LEFT, this.flight.timeLeft());
|
||||||
tag.putString(TAG_DIMENSION, this.flight.dimension().location().toString());
|
tag.putString(TAG_DIMENSION, this.flight.dimension().location().toString());
|
||||||
tag.put(TAG_ORIGIN, HexUtils.serializeToNBT(this.flight.origin()));
|
tag.put(TAG_ORIGIN, HexUtils.serializeToNBT(this.flight.origin()));
|
||||||
|
|
|
@ -120,6 +120,8 @@ repositories {
|
||||||
name = "ModMaven"
|
name = "ModMaven"
|
||||||
url = "https://modmaven.dev"
|
url = "https://modmaven.dev"
|
||||||
}
|
}
|
||||||
|
// caelus elytra
|
||||||
|
maven { url = "https://maven.theillusivec4.top" }
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
|
@ -176,8 +176,10 @@ public class ForgeHexInitializer {
|
||||||
BrainsweepingEvents.copyBrainsweepPostTransformation(evt.getEntity(), evt.getOutcome()));
|
BrainsweepingEvents.copyBrainsweepPostTransformation(evt.getEntity(), evt.getOutcome()));
|
||||||
|
|
||||||
evBus.addListener((LivingEvent.LivingTickEvent evt) -> {
|
evBus.addListener((LivingEvent.LivingTickEvent evt) -> {
|
||||||
OpFlight.INSTANCE.tickDownFlight(evt.getEntity());
|
if (evt.getEntity() instanceof ServerPlayer splayer) {
|
||||||
ItemLens.tickLens(evt.getEntity());
|
OpFlight.tickDownFlight(splayer);
|
||||||
|
ItemLens.tickLens(splayer);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
evBus.addListener((TickEvent.LevelTickEvent evt) -> {
|
evBus.addListener((TickEvent.LevelTickEvent evt) -> {
|
||||||
|
|
|
@ -139,8 +139,8 @@ public class ForgeXplatImpl implements IXplatAbstractions {
|
||||||
@Override
|
@Override
|
||||||
public void setFlight(ServerPlayer player, FlightAbility flight) {
|
public void setFlight(ServerPlayer player, FlightAbility flight) {
|
||||||
CompoundTag tag = player.getPersistentData();
|
CompoundTag tag = player.getPersistentData();
|
||||||
tag.putBoolean(TAG_FLIGHT_ALLOWED, flight.allowed());
|
tag.putBoolean(TAG_FLIGHT_ALLOWED, flight != null);
|
||||||
if (flight.allowed()) {
|
if (flight != null) {
|
||||||
tag.putInt(TAG_FLIGHT_TIME, flight.timeLeft());
|
tag.putInt(TAG_FLIGHT_TIME, flight.timeLeft());
|
||||||
tag.put(TAG_FLIGHT_ORIGIN, HexUtils.serializeToNBT(flight.origin()));
|
tag.put(TAG_FLIGHT_ORIGIN, HexUtils.serializeToNBT(flight.origin()));
|
||||||
tag.putString(TAG_FLIGHT_DIMENSION, flight.dimension().location().toString());
|
tag.putString(TAG_FLIGHT_DIMENSION, flight.dimension().location().toString());
|
||||||
|
@ -211,9 +211,9 @@ public class ForgeXplatImpl implements IXplatAbstractions {
|
||||||
var radius = tag.getDouble(TAG_FLIGHT_RADIUS);
|
var radius = tag.getDouble(TAG_FLIGHT_RADIUS);
|
||||||
var dimension = ResourceKey.create(Registry.DIMENSION_REGISTRY,
|
var dimension = ResourceKey.create(Registry.DIMENSION_REGISTRY,
|
||||||
new ResourceLocation(tag.getString(TAG_FLIGHT_DIMENSION)));
|
new ResourceLocation(tag.getString(TAG_FLIGHT_DIMENSION)));
|
||||||
return new FlightAbility(true, timeLeft, dimension, origin, radius);
|
return new FlightAbility(timeLeft, dimension, origin, radius);
|
||||||
}
|
}
|
||||||
return FlightAbility.deny();
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
16
README.md
16
README.md
|
@ -7,8 +7,20 @@ A minecraft mod about casting Hexes, powerful and programmable magical effects,
|
||||||
|
|
||||||
[Curseforge Link](https://www.curseforge.com/minecraft/mc-mods/hexcasting)
|
[Curseforge Link](https://www.curseforge.com/minecraft/mc-mods/hexcasting)
|
||||||
|
|
||||||
On Forge, this mod requires PAUCAL, Patchouli and Kotlin for Forge. On Fabric, it requires PAUCAL, Patchouli, and Fabric
|
On Forge, this mod requires:
|
||||||
Language Kotlin.
|
|
||||||
|
- PAUCAL
|
||||||
|
- Patchouli
|
||||||
|
- Kotlin for Forge
|
||||||
|
- Caelus elytra api
|
||||||
|
|
||||||
|
On Fabric, it requires:
|
||||||
|
|
||||||
|
- PAUCAL
|
||||||
|
- Patchouli
|
||||||
|
- Fabric Language Kotlin
|
||||||
|
- Cardinal Components
|
||||||
|
- ClothConfig and ModMenu
|
||||||
|
|
||||||
- [Read the documentation online here!](https://gamma-delta.github.io/HexMod/)
|
- [Read the documentation online here!](https://gamma-delta.github.io/HexMod/)
|
||||||
- [Discord link](https://discord.gg/4xxHGYteWk)
|
- [Discord link](https://discord.gg/4xxHGYteWk)
|
||||||
|
|
Loading…
Reference in a new issue