Skip to content

Commit

Permalink
spin implementation
Browse files Browse the repository at this point in the history
Initial implementation for /spin
  • Loading branch information
fill1890 committed Jun 19, 2022
1 parent f4352f4 commit 21f8e9e
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 7 deletions.
2 changes: 2 additions & 0 deletions src/main/java/net/fill1890/fabsit/FabSit.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fill1890.fabsit.command.LayCommand;
import net.fill1890.fabsit.command.SitCommand;
import net.fill1890.fabsit.command.SpinCommand;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -16,6 +17,7 @@ public class FabSit implements ModInitializer {
public void onInitialize() {
CommandRegistrationCallback.EVENT.register(SitCommand::register);
CommandRegistrationCallback.EVENT.register(LayCommand::register);
CommandRegistrationCallback.EVENT.register(SpinCommand::register);

LOGGER.info("FabSit finished loading");
}
Expand Down
71 changes: 71 additions & 0 deletions src/main/java/net/fill1890/fabsit/command/SpinCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package net.fill1890.fabsit.command;

import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import me.lucko.fabric.api.permissions.v0.Permissions;
import net.fill1890.fabsit.entity.Pose;
import net.fill1890.fabsit.entity.PoseManagerEntity;
import net.minecraft.block.BlockState;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPos;

import static net.minecraft.server.command.CommandManager.literal;

/**
* /spin command implementation
* <br>
* Requires <code>fabsit.commands.spin</code> permission node, granted to all players by default
* <br>
* Implementation details taken from <a href="https://github.com/Gecolay/GSit">GSit</a>
*/
public class SpinCommand {
public static void register(CommandDispatcher<ServerCommandSource> dispatcher, CommandRegistryAccess commandRegistryAccess, CommandManager.RegistrationEnvironment registrationEnvironment) {
dispatcher.register(literal("spin")
.requires(Permissions.require("fabsit.commands.spin", true))
.executes(SpinCommand::run));
}

public static int run(CommandContext<ServerCommandSource> context) {
final ServerCommandSource source = context.getSource();
ServerPlayerEntity player;

try {
player = source.getPlayerOrThrow();
} catch (CommandSyntaxException e) {
source.sendError(Text.of("You must be a player to run this command!"));
return -1;
}

// toggle sitting if the player was sat down
if(player.hasVehicle()) {
player.dismountVehicle();
player.teleport(player.getX(), player.getY() + 0.6, player.getZ());
return 1;
}

// get the block below to check it isn't air
BlockState standingBlock = player.getEntityWorld().getBlockState(new BlockPos(player.getPos()).down());
// check cancel conditions
if(
player.isFallFlying()
|| player.isSleeping()
|| player.isSwimming()
|| player.isSpectator()
|| standingBlock.isAir()
) { return -1; }

// create a new pose manager for spinning and sit the player down
// (player is then invisible and an npc spins)
PoseManagerEntity chair = new PoseManagerEntity(player.getEntityWorld(), player.getPos(), Pose.SPINNING, player);
player.getEntityWorld().spawnEntity(chair);
player.startRiding(chair, true);

return 1;

}
}
3 changes: 2 additions & 1 deletion src/main/java/net/fill1890/fabsit/entity/Pose.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

public enum Pose {
SITTING,
LAYING;
LAYING,
SPINNING;
}
13 changes: 7 additions & 6 deletions src/main/java/net/fill1890/fabsit/entity/PoseManagerEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,13 @@ public PoseManagerEntity(World world, Vec3d pos, Pose pose, ServerPlayerEntity p
this.setYaw(player.getYaw()); // TODO: test this properly

// if the pose is more complex than sitting, create a posing npc
if(pose == Pose.LAYING) {
if(pose == Pose.LAYING || pose == Pose.SPINNING) {
// copy player game profile with a random uuid
GameProfile gameProfile = new GameProfile(UUID.randomUUID(), player.getEntityName());
gameProfile.getProperties().putAll(player.getGameProfile().getProperties());

this.poser = new LayingEntity(player, gameProfile);
if(pose == Pose.LAYING) this.poser = new LayingEntity(player, gameProfile);
if(pose == Pose.SPINNING) this.poser = new SpinningEntity(player, gameProfile);
}

this.pose = pose;
Expand All @@ -60,7 +61,7 @@ protected void addPassenger(Entity passenger) {
super.addPassenger(passenger);

// if the pose is npc-based, hide the player when initiated
if(this.pose == Pose.LAYING) {
if(this.pose == Pose.LAYING || this.pose == Pose.SPINNING) {
passenger.setInvisible(true);

// update shoulder entities
Expand All @@ -80,7 +81,7 @@ protected void removePassenger(Entity passenger) {
super.removePassenger(passenger);

// if the pose was npc-based, show the player again when exited
if(this.pose == Pose.LAYING) {
if(this.pose == Pose.LAYING || this.pose == Pose.SPINNING) {
passenger.setInvisible(false);

// replace shoulder entities
Expand All @@ -92,7 +93,7 @@ protected void removePassenger(Entity passenger) {
}

public void animate(int id) {
if(this.pose == Pose.LAYING) {
if(this.pose == Pose.LAYING || this.pose == Pose.SPINNING) {
poser.animate(id);
}
}
Expand Down Expand Up @@ -133,7 +134,7 @@ public void tick() {
if(sittingBlock.isAir()) { kill(); }

// if pose is npc-based, update players with npc info
if(this.pose == Pose.LAYING) {
if(this.pose == Pose.LAYING || this.pose == Pose.SPINNING) {
poser.sendUpdates();
}

Expand Down
38 changes: 38 additions & 0 deletions src/main/java/net/fill1890/fabsit/entity/SpinningEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package net.fill1890.fabsit.entity;

import com.mojang.authlib.GameProfile;
import net.minecraft.network.packet.s2c.play.EntityS2CPacket;
import net.minecraft.network.packet.s2c.play.EntityTrackerUpdateS2CPacket;
import net.minecraft.server.network.ServerPlayerEntity;

import static net.fill1890.fabsit.mixin.LivingEntityAccessor.getLIVING_FLAGS;

public class SpinningEntity extends PosingEntity {
// pivot the poser to face vertically
EntityS2CPacket pivotPacket;

public SpinningEntity(ServerPlayerEntity player, GameProfile gameProfile) {
super(player, gameProfile);

// set spinning state
this.getDataTracker().set(getLIVING_FLAGS(), (byte) 0x04);
// refresh data packet
this.trackerPoserPacket = new EntityTrackerUpdateS2CPacket(this.getId(), this.getDataTracker(), true);

this.pivotPacket = new EntityS2CPacket.RotateAndMoveRelative(this.getId(), (short) 0, (short) 0, (short) 0, (byte) 0, (byte) (-90.0f * 256.0f / 360.0f), true);
}

@Override
public void sendUpdates() {
super.sendUpdates();

// rotate the poser to be spinning vertically
this.addingPlayers.forEach(p -> p.networkHandler.sendPacket(this.pivotPacket));
}

@Override
protected void syncHeadYaw() {
// do nothing; no point since already rotating
// also might mess up angle
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@ public interface LivingEntityAccessor {
static TrackedData<Optional<BlockPos>> getSLEEPING_POSITION() {
throw new AssertionError();
}

@Accessor("LIVING_FLAGS")
static TrackedData<Byte> getLIVING_FLAGS() { throw new AssertionError(); }
}

0 comments on commit 21f8e9e

Please sign in to comment.