diff --git a/gradle.properties b/gradle.properties index 9a99879..2d77dbd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ loader_version=0.14.25 # Mod Properties mod_version=1.0.0 maven_group=net.touhoudiscord -archives_base_name=hardcore-redeploy +archives_base_name=hardcore_redeploy # Dependencies fabric_version=0.91.0+1.20.1 \ No newline at end of file diff --git a/src/main/java/net/touhoudiscord/BuyStationCapable.java b/src/main/java/net/touhoudiscord/BuyStationCapable.java new file mode 100644 index 0000000..384dbc4 --- /dev/null +++ b/src/main/java/net/touhoudiscord/BuyStationCapable.java @@ -0,0 +1,9 @@ +package net.touhoudiscord; + +import net.minecraft.util.math.BlockPos; + +public interface BuyStationCapable { + default void hardcoreredeploy_openBuyStationScreen(BlockPos blockPos) { + + } +} diff --git a/src/main/java/net/touhoudiscord/HardcoreRedeploy.java b/src/main/java/net/touhoudiscord/HardcoreRedeploy.java index 1c90d25..db13b76 100644 --- a/src/main/java/net/touhoudiscord/HardcoreRedeploy.java +++ b/src/main/java/net/touhoudiscord/HardcoreRedeploy.java @@ -1,19 +1,33 @@ package net.touhoudiscord; import net.fabricmc.api.ModInitializer; - import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.fabric.api.item.v1.FabricItemSettings; +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; import net.minecraft.block.Block; -import net.minecraft.block.Blocks; +import net.minecraft.block.BlockState; +import net.minecraft.block.HorizontalFacingBlock; import net.minecraft.block.entity.BlockEntityType; import net.minecraft.entity.effect.StatusEffect; +import net.minecraft.entity.projectile.FireworkRocketEntity; import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.network.PacketByteBuf; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.sound.SoundEvent; import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.GameMode; import net.touhoudiscord.block.BuyStation; import net.touhoudiscord.block.BuyStationEntity; import net.touhoudiscord.commands.RedeployPlayerCommand; @@ -23,26 +37,104 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import software.bernie.geckolib.GeckoLib; +import java.util.UUID; + +import static net.touhoudiscord.HardcoreRedeployConfigHandler.config; +import static net.touhoudiscord.block.BuyStation.BUY_STATION_PART; + public class HardcoreRedeploy implements ModInitializer { - public static final String MOD_ID = "hardcore-redeploy"; - public static final Logger LOGGER = LoggerFactory.getLogger("hardcore-redeploy"); + public static final String MOD_ID = "hardcore_redeploy"; + public static final Logger LOGGER = LoggerFactory.getLogger("hardcore_redeploy"); public static final StatusEffect REDEPLOYING = new RedeployingStatusEffect(); - public static final Block BUY_STATION = Registry.register(Registries.BLOCK, new Identifier(HardcoreRedeploy.MOD_ID, "buy_station"), new BuyStation(FabricBlockSettings.copyOf(Blocks.HOPPER).nonOpaque())); + public static final Block BUY_STATION = Registry.register(Registries.BLOCK, new Identifier(HardcoreRedeploy.MOD_ID, "buy_station"), new BuyStation(FabricBlockSettings.create().nonOpaque().requiresTool().resistance(6).hardness(3))); public static final Item BUY_STATION_ITEM = Registry.register(Registries.ITEM, new Identifier(HardcoreRedeploy.MOD_ID, "buy_station"), new BuyStationItem(HardcoreRedeploy.BUY_STATION, new FabricItemSettings())); + public static final Identifier BUY_STATION_SOUND_ID = new Identifier(HardcoreRedeploy.MOD_ID, "buy_station"); + public static SoundEvent BUY_STATION_SOUND_EVENT = SoundEvent.of(BUY_STATION_SOUND_ID); public static BlockEntityType BUY_STATION_ENTITY; + public static final Identifier SEND_REVIVES_UPDATE = new Identifier(HardcoreRedeploy.MOD_ID, "send_revives_update"); + public static final Identifier REQUEST_REVIVE = new Identifier(HardcoreRedeploy.MOD_ID, "request_revive"); + public static final Identifier SEND_REVIVE = new Identifier(HardcoreRedeploy.MOD_ID, "send_revive"); + public static final Identifier SYNC_CONFIG = new Identifier(HardcoreRedeploy.MOD_ID, "sync_config"); + + private static final ItemStack firework; + static { + firework = new ItemStack(Registries.ITEM.get(new Identifier("minecraft", "firework_rocket"))); + NbtCompound nbt = new NbtCompound(); + nbt.putByte("Flight", (byte)3); + firework.setSubNbt("Fireworks", nbt); + } + + @Override public void onInitialize() { LOGGER.info("Initializing Hardcore Redeploy"); GeckoLib.initialize(); + ServerPlayNetworking.registerGlobalReceiver(REQUEST_REVIVE, (server, player, handler, buf, responseSender) -> { + ServerPlayerEntity spectator = server.getPlayerManager().getPlayer(buf.readUuid()); + if (spectator == null) return; + + BlockPos blockPos = buf.readBlockPos(); + BlockState invokingBlock = player.getWorld().getBlockState(blockPos); + + if (invokingBlock.getBlock() instanceof BuyStation && player.getPos().isInRange(blockPos.toCenterPos(), 5)) { + + int cost = config.baseCost+config.additiveCost*RedeployStateSaver.getPlayerState(spectator).timesRevived; + boolean isCreative = player.interactionManager.getGameMode() == GameMode.CREATIVE; + if (!isCreative && player.experienceLevel < cost) return; + + Vec3d fireworkPos = blockPos.toCenterPos(); + BlockState blockState = player.getWorld().getBlockState(blockPos); + Direction offset = blockState.get(HorizontalFacingBlock.FACING).rotateYClockwise(); + if (blockState.get(BUY_STATION_PART) == BuyStation.BuyStationPart.AUX) offset = offset.getOpposite(); + FireworkRocketEntity fireworkRocketEntity = new FireworkRocketEntity(player.getWorld(), fireworkPos.x+offset.getOffsetX()/2., fireworkPos.y, fireworkPos.z+offset.getOffsetZ()/2., firework); + player.getWorld().spawnEntity(fireworkRocketEntity); + + if (!isCreative) player.setExperienceLevel(player.experienceLevel-cost); + ((TimerAccess) server).hardcoreredeploy_redeployInTicks(spectator, player, 60L); + server.execute(() -> { + PacketByteBuf buf1 = PacketByteBufs.create(); + ServerPlayNetworking.send(spectator, SEND_REVIVE, buf1); + }); + } + }); + + ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { + syncConfig(server, handler.getPlayer()); + + RedeployStateSaver.getServerState(server).players.forEach((uuid, playerData) -> { + syncRevives(server, handler.getPlayer(), uuid); + }); + }); + BUY_STATION_ENTITY = Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(HardcoreRedeploy.MOD_ID, "buy_station_entity"), FabricBlockEntityTypeBuilder.create(BuyStationEntity::new, HardcoreRedeploy.BUY_STATION).build()); Registry.register(Registries.STATUS_EFFECT, new Identifier(HardcoreRedeploy.MOD_ID, "redeploying"), REDEPLOYING); CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> RedeployPlayerCommand.register(dispatcher)); + Registry.register(Registries.SOUND_EVENT, BUY_STATION_SOUND_ID, BUY_STATION_SOUND_EVENT); + } + + public static void syncConfig(MinecraftServer server, ServerPlayerEntity receiver) { + PacketByteBuf buf = PacketByteBufs.create(); + buf.writeInt(HardcoreRedeployConfigHandler.config.baseCost); + buf.writeInt(HardcoreRedeployConfigHandler.config.additiveCost); + server.execute(() -> { + ServerPlayNetworking.send(receiver, SYNC_CONFIG, buf); + }); + } + + public static void syncRevives(MinecraftServer server, ServerPlayerEntity receiver, UUID uuid) { + PlayerData playerData = RedeployStateSaver.getPlayerState(server, uuid); + PacketByteBuf buf = PacketByteBufs.create(); + buf.writeUuid(uuid); + buf.writeInt(playerData.timesRevived); + server.execute(() -> { + ServerPlayNetworking.send(receiver, SEND_REVIVES_UPDATE, buf); + }); } } \ No newline at end of file diff --git a/src/main/java/net/touhoudiscord/HardcoreRedeployClient.java b/src/main/java/net/touhoudiscord/HardcoreRedeployClient.java index 5a99d37..3b54ebb 100644 --- a/src/main/java/net/touhoudiscord/HardcoreRedeployClient.java +++ b/src/main/java/net/touhoudiscord/HardcoreRedeployClient.java @@ -1,12 +1,45 @@ package net.touhoudiscord; import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.minecraft.client.render.block.entity.BlockEntityRendererFactories; +import net.touhoudiscord.HardcoreRedeployConfigHandler.HardcoreRedeployConfig; import net.touhoudiscord.block.client.BuyStationRenderer; +import net.touhoudiscord.screen.RedeployingScreen; +import java.util.HashMap; +import java.util.UUID; + +@Environment(EnvType.CLIENT) public class HardcoreRedeployClient implements ClientModInitializer { + + public static HashMap reviveMap = new HashMap<>(); + public static HardcoreRedeployConfig serverConfig = HardcoreRedeployConfigHandler.config; + @Override public void onInitializeClient() { BlockEntityRendererFactories.register(HardcoreRedeploy.BUY_STATION_ENTITY, BuyStationRenderer::new); + + ClientPlayNetworking.registerGlobalReceiver(HardcoreRedeploy.SEND_REVIVES_UPDATE, (client, handler, buf, responseSender) -> { + reviveMap.put(buf.readUuid(), buf.readInt()); + + HardcoreRedeploy.LOGGER.info("Synced player revives"); + }); + + ClientPlayNetworking.registerGlobalReceiver(HardcoreRedeploy.SEND_REVIVE, (client, handler, buf, responseSender) -> { + client.execute(() -> { + client.setScreen(new RedeployingScreen(6*20)); + }); + }); + + ClientPlayNetworking.registerGlobalReceiver(HardcoreRedeploy.SYNC_CONFIG, (client, handler, buf, responseSender) -> { + serverConfig = new HardcoreRedeployConfig(); + serverConfig.baseCost = buf.readInt(); + serverConfig.additiveCost = buf.readInt(); + + HardcoreRedeploy.LOGGER.info("Synced server config"); + }); } } \ No newline at end of file diff --git a/src/main/java/net/touhoudiscord/HardcoreRedeployConfigHandler.java b/src/main/java/net/touhoudiscord/HardcoreRedeployConfigHandler.java new file mode 100644 index 0000000..4c8d355 --- /dev/null +++ b/src/main/java/net/touhoudiscord/HardcoreRedeployConfigHandler.java @@ -0,0 +1,39 @@ +package net.touhoudiscord; + +import com.google.gson.Gson; +import net.fabricmc.loader.api.FabricLoader; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; + +public class HardcoreRedeployConfigHandler { + private static final Path configPath = FabricLoader.getInstance().getConfigDir().resolve("hardcore_redeploy.json"); + private static final Gson gson = new Gson(); + public static HardcoreRedeployConfig config = readOrCreateConfig(); + + public HardcoreRedeployConfigHandler() { + } + + private static HardcoreRedeployConfig readOrCreateConfig() { + try { + return gson.fromJson(Files.readString(configPath), HardcoreRedeployConfig.class); + } + catch(IOException e) { + HardcoreRedeployConfig newConfig = new HardcoreRedeployConfig(); + try { + Files.writeString(configPath, gson.toJson(newConfig), StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + return newConfig; + } + } + + public static class HardcoreRedeployConfig { + public int baseCost = 10; + public int additiveCost = 10; + HardcoreRedeployConfig(){} + } +} diff --git a/src/main/java/net/touhoudiscord/PlayerData.java b/src/main/java/net/touhoudiscord/PlayerData.java new file mode 100644 index 0000000..8d58455 --- /dev/null +++ b/src/main/java/net/touhoudiscord/PlayerData.java @@ -0,0 +1,5 @@ +package net.touhoudiscord; + +public class PlayerData { + public int timesRevived = 0; +} diff --git a/src/main/java/net/touhoudiscord/PlayerTimer.java b/src/main/java/net/touhoudiscord/PlayerTimer.java new file mode 100644 index 0000000..814327f --- /dev/null +++ b/src/main/java/net/touhoudiscord/PlayerTimer.java @@ -0,0 +1,13 @@ +package net.touhoudiscord; + +import java.util.UUID; + +public class PlayerTimer { + public UUID target; + public Long ticks; + + public PlayerTimer(UUID target, Long ticks) { + this.target = target; + this.ticks = ticks; + } +} \ No newline at end of file diff --git a/src/main/java/net/touhoudiscord/RedeployPlayer.java b/src/main/java/net/touhoudiscord/RedeployPlayer.java index 4c97c75..44c2dc6 100644 --- a/src/main/java/net/touhoudiscord/RedeployPlayer.java +++ b/src/main/java/net/touhoudiscord/RedeployPlayer.java @@ -6,8 +6,15 @@ import net.minecraft.world.GameMode; public class RedeployPlayer { public static void redeploy(ServerPlayerEntity spectator, ServerPlayerEntity target) { + if (!(spectator.interactionManager.getGameMode() == GameMode.SPECTATOR)) return; + if (!target.getServerWorld().getDimension().hasCeiling()) spectator.addStatusEffect(new StatusEffectInstance(HardcoreRedeploy.REDEPLOYING, 20*20, 0)); spectator.teleport(target.getServerWorld(), target.getPos().x, target.getServerWorld().getDimension().hasCeiling() ? target.getPos().y : 320, target.getPos().z, 0, 30); spectator.changeGameMode(GameMode.SURVIVAL); + + RedeployStateSaver.getPlayerState(spectator).timesRevived++; + spectator.server.getPlayerManager().getPlayerList().forEach(player -> { + HardcoreRedeploy.syncRevives(player.server, player, spectator.getUuid()); + }); } } diff --git a/src/main/java/net/touhoudiscord/RedeployStateSaver.java b/src/main/java/net/touhoudiscord/RedeployStateSaver.java new file mode 100644 index 0000000..e38cfd0 --- /dev/null +++ b/src/main/java/net/touhoudiscord/RedeployStateSaver.java @@ -0,0 +1,74 @@ +package net.touhoudiscord; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.PersistentState; +import net.minecraft.world.PersistentStateManager; +import net.minecraft.world.World; + +import java.util.HashMap; +import java.util.UUID; + +public class RedeployStateSaver extends PersistentState { + + public HashMap players = new HashMap<>(); + + @Override + public NbtCompound writeNbt(NbtCompound nbt) { + + NbtCompound playersNbt = new NbtCompound(); + players.forEach((uuid, playerData) -> { + NbtCompound playerNbt = new NbtCompound(); + + playerNbt.putInt("timesRevived", playerData.timesRevived); + + playersNbt.put(uuid.toString(), playerNbt); + }); + nbt.put("players", playersNbt); + + return nbt; + } + + public static RedeployStateSaver createFromNbt(NbtCompound tag) { + RedeployStateSaver state = new RedeployStateSaver(); + + NbtCompound playersNbt = tag.getCompound("players"); + playersNbt.getKeys().forEach(key -> { + PlayerData playerData = new PlayerData(); + + playerData.timesRevived = playersNbt.getCompound(key).getInt("timesRevived"); + + UUID uuid = UUID.fromString(key); + state.players.put(uuid, playerData); + }); + + return state; + } + + public static RedeployStateSaver getServerState(MinecraftServer server) { + PersistentStateManager persistentStateManager = server.getWorld(World.OVERWORLD).getPersistentStateManager(); + + RedeployStateSaver state = persistentStateManager.getOrCreate(RedeployStateSaver::createFromNbt, RedeployStateSaver::new, HardcoreRedeploy.MOD_ID); + + state.markDirty(); + + return state; + } + + public static PlayerData getPlayerState(LivingEntity player) { + RedeployStateSaver serverState = getServerState(player.getWorld().getServer()); + + PlayerData playerState = serverState.players.computeIfAbsent(player.getUuid(), uuid -> new PlayerData()); + + return playerState; + } + + public static PlayerData getPlayerState(MinecraftServer server, UUID uuid) { + RedeployStateSaver serverState = getServerState(server); + + PlayerData playerState = serverState.players.computeIfAbsent(uuid, i -> new PlayerData()); + + return playerState; + } +} diff --git a/src/main/java/net/touhoudiscord/TimerAccess.java b/src/main/java/net/touhoudiscord/TimerAccess.java new file mode 100644 index 0000000..3987797 --- /dev/null +++ b/src/main/java/net/touhoudiscord/TimerAccess.java @@ -0,0 +1,7 @@ +package net.touhoudiscord; + +import net.minecraft.server.network.ServerPlayerEntity; + +public interface TimerAccess { + void hardcoreredeploy_redeployInTicks(ServerPlayerEntity spectator, ServerPlayerEntity target, Long ticks); +} diff --git a/src/main/java/net/touhoudiscord/block/BuyStation.java b/src/main/java/net/touhoudiscord/block/BuyStation.java index 920f2d7..27fdaee 100644 --- a/src/main/java/net/touhoudiscord/block/BuyStation.java +++ b/src/main/java/net/touhoudiscord/block/BuyStation.java @@ -1,31 +1,144 @@ package net.touhoudiscord.block; -import net.minecraft.block.BlockRenderType; -import net.minecraft.block.BlockState; -import net.minecraft.block.BlockWithEntity; +import net.minecraft.block.*; import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.item.ItemStack; +import net.minecraft.state.StateManager; +import net.minecraft.state.property.EnumProperty; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.StringIdentifiable; +import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.world.BlockView; +import net.minecraft.world.World; +import net.minecraft.world.WorldEvents; import net.minecraft.world.WorldView; +import net.touhoudiscord.BuyStationCapable; import org.jetbrains.annotations.Nullable; public class BuyStation extends BlockWithEntity { + public static final EnumProperty BUY_STATION_PART = EnumProperty.of("part", BuyStationPart.class); + + protected static final VoxelShape NORTH_SHAPE = Block.createCuboidShape(1.0, 0.0, 1.0, 16.0, 12.0, 15.0); + protected static final VoxelShape SOUTH_SHAPE = Block.createCuboidShape(0.0, 0.0, 1.0, 15.0, 12.0, 15.0); + protected static final VoxelShape WEST_SHAPE = Block.createCuboidShape(1.0, 0.0, 0.0, 15.0, 12.0, 15.0); + protected static final VoxelShape EAST_SHAPE = Block.createCuboidShape(1.0, 0.0, 1.0, 15.0, 12.0, 16.0); + public BuyStation(Settings settings) { super(settings); + this.setDefaultState(this.getDefaultState() + .with(HorizontalFacingBlock.FACING, Direction.NORTH) + .with(BUY_STATION_PART, BuyStationPart.MAIN)); + } + + @Nullable + @Override + public BlockState getPlacementState(ItemPlacementContext ctx) { + return this.getDefaultState().with(HorizontalFacingBlock.FACING, ctx.getHorizontalPlayerFacing()); + } + + @Override + public void onPlaced(World world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack itemStack) { + super.onPlaced(world, pos, state, placer, itemStack); + if (!world.isClient) { + BlockPos blockPos = pos.offset(state.get(HorizontalFacingBlock.FACING).rotateYClockwise()); + world.setBlockState(blockPos, state.with(BUY_STATION_PART, BuyStationPart.AUX), Block.NOTIFY_ALL); + world.updateNeighbors(pos, Blocks.AIR); + state.updateNeighbors(world, pos, Block.NOTIFY_ALL); + } + } + + @Override + public void onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) { + if (world.isClient()) { + super.onBreak(world, pos, state, player); + } + + BuyStationPart part = state.get(BUY_STATION_PART); + if (part == BuyStationPart.MAIN) { + BlockPos otherpos = pos.offset(state.get(HorizontalFacingBlock.FACING).rotateYClockwise()); + BlockState otherstate = world.getBlockState(otherpos); + if (otherstate.getBlock() == this) { + world.setBlockState(otherpos, Blocks.AIR.getDefaultState(), Block.NOTIFY_ALL); + world.syncWorldEvent(player, WorldEvents.BLOCK_BROKEN, otherpos, Block.getRawIdFromState(otherstate)); + } + } + else if (part == BuyStationPart.AUX) { + BlockPos otherpos = pos.offset(state.get(HorizontalFacingBlock.FACING).rotateYCounterclockwise()); + BlockState otherstate = world.getBlockState(otherpos); + if (otherstate.getBlock() == this) { + world.setBlockState(otherpos, Blocks.AIR.getDefaultState(), Block.NOTIFY_ALL); + world.syncWorldEvent(player, WorldEvents.BLOCK_BROKEN, otherpos, Block.getRawIdFromState(otherstate)); + } + } + } + + public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + Direction direction = state.get(HorizontalFacingBlock.FACING); + BuyStationPart part = state.get(BUY_STATION_PART); + if (part == BuyStationPart.AUX) direction = direction.getOpposite(); + return switch (direction) { + default -> NORTH_SHAPE; + case SOUTH -> SOUTH_SHAPE; + case WEST -> WEST_SHAPE; + case EAST -> EAST_SHAPE; + }; + } + + @Override + public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { + Block block = world.getBlockState(pos).getBlock(); + if (block instanceof BuyStation) { + ((BuyStationCapable) player).hardcoreredeploy_openBuyStationScreen(pos); + return ActionResult.success(world.isClient); + } else { + return ActionResult.PASS; + } + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + builder.add(HorizontalFacingBlock.FACING, BUY_STATION_PART); } @Nullable @Override public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { - return new BuyStationEntity(pos, state); + return state.get(BUY_STATION_PART) == BuyStationPart.MAIN ? new BuyStationEntity(pos, state) : null; } @Override public BlockRenderType getRenderType(BlockState state) { - return BlockRenderType.MODEL; + return state.get(BUY_STATION_PART) == BuyStationPart.MAIN ? BlockRenderType.MODEL : BlockRenderType.INVISIBLE; } @Override public boolean canPlaceAt(BlockState state, WorldView world, BlockPos pos) { - return super.canPlaceAt(state, world, pos); + return world.getBlockState(pos.offset(state.get(HorizontalFacingBlock.FACING).rotateYClockwise())).isReplaceable() && super.canPlaceAt(state, world, pos); + } + + public enum BuyStationPart implements StringIdentifiable { + MAIN("main"), + AUX("aux"); + + private final String name; + + BuyStationPart(String name) { + this.name = name; + } + + public String toString() { + return this.name; + } + + public String asString() { + return this.name; + } } } diff --git a/src/main/java/net/touhoudiscord/block/BuyStationEntity.java b/src/main/java/net/touhoudiscord/block/BuyStationEntity.java index 9995ca9..9dfc5c2 100644 --- a/src/main/java/net/touhoudiscord/block/BuyStationEntity.java +++ b/src/main/java/net/touhoudiscord/block/BuyStationEntity.java @@ -3,17 +3,21 @@ package net.touhoudiscord.block; import net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.sound.SoundCategory; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.touhoudiscord.HardcoreRedeploy; import software.bernie.geckolib.animatable.GeoBlockEntity; import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache; import software.bernie.geckolib.core.animatable.instance.SingletonAnimatableInstanceCache; -import software.bernie.geckolib.core.animation.*; +import software.bernie.geckolib.core.animation.AnimatableManager; +import software.bernie.geckolib.core.animation.AnimationController; +import software.bernie.geckolib.core.animation.RawAnimation; +import software.bernie.geckolib.util.ClientUtils; import software.bernie.geckolib.util.RenderUtils; public class BuyStationEntity extends BlockEntity implements GeoBlockEntity { - private AnimatableInstanceCache cache = new SingletonAnimatableInstanceCache(this); + private final AnimatableInstanceCache cache = new SingletonAnimatableInstanceCache(this); private static final RawAnimation OPEN = RawAnimation.begin().thenPlay("animation.model.open").thenLoop("animation.model.idle"); private static final RawAnimation CLOSE = RawAnimation.begin().thenPlay("animation.model.close"); @@ -26,11 +30,20 @@ public class BuyStationEntity extends BlockEntity implements GeoBlockEntity { public void registerControllers(AnimatableManager.ControllerRegistrar controllers) { controllers.add(new AnimationController<>(this, "buystationcontroller", 0, state -> { Vec3d pos = state.getAnimatable().getPos().toCenterPos(); - if (state.getAnimatable().getWorld().getClosestPlayer(pos.x, pos.y, pos.z, 5, false) instanceof PlayerEntity) + if (state.getAnimatable().getWorld().getClosestPlayer(pos.x, pos.y, pos.z, 5, false) instanceof PlayerEntity) { return state.setAndContinue(OPEN); - else + } + else { return state.setAndContinue(CLOSE); - })); + } + }) + .setSoundKeyframeHandler(event -> { + PlayerEntity player = ClientUtils.getClientPlayer(); + + if (player != null) { + player.getWorld().playSound(player, this.getPos(), HardcoreRedeploy.BUY_STATION_SOUND_EVENT, SoundCategory.BLOCKS, 1, 1); + } + })); } @Override diff --git a/src/main/java/net/touhoudiscord/block/client/BuyStationModel.java b/src/main/java/net/touhoudiscord/block/client/BuyStationModel.java index c21a218..4700525 100644 --- a/src/main/java/net/touhoudiscord/block/client/BuyStationModel.java +++ b/src/main/java/net/touhoudiscord/block/client/BuyStationModel.java @@ -1,10 +1,13 @@ package net.touhoudiscord.block.client; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.minecraft.util.Identifier; import net.touhoudiscord.HardcoreRedeploy; import net.touhoudiscord.block.BuyStationEntity; import software.bernie.geckolib.model.GeoModel; +@Environment(EnvType.CLIENT) public class BuyStationModel extends GeoModel { @Override public Identifier getModelResource(BuyStationEntity animatable) { diff --git a/src/main/java/net/touhoudiscord/block/client/BuyStationRenderer.java b/src/main/java/net/touhoudiscord/block/client/BuyStationRenderer.java index 03e4267..3f0572f 100644 --- a/src/main/java/net/touhoudiscord/block/client/BuyStationRenderer.java +++ b/src/main/java/net/touhoudiscord/block/client/BuyStationRenderer.java @@ -1,11 +1,27 @@ package net.touhoudiscord.block.client; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.block.HorizontalFacingBlock; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.block.entity.BlockEntityRendererFactory; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.Direction; import net.touhoudiscord.block.BuyStationEntity; +import software.bernie.geckolib.cache.object.BakedGeoModel; import software.bernie.geckolib.renderer.GeoBlockRenderer; +@Environment(EnvType.CLIENT) public class BuyStationRenderer extends GeoBlockRenderer { public BuyStationRenderer(BlockEntityRendererFactory.Context context) { super(new BuyStationModel()); } + + @Override + public void preRender(MatrixStack poseStack, BuyStationEntity animatable, BakedGeoModel model, VertexConsumerProvider bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) { + Direction direction = animatable.getCachedState().get(HorizontalFacingBlock.FACING).rotateYClockwise(); + poseStack.translate(direction.getOffsetX()/2., 0, direction.getOffsetZ()/2.); + super.preRender(poseStack, animatable, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, red, green, blue, alpha); + } } diff --git a/src/main/java/net/touhoudiscord/commands/RedeployPlayerCommand.java b/src/main/java/net/touhoudiscord/commands/RedeployPlayerCommand.java index 298f7ce..5cdeed9 100644 --- a/src/main/java/net/touhoudiscord/commands/RedeployPlayerCommand.java +++ b/src/main/java/net/touhoudiscord/commands/RedeployPlayerCommand.java @@ -8,10 +8,10 @@ import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; import net.minecraft.world.GameMode; -import net.touhoudiscord.HardcoreRedeploy; import net.touhoudiscord.RedeployPlayer; -import static net.minecraft.server.command.CommandManager.*; +import static net.minecraft.server.command.CommandManager.argument; +import static net.minecraft.server.command.CommandManager.literal; public class RedeployPlayerCommand { @@ -36,7 +36,5 @@ public class RedeployPlayerCommand { return 1; }))); - - HardcoreRedeploy.LOGGER.info("Registered RedeployPlayer command"); } } diff --git a/src/main/java/net/touhoudiscord/item/BuyStationItem.java b/src/main/java/net/touhoudiscord/item/BuyStationItem.java index 994c27e..3b612af 100644 --- a/src/main/java/net/touhoudiscord/item/BuyStationItem.java +++ b/src/main/java/net/touhoudiscord/item/BuyStationItem.java @@ -9,7 +9,8 @@ import software.bernie.geckolib.animatable.SingletonGeoAnimatable; import software.bernie.geckolib.animatable.client.RenderProvider; import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache; import software.bernie.geckolib.core.animatable.instance.SingletonAnimatableInstanceCache; -import software.bernie.geckolib.core.animation.*; +import software.bernie.geckolib.core.animation.AnimatableManager; +import software.bernie.geckolib.core.animation.AnimationController; import software.bernie.geckolib.core.object.PlayState; import software.bernie.geckolib.util.RenderUtils; @@ -17,7 +18,7 @@ import java.util.function.Consumer; import java.util.function.Supplier; public class BuyStationItem extends BlockItem implements GeoItem { - private AnimatableInstanceCache cache = new SingletonAnimatableInstanceCache(this); + private final AnimatableInstanceCache cache = new SingletonAnimatableInstanceCache(this); private final Supplier renderProvider = GeoItem.makeRenderer(this); public BuyStationItem(Block block, Settings settings) { diff --git a/src/main/java/net/touhoudiscord/item/client/BuyStationItemModel.java b/src/main/java/net/touhoudiscord/item/client/BuyStationItemModel.java index 1e44bf0..d408eed 100644 --- a/src/main/java/net/touhoudiscord/item/client/BuyStationItemModel.java +++ b/src/main/java/net/touhoudiscord/item/client/BuyStationItemModel.java @@ -1,10 +1,13 @@ package net.touhoudiscord.item.client; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.minecraft.util.Identifier; import net.touhoudiscord.HardcoreRedeploy; import net.touhoudiscord.item.BuyStationItem; import software.bernie.geckolib.model.GeoModel; +@Environment(EnvType.CLIENT) public class BuyStationItemModel extends GeoModel { @Override public Identifier getModelResource(BuyStationItem animatable) { diff --git a/src/main/java/net/touhoudiscord/item/client/BuyStationItemRenderer.java b/src/main/java/net/touhoudiscord/item/client/BuyStationItemRenderer.java index 29a9282..28b36a5 100644 --- a/src/main/java/net/touhoudiscord/item/client/BuyStationItemRenderer.java +++ b/src/main/java/net/touhoudiscord/item/client/BuyStationItemRenderer.java @@ -1,8 +1,11 @@ package net.touhoudiscord.item.client; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.touhoudiscord.item.BuyStationItem; import software.bernie.geckolib.renderer.GeoItemRenderer; +@Environment(EnvType.CLIENT) public class BuyStationItemRenderer extends GeoItemRenderer { public BuyStationItemRenderer() { super(new BuyStationItemModel()); diff --git a/src/main/java/net/touhoudiscord/mixin/BuyStationScreenMixin.java b/src/main/java/net/touhoudiscord/mixin/BuyStationScreenMixin.java new file mode 100644 index 0000000..93fedd2 --- /dev/null +++ b/src/main/java/net/touhoudiscord/mixin/BuyStationScreenMixin.java @@ -0,0 +1,13 @@ +package net.touhoudiscord.mixin; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.math.BlockPos; +import net.touhoudiscord.BuyStationCapable; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(PlayerEntity.class) +public class BuyStationScreenMixin implements BuyStationCapable { + @Override + public void hardcoreredeploy_openBuyStationScreen(BlockPos blockPos) { + } +} diff --git a/src/main/java/net/touhoudiscord/mixin/ClientBuyStationScreenMixin.java b/src/main/java/net/touhoudiscord/mixin/ClientBuyStationScreenMixin.java new file mode 100644 index 0000000..7f5791d --- /dev/null +++ b/src/main/java/net/touhoudiscord/mixin/ClientBuyStationScreenMixin.java @@ -0,0 +1,20 @@ +package net.touhoudiscord.mixin; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.util.math.BlockPos; +import net.touhoudiscord.BuyStationCapable; +import net.touhoudiscord.screen.BuyStationScreen; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(ClientPlayerEntity.class) +public class ClientBuyStationScreenMixin implements BuyStationCapable { + @Shadow @Final protected MinecraftClient client; + + @Override + public void hardcoreredeploy_openBuyStationScreen(BlockPos blockPos) { + this.client.setScreen(new BuyStationScreen(blockPos)); + } +} diff --git a/src/main/java/net/touhoudiscord/mixin/RedeployTimerMixin.java b/src/main/java/net/touhoudiscord/mixin/RedeployTimerMixin.java new file mode 100644 index 0000000..bc6f41f --- /dev/null +++ b/src/main/java/net/touhoudiscord/mixin/RedeployTimerMixin.java @@ -0,0 +1,41 @@ +package net.touhoudiscord.mixin; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.PlayerManager; +import net.minecraft.server.network.ServerPlayerEntity; +import net.touhoudiscord.PlayerTimer; +import net.touhoudiscord.RedeployPlayer; +import net.touhoudiscord.TimerAccess; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.HashMap; +import java.util.UUID; + +@Mixin(MinecraftServer.class) +public abstract class RedeployTimerMixin implements TimerAccess { + @Shadow public abstract PlayerManager getPlayerManager(); + + @Unique + private final HashMap playerTimers = new HashMap<>(); + + @Inject(method = "tick", at = @At("TAIL")) + private void onTick(CallbackInfo ci) { + this.playerTimers.forEach((uuid, timer) -> { + if (--timer.ticks == 0L) { + ServerPlayerEntity spectator = this.getPlayerManager().getPlayer(uuid); + ServerPlayerEntity target = this.getPlayerManager().getPlayer(timer.target); + if (spectator != null && target != null) RedeployPlayer.redeploy(spectator, target); + } + }); + } + + @Override + public void hardcoreredeploy_redeployInTicks(ServerPlayerEntity spectator, ServerPlayerEntity target, Long ticks) { + this.playerTimers.put(spectator.getUuid(), new PlayerTimer(target.getUuid(), ticks)); + } +} \ No newline at end of file diff --git a/src/main/java/net/touhoudiscord/screen/BuyStationScreen.java b/src/main/java/net/touhoudiscord/screen/BuyStationScreen.java new file mode 100644 index 0000000..8845f6a --- /dev/null +++ b/src/main/java/net/touhoudiscord/screen/BuyStationScreen.java @@ -0,0 +1,125 @@ +package net.touhoudiscord.screen; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.Element; +import net.minecraft.client.gui.Selectable; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.ElementListWidget; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.GameMode; +import net.touhoudiscord.HardcoreRedeploy; +import net.touhoudiscord.HardcoreRedeployClient; + +import java.util.List; +import java.util.UUID; + +import static net.touhoudiscord.HardcoreRedeployClient.serverConfig; + +@Environment(EnvType.CLIENT) +public class BuyStationScreen extends Screen { + private final BlockPos blockPos; + + private PlayerListWidget playerList; + + public BuyStationScreen(BlockPos blockPos) { + super(Text.literal("Buy Station")); + this.blockPos = blockPos; + } + + @Override + protected void init() { + super.init(); + playerList = new PlayerListWidget(client, width+38, height, height/2-58, height/2+84, 28); + client.player.networkHandler.getListedPlayerListEntries().forEach(entry -> { + if (entry.getGameMode() == GameMode.SPECTATOR) playerList.addPlayerEntry(new PlayerListEntry(Text.literal(entry.getProfile().getName()), entry.getProfile().getId())); + }); + + addDrawableChild(playerList); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + renderBackground(context); + context.fill(width/2-93, height/2-84, width/2+93, height/2+84, 0x8F_000000); + context.fill(width/2-93, height/2-84, width/2+93, height/2-58, 0xA0_000000); + context.getMatrices().push(); + context.getMatrices().scale(1.5f, 1.5f, 1f); + context.drawText(textRenderer, Text.literal("Buy Station"), Math.round((width/2-80)/1.5f), Math.round((height/2-75)/1.5f), 0xFF_73c0e7, false); + context.getMatrices().pop(); + Text money = Text.literal("$").append(Text.literal(String.valueOf(client.player.experienceLevel*100))); + context.drawText(textRenderer, money, width/2+80-textRenderer.getWidth(money), height/2-72, 0xFF_FFFFFF, false); + playerList.render(context, mouseX, mouseY, delta); + super.render(context, mouseX, mouseY, delta); + } + + @Override + public boolean shouldPause() { + return false; + } + + public class PlayerListWidget extends ElementListWidget { + public PlayerListWidget(MinecraftClient minecraftClient, int i, int j, int k, int l, int m) { + super(minecraftClient, i, j, k, l, m); + this.setRenderBackground(false); + this.setRenderHorizontalShadows(false); + } + + public void addPlayerEntry(PlayerListEntry entry) { + this.addEntry(entry); + } + } + + public class PlayerListEntry extends ElementListWidget.Entry { + private final ButtonWidget button; + private final Text name; + private final UUID uuid; + + public PlayerListEntry(Text name, UUID uuid) { + this.button = ButtonWidget.builder(name, button1 -> { + PacketByteBuf buf = PacketByteBufs.create(); + buf.writeUuid(uuid); + buf.writeBlockPos(blockPos); + ClientPlayNetworking.send(HardcoreRedeploy.REQUEST_REVIVE, buf); + client.setScreen(null); + }) + .position(4,2) + .size(178, 18) + .build(); + this.name = name; + this.uuid = uuid; + } + + @Override + public List selectableChildren() { + return List.of(button); + } + + @Override + public List children() { + return List.of(button); + } + + @Override + public void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { + button.setX(x); + button.setY(y); + boolean isHovered = mouseX >= x && mouseX <= x+178 && mouseY >= y && mouseY <= y+18; + Integer revives = HardcoreRedeployClient.reviveMap.get(this.uuid); + int cost = serverConfig.baseCost+(revives == null ? 0 : revives)*serverConfig.additiveCost; + int backgroundColor = ((isHovered ? 0x30 : 0x20) << 24) + + ((client.player.experienceLevel >= cost) ? 0x2397d1 : 0xa3a3a3); + context.fill(x, y, x+178, y+18, backgroundColor); + context.drawText(textRenderer, button.getMessage(), x+4, y+5, 0xFF_73c0e7, false); + Text money = Text.literal("$").append(Text.literal(String.valueOf(cost*100))); + context.drawText(textRenderer, money, x+178-4-textRenderer.getWidth(money), y+5, 0xFF_7efc20, false); + } + } +} diff --git a/src/main/java/net/touhoudiscord/screen/RedeployingScreen.java b/src/main/java/net/touhoudiscord/screen/RedeployingScreen.java new file mode 100644 index 0000000..8de66b8 --- /dev/null +++ b/src/main/java/net/touhoudiscord/screen/RedeployingScreen.java @@ -0,0 +1,34 @@ +package net.touhoudiscord.screen; + +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.text.Text; + +public class RedeployingScreen extends Screen { + + private final float duration; + private float time; + + public RedeployingScreen(float duration) { + super(Text.empty()); + this.duration = duration; + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + time += delta; + context.fill(0, 0, width, height, Math.round((1-Math.abs((float)Math.sin(((time/(duration/2))-1)*(Math.PI/2))))*255)<<24); + super.render(context, mouseX, mouseY, delta); + if (time > duration) client.setScreen(null); + } + + @Override + public boolean shouldPause() { + return false; + } + + @Override + public boolean shouldCloseOnEsc() { + return false; + } +} diff --git a/src/main/resources/assets/hardcore-redeploy/blockstates/buy_station.json b/src/main/resources/assets/hardcore-redeploy/blockstates/buy_station.json deleted file mode 100644 index dcf3530..0000000 --- a/src/main/resources/assets/hardcore-redeploy/blockstates/buy_station.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "variants": { - "": { "model": "hardcore-redeploy:block/buy_station" } - } -} \ No newline at end of file diff --git a/src/main/resources/assets/hardcore-redeploy/lang/en_us.json b/src/main/resources/assets/hardcore-redeploy/lang/en_us.json deleted file mode 100644 index c2730d5..0000000 --- a/src/main/resources/assets/hardcore-redeploy/lang/en_us.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "block.hardcore-redeploy.buy_station": "Buy Station", - "effect.hardcore-redeploy.redeploying": "Redeploying" -} \ No newline at end of file diff --git a/src/main/resources/assets/hardcore-redeploy/models/block/buy_station.json b/src/main/resources/assets/hardcore-redeploy/models/block/buy_station.json deleted file mode 100644 index e86cd08..0000000 --- a/src/main/resources/assets/hardcore-redeploy/models/block/buy_station.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "credit": "Made with Blockbench", - "parent": "builtin/entity", - "texture_size": [ - 64, - 64 - ], - "textures": { - "particle": "minecraft:block/hopper_outside" - } -} \ No newline at end of file diff --git a/src/main/resources/assets/hardcore-redeploy/models/item/buy_station.json b/src/main/resources/assets/hardcore-redeploy/models/item/buy_station.json deleted file mode 100644 index 3f1b0df..0000000 --- a/src/main/resources/assets/hardcore-redeploy/models/item/buy_station.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parent": "hardcore-redeploy:block/buy_station" -} \ No newline at end of file diff --git a/src/main/resources/assets/hardcore-redeploy/animations/buy_station.animation.json b/src/main/resources/assets/hardcore_redeploy/animations/buy_station.animation.json similarity index 80% rename from src/main/resources/assets/hardcore-redeploy/animations/buy_station.animation.json rename to src/main/resources/assets/hardcore_redeploy/animations/buy_station.animation.json index 13b9736..8999dc9 100644 --- a/src/main/resources/assets/hardcore-redeploy/animations/buy_station.animation.json +++ b/src/main/resources/assets/hardcore_redeploy/animations/buy_station.animation.json @@ -28,7 +28,7 @@ "vector": [0, 0, 0] }, "0.25": { - "vector": [-25, 0, 0] + "vector": [-37.5, 0, 0] }, "1.0": { "vector": [-10, 0, 0] @@ -58,7 +58,8 @@ "vector": [0, 0, 0] }, "0.3333": { - "vector": [0, 2, 0] + "vector": [0, 2, 0], + "easing": "easeOutBack" }, "0.6667": { "vector": [-11, 3, 0], @@ -72,7 +73,8 @@ "vector": [0, 0, 0] }, "0.3333": { - "vector": [0, 2, 0] + "vector": [0, 2, 0], + "easing": "easeOutBack" }, "0.6667": { "vector": [11, 3, 0], @@ -108,6 +110,11 @@ } } } + }, + "sound_effects": { + "0.0": { + "effect": "buy_station" + } } }, "animation.model.idle": { @@ -182,7 +189,7 @@ "vector": [-10, 0, 0] }, "0.5833": { - "vector": [-25, 0, 0] + "vector": [-35, 0, 0] }, "1.0": { "vector": [0, 0, 0] @@ -199,69 +206,86 @@ "vector": [0, 6, -2] }, "0.5833": { - "vector": [0, 6, -2] + "vector": [0, 6, -2], + "easing": "easeOutBack" }, "1.0": { - "vector": [0, 0, 0] + "vector": [0, 0, 0], + "easing": "linear" } } }, "botshelfR": { "position": { - "0.0": { + "0.25": { "vector": [-11, 3, 0], "easing": "easeOutBack" }, - "0.2917": { - "vector": [0, 2, 0] - }, "0.5417": { - "vector": [0, 0, 0] + "vector": [0, 2, 0], + "easing": "easeOutBack" + }, + "0.7917": { + "vector": [0, 0, 0], + "easing": "easeOutBack" } } }, "botshelfL": { "position": { - "0.0": { + "0.25": { "vector": [11, 3, 0], "easing": "easeOutBack" }, - "0.2917": { - "vector": [0, 2, 0] - }, "0.5417": { - "vector": [0, 0, 0] + "vector": [0, 2, 0], + "easing": "easeOutBack" + }, + "0.7917": { + "vector": [0, 0, 0], + "easing": "easeOutBack" } } }, "hingeL": { "position": { - "0.0": { + "0.25": { "vector": [1, 3, 0], "easing": "easeOutBack" }, - "0.2917": { + "0.4167": { + "vector": [-1.57, 2.43, 0] + }, + "0.5417": { "vector": [0, 2, 0] }, - "0.5833": { + "0.8333": { "vector": [0, 0, 0] } } }, "hingeR": { "position": { - "0.0": { + "0.25": { "vector": [-1, 3, 0], "easing": "easeOutBack" }, - "0.2917": { + "0.4167": { + "vector": [1.57, 2.43, 0] + }, + "0.5417": { "vector": [0, 2, 0] }, - "0.5833": { + "0.8333": { "vector": [0, 0, 0] } } } + }, + "sound_effects": { + "0.0": { + "effect": "buy_station" + } } } }, diff --git a/src/main/resources/assets/hardcore_redeploy/blockstates/buy_station.json b/src/main/resources/assets/hardcore_redeploy/blockstates/buy_station.json new file mode 100644 index 0000000..f9beb1c --- /dev/null +++ b/src/main/resources/assets/hardcore_redeploy/blockstates/buy_station.json @@ -0,0 +1,5 @@ +{ + "variants": { + "": { "model": "hardcore_redeploy:block/buy_station" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/hardcore-redeploy/geo/buy_station.geo.json b/src/main/resources/assets/hardcore_redeploy/geo/buy_station.geo.json similarity index 100% rename from src/main/resources/assets/hardcore-redeploy/geo/buy_station.geo.json rename to src/main/resources/assets/hardcore_redeploy/geo/buy_station.geo.json diff --git a/src/main/resources/assets/hardcore_redeploy/icon.png b/src/main/resources/assets/hardcore_redeploy/icon.png new file mode 100644 index 0000000..f99559d Binary files /dev/null and b/src/main/resources/assets/hardcore_redeploy/icon.png differ diff --git a/src/main/resources/assets/hardcore_redeploy/lang/en_us.json b/src/main/resources/assets/hardcore_redeploy/lang/en_us.json new file mode 100644 index 0000000..af0e299 --- /dev/null +++ b/src/main/resources/assets/hardcore_redeploy/lang/en_us.json @@ -0,0 +1,5 @@ +{ + "block.hardcore_redeploy.buy_station": "Buy Station", + "effect.hardcore_redeploy.redeploying": "Redeploying", + "subtitles.hardcore_redeploy.buy_station": "Buy station noise" +} \ No newline at end of file diff --git a/src/main/resources/assets/hardcore_redeploy/models/block/buy_station.json b/src/main/resources/assets/hardcore_redeploy/models/block/buy_station.json new file mode 100644 index 0000000..c92c841 --- /dev/null +++ b/src/main/resources/assets/hardcore_redeploy/models/block/buy_station.json @@ -0,0 +1,72 @@ +{ + "credit": "Made with Blockbench", + "parent": "builtin/entity", + "texture_size": [ + 64, + 64 + ], + "textures": { + "particle": "minecraft:block/hopper_outside" + }, + "display": { + "thirdperson_righthand": { + "scale": [ + 0.3, + 0.3, + 0.3 + ] + }, + "thirdperson_lefthand": { + "scale": [ + 0.3, + 0.3, + 0.3 + ] + }, + "firstperson_righthand": { + "scale": [ + 0.2, + 0.2, + 0.2 + ] + }, + "firstperson_lefthand": { + "scale": [ + 0.2, + 0.2, + 0.2 + ] + }, + "ground": { + "scale": [ + 0.7, + 0.7, + 0.7 + ] + }, + "gui": { + "rotation": [ + 0, + 23, + 21 + ], + "translation": [ + 1, + -2.75, + 0 + ], + "scale": [ + 0.5, + 0.5, + 0.5 + ] + }, + "fixed": { + "rotation": [ + -90, + 0, + 0 + ] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/hardcore_redeploy/models/item/buy_station.json b/src/main/resources/assets/hardcore_redeploy/models/item/buy_station.json new file mode 100644 index 0000000..674a6ba --- /dev/null +++ b/src/main/resources/assets/hardcore_redeploy/models/item/buy_station.json @@ -0,0 +1,3 @@ +{ + "parent": "hardcore_redeploy:block/buy_station" +} \ No newline at end of file diff --git a/src/main/resources/assets/hardcore_redeploy/sounds.json b/src/main/resources/assets/hardcore_redeploy/sounds.json new file mode 100644 index 0000000..858c6a4 --- /dev/null +++ b/src/main/resources/assets/hardcore_redeploy/sounds.json @@ -0,0 +1,8 @@ +{ + "buy_station": { + "subtitle": "subtitles.hardcore_redeploy.buy_station", + "sounds": [ + "hardcore_redeploy:buy_station" + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/hardcore_redeploy/sounds/buy_station.ogg b/src/main/resources/assets/hardcore_redeploy/sounds/buy_station.ogg new file mode 100644 index 0000000..0ccda3b Binary files /dev/null and b/src/main/resources/assets/hardcore_redeploy/sounds/buy_station.ogg differ diff --git a/src/main/resources/assets/hardcore-redeploy/textures/block/buy_station.png b/src/main/resources/assets/hardcore_redeploy/textures/block/buy_station.png similarity index 100% rename from src/main/resources/assets/hardcore-redeploy/textures/block/buy_station.png rename to src/main/resources/assets/hardcore_redeploy/textures/block/buy_station.png diff --git a/src/main/resources/assets/hardcore_redeploy/textures/mob_effect/redeploying.png b/src/main/resources/assets/hardcore_redeploy/textures/mob_effect/redeploying.png new file mode 100644 index 0000000..8d39fe6 Binary files /dev/null and b/src/main/resources/assets/hardcore_redeploy/textures/mob_effect/redeploying.png differ diff --git a/src/main/resources/data/hardcore_redeploy/loot_tables/blocks/buy_station.json b/src/main/resources/data/hardcore_redeploy/loot_tables/blocks/buy_station.json new file mode 100644 index 0000000..3ad3f7a --- /dev/null +++ b/src/main/resources/data/hardcore_redeploy/loot_tables/blocks/buy_station.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "hardcore_redeploy:buy_station" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/data/hardcore_redeploy/recipes/buy_station.json b/src/main/resources/data/hardcore_redeploy/recipes/buy_station.json new file mode 100644 index 0000000..8c3a27c --- /dev/null +++ b/src/main/resources/data/hardcore_redeploy/recipes/buy_station.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "III", + "ICI", + "III" + ], + "key": { + "I": { + "item": "minecraft:iron_ingot" + }, + "C": { + "item": "minecraft:crafting_table" + } + }, + "result": { + "item": "hardcore_redeploy:buy_station", + "count": 1 + } +} + diff --git a/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json b/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json new file mode 100644 index 0000000..ccf9d2c --- /dev/null +++ b/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "hardcore_redeploy:buy_station" + ] +} \ No newline at end of file diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index e23f91b..42d8021 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -1,19 +1,19 @@ { "schemaVersion": 1, - "id": "hardcore-redeploy", + "id": "hardcore_redeploy", "version": "${version}", "name": "Hardcore Redeploy", "description": "A mod that allows reviving players in hardcore servers, at a cost", "authors": [ "Hexugory", - "Kaptcha" + "Kaptchadelta" ], "contact": { "homepage": "", "sources": "https://git.touhoudiscord.net/Hexugory/HardcoreRedeploy" }, "license": "LGPL-3.0", - "icon": "assets/hardcore-redeploy/icon.png", + "icon": "assets/hardcore_redeploy/icon.png", "environment": "*", "entrypoints": { "main": [ @@ -24,15 +24,19 @@ ] }, "mixins": [ - "hardcore-redeploy.mixins.json" + "hardcore_redeploy.mixins.json" ], "depends": { "fabricloader": ">=0.14.25", "minecraft": "~1.20.1", "java": ">=17", - "fabric-api": "*" + "fabric-api": "*", + "geckolib": "^4.4.2" }, - "suggests": { - "another-mod": "*" + "custom": { + "loom:injected_interfaces": { + "net/minecraft/class_1657": ["net/touhoudiscord/BuyStationCapable"], + "net/minecraft/class_746": ["net/touhoudiscord/BuyStationCapable"] } +} } \ No newline at end of file diff --git a/src/main/resources/hardcore-redeploy.mixins.json b/src/main/resources/hardcore-redeploy.mixins.json deleted file mode 100644 index 4270c3a..0000000 --- a/src/main/resources/hardcore-redeploy.mixins.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "required": true, - "package": "net.touhoudiscord.mixin", - "compatibilityLevel": "JAVA_17", - "mixins": [ - "RedeployingMixin" - ], - "injectors": { - "defaultRequire": 1 - } -} \ No newline at end of file diff --git a/src/main/resources/hardcore_redeploy.mixins.json b/src/main/resources/hardcore_redeploy.mixins.json new file mode 100644 index 0000000..8a3b1ec --- /dev/null +++ b/src/main/resources/hardcore_redeploy.mixins.json @@ -0,0 +1,16 @@ +{ + "required": true, + "package": "net.touhoudiscord.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "BuyStationScreenMixin", + "RedeployingMixin", + "RedeployTimerMixin" + ], + "injectors": { + "defaultRequire": 1 + }, + "client": [ + "ClientBuyStationScreenMixin" + ] +} \ No newline at end of file