From 871c10bba33ad8dba20510e51eee82558ae74610 Mon Sep 17 00:00:00 2001 From: Hexugory Date: Fri, 23 Feb 2024 02:01:37 -0600 Subject: [PATCH] add the mod --- gradle.properties | 2 +- .../net/touhoudiscord/BuyStationCapable.java | 9 ++ .../net/touhoudiscord/HardcoreRedeploy.java | 102 +++++++++++++- .../touhoudiscord/HardcoreRedeployClient.java | 33 +++++ .../HardcoreRedeployConfigHandler.java | 39 ++++++ .../java/net/touhoudiscord/PlayerData.java | 5 + .../java/net/touhoudiscord/PlayerTimer.java | 13 ++ .../net/touhoudiscord/RedeployPlayer.java | 7 + .../net/touhoudiscord/RedeployStateSaver.java | 74 +++++++++++ .../java/net/touhoudiscord/TimerAccess.java | 7 + .../net/touhoudiscord/block/BuyStation.java | 125 +++++++++++++++++- .../touhoudiscord/block/BuyStationEntity.java | 23 +++- .../block/client/BuyStationModel.java | 3 + .../block/client/BuyStationRenderer.java | 16 +++ .../commands/RedeployPlayerCommand.java | 6 +- .../touhoudiscord/item/BuyStationItem.java | 5 +- .../item/client/BuyStationItemModel.java | 3 + .../item/client/BuyStationItemRenderer.java | 3 + .../mixin/BuyStationScreenMixin.java | 13 ++ .../mixin/ClientBuyStationScreenMixin.java | 20 +++ .../mixin/RedeployTimerMixin.java | 41 ++++++ .../screen/BuyStationScreen.java | 125 ++++++++++++++++++ .../screen/RedeployingScreen.java | 34 +++++ .../blockstates/buy_station.json | 5 - .../assets/hardcore-redeploy/lang/en_us.json | 4 - .../models/block/buy_station.json | 11 -- .../models/item/buy_station.json | 3 - .../animations/buy_station.animation.json | 68 +++++++--- .../blockstates/buy_station.json | 5 + .../geo/buy_station.geo.json | 0 .../assets/hardcore_redeploy/icon.png | Bin 0 -> 15447 bytes .../assets/hardcore_redeploy/lang/en_us.json | 5 + .../models/block/buy_station.json | 72 ++++++++++ .../models/item/buy_station.json | 3 + .../assets/hardcore_redeploy/sounds.json | 8 ++ .../hardcore_redeploy/sounds/buy_station.ogg | Bin 0 -> 36292 bytes .../textures/block/buy_station.png | Bin .../textures/mob_effect/redeploying.png | Bin 0 -> 928 bytes .../loot_tables/blocks/buy_station.json | 19 +++ .../recipes/buy_station.json | 21 +++ .../tags/blocks/mineable/pickaxe.json | 6 + src/main/resources/fabric.mod.json | 18 ++- .../resources/hardcore-redeploy.mixins.json | 11 -- .../resources/hardcore_redeploy.mixins.json | 16 +++ 44 files changed, 897 insertions(+), 86 deletions(-) create mode 100644 src/main/java/net/touhoudiscord/BuyStationCapable.java create mode 100644 src/main/java/net/touhoudiscord/HardcoreRedeployConfigHandler.java create mode 100644 src/main/java/net/touhoudiscord/PlayerData.java create mode 100644 src/main/java/net/touhoudiscord/PlayerTimer.java create mode 100644 src/main/java/net/touhoudiscord/RedeployStateSaver.java create mode 100644 src/main/java/net/touhoudiscord/TimerAccess.java create mode 100644 src/main/java/net/touhoudiscord/mixin/BuyStationScreenMixin.java create mode 100644 src/main/java/net/touhoudiscord/mixin/ClientBuyStationScreenMixin.java create mode 100644 src/main/java/net/touhoudiscord/mixin/RedeployTimerMixin.java create mode 100644 src/main/java/net/touhoudiscord/screen/BuyStationScreen.java create mode 100644 src/main/java/net/touhoudiscord/screen/RedeployingScreen.java delete mode 100644 src/main/resources/assets/hardcore-redeploy/blockstates/buy_station.json delete mode 100644 src/main/resources/assets/hardcore-redeploy/lang/en_us.json delete mode 100644 src/main/resources/assets/hardcore-redeploy/models/block/buy_station.json delete mode 100644 src/main/resources/assets/hardcore-redeploy/models/item/buy_station.json rename src/main/resources/assets/{hardcore-redeploy => hardcore_redeploy}/animations/buy_station.animation.json (80%) create mode 100644 src/main/resources/assets/hardcore_redeploy/blockstates/buy_station.json rename src/main/resources/assets/{hardcore-redeploy => hardcore_redeploy}/geo/buy_station.geo.json (100%) create mode 100644 src/main/resources/assets/hardcore_redeploy/icon.png create mode 100644 src/main/resources/assets/hardcore_redeploy/lang/en_us.json create mode 100644 src/main/resources/assets/hardcore_redeploy/models/block/buy_station.json create mode 100644 src/main/resources/assets/hardcore_redeploy/models/item/buy_station.json create mode 100644 src/main/resources/assets/hardcore_redeploy/sounds.json create mode 100644 src/main/resources/assets/hardcore_redeploy/sounds/buy_station.ogg rename src/main/resources/assets/{hardcore-redeploy => hardcore_redeploy}/textures/block/buy_station.png (100%) create mode 100644 src/main/resources/assets/hardcore_redeploy/textures/mob_effect/redeploying.png create mode 100644 src/main/resources/data/hardcore_redeploy/loot_tables/blocks/buy_station.json create mode 100644 src/main/resources/data/hardcore_redeploy/recipes/buy_station.json create mode 100644 src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json delete mode 100644 src/main/resources/hardcore-redeploy.mixins.json create mode 100644 src/main/resources/hardcore_redeploy.mixins.json 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 0000000000000000000000000000000000000000..f99559d8e7ffc0dcfc14fe4bf5c83533d5e11ccb GIT binary patch literal 15447 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 xZf8RIiIb^Gdl2!q zui*pu0v^10@fGwP^y)!&opjr-2Wwz5fB3%d_h-Jj=yhKl9X>b|1mVazvHE=8E5^ZX z{(pG)%LSkAv(Av6k}=CXiUlJeBMh9#o8Uh7g2n5vxG4zxkHW!_4c(W>Cz0e87%7hu z&K87bD^EOsh8Y;)Nf_(m&rhF45C*z<;|p%+~_3^$av~#04VE zJdj7{af)(XTrHRuDGR#p|SoZV#A*Vo;T8C10sjL0yxSTDhWWPk|~c4JbFD zQZ6YqRFRRYg7qizXfzn3zGbgt@trPC8A}j^S(ZszSt4`-6;0EitU^^SaYQLy#LUY} zaeBN_uyE?rFkvByL80i4$eigS&-A*4DA~%!>AFq4VKDa+s7P{A(gx_d|A$7=7M-#_ zzRCBW!s%d^6+mF>1sQ#H%3SIc!{!?lP%k8sR3 z+~9_5?&KDBh!P&z!Zdt?1Dlcvtjb2=?p(B;dTVa5I~QXo7xH9aak+n8_U4E?s90{T z%Qsu|*}ht|NPyaaPa%q<@XQnz2eO{ov!t<{p$T6 D5E2}W literal 0 HcmV?d00001 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