├── src └── main │ ├── resources │ ├── tcuhc.accesswidener │ ├── data │ │ └── tcuhc │ │ │ ├── recipes │ │ │ ├── golden_apple.json │ │ │ └── repair_armor.json │ │ │ ├── structures │ │ │ ├── greenhouse │ │ │ │ ├── snow.nbt │ │ │ │ └── desert.nbt │ │ │ ├── ender_pyramid │ │ │ │ └── main.nbt │ │ │ ├── plain_cottage │ │ │ │ └── main.nbt │ │ │ ├── villain_house │ │ │ │ └── main.nbt │ │ │ └── honey_workshop │ │ │ │ └── main.nbt │ │ │ ├── lootentries │ │ │ ├── lapis_ore.json │ │ │ └── glowstone.json │ │ │ ├── loot_tables │ │ │ ├── honey_workshop │ │ │ │ └── chest.json │ │ │ ├── greenhouse │ │ │ │ ├── chest_desert.json │ │ │ │ └── chest_snow.json │ │ │ ├── plain_cottage │ │ │ │ └── chest.json │ │ │ ├── villain_house │ │ │ │ └── chest.json │ │ │ └── ender_pyramid │ │ │ │ └── chest.json │ │ │ └── lootpools │ │ │ └── apple.json │ ├── assets │ │ └── tcuhc │ │ │ └── icon.png │ ├── fabric.mod.json │ └── tcuhc.mixins.json │ └── java │ └── me │ └── fallenbreath │ └── tcuhc │ ├── interfaces │ ├── IPlayerInventory.java │ ├── LootTableAccessor.java │ ├── LootPoolAccessor.java │ └── IOreFeature.java │ ├── helpers │ └── ServerPlayerEntityHelper.java │ ├── mixins │ ├── entity │ │ ├── MobEntityAccessor.java │ │ ├── TradeOffersEnchantBookFactoryMixin.java │ │ ├── ServerWorldMixin.java │ │ ├── EntityCategoryMixin.java │ │ ├── VillagerEntityMixin.java │ │ ├── PersistentProjectileEntityMixin.java │ │ ├── EntityDamageSourceMixin.java │ │ ├── BoatEntityMixin.java │ │ ├── WitchEntityMixin.java │ │ ├── LivingEntityMixin.java │ │ ├── AbstractMinecartEntityMixin.java │ │ ├── PlayerInventoryMixin.java │ │ ├── DrownedEntityMixin.java │ │ ├── MobEntityMixin.java │ │ ├── StatusEffectInstanceMixin.java │ │ ├── SpectralArrowEntityMixin.java │ │ ├── EndCrystalEntityMixin.java │ │ └── ServerPlayerEntityMixin.java │ ├── loot │ │ ├── ItemEntryAccessor.java │ │ ├── LootManagerAccessor.java │ │ ├── LootPoolMixin.java │ │ └── LootTableMixin.java │ ├── recipe │ │ ├── RegistryMixin.java │ │ └── SynchronizeRecipesS2CPacketMixin.java │ ├── core │ │ ├── SessionAccessor.java │ │ ├── MinecraftServerAccessor.java │ │ ├── LevelStorageMixin.java │ │ ├── CommandManagerMixin.java │ │ ├── PlayerManagerMixin.java │ │ └── MinecraftServerMixin.java │ ├── item │ │ ├── StatusEffectInstanceAccessor.java │ │ ├── AbsorptionStatusEffectMixin.java │ │ ├── ItemMixin.java │ │ ├── FoodComponentBuilderMixin.java │ │ ├── ChorusFruitMixin.java │ │ ├── FlowerBlockMixin.java │ │ ├── PlayerEntityMixin.java │ │ ├── LivingEntityMixin.java │ │ └── ItemStackMixin.java │ ├── util │ │ └── SheepEntityAccessor.java │ ├── task │ │ ├── PlayerListHeaderS2CPacketAccessor.java │ │ └── ServerChunkManagerAccessor.java │ ├── feature │ │ ├── structure │ │ │ ├── WeightedListAccessor.java │ │ │ ├── StructureFeatureAccessor.java │ │ │ └── StructuresConfigAccessor.java │ │ └── HorizontalConnectingBlockAccessor.java │ ├── worldgen │ │ ├── structure │ │ │ ├── StructuresConfigMixin.java │ │ │ ├── ShipwreckFeatureMixin.java │ │ │ └── BuriedTreasureFeatureMixin.java │ │ ├── ore │ │ │ ├── PlacedFeatureAccessor.java │ │ │ ├── PlacedFeaturesMixin.java │ │ │ └── OreFeatureMixin.java │ │ ├── world │ │ │ ├── StructuresConfigMixin.java │ │ │ ├── NoiseColumnSamplerMixin.java │ │ │ └── CaveCarverMixin.java │ │ └── feature │ │ │ ├── DefaultBiomeFeaturesMixin.java │ │ │ ├── StructureFeatureMixin.java │ │ │ ├── BastionRemnantFeatureMixin.java │ │ │ ├── NetherFortressFeatureMixin.java │ │ │ └── ConfiguredStructureFeaturesMixin.java │ ├── block │ │ ├── OreBlockMixin.java │ │ ├── ChestBlockEntityMixin.java │ │ └── LootManagerMixin.java │ └── network │ │ └── ServerPlayNetworkHandlerMixin.java │ ├── task │ ├── TaskOnce.java │ ├── MsptRecorder.java │ ├── Taskable.java │ ├── TaskFindPlayer.java │ ├── Task.java │ ├── TaskSpawnPlatformProtect.java │ ├── TaskHUDInfo.java │ ├── TaskKeepSpectate.java │ ├── TaskKingEffectField.java │ ├── TaskBorderReminder.java │ ├── TaskBroadcastData.java │ ├── TaskTitleCountDown.java │ └── TaskScoreboard.java │ ├── gen │ ├── structure │ │ ├── GreenhouseConfig.java │ │ ├── HoneyWorkshopStructure.java │ │ ├── EnderPyramidStructure.java │ │ ├── VillainHouseStructure.java │ │ └── PlainCottageStructure.java │ └── feature │ │ └── UhcFeatures.java │ ├── util │ ├── Position.java │ ├── SpawnPosition.java │ ├── TitleUtil.java │ ├── LootTableUtil.java │ ├── AverageIntProvider.java │ ├── LastWinnerList.java │ ├── UhcWorldData.java │ ├── collection │ │ └── ExpiringMap.java │ ├── SpectateTargetUtil.java │ ├── ColorUtil.java │ ├── UhcRegistry.java │ └── SpawnPlatform.java │ ├── recipe │ ├── UhcRecipeSerializer.java │ ├── RecipeGoldenApple.java │ └── RecipeArmorRepair.java │ ├── TcUhcMod.java │ ├── UhcConfigManager.java │ ├── UhcGameColor.java │ ├── options │ ├── Option.java │ └── OptionType.java │ ├── UhcGameTeam.java │ └── UhcGamePlayer.java ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── settings.gradle ├── gradle.properties ├── .github └── workflows │ └── gradle.yml ├── README.md └── gradlew.bat /src/main/resources/tcuhc.accesswidener: -------------------------------------------------------------------------------- 1 | accessWidener v1 named 2 | 3 | -------------------------------------------------------------------------------- /src/main/resources/data/tcuhc/recipes/golden_apple.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "tcuhc:crafting_golden_apple" 3 | } -------------------------------------------------------------------------------- /src/main/resources/data/tcuhc/recipes/repair_armor.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "tcuhc:crafting_repair_armor" 3 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fallen-Breath/tcuhc-fabric/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/assets/tcuhc/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fallen-Breath/tcuhc-fabric/HEAD/src/main/resources/assets/tcuhc/icon.png -------------------------------------------------------------------------------- /src/main/resources/data/tcuhc/structures/greenhouse/snow.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fallen-Breath/tcuhc-fabric/HEAD/src/main/resources/data/tcuhc/structures/greenhouse/snow.nbt -------------------------------------------------------------------------------- /src/main/resources/data/tcuhc/structures/ender_pyramid/main.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fallen-Breath/tcuhc-fabric/HEAD/src/main/resources/data/tcuhc/structures/ender_pyramid/main.nbt -------------------------------------------------------------------------------- /src/main/resources/data/tcuhc/structures/greenhouse/desert.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fallen-Breath/tcuhc-fabric/HEAD/src/main/resources/data/tcuhc/structures/greenhouse/desert.nbt -------------------------------------------------------------------------------- /src/main/resources/data/tcuhc/structures/plain_cottage/main.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fallen-Breath/tcuhc-fabric/HEAD/src/main/resources/data/tcuhc/structures/plain_cottage/main.nbt -------------------------------------------------------------------------------- /src/main/resources/data/tcuhc/structures/villain_house/main.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fallen-Breath/tcuhc-fabric/HEAD/src/main/resources/data/tcuhc/structures/villain_house/main.nbt -------------------------------------------------------------------------------- /src/main/resources/data/tcuhc/structures/honey_workshop/main.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fallen-Breath/tcuhc-fabric/HEAD/src/main/resources/data/tcuhc/structures/honey_workshop/main.nbt -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/interfaces/IPlayerInventory.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.interfaces; 2 | 3 | public interface IPlayerInventory 4 | { 5 | void dropAllItemsWithoutClear(); 6 | } 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/helpers/ServerPlayerEntityHelper.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.helpers; 2 | 3 | public class ServerPlayerEntityHelper 4 | { 5 | public static final ThreadLocal doSpectateCheck = ThreadLocal.withInitial(() -> true); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/interfaces/LootTableAccessor.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.interfaces; 2 | 3 | import net.minecraft.loot.LootPool; 4 | 5 | public interface LootTableAccessor 6 | { 7 | LootPool[] getPools(); 8 | 9 | void setPools(LootPool[] lootPools); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/interfaces/LootPoolAccessor.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.interfaces; 2 | 3 | import net.minecraft.loot.entry.LootPoolEntry; 4 | 5 | public interface LootPoolAccessor 6 | { 7 | LootPoolEntry[] getEntries(); 8 | 9 | void setEntries(LootPoolEntry[] entries); 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # gradle 2 | 3 | .gradle/ 4 | build/ 5 | out/ 6 | classes/ 7 | 8 | # eclipse 9 | 10 | *.launch 11 | 12 | # idea 13 | 14 | .idea/ 15 | *.iml 16 | *.ipr 17 | *.iws 18 | 19 | # vscode 20 | 21 | .settings/ 22 | .vscode/ 23 | bin/ 24 | .classpath 25 | .project 26 | 27 | # macos 28 | 29 | *.DS_Store 30 | 31 | # fabric 32 | 33 | run/ 34 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | jcenter() 4 | maven { 5 | name = 'Fabric' 6 | url = 'https://maven.fabricmc.net/' 7 | } 8 | maven { 9 | name = 'Cotton' 10 | url = 'https://server.bbkr.space/artifactory/libs-release/' 11 | } 12 | gradlePluginPortal() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/entity/MobEntityAccessor.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.entity; 2 | 3 | import net.minecraft.entity.mob.MobEntity; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.gen.Invoker; 6 | 7 | @Mixin(MobEntity.class) 8 | public interface MobEntityAccessor 9 | { 10 | @Invoker 11 | void invokeCheckDespawn(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/loot/ItemEntryAccessor.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.loot; 2 | 3 | import net.minecraft.item.Item; 4 | import net.minecraft.loot.entry.ItemEntry; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | @Mixin(ItemEntry.class) 9 | public interface ItemEntryAccessor 10 | { 11 | @Accessor 12 | Item getItem(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/recipe/RegistryMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.recipe; 2 | 3 | import me.fallenbreath.tcuhc.recipe.UhcRecipeSerializer; 4 | import net.minecraft.util.registry.Registry; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | 7 | @Mixin(Registry.class) 8 | public abstract class RegistryMixin 9 | { 10 | static 11 | { 12 | UhcRecipeSerializer.noop(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/core/SessionAccessor.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.core; 2 | 3 | import net.minecraft.world.level.storage.LevelStorage; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.gen.Accessor; 6 | 7 | import java.nio.file.Path; 8 | 9 | @Mixin(LevelStorage.Session.class) 10 | public interface SessionAccessor 11 | { 12 | @Accessor 13 | Path getDirectory(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/interfaces/IOreFeature.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.interfaces; 2 | 3 | import net.minecraft.block.BlockState; 4 | import net.minecraft.util.math.BlockPos; 5 | 6 | import java.util.function.Function; 7 | 8 | public interface IOreFeature 9 | { 10 | default boolean isValidPositionForValuableOre(Function posToState, BlockPos pos, BlockState oreState) 11 | { 12 | return true; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/loot/LootManagerAccessor.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.loot; 2 | 3 | import com.google.gson.Gson; 4 | import net.minecraft.loot.LootManager; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | @Mixin(LootManager.class) 9 | public interface LootManagerAccessor 10 | { 11 | @Accessor 12 | static Gson getGSON() 13 | { 14 | return null; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/data/tcuhc/lootentries/lapis_ore.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:item", 3 | "functions": [ 4 | { 5 | "function": "minecraft:set_count", 6 | "count": 2 7 | }, 8 | { 9 | "function": "minecraft:apply_bonus", 10 | "enchantment": "minecraft:fortune", 11 | "formula": "minecraft:ore_drops" 12 | }, 13 | { 14 | "function": "minecraft:explosion_decay" 15 | } 16 | ], 17 | "name": "minecraft:lapis_lazuli" 18 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx1G 3 | 4 | # Fabric Properties 5 | # check these on https://fabricmc.net/versions.html?&version=1.18.1 6 | minecraft_version=1.18.1 7 | yarn_mappings=1.18.1+build.12 8 | loader_version=0.12.12 9 | 10 | # Mod Properties 11 | mod_version = 1.1.2 12 | maven_group = me.fallenbreath 13 | archives_base_name = tcuhc-fabric 14 | 15 | # Dependencies 16 | fabric_api_version=0.45.2+1.18 17 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/core/MinecraftServerAccessor.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.core; 2 | 3 | import net.minecraft.server.MinecraftServer; 4 | import net.minecraft.world.level.storage.LevelStorage; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | @Mixin(MinecraftServer.class) 9 | public interface MinecraftServerAccessor 10 | { 11 | @Accessor 12 | LevelStorage.Session getSession(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/item/StatusEffectInstanceAccessor.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.item; 2 | 3 | import net.minecraft.entity.effect.StatusEffectInstance; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.gen.Accessor; 6 | 7 | @Mixin(StatusEffectInstance.class) 8 | public interface StatusEffectInstanceAccessor 9 | { 10 | @Accessor 11 | void setDuration(int duration); 12 | 13 | @Accessor 14 | void setAmplifier(int amplifier); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/util/SheepEntityAccessor.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.util; 2 | 3 | import net.minecraft.entity.passive.SheepEntity; 4 | import net.minecraft.item.ItemConvertible; 5 | import net.minecraft.util.DyeColor; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.gen.Accessor; 8 | 9 | import java.util.Map; 10 | 11 | @Mixin(SheepEntity.class) 12 | public interface SheepEntityAccessor 13 | { 14 | @Accessor 15 | static Map getDROPS() 16 | { 17 | return null; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/task/PlayerListHeaderS2CPacketAccessor.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.task; 2 | 3 | import net.minecraft.network.packet.s2c.play.PlayerListHeaderS2CPacket; 4 | import net.minecraft.text.Text; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | // unused since 1.17 9 | @Mixin(PlayerListHeaderS2CPacket.class) 10 | public interface PlayerListHeaderS2CPacketAccessor 11 | { 12 | @Accessor 13 | void setHeader(Text header); 14 | 15 | @Accessor 16 | void setFooter(Text footer); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/task/ServerChunkManagerAccessor.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.task; 2 | 3 | import net.minecraft.server.world.ChunkHolder; 4 | import net.minecraft.server.world.ServerChunkManager; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Invoker; 7 | 8 | @Mixin(ServerChunkManager.class) 9 | public interface ServerChunkManagerAccessor 10 | { 11 | @Invoker 12 | ChunkHolder invokeGetChunkHolder(long pos); 13 | 14 | @SuppressWarnings("UnusedReturnValue") 15 | @Invoker 16 | boolean invokeTick(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/task/TaskOnce.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.task; 6 | 7 | public class TaskOnce extends Task { 8 | 9 | private Task parent; 10 | 11 | public TaskOnce(Task parent) { 12 | this.parent = parent; 13 | } 14 | 15 | @Override 16 | public void onUpdate() { 17 | parent.onUpdate(); 18 | } 19 | 20 | @Override 21 | public boolean hasFinished() { 22 | return true; 23 | } 24 | 25 | @Override 26 | public void onFinish() { 27 | parent.onFinish(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/gen/structure/GreenhouseConfig.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.gen.structure; 2 | 3 | import com.mojang.serialization.Codec; 4 | import net.minecraft.world.gen.feature.FeatureConfig; 5 | 6 | public class GreenhouseConfig implements FeatureConfig 7 | { 8 | public static final Codec CODEC = Codec.STRING.fieldOf("type").orElse("snow"). 9 | xmap(GreenhouseConfig::new, greenhouseConfig -> greenhouseConfig.type).codec(); 10 | 11 | public final String type; 12 | 13 | public GreenhouseConfig(String type) 14 | { 15 | this.type = type; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/util/Position.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.util; 2 | 3 | import net.minecraft.util.math.Vec3d; 4 | import net.minecraft.util.registry.RegistryKey; 5 | import net.minecraft.world.World; 6 | 7 | public class Position 8 | { 9 | public final Vec3d pos; 10 | public final RegistryKey dimension; 11 | public final float yaw; 12 | public final float pitch; 13 | 14 | public Position(Vec3d pos, RegistryKey dimension, float yaw, float pitch) 15 | { 16 | this.pos = pos; 17 | this.dimension = dimension; 18 | this.yaw = yaw; 19 | this.pitch = pitch; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/feature/structure/WeightedListAccessor.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.feature.structure; 2 | 3 | import net.minecraft.util.collection.WeightedList; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Mutable; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | import java.util.List; 9 | import java.util.Random; 10 | 11 | @Mixin(WeightedList.class) 12 | public interface WeightedListAccessor 13 | { 14 | @Accessor 15 | List> getEntries(); 16 | 17 | @Accessor 18 | @Mutable 19 | void setRandom(Random random); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/item/AbsorptionStatusEffectMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.item; 2 | 3 | import net.minecraft.entity.effect.AbsorptionStatusEffect; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.Constant; 6 | import org.spongepowered.asm.mixin.injection.ModifyConstant; 7 | 8 | @Mixin(AbsorptionStatusEffect.class) 9 | public abstract class AbsorptionStatusEffectMixin 10 | { 11 | @ModifyConstant(method = {"onRemoved", "onApplied"}, constant = @Constant(intValue = 4)) 12 | private int modifyBaseAbsorption(int value) 13 | { 14 | return 1; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/feature/HorizontalConnectingBlockAccessor.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.feature; 2 | 3 | import net.minecraft.block.HorizontalConnectingBlock; 4 | import net.minecraft.state.property.BooleanProperty; 5 | import net.minecraft.util.math.Direction; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.gen.Accessor; 8 | 9 | import java.util.Map; 10 | 11 | @Mixin(HorizontalConnectingBlock.class) 12 | public interface HorizontalConnectingBlockAccessor 13 | { 14 | @Accessor 15 | static Map getFACING_PROPERTIES() 16 | { 17 | throw new AbstractMethodError(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/data/tcuhc/lootentries/glowstone.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:item", 3 | "functions": [ 4 | { 5 | "function": "minecraft:set_count", 6 | "count": 1 7 | }, 8 | { 9 | "function": "minecraft:apply_bonus", 10 | "enchantment": "minecraft:fortune", 11 | "formula": "minecraft:uniform_bonus_count", 12 | "parameters": { 13 | "bonusMultiplier": 1 14 | } 15 | }, 16 | { 17 | "function": "minecraft:limit_count", 18 | "limit": { 19 | "max": 4, 20 | "min": 1 21 | } 22 | }, 23 | { 24 | "function": "minecraft:explosion_decay" 25 | } 26 | ], 27 | "name": "minecraft:glowstone_dust" 28 | } -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/recipe/UhcRecipeSerializer.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.recipe; 2 | 3 | import me.fallenbreath.tcuhc.util.UhcRegistry; 4 | import net.minecraft.recipe.SpecialRecipeSerializer; 5 | 6 | public class UhcRecipeSerializer 7 | { 8 | public static final SpecialRecipeSerializer REPAIR_ARMOR = UhcRegistry.registerRecipeSerializer("crafting_repair_armor", new SpecialRecipeSerializer<>(RecipeArmorRepair::new)); 9 | public static final SpecialRecipeSerializer GOLDEN_APPLE = UhcRegistry.registerRecipeSerializer("crafting_golden_apple", new SpecialRecipeSerializer<>(RecipeGoldenApple::new)); 10 | 11 | public static void noop() 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/worldgen/structure/StructuresConfigMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.worldgen.structure; 2 | 3 | import me.fallenbreath.tcuhc.gen.structure.UhcStructures; 4 | import net.minecraft.world.gen.chunk.StructuresConfig; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | 10 | @Mixin(StructuresConfig.class) 11 | public abstract class StructuresConfigMixin 12 | { 13 | @Inject(method = "", at = @At("TAIL")) 14 | private static void loadUhcStructures(CallbackInfo ci) 15 | { 16 | UhcStructures.load(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/util/SpawnPosition.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.util; 6 | 7 | import net.minecraft.util.math.BlockPos; 8 | 9 | public class SpawnPosition { 10 | 11 | int next = 0; 12 | BlockPos[] poses; 13 | 14 | public SpawnPosition(int cnt, int border) { 15 | poses = new BlockPos[cnt]; 16 | border *= 0.45; 17 | for (int i = 0; i < cnt; i++) { 18 | double angle = i * (360.0 / cnt) * Math.PI / 180; 19 | int x = (int) (border * Math.sin(angle)); 20 | int z = (int) (border * Math.cos(angle)); 21 | poses[i] = new BlockPos(x, 255, z); 22 | } 23 | } 24 | 25 | public BlockPos nextPos() { 26 | return poses[next++]; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/entity/TradeOffersEnchantBookFactoryMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.entity; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.At; 5 | import org.spongepowered.asm.mixin.injection.ModifyArg; 6 | 7 | @Mixin(targets = "net.minecraft.village.TradeOffers$EnchantBookFactory") 8 | public abstract class TradeOffersEnchantBookFactoryMixin 9 | { 10 | @ModifyArg( 11 | method = "create", 12 | at = @At( 13 | value = "INVOKE", 14 | target = "Lnet/minecraft/village/TradeOffer;(Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ItemStack;IIF)V" 15 | ), 16 | index = 3 17 | ) 18 | private int modifyEnchantBookMaxUse(int maxUses) 19 | { 20 | return 1; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "tcuhc", 4 | "version": "${version}", 5 | 6 | "name": "TC UHC", 7 | "description": "TC UHC in fabric", 8 | "authors": [ 9 | "Gamepiaynmo", 10 | "Fallen_Breath" 11 | ], 12 | "contact": { 13 | "homepage": "https://github.com/Fallen-Breath/tcuhc-fabric", 14 | "sources": "https://github.com/Fallen-Breath/tcuhc-fabric" 15 | }, 16 | 17 | "icon": "assets/tcuhc/icon.png", 18 | 19 | "environment": "server", 20 | "entrypoints": { 21 | "main": [ 22 | "me.fallenbreath.tcuhc.TcUhcMod" 23 | ] 24 | }, 25 | "mixins": [ 26 | "tcuhc.mixins.json" 27 | ], 28 | "accessWidener": "tcuhc.accesswidener", 29 | 30 | "depends": { 31 | "fabricloader": ">=0.7.1", 32 | "minecraft": "1.18.x" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/task/MsptRecorder.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.task; 2 | 3 | import net.minecraft.util.math.MathHelper; 4 | 5 | public class MsptRecorder 6 | { 7 | public long[] lastTickLengths = new long[100]; 8 | private long lastMiliTime = System.currentTimeMillis(); 9 | private long ticks; 10 | 11 | public double getMspt() 12 | { 13 | return MathHelper.average(this.lastTickLengths); 14 | } 15 | 16 | public double getThisTickMspt() 17 | { 18 | return System.currentTimeMillis() - this.lastMiliTime; 19 | } 20 | 21 | public void startTick() 22 | { 23 | this.lastMiliTime = System.currentTimeMillis(); 24 | } 25 | 26 | public void endTick() 27 | { 28 | this.lastTickLengths[(int)(this.ticks % 100)] = System.currentTimeMillis() - this.lastMiliTime; 29 | this.ticks++; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/resources/data/tcuhc/loot_tables/honey_workshop/chest.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "rolls": {"type": "minecraft:uniform", "min": 1, "max": 3}, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "name": "minecraft:honey_bottle" 10 | } 11 | ] 12 | }, 13 | { 14 | "rolls": {"type": "minecraft:uniform", "min": 0, "max": 3}, 15 | "entries": [ 16 | { 17 | "type": "minecraft:item", 18 | "name": "minecraft:orange_tulip" 19 | }, 20 | { 21 | "type": "minecraft:item", 22 | "name": "minecraft:white_tulip" 23 | }, 24 | { 25 | "type": "minecraft:item", 26 | "name": "minecraft:pink_tulip" 27 | } 28 | ] 29 | } 30 | ] 31 | } -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/entity/ServerWorldMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.entity; 2 | 3 | import net.minecraft.server.world.ServerWorld; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | 6 | @Mixin(ServerWorld.class) 7 | public abstract class ServerWorldMixin 8 | { 9 | // @Inject( 10 | // method = "tick", 11 | // at = @At( 12 | // value = "INVOKE", 13 | // target = "Lnet/minecraft/server/MinecraftServer;shouldSpawnNpcs()Z" 14 | // ), 15 | // locals = LocalCapture.CAPTURE_FAILHARD 16 | // ) 17 | // private void checkMobDespawn(BooleanSupplier shouldKeepTicking, CallbackInfo ci, Profiler profiler, ObjectIterator objectIterator, Int2ObjectMap.Entry entry, Entity entity2, Entity entity3) 18 | // { 19 | // if (true) // no need in 1.15+ 20 | // { 21 | // return; 22 | // } 23 | // } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/core/LevelStorageMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.core; 2 | 3 | import me.fallenbreath.tcuhc.UhcGameManager; 4 | import net.minecraft.util.WorldSavePath; 5 | import net.minecraft.world.level.storage.LevelStorage; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 10 | 11 | @Mixin(LevelStorage.class) 12 | public abstract class LevelStorageMixin 13 | { 14 | @Inject(method = "createSession", at = @At("TAIL")) 15 | private void removeOldUhcWorld(String directoryName, CallbackInfoReturnable cir) 16 | { 17 | UhcGameManager.tryUpdateSaveFolder(cir.getReturnValue().getDirectory(WorldSavePath.ROOT)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/item/ItemMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.item; 2 | 3 | import net.minecraft.item.Item; 4 | import net.minecraft.item.ItemStack; 5 | import net.minecraft.item.Items; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 10 | 11 | @Mixin(Item.class) 12 | public abstract class ItemMixin 13 | { 14 | @Inject(method = "getMaxUseTime", at = @At("HEAD"), cancellable = true) 15 | private void modifyMaxUseTimeForGApples(ItemStack stack, CallbackInfoReturnable cir) 16 | { 17 | if (stack.getItem() == Items.GOLDEN_APPLE || stack.getItem() == Items.ENCHANTED_GOLDEN_APPLE) 18 | { 19 | cir.setReturnValue(10); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/block/OreBlockMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.block; 2 | 3 | import net.minecraft.block.Blocks; 4 | import net.minecraft.block.OreBlock; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.ModifyVariable; 8 | 9 | @Mixin(OreBlock.class) 10 | public abstract class OreBlockMixin 11 | { 12 | @SuppressWarnings("ConstantConditions") 13 | @ModifyVariable( 14 | method = "onStacksDropped", 15 | at = @At( 16 | value = "INVOKE_ASSIGN", 17 | target = "Lnet/minecraft/util/math/intprovider/UniformIntProvider;get(Ljava/util/Random;)I" 18 | ) 19 | ) 20 | private int noXpForQuartzOre(int exp) 21 | { 22 | if ((Object)this == Blocks.NETHER_QUARTZ_ORE) 23 | { 24 | return 0; 25 | } 26 | return exp; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/worldgen/ore/PlacedFeatureAccessor.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.worldgen.ore; 2 | 3 | import net.minecraft.world.gen.decorator.PlacementModifier; 4 | import net.minecraft.world.gen.feature.ConfiguredFeature; 5 | import net.minecraft.world.gen.feature.PlacedFeature; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.Mutable; 8 | import org.spongepowered.asm.mixin.gen.Accessor; 9 | 10 | import java.util.List; 11 | import java.util.function.Supplier; 12 | 13 | @Mixin(PlacedFeature.class) 14 | public interface PlacedFeatureAccessor 15 | { 16 | @Accessor 17 | Supplier> getFeature(); 18 | 19 | @Accessor 20 | List getPlacementModifiers(); 21 | 22 | @Accessor @Mutable 23 | void setPlacementModifiers(List placementModifiers); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/entity/EntityCategoryMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.entity; 2 | 3 | import me.fallenbreath.tcuhc.options.Options; 4 | import net.minecraft.entity.SpawnGroup; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 9 | 10 | @Mixin(SpawnGroup.class) 11 | public abstract class EntityCategoryMixin 12 | { 13 | @SuppressWarnings("ConstantConditions") 14 | @Inject(method = "getCapacity", at = @At("HEAD"), cancellable = true) 15 | private void modifyMobCap(CallbackInfoReturnable cir) 16 | { 17 | if (((Object)this) == SpawnGroup.MONSTER) 18 | { 19 | cir.setReturnValue(Options.instance.getIntegerOptionValue("mobCount")); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/feature/structure/StructureFeatureAccessor.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.feature.structure; 2 | 3 | import net.minecraft.world.gen.GenerationStep; 4 | import net.minecraft.world.gen.feature.StructureFeature; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.Mutable; 7 | import org.spongepowered.asm.mixin.gen.Accessor; 8 | 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | @Mixin(StructureFeature.class) 13 | public interface StructureFeatureAccessor 14 | { 15 | @Accessor 16 | static Map, GenerationStep.Feature> getSTRUCTURE_TO_GENERATION_STEP() 17 | { 18 | throw new RuntimeException(); 19 | } 20 | 21 | @Accessor 22 | @Mutable 23 | static void setLAND_MODIFYING_STRUCTURES(List> list) 24 | { 25 | throw new RuntimeException(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/loot/LootPoolMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.loot; 2 | 3 | import me.fallenbreath.tcuhc.interfaces.LootPoolAccessor; 4 | import net.minecraft.loot.LootPool; 5 | import net.minecraft.loot.entry.LootPoolEntry; 6 | import org.spongepowered.asm.mixin.Final; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Mutable; 9 | import org.spongepowered.asm.mixin.Shadow; 10 | 11 | // cannot use an Accessor or IllegalAccessError will appear, idk why 12 | @Mixin(LootPool.class) 13 | public abstract class LootPoolMixin implements LootPoolAccessor 14 | { 15 | @Mutable 16 | @Shadow @Final LootPoolEntry[] entries; 17 | 18 | public LootPoolEntry[] getEntries() 19 | { 20 | return this.entries; 21 | } 22 | 23 | public void setEntries(LootPoolEntry[] entries) 24 | { 25 | this.entries = entries; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/loot/LootTableMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.loot; 2 | 3 | import me.fallenbreath.tcuhc.interfaces.LootTableAccessor; 4 | import net.minecraft.loot.LootPool; 5 | import net.minecraft.loot.LootTable; 6 | import org.spongepowered.asm.mixin.Final; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Mutable; 9 | import org.spongepowered.asm.mixin.Shadow; 10 | 11 | // cannot use an Accessor or IllegalAccessError will appear, idk why 12 | @Mixin(LootTable.class) 13 | public abstract class LootTableMixin implements LootTableAccessor 14 | { 15 | @Mutable 16 | @Shadow @Final LootPool[] pools; 17 | 18 | @Override 19 | public LootPool[] getPools() 20 | { 21 | return this.pools; 22 | } 23 | 24 | @Override 25 | public void setPools(LootPool[] lootPools) 26 | { 27 | this.pools = lootPools; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/task/Taskable.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.task; 6 | 7 | import com.google.common.collect.Lists; 8 | 9 | import java.util.List; 10 | 11 | public class Taskable { 12 | 13 | private final List tasks = Lists.newArrayList(); 14 | private final List toRemove = Lists.newArrayList(); 15 | 16 | public Taskable addTask(Task task) { 17 | tasks.add(task); 18 | task.onAdd(); 19 | return this; 20 | } 21 | 22 | public void updateTasks() { 23 | //noinspection ForLoopReplaceableByForEach 24 | for (int i = 0; i < tasks.size(); i++) { 25 | tasks.get(i).onUpdate(); 26 | } 27 | tasks.stream().filter(Task::hasFinished).forEach(toRemove::add); 28 | toRemove.forEach(Task::onFinish); 29 | tasks.removeAll(toRemove); 30 | toRemove.clear(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/worldgen/world/StructuresConfigMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.worldgen.world; 2 | 3 | import net.minecraft.world.gen.chunk.StructuresConfig; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.ModifyArg; 7 | 8 | @Mixin(StructuresConfig.class) 9 | public abstract class StructuresConfigMixin 10 | { 11 | @ModifyArg( 12 | method = "", 13 | at = @At( 14 | value = "INVOKE", 15 | target = "Lnet/minecraft/world/gen/chunk/StrongholdConfig;(III)V" 16 | ), 17 | index = 0 18 | ) 19 | private static int modifyDistance(int distance) 20 | { 21 | // 32 -> 12 22 | // see net.minecraft.world.gen.chunk.ChunkGenerator.generateStrongholdPositions for stronghold generation 23 | // so the first ring of stronghold will be inside 1000 blocks 24 | return 12; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/feature/structure/StructuresConfigAccessor.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.feature.structure; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | import net.minecraft.world.gen.chunk.StructureConfig; 5 | import net.minecraft.world.gen.chunk.StructuresConfig; 6 | import net.minecraft.world.gen.feature.StructureFeature; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Mutable; 9 | import org.spongepowered.asm.mixin.gen.Accessor; 10 | 11 | @Mixin(StructuresConfig.class) 12 | public interface StructuresConfigAccessor 13 | { 14 | @Accessor 15 | static ImmutableMap, StructureConfig> getDEFAULT_STRUCTURES() 16 | { 17 | throw new RuntimeException(); 18 | } 19 | 20 | @Accessor 21 | @Mutable 22 | static void setDEFAULT_STRUCTURES(ImmutableMap, StructureConfig> defaultStructures) 23 | { 24 | throw new RuntimeException(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/task/TaskFindPlayer.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.task; 6 | 7 | import me.fallenbreath.tcuhc.UhcGamePlayer; 8 | import net.minecraft.server.network.ServerPlayerEntity; 9 | 10 | public class TaskFindPlayer extends Task { 11 | 12 | private UhcGamePlayer player; 13 | private ServerPlayerEntity realPlayer; 14 | 15 | public TaskFindPlayer(UhcGamePlayer player) { 16 | this.player = player; 17 | } 18 | 19 | public UhcGamePlayer getGamePlayer() { 20 | return player; 21 | } 22 | 23 | public void onFindPlayer(ServerPlayerEntity player) { } 24 | 25 | @Override 26 | public final void onUpdate() { 27 | player.getRealPlayer().ifPresent(playermp -> { 28 | realPlayer = playermp; 29 | onFindPlayer(realPlayer); 30 | }); 31 | } 32 | 33 | @Override 34 | public final boolean hasFinished() { 35 | return realPlayer != null; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/core/CommandManagerMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.core; 2 | 3 | import com.mojang.brigadier.CommandDispatcher; 4 | import me.fallenbreath.tcuhc.UhcGameCommand; 5 | import net.minecraft.server.command.CommandManager; 6 | import net.minecraft.server.command.ServerCommandSource; 7 | import org.spongepowered.asm.mixin.Final; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.Shadow; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | @Mixin(CommandManager.class) 15 | public abstract class CommandManagerMixin 16 | { 17 | @Shadow @Final private CommandDispatcher dispatcher; 18 | 19 | @Inject(method = "", at = @At("TAIL")) 20 | private void registerUhcCommand(CallbackInfo ci) 21 | { 22 | UhcGameCommand.registerCommand(this.dispatcher); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/item/FoodComponentBuilderMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.item; 2 | 3 | import net.minecraft.entity.effect.StatusEffectInstance; 4 | import net.minecraft.entity.effect.StatusEffects; 5 | import net.minecraft.item.FoodComponent; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 10 | 11 | @Mixin(FoodComponent.Builder.class) 12 | public abstract class FoodComponentBuilderMixin 13 | { 14 | @Inject(method = "statusEffect", at = @At("HEAD")) 15 | private void modifyAbsorptionLevel(StatusEffectInstance effect, float chance, CallbackInfoReturnable cir) 16 | { 17 | if (effect.getEffectType() == StatusEffects.ABSORPTION) 18 | { 19 | int amp = (effect.getAmplifier() + 1) * 4 - 1; 20 | ((StatusEffectInstanceAccessor)effect).setAmplifier(amp); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/entity/VillagerEntityMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.entity; 2 | 3 | import net.minecraft.entity.EntityType; 4 | import net.minecraft.entity.passive.MerchantEntity; 5 | import net.minecraft.entity.passive.VillagerEntity; 6 | import net.minecraft.world.World; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | 12 | @Mixin(VillagerEntity.class) 13 | public abstract class VillagerEntityMixin extends MerchantEntity 14 | { 15 | public VillagerEntityMixin(EntityType entityType, World world) 16 | { 17 | super(entityType, world); 18 | } 19 | 20 | @Inject(method = "prepareOffersFor", at = @At("HEAD"), cancellable = true) 21 | private void dontPrepareIfYouAreAUhcMerchant(CallbackInfo ci) 22 | { 23 | if (this.isInvulnerable()) 24 | { 25 | ci.cancel(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/entity/PersistentProjectileEntityMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.entity; 2 | 3 | import net.minecraft.entity.projectile.PersistentProjectileEntity; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Shadow; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | 10 | @Mixin(PersistentProjectileEntity.class) 11 | public abstract class PersistentProjectileEntityMixin 12 | { 13 | @Shadow public abstract void setCritical(boolean critical); 14 | 15 | /** 16 | * When the projectile hits an entity but fails to damage the entity, cancel its critical state 17 | */ 18 | @Inject( 19 | method = "onEntityHit", 20 | at = @At( 21 | value = "INVOKE", 22 | target = "Lnet/minecraft/entity/Entity;setFireTicks(I)V" 23 | ) 24 | ) 25 | private void cancelCritical(CallbackInfo ci) 26 | { 27 | this.setCritical(false); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/task/Task.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.task; 6 | 7 | public class Task { 8 | 9 | public void onAdd() {} 10 | public void onUpdate() {} 11 | public boolean hasFinished() { return true; } 12 | public void onFinish() {} 13 | 14 | public static class TaskTimer extends Task { 15 | 16 | private int delay, interval; 17 | private boolean canceled; 18 | 19 | public TaskTimer(int delay, int interval) { 20 | this.delay = delay; 21 | this.interval = interval; 22 | } 23 | 24 | public final void setCanceled() { 25 | canceled = true; 26 | } 27 | 28 | @Override 29 | public final void onUpdate() { 30 | if (--delay <= 0) { 31 | onTimer(); 32 | if (interval > 0) { 33 | delay = interval; 34 | } else canceled = true; 35 | } 36 | } 37 | 38 | public void onTimer() {} 39 | 40 | @Override 41 | public final boolean hasFinished() { 42 | return canceled; 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/entity/EntityDamageSourceMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.entity; 2 | 3 | import net.minecraft.entity.Entity; 4 | import net.minecraft.entity.damage.EntityDamageSource; 5 | import net.minecraft.entity.decoration.EndCrystalEntity; 6 | import org.spongepowered.asm.mixin.Final; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 12 | 13 | @Mixin(EntityDamageSource.class) 14 | public abstract class EntityDamageSourceMixin 15 | { 16 | @Shadow @Final protected Entity source; 17 | 18 | @Inject(method = "isScaledWithDifficulty", at = @At("HEAD"), cancellable = true) 19 | private void endCrystalIsAlsoAbleToHaveDamageScaled(CallbackInfoReturnable cir) 20 | { 21 | if (this.source instanceof EndCrystalEntity) 22 | { 23 | cir.setReturnValue(true); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/entity/BoatEntityMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.entity; 2 | 3 | import net.minecraft.entity.Entity; 4 | import net.minecraft.entity.passive.VillagerEntity; 5 | import net.minecraft.entity.vehicle.BoatEntity; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Redirect; 9 | import org.spongepowered.asm.mixin.injection.Slice; 10 | 11 | @Mixin(BoatEntity.class) 12 | public abstract class BoatEntityMixin 13 | { 14 | @Redirect( 15 | method = "tick", 16 | slice = @Slice( 17 | from = @At( 18 | value = "INVOKE", 19 | target = "Lnet/minecraft/entity/vehicle/BoatEntity;checkBlockCollision()V" 20 | ) 21 | ), 22 | at = @At( 23 | value = "INVOKE", 24 | target = "Lnet/minecraft/entity/Entity;hasVehicle()Z", 25 | ordinal = 0 26 | ) 27 | ) 28 | private boolean hasVehicleAndNotUhcVillager(Entity entity) 29 | { 30 | return entity.hasVehicle() && !(entity instanceof VillagerEntity); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/entity/WitchEntityMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.entity; 2 | 3 | import net.minecraft.entity.EntityType; 4 | import net.minecraft.entity.EquipmentSlot; 5 | import net.minecraft.entity.mob.WitchEntity; 6 | import net.minecraft.entity.raid.RaiderEntity; 7 | import net.minecraft.world.World; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 12 | 13 | @Mixin(WitchEntity.class) 14 | public abstract class WitchEntityMixin extends RaiderEntity 15 | { 16 | protected WitchEntityMixin(EntityType type, World world) 17 | { 18 | super(type, world); 19 | } 20 | 21 | /** 22 | * TC Plugin: change witch potion drop chance to 100% 23 | */ 24 | @Inject(method = "", at = @At("TAIL")) 25 | private void constructUhcGameManager(CallbackInfo ci) 26 | { 27 | this.handDropChances[EquipmentSlot.MAINHAND.getEntitySlotId()] = 2.0F; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/item/ChorusFruitMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.item; 2 | 3 | import net.minecraft.entity.LivingEntity; 4 | import net.minecraft.item.ChorusFruitItem; 5 | import net.minecraft.util.math.Box; 6 | import net.minecraft.util.math.Vec3d; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Redirect; 10 | 11 | @Mixin(ChorusFruitItem.class) 12 | public abstract class ChorusFruitMixin 13 | { 14 | @Redirect( 15 | method = "finishUsing", 16 | at = @At( 17 | value = "INVOKE", 18 | target = "Lnet/minecraft/entity/LivingEntity;teleport(DDDZ)Z" 19 | ) 20 | ) 21 | private boolean onlyTeleportIntoWorldBorder(LivingEntity livingEntity, double x, double y, double z, boolean particleEffects) 22 | { 23 | Vec3d vec3d = new Vec3d(x, y, z); 24 | if (livingEntity.getEntityWorld().getWorldBorder().contains(new Box(vec3d, vec3d))) 25 | { 26 | return livingEntity.teleport(x, y, z, particleEffects); 27 | } 28 | return false; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/TcUhcMod.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc; 2 | 3 | import net.fabricmc.api.ModInitializer; 4 | import net.fabricmc.loader.api.FabricLoader; 5 | import net.minecraft.MinecraftVersion; 6 | import net.minecraft.util.Identifier; 7 | 8 | public class TcUhcMod implements ModInitializer 9 | { 10 | private static final String MOD_ID = "tcuhc"; 11 | private static String version; 12 | private static final String MINECRAFT_VERSION = MinecraftVersion.CURRENT.getName(); 13 | 14 | @Override 15 | public void onInitialize() 16 | { 17 | version = FabricLoader.getInstance().getModContainer(MOD_ID).orElseThrow(RuntimeException::new).getMetadata().getVersion().getFriendlyString(); 18 | } 19 | 20 | public static String getModId() 21 | { 22 | return MOD_ID; 23 | } 24 | 25 | public static String getModVersion() 26 | { 27 | return version; 28 | } 29 | 30 | public static String getMinecraftVersion() 31 | { 32 | return MINECRAFT_VERSION; 33 | } 34 | 35 | public static Identifier id(String name) 36 | { 37 | return new Identifier(MOD_ID, name); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/entity/LivingEntityMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.entity; 2 | 3 | import net.minecraft.entity.LivingEntity; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Shadow; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 9 | 10 | @Mixin(LivingEntity.class) 11 | public abstract class LivingEntityMixin 12 | { 13 | @Shadow public abstract void setAbsorptionAmount(float amount); 14 | 15 | /** 16 | * Clean the absorption amount manually here due to {@link StatusEffectInstanceMixin#alwaysOverwriteForAbsorptionEffect} 17 | * To prevent eating egapple then eating gapple then /effect clear resulting in remaining absorption amount 18 | */ 19 | @SuppressWarnings("JavadocReference") 20 | @Inject(method = "clearStatusEffects", at = @At("TAIL")) 21 | private void removeAbsorptionYellowHearts(CallbackInfoReturnable cir) 22 | { 23 | this.setAbsorptionAmount(0.0F); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/task/TaskSpawnPlatformProtect.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.task; 6 | 7 | import me.fallenbreath.tcuhc.UhcGameManager; 8 | import me.fallenbreath.tcuhc.util.SpawnPlatform; 9 | import net.minecraft.server.network.ServerPlayerEntity; 10 | 11 | public class TaskSpawnPlatformProtect extends Task { 12 | 13 | private UhcGameManager gameManager; 14 | 15 | public TaskSpawnPlatformProtect(UhcGameManager manager) { 16 | gameManager = manager; 17 | } 18 | 19 | @Override 20 | public void onUpdate() { 21 | for (ServerPlayerEntity player : gameManager.getServerPlayerManager().getPlayerList()) { 22 | if (player.isAlive() && !player.isCreative() && !player.isSpectator()) { 23 | if (player.getPos().getY() < SpawnPlatform.height - 20 && Math.abs(player.getPos().getX()) < 64 && Math.abs(player.getPos().getZ()) < 64) { 24 | gameManager.getUhcPlayerManager().randomSpawnPosition(player); 25 | } 26 | } 27 | } 28 | } 29 | 30 | @Override 31 | public boolean hasFinished() { 32 | return gameManager.isGamePlaying(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/entity/AbstractMinecartEntityMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.entity; 2 | 3 | import net.minecraft.entity.Entity; 4 | import net.minecraft.entity.passive.VillagerEntity; 5 | import net.minecraft.entity.vehicle.AbstractMinecartEntity; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Redirect; 9 | import org.spongepowered.asm.mixin.injection.Slice; 10 | 11 | @Mixin(AbstractMinecartEntity.class) 12 | public abstract class AbstractMinecartEntityMixin 13 | { 14 | @Redirect( 15 | method = "tick", 16 | slice = @Slice( 17 | from = @At( 18 | value = "FIELD", 19 | target = "Lnet/minecraft/entity/vehicle/AbstractMinecartEntity$Type;RIDEABLE:Lnet/minecraft/entity/vehicle/AbstractMinecartEntity$Type;" 20 | ) 21 | ), 22 | at = @At( 23 | value = "INVOKE", 24 | target = "Lnet/minecraft/entity/Entity;hasVehicle()Z", 25 | ordinal = 0 26 | ) 27 | ) 28 | private boolean hasVehicleAndNotUhcVillager(Entity entity) 29 | { 30 | return entity.hasVehicle() && !(entity instanceof VillagerEntity); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/util/TitleUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.util; 6 | 7 | import me.fallenbreath.tcuhc.UhcGameManager; 8 | import net.minecraft.network.packet.s2c.play.SubtitleS2CPacket; 9 | import net.minecraft.network.packet.s2c.play.TitleS2CPacket; 10 | import net.minecraft.server.network.ServerPlayerEntity; 11 | import net.minecraft.text.LiteralText; 12 | 13 | public class TitleUtil 14 | { 15 | public static void sendTitleToPlayer(String title, String subtitle, ServerPlayerEntity player) 16 | { 17 | TitleS2CPacket titlePacket = new TitleS2CPacket(new LiteralText(title)); 18 | player.networkHandler.sendPacket(titlePacket); 19 | if (subtitle != null) 20 | { 21 | SubtitleS2CPacket subtitlePacket = new SubtitleS2CPacket(new LiteralText(subtitle)); 22 | player.networkHandler.sendPacket(subtitlePacket); 23 | } 24 | } 25 | 26 | public static void sendTitleToAllPlayers(String title, String subtitle) 27 | { 28 | for (ServerPlayerEntity player : UhcGameManager.instance.getServerPlayerManager().getPlayerList()) 29 | { 30 | sendTitleToPlayer(title, subtitle, player); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/worldgen/world/NoiseColumnSamplerMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.worldgen.world; 2 | 3 | import net.minecraft.world.gen.NoiseColumnSampler; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Inject; 7 | import org.spongepowered.asm.mixin.injection.Slice; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 9 | 10 | @Mixin(NoiseColumnSampler.class) 11 | public abstract class NoiseColumnSamplerMixin 12 | { 13 | /** 14 | * Does not eliminate 100% ocean like terrains, but the percentage of ocean is much smaller 15 | */ 16 | @Inject( 17 | method = "sampleContinentalnessNoise", 18 | slice = @Slice( 19 | from = @At( 20 | value = "INVOKE", 21 | target = "Lnet/minecraft/util/math/noise/DoublePerlinNoiseSampler;sample(DDD)D" 22 | ) 23 | ), 24 | at = @At(value = "RETURN", ordinal = 0), 25 | cancellable = true 26 | ) 27 | private void iHateOceansSoPleaseMakeTheReturnValueLarger(CallbackInfoReturnable cir) 28 | { 29 | double x = cir.getReturnValue(); 30 | cir.setReturnValue(0.6 * x + 0.4); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/entity/PlayerInventoryMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.entity; 2 | 3 | import me.fallenbreath.tcuhc.interfaces.IPlayerInventory; 4 | import net.minecraft.entity.player.PlayerEntity; 5 | import net.minecraft.entity.player.PlayerInventory; 6 | import net.minecraft.item.ItemStack; 7 | import net.minecraft.util.collection.DefaultedList; 8 | import org.spongepowered.asm.mixin.Final; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.Shadow; 11 | 12 | import java.util.List; 13 | 14 | @Mixin(PlayerInventory.class) 15 | public abstract class PlayerInventoryMixin implements IPlayerInventory 16 | { 17 | @Shadow @Final private List> combinedInventory; 18 | 19 | @Shadow @Final public PlayerEntity player; 20 | 21 | /** 22 | * Like {@link PlayerInventory#dropAll()}, but doesn't remove the actual item 23 | */ 24 | @Override 25 | public void dropAllItemsWithoutClear() 26 | { 27 | for (List list : this.combinedInventory) 28 | { 29 | for (ItemStack itemstack : list) 30 | { 31 | if (!itemstack.isEmpty()) 32 | { 33 | this.player.dropItem(itemstack.copy(), true, false); 34 | } 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/entity/DrownedEntityMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.entity; 2 | 3 | import net.minecraft.entity.EntityData; 4 | import net.minecraft.entity.EntityType; 5 | import net.minecraft.entity.EquipmentSlot; 6 | import net.minecraft.entity.mob.DrownedEntity; 7 | import net.minecraft.entity.mob.ZombieEntity; 8 | import net.minecraft.item.Items; 9 | import net.minecraft.world.World; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 14 | 15 | @Mixin(DrownedEntity.class) 16 | public abstract class DrownedEntityMixin extends ZombieEntity 17 | { 18 | public DrownedEntityMixin(EntityType entityType, World world) 19 | { 20 | super(entityType, world); 21 | } 22 | 23 | @Inject(method = "initialize", at = @At("TAIL")) 24 | private void drownedAlwaysDropsTridentIfHolding(CallbackInfoReturnable cir) 25 | { 26 | if (this.getEquippedStack(EquipmentSlot.MAINHAND).getItem() == Items.TRIDENT) 27 | { 28 | this.handDropChances[EquipmentSlot.MAINHAND.getEntitySlotId()] = 2.0F; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/item/FlowerBlockMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.item; 2 | 3 | import net.minecraft.block.FlowerBlock; 4 | import net.minecraft.entity.effect.StatusEffect; 5 | import net.minecraft.entity.effect.StatusEffects; 6 | import org.spongepowered.asm.mixin.Final; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Mutable; 9 | import org.spongepowered.asm.mixin.Shadow; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | @Mixin(FlowerBlock.class) 15 | public abstract class FlowerBlockMixin 16 | { 17 | @Shadow @Final private StatusEffect effectInStew; 18 | 19 | @Mutable 20 | @Shadow @Final private int effectInStewDuration; 21 | 22 | /** 23 | * The regeneration of vanilla oxeye daisy is too op, regen 3 hp 24 | * We reduce the amount of hp to 1 by reducing the effect duration 25 | */ 26 | @Inject(method = "", at = @At("TAIL")) 27 | private void modifyOxeyeDaisyRegenerationDuration(CallbackInfo ci) 28 | { 29 | if (this.effectInStew == StatusEffects.REGENERATION) 30 | { 31 | this.effectInStewDuration /= 3; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/worldgen/world/CaveCarverMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.worldgen.world; 2 | 3 | import net.minecraft.world.gen.carver.CaveCarver; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Shadow; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Redirect; 8 | 9 | import java.util.Random; 10 | 11 | @Mixin(CaveCarver.class) 12 | public abstract class CaveCarverMixin 13 | { 14 | @Shadow protected abstract int getMaxCaveCount(); 15 | 16 | @Redirect( 17 | method = "carve(Lnet/minecraft/world/gen/carver/CarverContext;Lnet/minecraft/world/gen/carver/CaveCarverConfig;Lnet/minecraft/world/chunk/Chunk;Ljava/util/function/Function;Ljava/util/Random;Lnet/minecraft/world/gen/chunk/AquiferSampler;Lnet/minecraft/util/math/ChunkPos;Lnet/minecraft/world/gen/carver/CarvingMask;)Z", 18 | at = @At( 19 | value = "INVOKE", 20 | target = "Ljava/util/Random;nextInt(I)I", 21 | ordinal = 2 22 | ) 23 | ) 24 | private int customRandomizer(Random random, int bound) 25 | { 26 | // vanilla: random.nextInt(bound) 27 | if (random.nextFloat() < 0.6F) 28 | { 29 | return random.nextInt(this.getMaxCaveCount()); 30 | } 31 | return bound; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Gradle 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle 3 | 4 | name: Java CI with Gradle 5 | 6 | on: 7 | push: 8 | paths: 9 | - "*.gradle" 10 | - "gradle.properties" 11 | - "src/**" 12 | - ".github/workflows/**" 13 | pull_request: 14 | 15 | 16 | jobs: 17 | build: 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v2 22 | - name: Set up JDK 17 23 | uses: actions/setup-java@v2 24 | with: 25 | distribution: 'temurin' 26 | java-version: 17 27 | 28 | - name: Cache gradle files 29 | uses: actions/cache@v2 30 | with: 31 | path: | 32 | ~/.gradle/caches 33 | ~/.gradle/wrapper 34 | ./.gradle/loom-cache 35 | key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle', 'gradle.properties', '**/*.accesswidener') }} 36 | restore-keys: | 37 | ${{ runner.os }}-gradle- 38 | 39 | - name: Grant execute permission for gradlew 40 | run: chmod +x gradlew 41 | - name: Build with Gradle 42 | run: ./gradlew build 43 | - uses: actions/upload-artifact@v2 44 | with: 45 | name: build-artifacts 46 | path: build/libs/ 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TC UHC in fabric 2 | ------------ 3 | 4 | <3 gp: https://github.com/Gamepiaynmo/TC-UHC 5 | 6 | Changes: 7 | 8 | - Modified emerald trade: 1 -> \[3, 6\] 9 | - Reduced the effect duration of oxeye daisy suspicious stew to +1 hp 10 | - Librarian villager has only maximum trade amount 1 for each enchant book trades 11 | - (1.16+) Added netherite scrap trade: 1 -> \[20, 32\] 12 | - Make the stronghold closer to (0, 0) 13 | - Nether fortress or bastion remnant will be chosen randomly, the chosen one will and only will be generated at nether (0, 0) 14 | - The not-chosen one will generate vanillaly 15 | - Bastion remnant is allowed to be generated in basalt deltas biome 16 | - Lighting sound will be played when a player dies 17 | - You can right click a wither skeleton skull block with a moral item to respawn the player 18 | - End crystal deals more damage with less distance to player 19 | - Its damage now scales with difficulty 20 | 21 | New structures 22 | 23 | - Ender Pyramid 24 | - Similar to Ender Altar, but with more challenging layout and more bonus 25 | - Greenhouse 26 | - Generated in biomes which don't rain 27 | - There some plants e.g. flowers and mushroom inside 28 | - Villain House 29 | - Generated in forests 30 | - Spawns 1~2 villains. A villain can be a witch, a vindicator or a pillager 31 | 32 | In dev branch 33 | - 1.18.x 34 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/recipe/SynchronizeRecipesS2CPacketMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.recipe; 2 | 3 | import com.google.common.collect.Lists; 4 | import me.fallenbreath.tcuhc.util.UhcRegistry; 5 | import net.minecraft.network.packet.s2c.play.SynchronizeRecipesS2CPacket; 6 | import net.minecraft.recipe.Recipe; 7 | import org.spongepowered.asm.mixin.Final; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.Mutable; 10 | import org.spongepowered.asm.mixin.Shadow; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 14 | 15 | import java.util.List; 16 | 17 | @Mixin(SynchronizeRecipesS2CPacket.class) 18 | public abstract class SynchronizeRecipesS2CPacketMixin 19 | { 20 | @Mutable 21 | @Final 22 | @Shadow private List> recipes; 23 | 24 | @Inject(method = "(Ljava/util/Collection;)V", at = @At("TAIL")) 25 | private void dontWriteUhcRecipes(CallbackInfo ci) 26 | { 27 | List> filteredRecipes = Lists.newArrayList(); 28 | for (Recipe recipe : this.recipes) 29 | { 30 | if (!UhcRegistry.getRecipeSerializers().contains(recipe.getSerializer())) 31 | { 32 | filteredRecipes.add(recipe); 33 | } 34 | } 35 | this.recipes = filteredRecipes; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/worldgen/feature/DefaultBiomeFeaturesMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.worldgen.feature; 2 | 3 | import me.fallenbreath.tcuhc.gen.feature.UhcFeatures; 4 | import net.minecraft.world.biome.GenerationSettings; 5 | import net.minecraft.world.gen.GenerationStep; 6 | import net.minecraft.world.gen.feature.DefaultBiomeFeatures; 7 | import net.minecraft.world.gen.feature.PlacedFeature; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 12 | 13 | @Mixin(DefaultBiomeFeatures.class) 14 | public abstract class DefaultBiomeFeaturesMixin 15 | { 16 | private static void addSurfaceFeature(GenerationSettings.Builder builder, PlacedFeature feature) 17 | { 18 | builder.feature(GenerationStep.Feature.SURFACE_STRUCTURES, feature); 19 | } 20 | 21 | @Inject(method = "addDefaultOres(Lnet/minecraft/world/biome/GenerationSettings$Builder;Z)V", at = @At("TAIL")) 22 | private static void addUhcFeatures(GenerationSettings.Builder builder, boolean largeCopperOreBlob, CallbackInfo ci) 23 | { 24 | addSurfaceFeature(builder, UhcFeatures.MERCHANTS); 25 | addSurfaceFeature(builder, UhcFeatures.BONUS_CHEST); 26 | addSurfaceFeature(builder, UhcFeatures.ENDER_ALTAR); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/task/TaskHUDInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.task; 6 | 7 | import me.fallenbreath.tcuhc.UhcGameManager; 8 | import net.minecraft.network.packet.s2c.play.PlayerListHeaderS2CPacket; 9 | import net.minecraft.server.MinecraftServer; 10 | import net.minecraft.server.network.ServerPlayerEntity; 11 | import net.minecraft.text.BaseText; 12 | import net.minecraft.text.LiteralText; 13 | 14 | public class TaskHUDInfo extends Task.TaskTimer 15 | { 16 | private final MinecraftServer mcServer; 17 | 18 | public TaskHUDInfo(MinecraftServer mcServer) 19 | { 20 | super(0, 5); 21 | this.mcServer = mcServer; 22 | } 23 | 24 | private BaseText getHUDTexts(ServerPlayerEntity player) 25 | { 26 | BaseText text = new LiteralText(""); 27 | double mspt = UhcGameManager.instance.msptRecorder.getMspt(); 28 | double tps = 1000.0D / Math.max(mspt, 50.0D); 29 | text.append(new LiteralText(String.format("TPS: %.1f MSPT: %.1f Ping: %dms", tps, mspt, player.pingMilliseconds))); 30 | return text; 31 | } 32 | 33 | @Override 34 | public void onTimer() 35 | { 36 | this.mcServer.getPlayerManager().getPlayerList().forEach(player -> { 37 | PlayerListHeaderS2CPacket packet = new PlayerListHeaderS2CPacket(new LiteralText(""), this.getHUDTexts(player)); 38 | player.networkHandler.sendPacket(packet); 39 | }); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/item/PlayerEntityMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.item; 2 | 3 | import me.fallenbreath.tcuhc.UhcGameManager; 4 | import me.fallenbreath.tcuhc.UhcGamePlayer; 5 | import net.minecraft.entity.player.PlayerEntity; 6 | import net.minecraft.item.ItemStack; 7 | import net.minecraft.item.Items; 8 | import net.minecraft.server.network.ServerPlayerEntity; 9 | import net.minecraft.world.World; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 14 | 15 | @Mixin(PlayerEntity.class) 16 | public abstract class PlayerEntityMixin 17 | { 18 | @Inject(method = "eatFood", at = @At("HEAD")) 19 | private void checkAndAddUhcGAppleStat(World world, ItemStack stack, CallbackInfoReturnable cir) 20 | { 21 | PlayerEntity self = (PlayerEntity)(Object)this; 22 | if (self instanceof ServerPlayerEntity && stack.getItem() == Items.GOLDEN_APPLE) 23 | { 24 | float value; 25 | if (stack.getNbt() != null) 26 | { 27 | int goldenAppleLevel = stack.getNbt().getInt("level"); 28 | value = goldenAppleLevel / 4.0F; 29 | } 30 | else 31 | { 32 | value = 1.0F; 33 | } 34 | UhcGameManager.instance.getUhcPlayerManager().getGamePlayer(self).getStat().addStat(UhcGamePlayer.EnumStat.GOLDEN_APPLE_EATEN, value); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/resources/data/tcuhc/lootpools/apple.json: -------------------------------------------------------------------------------- 1 | { 2 | "rolls": 1.0, 3 | "bonus_rolls": 0.0, 4 | "entries": [ 5 | { 6 | "type": "minecraft:item", 7 | "conditions": [ 8 | { 9 | "condition": "minecraft:survives_explosion" 10 | }, 11 | { 12 | "condition": "minecraft:table_bonus", 13 | "enchantment": "minecraft:fortune", 14 | "chances": [ 15 | 0.0125, 16 | 0.016666667, 17 | 0.025, 18 | 0.025, 19 | 0.025 20 | ] 21 | } 22 | ], 23 | "name": "minecraft:apple" 24 | } 25 | ], 26 | "conditions": [ 27 | { 28 | "condition": "minecraft:inverted", 29 | "term": { 30 | "condition": "minecraft:alternative", 31 | "terms": [ 32 | { 33 | "condition": "minecraft:match_tool", 34 | "predicate": { 35 | "items": [ 36 | "minecraft:shears" 37 | ] 38 | } 39 | }, 40 | { 41 | "condition": "minecraft:match_tool", 42 | "predicate": { 43 | "enchantments": [ 44 | { 45 | "enchantment": "minecraft:silk_touch", 46 | "levels": { 47 | "min": 1 48 | } 49 | } 50 | ] 51 | } 52 | } 53 | ] 54 | } 55 | } 56 | ] 57 | } -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/task/TaskKeepSpectate.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.task; 6 | 7 | import me.fallenbreath.tcuhc.UhcGameManager; 8 | import me.fallenbreath.tcuhc.UhcGamePlayer; 9 | import me.fallenbreath.tcuhc.task.Task.TaskTimer; 10 | import net.minecraft.entity.Entity; 11 | import net.minecraft.network.packet.c2s.play.SpectatorTeleportC2SPacket; 12 | 13 | public class TaskKeepSpectate extends TaskTimer { 14 | 15 | private UhcGamePlayer gamePlayer; 16 | 17 | public TaskKeepSpectate(UhcGamePlayer gamePlayer) { 18 | super(0, 10); 19 | this.gamePlayer = gamePlayer; 20 | } 21 | 22 | @Override 23 | public void onTimer() { 24 | if (!UhcGameManager.instance.isGamePlaying() || gamePlayer.getTeam().getAliveCount() == 0 || gamePlayer.isAlive()) 25 | { 26 | this.setCanceled(); 27 | return; 28 | } 29 | gamePlayer.getRealPlayer().ifPresent(player -> { 30 | if (player.isSpectator()) 31 | { 32 | Entity target = player.getCameraEntity(); 33 | if (target != null) 34 | { 35 | player.setCameraEntity(target); 36 | if (player.world != target.world) 37 | { 38 | player.networkHandler.onSpectatorTeleport(new SpectatorTeleportC2SPacket(target.getUuid())); 39 | } 40 | } 41 | } 42 | }); 43 | } 44 | 45 | @Override 46 | public void onFinish() { 47 | gamePlayer.getRealPlayer().ifPresent(player -> player.setCameraEntity(player)); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/worldgen/feature/StructureFeatureMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.worldgen.feature; 2 | 3 | import me.fallenbreath.tcuhc.UhcGameManager; 4 | import me.fallenbreath.tcuhc.util.UhcWorldData; 5 | import net.minecraft.util.math.ChunkPos; 6 | import net.minecraft.world.gen.feature.BastionRemnantFeature; 7 | import net.minecraft.world.gen.feature.NetherFortressFeature; 8 | import net.minecraft.world.gen.feature.StructureFeature; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 13 | 14 | @Mixin(StructureFeature.class) 15 | public abstract class StructureFeatureMixin 16 | { 17 | @Inject(method = "getStartChunk", at = @At("HEAD"), cancellable = true) 18 | private void fortressStartChunkIsAlways00(CallbackInfoReturnable cir) 19 | { 20 | StructureFeature self = (StructureFeature)(Object)this; 21 | UhcWorldData.StructureType type = UhcGameManager.instance.getWorldData().netherFortressType; 22 | ChunkPos zero = new ChunkPos(0, 0); 23 | 24 | if (self instanceof NetherFortressFeature && type == UhcWorldData.StructureType.NETHER_FORTRESS) 25 | { 26 | cir.setReturnValue(zero); 27 | } 28 | if (self instanceof BastionRemnantFeature && type == UhcWorldData.StructureType.BASTION_REMNANT) 29 | { 30 | cir.setReturnValue(zero); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/util/LootTableUtil.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.util; 2 | 3 | import com.google.gson.Gson; 4 | import me.fallenbreath.tcuhc.mixins.loot.LootManagerAccessor; 5 | import net.minecraft.loot.LootPool; 6 | import net.minecraft.loot.entry.LootPoolEntry; 7 | import net.minecraft.util.JsonHelper; 8 | 9 | import java.io.BufferedReader; 10 | import java.io.InputStream; 11 | import java.io.InputStreamReader; 12 | import java.io.Reader; 13 | import java.nio.charset.StandardCharsets; 14 | 15 | public class LootTableUtil 16 | { 17 | public static T getUhcLootData(String type, String dir, Class class_) 18 | { 19 | Gson gson = LootManagerAccessor.getGSON(); 20 | String filePath = String.format("data/tcuhc/%s/%s.json", type, dir); 21 | InputStream inputStream = LootTableUtil.class.getClassLoader().getResourceAsStream(filePath); 22 | if (inputStream != null && gson != null) 23 | { 24 | Reader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); 25 | return JsonHelper.deserialize(gson, reader, class_); 26 | } 27 | else 28 | { 29 | throw new RuntimeException("Unable to load loot data from " + filePath); 30 | } 31 | } 32 | 33 | public static LootPool getUhcLootPool(String name) 34 | { 35 | return getUhcLootData("lootpools", name, LootPool.class); 36 | } 37 | 38 | public static LootPoolEntry getUhcLootEntry(String name) 39 | { 40 | return getUhcLootData("lootentries", name, LootPoolEntry.class); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/task/TaskKingEffectField.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.task; 6 | 7 | import me.fallenbreath.tcuhc.UhcGameManager; 8 | import me.fallenbreath.tcuhc.UhcGamePlayer; 9 | import net.minecraft.entity.effect.StatusEffectInstance; 10 | import net.minecraft.entity.effect.StatusEffects; 11 | 12 | public class TaskKingEffectField extends Task.TaskTimer 13 | { 14 | public TaskKingEffectField() 15 | { 16 | super(0, 10); 17 | } 18 | 19 | // give 2 seconds speed I to any player near its king 20 | @Override 21 | public void onTimer() 22 | { 23 | if (UhcGameManager.instance.isGamePlaying() && UhcGameManager.getGameMode() == UhcGameManager.EnumMode.KING) { 24 | UhcGameManager.instance.getUhcPlayerManager().getCombatPlayers().forEach(gamePlayer -> { 25 | // only non-king players are able to have the boost 26 | if (!gamePlayer.isKing() && gamePlayer.isAlive() && gamePlayer.getRealPlayer().isPresent()) { 27 | UhcGamePlayer king = gamePlayer.getTeam().getKing(); 28 | if (king.isAlive() && king.getRealPlayer().isPresent()) { 29 | double distanceToKing = gamePlayer.getRealPlayer().get().distanceTo(king.getRealPlayer().get()); 30 | if (distanceToKing <= 5) { 31 | gamePlayer.getRealPlayer().get().addStatusEffect(new StatusEffectInstance(StatusEffects.SPEED, 40, 0)); 32 | } 33 | } 34 | } 35 | }); 36 | } 37 | else { 38 | this.setCanceled(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/resources/data/tcuhc/loot_tables/greenhouse/chest_desert.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "rolls": {"type": "minecraft:uniform", "min": 4, "max": 8}, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "name": "minecraft:potion", 10 | "weight": 1, 11 | "functions": [{"function": "minecraft:set_nbt", "tag": "{\"Potion\":\"minecraft:water\"}"}] 12 | }, 13 | { 14 | "type": "minecraft:item", 15 | "name": "minecraft:stick", 16 | "weight": 1, 17 | "functions": [{"function": "minecraft:set_count", "count": {"type": "minecraft:uniform", "min": 1, "max": 2}}] 18 | }, 19 | { 20 | "type": "minecraft:item", 21 | "name": "minecraft:wheat_seeds", 22 | "weight": 1, 23 | "functions": [{"function": "minecraft:set_count", "count": {"type": "minecraft:uniform", "min": 1, "max": 2}}] 24 | }, 25 | { 26 | "type": "minecraft:item", 27 | "name": "minecraft:grass", 28 | "weight": 2, 29 | "functions": [{"function": "minecraft:set_count", "count": {"type": "minecraft:uniform", "min": 1, "max": 2}}] 30 | }, 31 | { 32 | "type": "minecraft:item", 33 | "name": "minecraft:dead_bush", 34 | "weight": 3, 35 | "functions": [{"function": "minecraft:set_count", "count": {"type": "minecraft:uniform", "min": 1, "max": 2}}] 36 | } 37 | ] 38 | } 39 | ] 40 | } -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/UhcConfigManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc; 6 | 7 | import me.fallenbreath.tcuhc.options.Option; 8 | import net.minecraft.server.network.ServerPlayerEntity; 9 | import net.minecraft.text.LiteralText; 10 | 11 | public class UhcConfigManager 12 | { 13 | private UhcGamePlayer operator; 14 | private boolean isConfiguring; 15 | private boolean isInputting; 16 | private Option curOption; 17 | 18 | public void startConfiguring(UhcGamePlayer op) { 19 | operator = op; 20 | isConfiguring = true; 21 | } 22 | 23 | public void stopConfiguring() { 24 | isConfiguring = false; 25 | } 26 | 27 | public boolean isConfiguring() { 28 | return isConfiguring; 29 | } 30 | 31 | public boolean isOperator(ServerPlayerEntity player) { 32 | return operator.isSamePlayer(player); 33 | } 34 | 35 | public UhcGamePlayer getOperator() { 36 | return operator; 37 | } 38 | 39 | public void inputOptionValue(Option option) { 40 | isInputting = true; 41 | curOption = option; 42 | } 43 | 44 | public boolean onPlayerChat(ServerPlayerEntity player, String msg) { 45 | if (isConfiguring && operator.isSamePlayer(player) && isInputting) { 46 | curOption.setStringValue(msg); 47 | UhcGameManager.instance.getUhcPlayerManager().refreshConfigBook(); 48 | player.sendMessage(new LiteralText("Set " + curOption.getName() + " to " + curOption.getStringValue()), false); 49 | isInputting = false; 50 | return false; 51 | } 52 | return true; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/util/AverageIntProvider.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.util; 2 | 3 | import com.mojang.serialization.Codec; 4 | import com.mojang.serialization.codecs.RecordCodecBuilder; 5 | import net.minecraft.util.math.intprovider.IntProvider; 6 | import net.minecraft.util.math.intprovider.IntProviderType; 7 | 8 | import java.util.Random; 9 | 10 | public class AverageIntProvider extends IntProvider 11 | { 12 | // plz dont crash 13 | private static final Codec CODEC = RecordCodecBuilder.create( 14 | instance -> instance. 15 | group(Codec.FLOAT.fieldOf("value").forGetter(AverageIntProvider::getValue)). 16 | apply(instance, AverageIntProvider::new) 17 | ); 18 | private static final IntProviderType TYPE = UhcRegistry.registerIntProviderType("average", CODEC); 19 | 20 | private final float value; 21 | private final int base; 22 | private final float decimal; 23 | 24 | public AverageIntProvider(float value) 25 | { 26 | this.value = value; 27 | this.base = (int)value; 28 | this.decimal = value - this.base; 29 | } 30 | 31 | public float getValue() 32 | { 33 | return value; 34 | } 35 | 36 | @Override 37 | public int get(Random random) 38 | { 39 | return this.base + (random.nextFloat() < this.decimal ? 1 : 0); 40 | } 41 | 42 | @Override 43 | public int getMin() 44 | { 45 | return this.base; 46 | } 47 | 48 | @Override 49 | public int getMax() 50 | { 51 | return this.base + 1; 52 | } 53 | 54 | @Override 55 | public IntProviderType getType() 56 | { 57 | return TYPE; 58 | } 59 | } -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/worldgen/feature/BastionRemnantFeatureMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.worldgen.feature; 2 | 3 | import me.fallenbreath.tcuhc.UhcGameManager; 4 | import me.fallenbreath.tcuhc.util.UhcWorldData; 5 | import net.minecraft.structure.StructureGeneratorFactory; 6 | import net.minecraft.util.math.ChunkPos; 7 | import net.minecraft.world.gen.feature.BastionRemnantFeature; 8 | import net.minecraft.world.gen.feature.DefaultFeatureConfig; 9 | import net.minecraft.world.gen.random.ChunkRandom; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Redirect; 13 | 14 | @Mixin(BastionRemnantFeature.class) 15 | public abstract class BastionRemnantFeatureMixin 16 | { 17 | @Redirect( 18 | method = "canGenerate", 19 | at = @At( 20 | value = "INVOKE", 21 | target = "Lnet/minecraft/world/gen/random/ChunkRandom;nextInt(I)I" 22 | ) 23 | ) 24 | private static int fortressGenerateIffXZAre0(ChunkRandom chunkRandom, int bound, /* parent method parameters -> */ StructureGeneratorFactory.Context context) 25 | { 26 | if (UhcGameManager.instance.getWorldData().netherFortressType == UhcWorldData.StructureType.BASTION_REMNANT) 27 | { 28 | // vanilla: chunkRandom.nextInt(5) >= 2 ? true : false 29 | 30 | if (context.chunkPos().equals(new ChunkPos(0, 0))) 31 | { 32 | return 3; // nope 33 | } 34 | else 35 | { 36 | return 0; // ok 37 | } 38 | } 39 | 40 | return chunkRandom.nextInt(bound); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/worldgen/feature/NetherFortressFeatureMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.worldgen.feature; 2 | 3 | import me.fallenbreath.tcuhc.UhcGameManager; 4 | import me.fallenbreath.tcuhc.util.UhcWorldData; 5 | import net.minecraft.structure.StructureGeneratorFactory; 6 | import net.minecraft.util.math.ChunkPos; 7 | import net.minecraft.world.gen.feature.DefaultFeatureConfig; 8 | import net.minecraft.world.gen.feature.NetherFortressFeature; 9 | import net.minecraft.world.gen.random.ChunkRandom; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Redirect; 13 | 14 | @Mixin(NetherFortressFeature.class) 15 | public abstract class NetherFortressFeatureMixin 16 | { 17 | @Redirect( 18 | method = "canGenerate", 19 | at = @At( 20 | value = "INVOKE", 21 | target = "Lnet/minecraft/world/gen/random/ChunkRandom;nextInt(I)I" 22 | ) 23 | ) 24 | private static int fortressGenerateIffXZAre0(ChunkRandom chunkRandom, int bound, /* parent method parameters -> */ StructureGeneratorFactory.Context context) 25 | { 26 | if (UhcGameManager.instance.getWorldData().netherFortressType == UhcWorldData.StructureType.NETHER_FORTRESS) 27 | { 28 | // vanilla: chunkRandom.nextInt(5) >= 2 ? false: furtherTest() 29 | 30 | if (context.chunkPos().equals(new ChunkPos(0, 0))) 31 | { 32 | return 0; // ok 33 | } 34 | else 35 | { 36 | return 3; // nope 37 | } 38 | } 39 | 40 | return chunkRandom.nextInt(bound); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/UhcGameColor.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc; 6 | 7 | import net.minecraft.util.DyeColor; 8 | import net.minecraft.util.Formatting; 9 | 10 | public enum UhcGameColor 11 | { 12 | RED(DyeColor.RED, Formatting.RED, "Red", 0), 13 | BLUE(DyeColor.BLUE, Formatting.BLUE, "Blue", 1), 14 | YELLOW(DyeColor.YELLOW, Formatting.YELLOW, "Yellow", 2), 15 | GREEN(DyeColor.LIME, Formatting.GREEN, "Green", 3), 16 | ORANGE(DyeColor.ORANGE, Formatting.GOLD, "Orange", 4), 17 | PURPLE(DyeColor.PURPLE, Formatting.LIGHT_PURPLE, "Purple", 5), 18 | CYAN(DyeColor.CYAN, Formatting.DARK_BLUE, "Cyan", 6), 19 | BROWN(DyeColor.BROWN, Formatting.DARK_RED, "Brown", 7), 20 | WHITE(DyeColor.WHITE, Formatting.WHITE, "White", 8), 21 | BLACK(DyeColor.BLACK, Formatting.BLACK, "Black", 9); 22 | 23 | public static final int MAX_TEAM_COLORS = 8; 24 | private static int rand = 0; 25 | 26 | public final DyeColor dyeColor; 27 | public final Formatting chatColor; 28 | public final String name; 29 | private final int id; 30 | 31 | UhcGameColor(DyeColor dye, Formatting chat, String name, int id) 32 | { 33 | dyeColor = dye; 34 | chatColor = chat; 35 | this.name = name; 36 | this.id = id; 37 | } 38 | 39 | public static UhcGameColor randomColor() 40 | { 41 | return values()[(rand++) % MAX_TEAM_COLORS]; 42 | } 43 | 44 | public int getId() 45 | { 46 | return this.id; 47 | } 48 | 49 | public static UhcGameColor getColor(int id) 50 | { 51 | return id < 10 ? UhcGameColor.values()[id] : null; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/resources/data/tcuhc/loot_tables/greenhouse/chest_snow.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "rolls": {"type": "minecraft:uniform", "min": 4, "max": 8}, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "name": "minecraft:torch", 10 | "weight": 1, 11 | "functions": [{"function": "minecraft:set_count", "count": {"type": "minecraft:uniform", "min": 1, "max": 2}}] 12 | }, 13 | { 14 | "type": "minecraft:item", 15 | "name": "minecraft:stick", 16 | "weight": 1, 17 | "functions": [{"function": "minecraft:set_count", "count": {"type": "minecraft:uniform", "min": 1, "max": 2}}] 18 | }, 19 | { 20 | "type": "minecraft:item", 21 | "name": "minecraft:wheat_seeds", 22 | "weight": 1, 23 | "functions": [{"function": "minecraft:set_count", "count": {"type": "minecraft:uniform", "min": 1, "max": 2}}] 24 | }, 25 | { 26 | "type": "minecraft:item", 27 | "name": "minecraft:grass", 28 | "weight": 2, 29 | "functions": [{"function": "minecraft:set_count", "count": {"type": "minecraft:uniform", "min": 1, "max": 2}}] 30 | }, 31 | { 32 | "type": "minecraft:item", 33 | "name": "minecraft:spruce_log", 34 | "weight": 2, 35 | "functions": [{"function": "minecraft:set_count", "count": {"type": "minecraft:uniform", "min": 1, "max": 2}}] 36 | }, 37 | { 38 | "type": "minecraft:item", 39 | "name": "minecraft:charcoal", 40 | "weight": 1 41 | } 42 | ] 43 | } 44 | ] 45 | } -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/worldgen/structure/ShipwreckFeatureMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.worldgen.structure; 2 | 3 | import net.minecraft.structure.StructureGeneratorFactory; 4 | import net.minecraft.world.Heightmap; 5 | import net.minecraft.world.World; 6 | import net.minecraft.world.biome.Biome; 7 | import net.minecraft.world.biome.source.BiomeCoords; 8 | import net.minecraft.world.gen.feature.ShipwreckFeature; 9 | import net.minecraft.world.gen.feature.ShipwreckFeatureConfig; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 14 | 15 | @Mixin(ShipwreckFeature.class) 16 | public abstract class ShipwreckFeatureMixin 17 | { 18 | @Inject(method = "canGenerate", at = @At("HEAD"), cancellable = true) 19 | private static void dontGenerateTooHighWhenInRiver(StructureGeneratorFactory.Context context, CallbackInfoReturnable cir) 20 | { 21 | int x = context.chunkPos().getCenterX(); 22 | int z = context.chunkPos().getCenterZ(); 23 | int y = context.chunkGenerator().getHeightInGround(x, z, Heightmap.Type.OCEAN_FLOOR_WG, context.world()); 24 | Biome biome = context.chunkGenerator().getBiomeForNoiseGen(BiomeCoords.fromBlock(x), BiomeCoords.fromBlock(y), BiomeCoords.fromBlock(z)); 25 | // Biome.Category.RIVER equals to BiomeKeys.RIVER + BiomeKeys.FROZEN_RIVER 26 | if (biome.getCategory() == Biome.Category.RIVER) 27 | { 28 | if (context.world() instanceof World) 29 | { 30 | World world = (World)context.world(); 31 | if (y > world.getSeaLevel() - 7) 32 | { 33 | cir.setReturnValue(false); 34 | } 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/resources/data/tcuhc/loot_tables/plain_cottage/chest.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "rolls": {"type": "minecraft:uniform", "min": 2, "max": 5}, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "name": "minecraft:iron_ingot", 10 | "weight": 1 11 | }, 12 | { 13 | "type": "minecraft:item", 14 | "name": "minecraft:stick", 15 | "weight": 2 16 | }, 17 | { 18 | "type": "minecraft:item", 19 | "name": "minecraft:dirt", 20 | "weight": 1, 21 | "functions": [{"function": "minecraft:set_count", "count": {"type": "minecraft:uniform", "min": 1, "max": 2}}] 22 | }, 23 | { 24 | "type": "minecraft:item", 25 | "name": "minecraft:wheat_seeds", 26 | "weight": 1 27 | } 28 | ] 29 | }, 30 | { 31 | "rolls": {"type": "minecraft:uniform", "min": 1, "max": 4}, 32 | "entries": [ 33 | { 34 | "type": "minecraft:item", 35 | "name": "minecraft:bread", 36 | "weight": 1, 37 | "functions": [{"function": "minecraft:set_count", "count": {"type": "minecraft:uniform", "min": 1, "max": 2}}] 38 | }, 39 | { 40 | "type": "minecraft:item", 41 | "name": "minecraft:cooked_chicken", 42 | "weight": 2, 43 | "functions": [{"function": "minecraft:set_count", "count": {"type": "minecraft:uniform", "min": 1, "max": 2}}] 44 | }, 45 | { 46 | "type": "minecraft:item", 47 | "name": "minecraft:wheat", 48 | "weight": 1, 49 | "functions": [{"function": "minecraft:set_count", "count": {"type": "minecraft:uniform", "min": 1, "max": 2}}] 50 | } 51 | ] 52 | } 53 | ] 54 | } -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/recipe/RecipeGoldenApple.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.recipe; 2 | 3 | import net.minecraft.inventory.CraftingInventory; 4 | import net.minecraft.item.ItemStack; 5 | import net.minecraft.item.Items; 6 | import net.minecraft.nbt.NbtInt; 7 | import net.minecraft.recipe.RecipeSerializer; 8 | import net.minecraft.recipe.SpecialCraftingRecipe; 9 | import net.minecraft.util.Identifier; 10 | import net.minecraft.world.World; 11 | 12 | public class RecipeGoldenApple extends SpecialCraftingRecipe 13 | { 14 | public RecipeGoldenApple(Identifier id) 15 | { 16 | super(id); 17 | } 18 | 19 | @Override 20 | public boolean matches(CraftingInventory inv, World world) 21 | { 22 | return this.craft(inv) != ItemStack.EMPTY; 23 | } 24 | 25 | @Override 26 | public ItemStack craft(CraftingInventory inv) 27 | { 28 | boolean hasApple = false; 29 | int goldCnt = 0; 30 | for (int i = 0; i < inv.size(); ++i) 31 | { 32 | ItemStack itemstack = inv.getStack(i); 33 | if (itemstack.getItem() == Items.APPLE) 34 | { 35 | if (!hasApple) 36 | { 37 | hasApple = true; 38 | } 39 | else 40 | { 41 | return ItemStack.EMPTY; 42 | } 43 | } 44 | else if (itemstack.getItem() == Items.GOLD_INGOT) 45 | { 46 | goldCnt++; 47 | } 48 | } 49 | if (hasApple && goldCnt > 0 && goldCnt % 2 == 0) 50 | { 51 | int level = goldCnt / 2; 52 | ItemStack res = new ItemStack(Items.GOLDEN_APPLE); 53 | if (level != 4) 54 | { 55 | res.getOrCreateNbt().put("level", NbtInt.of(level)); 56 | } 57 | return res; 58 | } 59 | return ItemStack.EMPTY; 60 | } 61 | 62 | @Override 63 | public boolean fits(int width, int height) 64 | { 65 | return width >= 3 && height >= 3; 66 | } 67 | 68 | @Override 69 | public RecipeSerializer getSerializer() 70 | { 71 | return UhcRecipeSerializer.GOLDEN_APPLE; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/gen/feature/UhcFeatures.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.gen.feature; 2 | 3 | import com.google.common.collect.ImmutableSet; 4 | import me.fallenbreath.tcuhc.util.UhcRegistry; 5 | import net.minecraft.block.Block; 6 | import net.minecraft.block.Blocks; 7 | import net.minecraft.world.gen.decorator.SquarePlacementModifier; 8 | import net.minecraft.world.gen.feature.*; 9 | 10 | import java.util.Set; 11 | 12 | public class UhcFeatures 13 | { 14 | public static final PlacedFeature MERCHANTS = create("merchants", new MerchantsFeature(DefaultFeatureConfig.CODEC)); 15 | public static final PlacedFeature BONUS_CHEST = create("bonus_chest", new BonusChestFeature(DefaultFeatureConfig.CODEC)); 16 | public static final PlacedFeature ENDER_ALTAR = create("ender_altar", new EnderAltarFeature(DefaultFeatureConfig.CODEC)); 17 | 18 | private static > PlacedFeature create(String name, F feature) 19 | { 20 | F feat = UhcRegistry.registerFeature(name, feature); 21 | ConfiguredFeature cf = UhcRegistry.registerConfiguredFeature(name, feat.configure(FeatureConfig.DEFAULT)); 22 | return UhcRegistry.registerPlacedFeature(name, cf.withPlacement( 23 | SquarePlacementModifier.of(), 24 | PlacedFeatures.OCEAN_FLOOR_WG_HEIGHTMAP 25 | )); 26 | } 27 | 28 | private static final Set VALUABLE_ORES = new ImmutableSet.Builder(). 29 | add(Blocks.IRON_ORE).add(Blocks.DEEPSLATE_IRON_ORE). 30 | add(Blocks.GOLD_ORE).add(Blocks.DEEPSLATE_GOLD_ORE). 31 | add(Blocks.LAPIS_ORE).add(Blocks.DEEPSLATE_LAPIS_ORE). 32 | add(Blocks.DIAMOND_ORE).add(Blocks.DEEPSLATE_DIAMOND_ORE). 33 | add(Blocks.EMERALD_ORE).add(Blocks.DEEPSLATE_EMERALD_ORE). 34 | add(Blocks.NETHER_QUARTZ_ORE). 35 | build(); 36 | 37 | public static boolean isValuableOreBlock(Block block) 38 | { 39 | return VALUABLE_ORES.contains(block); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/core/PlayerManagerMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.core; 2 | 3 | import me.fallenbreath.tcuhc.UhcGameManager; 4 | import net.minecraft.network.ClientConnection; 5 | import net.minecraft.server.PlayerManager; 6 | import net.minecraft.server.network.ServerPlayerEntity; 7 | import net.minecraft.server.world.ServerWorld; 8 | import net.minecraft.util.math.BlockPos; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 14 | import org.spongepowered.asm.mixin.injection.callback.LocalCapture; 15 | 16 | import java.util.Optional; 17 | 18 | @Mixin(PlayerManager.class) 19 | public abstract class PlayerManagerMixin 20 | { 21 | @Inject( 22 | method = "onPlayerConnect", 23 | at = @At( 24 | value = "INVOKE", 25 | target = "Lnet/minecraft/server/world/ServerWorld;onPlayerConnected(Lnet/minecraft/server/network/ServerPlayerEntity;)V" 26 | ) 27 | ) 28 | private void playerJoinHook(ClientConnection connection, ServerPlayerEntity player, CallbackInfo ci) 29 | { 30 | UhcGameManager.instance.onPlayerJoin(player); 31 | } 32 | 33 | @Inject( 34 | method = "respawnPlayer", 35 | at = @At( 36 | value = "INVOKE", 37 | target = "Lnet/minecraft/world/World;getLevelProperties()Lnet/minecraft/world/WorldProperties;" 38 | ), 39 | locals = LocalCapture.CAPTURE_FAILHARD 40 | ) 41 | private void playerRespawnHook(ServerPlayerEntity player, boolean alive, CallbackInfoReturnable cir, BlockPos blockPos, float f, boolean bl, ServerWorld serverWorld, Optional optional2, ServerWorld serverWorld2, ServerPlayerEntity serverPlayerEntity, boolean bl2) 42 | { 43 | UhcGameManager.instance.onPlayerRespawn(serverPlayerEntity); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/entity/MobEntityMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.entity; 2 | 3 | import net.minecraft.entity.EntityType; 4 | import net.minecraft.entity.LivingEntity; 5 | import net.minecraft.entity.mob.MobEntity; 6 | import net.minecraft.world.World; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Constant; 10 | import org.spongepowered.asm.mixin.injection.ModifyConstant; 11 | import org.spongepowered.asm.mixin.injection.Redirect; 12 | 13 | @Mixin(MobEntity.class) 14 | public abstract class MobEntityMixin extends LivingEntity 15 | { 16 | protected MobEntityMixin(EntityType type, World world) 17 | { 18 | super(type, world); 19 | } 20 | 21 | @Redirect( 22 | method = "checkDespawn", 23 | at = @At( 24 | value = "INVOKE", 25 | target = "Lnet/minecraft/entity/mob/MobEntity;canImmediatelyDespawn(D)Z", 26 | ordinal = 0 27 | ) 28 | ) 29 | private boolean modifyImmediateDespawnChance(MobEntity mobEntity, double distanceSquared) 30 | { 31 | return mobEntity.canImmediatelyDespawn(distanceSquared) && this.random.nextInt(200) == 0; 32 | } 33 | 34 | @ModifyConstant(method = "checkDespawn", constant = @Constant(intValue = 600), allow = 1) 35 | private int modifyRandomlyDespawnThreshold(int value) 36 | { 37 | return 300; 38 | } 39 | 40 | @ModifyConstant(method = "checkDespawn", constant = @Constant(intValue = 800), allow = 1) 41 | private int modifyRandomlyDespawnChance(int value) 42 | { 43 | return 200; 44 | } 45 | 46 | // no need in 1.15.2 47 | // @Redirect( 48 | // method = "tickNewAi", 49 | // at = @At( 50 | // value = "INVOKE", 51 | // target = "Lnet/minecraft/entity/mob/MobEntity;checkDespawn()V" 52 | // ) 53 | // ) 54 | // private void modifyImmediateDespawnChance(MobEntity mobEntity) 55 | // { 56 | // // don't check despawn here 57 | // // do nothing 58 | // } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/util/LastWinnerList.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.util; 6 | 7 | import com.google.common.base.Charsets; 8 | import com.google.common.collect.Sets; 9 | import com.google.common.io.Files; 10 | import me.fallenbreath.tcuhc.UhcGamePlayer; 11 | import org.apache.commons.io.IOUtils; 12 | 13 | import java.io.*; 14 | import java.util.Set; 15 | 16 | public class LastWinnerList { 17 | private final Set winnerList = Sets.newHashSet(); 18 | private final File winnerFile; 19 | 20 | public LastWinnerList(File listFile) { 21 | winnerFile = listFile; 22 | readFile(); 23 | } 24 | 25 | public boolean isWinner(String name) { 26 | return winnerList.contains(name); 27 | } 28 | 29 | public void setWinner(Iterable playerList) { 30 | winnerList.clear(); 31 | if (playerList == null) 32 | return; 33 | playerList.forEach(player -> winnerList.add(player.getName())); 34 | saveFile(); 35 | } 36 | 37 | private void saveFile() { 38 | BufferedWriter bufferedwriter = null; 39 | try { 40 | bufferedwriter = Files.newWriter(this.winnerFile, Charsets.UTF_8); 41 | for (String name : winnerList) 42 | bufferedwriter.write(name + System.getProperty("line.separator", "\n")); 43 | } catch (Exception e) { 44 | e.printStackTrace(); 45 | } finally { 46 | IOUtils.closeQuietly((Writer) bufferedwriter); 47 | } 48 | } 49 | 50 | private void readFile() { 51 | BufferedReader bufferedreader = null; 52 | winnerList.clear(); 53 | String name; 54 | try { 55 | bufferedreader = Files.newReader(this.winnerFile, Charsets.UTF_8); 56 | while (bufferedreader.ready()) 57 | if ((name = bufferedreader.readLine()) != null) 58 | if (!name.isEmpty()) 59 | winnerList.add(name); 60 | } catch (FileNotFoundException ignored) { 61 | } catch (Exception e) { 62 | e.printStackTrace(); 63 | } finally { 64 | IOUtils.closeQuietly((Reader) bufferedreader); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/util/UhcWorldData.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.util; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import me.fallenbreath.tcuhc.UhcGameManager; 6 | 7 | import java.io.*; 8 | import java.util.Random; 9 | 10 | public class UhcWorldData 11 | { 12 | public int spawnPlatformHeight = -1; 13 | public StructureType netherFortressType = StructureType.randomChoose(); 14 | 15 | private UhcWorldData() 16 | { 17 | this.save(); 18 | } 19 | 20 | public boolean isSpawnPlatformHeightValid() 21 | { 22 | return this.spawnPlatformHeight != -1; 23 | } 24 | 25 | public static UhcWorldData load() 26 | { 27 | File file = UhcGameManager.getDataFile(); 28 | try (InputStreamReader reader = new InputStreamReader(new FileInputStream(file))) 29 | { 30 | UhcWorldData data = new Gson().fromJson(reader, UhcWorldData.class); 31 | UhcGameManager.LOG.info("Loaded uhc world data"); 32 | return data; 33 | } 34 | catch (Exception e) 35 | { 36 | if (e instanceof FileNotFoundException) 37 | { 38 | UhcGameManager.LOG.warn("Generating new uhc world data"); 39 | } 40 | else 41 | { 42 | UhcGameManager.LOG.error("Failed to read uhc world data file", e); 43 | } 44 | return new UhcWorldData(); 45 | } 46 | } 47 | 48 | public synchronized void save() 49 | { 50 | File file = UhcGameManager.getDataFile(); 51 | try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file))) 52 | { 53 | writer.write(new GsonBuilder().setPrettyPrinting().create().toJson(this)); 54 | } 55 | catch (Exception e) 56 | { 57 | UhcGameManager.LOG.error("Failed to save uhc data file", e); 58 | } 59 | } 60 | 61 | public enum StructureType 62 | { 63 | NETHER_FORTRESS, 64 | BASTION_REMNANT; 65 | 66 | private static final Random random = new Random(); 67 | 68 | public static StructureType randomChoose() 69 | { 70 | StructureType[] values = values(); 71 | return values[random.nextInt(values.length)]; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/recipe/RecipeArmorRepair.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.recipe; 2 | 3 | import net.minecraft.inventory.CraftingInventory; 4 | import net.minecraft.item.ArmorItem; 5 | import net.minecraft.item.ItemStack; 6 | import net.minecraft.recipe.RecipeSerializer; 7 | import net.minecraft.recipe.SpecialCraftingRecipe; 8 | import net.minecraft.util.Identifier; 9 | import net.minecraft.world.World; 10 | 11 | public class RecipeArmorRepair extends SpecialCraftingRecipe 12 | { 13 | public RecipeArmorRepair(Identifier id) 14 | { 15 | super(id); 16 | } 17 | 18 | @Override 19 | public boolean matches(CraftingInventory inv, World world) 20 | { 21 | return this.craft(inv) != ItemStack.EMPTY; 22 | } 23 | 24 | @Override 25 | public ItemStack craft(CraftingInventory inv) 26 | { 27 | ItemStack armor = null; 28 | for (int i = 0; i < inv.size(); ++i) 29 | { 30 | ItemStack itemstack = inv.getStack(i); 31 | if (itemstack.getItem() instanceof ArmorItem) 32 | { 33 | if (armor == null) 34 | { 35 | armor = itemstack; 36 | } 37 | else 38 | { 39 | return ItemStack.EMPTY; 40 | } 41 | } 42 | } 43 | if (armor == null) 44 | { 45 | return ItemStack.EMPTY; 46 | } 47 | ArmorItem armorItem = (ArmorItem)armor.getItem(); 48 | int repairCnt = 0; 49 | for (int i = 0; i < inv.size(); ++i) 50 | { 51 | ItemStack itemstack = inv.getStack(i); 52 | if (!itemstack.isEmpty() && !(itemstack.getItem() instanceof ArmorItem)) 53 | { 54 | if (armorItem.canRepair(armor, itemstack)) 55 | { 56 | repairCnt++; 57 | } 58 | else 59 | { 60 | return ItemStack.EMPTY; 61 | } 62 | } 63 | } 64 | if (repairCnt == 0) 65 | { 66 | return ItemStack.EMPTY; 67 | } 68 | ItemStack result = armor.copy(); 69 | result.setDamage(armor.getDamage() - repairCnt * armor.getMaxDamage() / 4); 70 | return result; 71 | } 72 | 73 | @Override 74 | public boolean fits(int width, int height) 75 | { 76 | return true; 77 | } 78 | 79 | @Override 80 | public RecipeSerializer getSerializer() 81 | { 82 | return UhcRecipeSerializer.REPAIR_ARMOR; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/util/collection/ExpiringMap.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.util.collection; 2 | 3 | import it.unimi.dsi.fastutil.longs.Long2LongLinkedOpenHashMap; 4 | import it.unimi.dsi.fastutil.longs.Long2LongMap; 5 | import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; 6 | import it.unimi.dsi.fastutil.objects.ObjectIterator; 7 | import net.minecraft.util.Util; 8 | 9 | import java.util.Map; 10 | 11 | public class ExpiringMap extends Long2ObjectOpenHashMap 12 | { 13 | private final int lifespanMs; 14 | private final Long2LongMap timeMap = new Long2LongLinkedOpenHashMap(); 15 | 16 | public ExpiringMap(int lifespanIn) 17 | { 18 | this.lifespanMs = lifespanIn; 19 | } 20 | 21 | private void refreshTimes(long key) 22 | { 23 | long currentTime = Util.getMeasuringTimeMs(); 24 | this.timeMap.put(key, currentTime); 25 | ObjectIterator iter = this.timeMap.long2LongEntrySet().iterator(); 26 | 27 | while (iter.hasNext()) 28 | { 29 | Long2LongMap.Entry entry = iter.next(); 30 | T element = super.get(entry.getLongKey()); 31 | 32 | if (currentTime - entry.getLongValue() <= (long)this.lifespanMs) 33 | { 34 | break; 35 | } 36 | 37 | if (element != null && this.shouldExpire(element)) 38 | { 39 | super.remove(entry.getLongKey()); 40 | iter.remove(); 41 | } 42 | } 43 | } 44 | 45 | protected boolean shouldExpire(T element) 46 | { 47 | return true; 48 | } 49 | 50 | public T put(long k, T t) 51 | { 52 | this.refreshTimes(k); 53 | return super.put(k, t); 54 | } 55 | 56 | @SuppressWarnings("deprecation") 57 | public T put(Long k, T t) 58 | { 59 | this.refreshTimes(k); 60 | return super.put(k, t); 61 | } 62 | 63 | public T get(long k) 64 | { 65 | this.refreshTimes(k); 66 | return super.get(k); 67 | } 68 | 69 | public void putAll(Map map) 70 | { 71 | throw new RuntimeException("Not implemented"); 72 | } 73 | 74 | public T remove(long k) 75 | { 76 | throw new RuntimeException("Not implemented"); 77 | } 78 | 79 | @SuppressWarnings("deprecation") 80 | public T remove(Object k) 81 | { 82 | throw new RuntimeException("Not implemented"); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/worldgen/structure/BuriedTreasureFeatureMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.worldgen.structure; 2 | 3 | import net.minecraft.structure.StructurePiecesCollector; 4 | import net.minecraft.structure.StructurePiecesGenerator; 5 | import net.minecraft.util.math.ChunkPos; 6 | import net.minecraft.world.gen.ProbabilityConfig; 7 | import net.minecraft.world.gen.feature.BuriedTreasureFeature; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.Unique; 10 | import org.spongepowered.asm.mixin.injection.Constant; 11 | import org.spongepowered.asm.mixin.injection.ModifyConstant; 12 | 13 | @Mixin(BuriedTreasureFeature.class) 14 | public abstract class BuriedTreasureFeatureMixin 15 | { 16 | @ModifyConstant(method = "addPieces", constant = @Constant(intValue = 9, ordinal = 0)) 17 | private static int tweaksXOffset(int x, StructurePiecesCollector collector, StructurePiecesGenerator.Context context) 18 | { 19 | return calcXOffset(context.chunkPos()); 20 | } 21 | 22 | @ModifyConstant(method = "addPieces", constant = @Constant(intValue = 9, ordinal = 1)) 23 | private static int tweaksZOffset(int z, StructurePiecesCollector collector, StructurePiecesGenerator.Context context) 24 | { 25 | return calcZOffset(context.chunkPos()); 26 | } 27 | 28 | @ModifyConstant(method = "getLocatedPos", constant = @Constant(intValue = 9, ordinal = 0)) 29 | private int tweaksXOffset(int x, ChunkPos chunkPos) 30 | { 31 | return calcXOffset(chunkPos); 32 | } 33 | 34 | @ModifyConstant(method = "getLocatedPos", constant = @Constant(intValue = 9, ordinal = 1)) 35 | private int tweaksZOffset(int z, ChunkPos chunkPos) 36 | { 37 | return calcZOffset(chunkPos); 38 | } 39 | 40 | @Unique 41 | private static int calcXOffset(ChunkPos chunkPos) 42 | { 43 | return magic(chunkPos) & 0xF; 44 | } 45 | 46 | @Unique 47 | private static int calcZOffset(ChunkPos chunkPos) 48 | { 49 | return (magic(chunkPos) >> 4) & 0xF; 50 | } 51 | 52 | @Unique 53 | private static int magic(ChunkPos chunkPos) 54 | { 55 | int hash = chunkPos.hashCode(); 56 | return hash ^ (hash >> 8) ^ (hash >> 16) ^ (hash >> 24); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/options/Option.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.options; 6 | 7 | import me.fallenbreath.tcuhc.task.Task; 8 | import me.fallenbreath.tcuhc.task.Taskable; 9 | 10 | public class Option extends Taskable { 11 | 12 | private String optionId; 13 | private String optionName, optionDescript; 14 | 15 | private OptionType type; 16 | private Object defaultValue; 17 | private boolean needToSave; 18 | 19 | public Option(String id, String name, OptionType type, Object defaultValue) { 20 | optionId = id; 21 | optionName = name; 22 | this.type = type; 23 | this.defaultValue = defaultValue; 24 | type.setValue(defaultValue); 25 | this.addTask(Options.instance.taskSaveProperties); 26 | } 27 | 28 | public Object getValue() { return type.getValue(); } 29 | public int getIntegerValue() { return (int) type.getValue(); } 30 | public float getFloatValue() { return (float) type.getValue(); } 31 | public String getStringValue() { return type.getStringValue(); } 32 | public void incValue() { type.applyInc(); this.updateTasks(); } 33 | public void decValue() { type.applyDec(); this.updateTasks(); } 34 | public void setValue(Object value) { type.setValue(value); this.updateTasks(); } 35 | public void setStringValue(String value) { type.setStringValue(value); this.updateTasks(); } 36 | public void setInitialValue(String value) { type.setStringValue(value); } 37 | 38 | public String getName() { return optionName; } 39 | public String getDescription() { return optionDescript; } 40 | public String getIncString() { return type.getIncString(); } 41 | public String getDecString() { return type.getDecString(); } 42 | 43 | @Override 44 | public String toString() { 45 | return getStringValue(); 46 | } 47 | 48 | @Override 49 | public Option addTask(Task task) { 50 | return (Option) super.addTask(task); 51 | } 52 | 53 | public Option setDescription(String des) { 54 | optionDescript = des; 55 | return this; 56 | } 57 | 58 | public Option setNeedToSave() { 59 | this.needToSave = true; 60 | return this; 61 | } 62 | 63 | public boolean needToSave() { return needToSave; } 64 | public String getId() { return optionId; } 65 | public void reset() { setValue(defaultValue); } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/task/TaskBorderReminder.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.task; 6 | 7 | import me.fallenbreath.tcuhc.UhcGameManager; 8 | import me.fallenbreath.tcuhc.options.Options; 9 | import me.fallenbreath.tcuhc.task.Task.TaskTimer; 10 | import net.minecraft.server.network.ServerPlayerEntity; 11 | import net.minecraft.text.LiteralText; 12 | import net.minecraft.util.Formatting; 13 | import net.minecraft.world.border.WorldBorder; 14 | 15 | public class TaskBorderReminder extends TaskTimer { 16 | 17 | private final int borderStart, borderEnd; 18 | private final int borderStartTime, borderEndTime, gameTime; 19 | private final WorldBorder border; 20 | 21 | public TaskBorderReminder() { 22 | super(0, 20); 23 | Options options = Options.instance; 24 | borderStart = options.getIntegerOptionValue("borderStart"); 25 | borderEnd = options.getIntegerOptionValue("borderEnd"); 26 | borderStartTime = options.getIntegerOptionValue("borderStartTime"); 27 | borderEndTime = options.getIntegerOptionValue("borderEndTime"); 28 | gameTime = options.getIntegerOptionValue("gameTime"); 29 | border = UhcGameManager.instance.getOverWorld().getWorldBorder(); 30 | border.interpolateSize(borderStart, borderEnd, (borderEndTime - borderStartTime) * 1000L); 31 | UhcGameManager.instance.broadcastMessage(Formatting.DARK_RED + "World border started to shrink."); 32 | } 33 | 34 | @Override 35 | public void onTimer() { 36 | if (this.hasFinished()) return; 37 | if (gameTime - UhcGameManager.instance.getGameTimeRemaining() >= borderEndTime) { 38 | UhcGameManager.instance.broadcastMessage(Formatting.DARK_RED + "World border stopped shrinking."); 39 | this.setCanceled(); 40 | } 41 | for (ServerPlayerEntity player : UhcGameManager.instance.getServerPlayerManager().getPlayerList()) { 42 | if (border.getDistanceInsideBorder(player) < 5 && !(Math.abs(player.getX()) < borderEnd / 2.0 && Math.abs(player.getZ()) < borderEnd / 2.0) 43 | && !player.isCreative() && !player.isSpectator() && UhcGameManager.instance.getUhcPlayerManager().getGamePlayer(player).borderRemindCooldown()) { 44 | player.sendMessage(new LiteralText(Formatting.DARK_RED + "You will fall behind the world border!"), false); 45 | } 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/entity/StatusEffectInstanceMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.entity; 2 | 3 | import net.minecraft.entity.effect.StatusEffect; 4 | import net.minecraft.entity.effect.StatusEffectInstance; 5 | import net.minecraft.entity.effect.StatusEffects; 6 | import org.spongepowered.asm.mixin.Final; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Redirect; 11 | 12 | @Mixin(StatusEffectInstance.class) 13 | public abstract class StatusEffectInstanceMixin 14 | { 15 | @Shadow @Final private StatusEffect type; 16 | 17 | /** 18 | * The result behavior will be using the maximum absorption between current absorption and the new absorption 19 | * It's the result we want instead of the vanilla one, which rejects to apply golden apple's absorption when having 20 | * enchanted golden apple's absorption effect with 0 yellow heart 21 | * At least for randomly eating golden apple and enchanted golden apple 22 | * 23 | * See the following methods for more Minecraft related implementation: the new effect will be re-applied so 24 | * the absorption stuffs works perfectly 25 | * - {@link net.minecraft.entity.LivingEntity#addStatusEffect(net.minecraft.entity.effect.StatusEffectInstance, net.minecraft.entity.Entity)} 26 | * - {@link net.minecraft.entity.LivingEntity#onStatusEffectUpgraded(net.minecraft.entity.effect.StatusEffectInstance, boolean, net.minecraft.entity.Entity)} 27 | * 28 | * {@link LivingEntityMixin#removeAbsorptionYellowHearts} fixes a side effect of this patch 29 | */ 30 | @SuppressWarnings("JavadocReference") 31 | @Redirect( 32 | method = "upgrade", 33 | at = @At( 34 | value = "FIELD", 35 | target = "Lnet/minecraft/entity/effect/StatusEffectInstance;amplifier:I", 36 | ordinal = 0 37 | ) 38 | ) 39 | private int alwaysOverwriteForAbsorptionEffect(StatusEffectInstance that) 40 | { 41 | // if (that.amplifier > this.amplifier) 42 | // ^ redirected 43 | if (this.type == StatusEffects.ABSORPTION) 44 | { 45 | // always results in true for the if statement 46 | // so the new effect will always overwrite the exists effect 47 | return Integer.MAX_VALUE; 48 | } 49 | 50 | // vanilla 51 | return that.getAmplifier(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/resources/data/tcuhc/loot_tables/villain_house/chest.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "rolls": {"type": "minecraft:uniform", "min": 0, "max": 1}, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "name": "minecraft:crossbow", 10 | "weight": 1, 11 | "functions": [{"function": "minecraft:set_damage", "damage": {"type": "minecraft:uniform", "min": 0.4, "max": 0.7}}] 12 | }, 13 | { 14 | "type": "minecraft:item", 15 | "name": "minecraft:iron_shovel", 16 | "weight": 1, 17 | "functions": [{"function": "minecraft:set_damage", "damage": {"type": "minecraft:uniform", "min": 0.5, "max": 0.8}}] 18 | } 19 | ] 20 | }, 21 | { 22 | "rolls": {"type": "minecraft:uniform", "min": 4, "max": 8}, 23 | "entries": [ 24 | { 25 | "type": "minecraft:item", 26 | "name": "minecraft:bone", 27 | "weight": 2 28 | }, 29 | { 30 | "type": "minecraft:item", 31 | "name": "minecraft:rotten_flesh", 32 | "weight": 2 33 | }, 34 | { 35 | "type": "minecraft:item", 36 | "name": "minecraft:redstone", 37 | "weight": 1 38 | }, 39 | { 40 | "type": "minecraft:item", 41 | "name": "minecraft:string", 42 | "weight": 1 43 | }, 44 | { 45 | "type": "minecraft:item", 46 | "name": "minecraft:emerald", 47 | "weight": 1 48 | }, 49 | { 50 | "type": "minecraft:item", 51 | "name": "minecraft:apple", 52 | "weight": 1 53 | }, 54 | { 55 | "type": "minecraft:item", 56 | "name": "minecraft:oak_sapling", 57 | "weight": 1 58 | } 59 | ] 60 | }, 61 | { 62 | "rolls": {"type": "minecraft:uniform", "min": 1, "max": 4}, 63 | "entries": [ 64 | { 65 | "type": "minecraft:item", 66 | "name": "minecraft:iron_ingot", 67 | "weight": 2, 68 | "functions": [{"function": "minecraft:set_count", "count": {"type": "minecraft:uniform", "min": 2, "max": 3}, "add": false}] 69 | }, 70 | { 71 | "type": "minecraft:item", 72 | "name": "minecraft:poppy", 73 | "weight": 1 74 | } 75 | ] 76 | } 77 | ] 78 | } -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/util/SpectateTargetUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.util; 6 | 7 | import me.fallenbreath.tcuhc.UhcGameManager; 8 | import me.fallenbreath.tcuhc.UhcGamePlayer; 9 | import me.fallenbreath.tcuhc.UhcGameTeam; 10 | import net.minecraft.entity.Entity; 11 | import net.minecraft.entity.decoration.ArmorStandEntity; 12 | import net.minecraft.server.network.ServerPlayerEntity; 13 | import net.minecraft.util.math.Vec3d; 14 | 15 | public class SpectateTargetUtil { 16 | 17 | public static boolean isCapableTarget(UhcGamePlayer player, Entity target) { 18 | UhcGameManager gameManager = UhcGameManager.instance; 19 | if (!gameManager.isGamePlaying()) return true; 20 | if (gameManager.getUhcPlayerManager().isObserver(player)) return true; 21 | if (!gameManager.getOptions().getBooleanOptionValue("forceViewport")) return true; 22 | UhcGameTeam team = player.getTeam(); 23 | if (team.getAliveCount() == 0) return true; 24 | if (target instanceof ArmorStandEntity) return true; 25 | if (!(target instanceof ServerPlayerEntity)) return false; 26 | if (UhcGameManager.instance.getServerPlayerManager().getPlayer(target.getUuid()) != target) return false; 27 | UhcGamePlayer targetPlayer = gameManager.getUhcPlayerManager().getGamePlayer((ServerPlayerEntity) target); 28 | if (player == targetPlayer) return false; 29 | return player.getTeam() == targetPlayer.getTeam(); 30 | } 31 | 32 | public static Entity getCapableTarget(UhcGamePlayer player, Entity origin) { 33 | if (isCapableTarget(player, origin)) return origin; 34 | for (UhcGamePlayer target : player.getTeam().getPlayers()) { 35 | if (target.isAlive() && target.getRealPlayer().isPresent()) { 36 | if (origin instanceof ArmorStandEntity) origin.discard(); 37 | return target.getRealPlayer().get(); 38 | } 39 | } 40 | for (UhcGamePlayer target : player.getTeam().getPlayers()) { 41 | if (target.isAlive()) { 42 | ServerPlayerEntity playermp = player.getRealPlayer().get(); 43 | Vec3d pos = playermp.getPos(); 44 | ArmorStandEntity armorStand = new ArmorStandEntity(playermp.world, pos.x, pos.y, pos.z); 45 | armorStand.setInvisible(true); 46 | armorStand.setInvulnerable(true); 47 | armorStand.setNoGravity(true); 48 | playermp.world.spawnEntity(armorStand); 49 | return armorStand; 50 | } 51 | } 52 | return origin; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/block/ChestBlockEntityMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.block; 2 | 3 | import me.fallenbreath.tcuhc.UhcGameManager; 4 | import me.fallenbreath.tcuhc.UhcGamePlayer; 5 | import me.fallenbreath.tcuhc.gen.feature.BonusChestFeature; 6 | import net.minecraft.block.BlockState; 7 | import net.minecraft.block.entity.BlockEntityType; 8 | import net.minecraft.block.entity.ChestBlockEntity; 9 | import net.minecraft.block.entity.LootableContainerBlockEntity; 10 | import net.minecraft.entity.player.PlayerEntity; 11 | import net.minecraft.text.LiteralText; 12 | import net.minecraft.util.math.BlockPos; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.injection.At; 15 | import org.spongepowered.asm.mixin.injection.Inject; 16 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 17 | 18 | @Mixin(ChestBlockEntity.class) 19 | public abstract class ChestBlockEntityMixin extends LootableContainerBlockEntity 20 | { 21 | protected ChestBlockEntityMixin(BlockEntityType blockEntityType, BlockPos blockPos, BlockState blockState) 22 | { 23 | super(blockEntityType, blockPos, blockState); 24 | } 25 | 26 | @Inject(method = "onOpen", at = @At("HEAD")) 27 | private void playerOpenChestHook(PlayerEntity player, CallbackInfo ci) 28 | { 29 | if (!player.isCreative() && !player.isSpectator() && this.getCustomName() != null) { 30 | UhcGamePlayer.EnumStat stat; 31 | switch (this.getCustomName().getString()) { 32 | case BonusChestFeature.BONUS_CHEST_NAME: 33 | stat = UhcGamePlayer.EnumStat.CHEST_FOUND; 34 | break; 35 | case BonusChestFeature.EMPTY_CHEST_NAME: 36 | stat = UhcGamePlayer.EnumStat.EMPTY_CHEST_FOUND; 37 | break; 38 | default: 39 | stat = null; 40 | } 41 | if (stat != null) { 42 | UhcGameManager.instance.getUhcPlayerManager().getGamePlayer(player).getStat().addStat(stat, 1); 43 | } 44 | } 45 | } 46 | 47 | @Inject(method = "onClose", at = @At("HEAD")) 48 | private void playerCloseChestHook(PlayerEntity player, CallbackInfo ci) 49 | { 50 | if (!player.isCreative() && !player.isSpectator() && this.getCustomName() != null) 51 | { 52 | String customName = this.getCustomName().getString(); 53 | if (customName.equals(BonusChestFeature.BONUS_CHEST_NAME) || customName.equals(BonusChestFeature.EMPTY_CHEST_NAME)) 54 | { 55 | this.setCustomName(new LiteralText("Opened " + customName)); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/worldgen/ore/PlacedFeaturesMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.worldgen.ore; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.google.common.collect.Lists; 5 | import me.fallenbreath.tcuhc.options.Options; 6 | import me.fallenbreath.tcuhc.util.AverageIntProvider; 7 | import net.minecraft.world.gen.decorator.CountPlacementModifier; 8 | import net.minecraft.world.gen.decorator.PlacementModifier; 9 | import net.minecraft.world.gen.feature.*; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 14 | 15 | import java.util.List; 16 | 17 | @Mixin(PlacedFeatures.class) 18 | public abstract class PlacedFeaturesMixin 19 | { 20 | /** 21 | * oreFrequency = 4 -> CountPlacementModifier.of(1.0) 22 | */ 23 | private static final float ADJUST_RATIO = 0.25F; 24 | 25 | /** 26 | * See comments in {@link DefaultBiomeFeaturesMixin} 27 | */ 28 | private static final List ORES_TO_BE_MODIFIED_COUNT = new ImmutableList.Builder(). 29 | // add("ore_coal"). 30 | // add("ore_copper"). 31 | add("ore_lapis"). 32 | add("ore_iron"). 33 | // add("ore_redstone"). 34 | add("ore_gold"). 35 | add("ore_diamond"). 36 | // add("ore_emerald"). 37 | // add("ore_debris"). 38 | build(); 39 | 40 | /** 41 | * Hooks here so we can modify placements in {@link net.minecraft.world.gen.feature.OrePlacedFeatures} easier 42 | */ 43 | @Inject(method = "register", at = @At("HEAD")) 44 | private static void uhcModifyOreFrequency(String id, PlacedFeature placedFeature, CallbackInfoReturnable cir) 45 | { 46 | if (id.startsWith("ore_") && !id.endsWith("_nether") && ORES_TO_BE_MODIFIED_COUNT.stream().anyMatch(id::startsWith)) 47 | { 48 | PlacedFeatureAccessor pfa = (PlacedFeatureAccessor)placedFeature; 49 | ConfiguredFeature configuredFeature = pfa.getFeature().get(); 50 | if (configuredFeature.feature == Feature.ORE && configuredFeature.config instanceof OreFeatureConfig) 51 | { 52 | float frequency = Options.instance.getIntegerOptionValue("oreFrequency") * ADJUST_RATIO; 53 | List list = Lists.newArrayList(); 54 | list.add(CountPlacementModifier.of(new AverageIntProvider(frequency))); 55 | list.addAll(pfa.getPlacementModifiers()); 56 | pfa.setPlacementModifiers(list); 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/UhcGameTeam.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc; 6 | 7 | import com.google.common.collect.Lists; 8 | import me.fallenbreath.tcuhc.UhcGamePlayer.EnumStat; 9 | import net.minecraft.util.Formatting; 10 | 11 | import java.util.List; 12 | 13 | public class UhcGameTeam 14 | { 15 | 16 | private final List players = Lists.newArrayList(); 17 | private final TeamType type = new TeamType(); 18 | 19 | public UhcGameTeam setColorTeam(UhcGameColor color) { type.setColor(color); players.clear(); return this; } 20 | public UhcGameTeam setPlayerTeam(UhcGamePlayer player) { type.setPlayer(player); players.clear(); addPlayer(player); return this; } 21 | public String getTeamName() { return type.teamName; } 22 | public String getColorfulTeamName() { return type.getColorfulName(); } 23 | public UhcGameColor getTeamColor() { return type.color; } 24 | 25 | public UhcGameTeam addPlayer(UhcGamePlayer player) { players.add(player); player.setTeam(this); return this; } 26 | public UhcGameTeam removePlayer(UhcGamePlayer player) { players.remove(player); return this; } 27 | public Iterable getPlayers() { return players; } 28 | 29 | // The first player of the team is always the king 30 | public UhcGamePlayer getKing() { return UhcGameManager.getGameMode() == UhcGameManager.EnumMode.KING ? players.get(0) : null; } 31 | 32 | public void clearTeam() { 33 | players.clear(); 34 | } 35 | 36 | public int getAliveCount() { 37 | return (int) players.stream().filter(UhcGamePlayer::isAlive).count(); 38 | } 39 | 40 | public int getKillCount() { 41 | return (int) (players.stream().mapToDouble(player -> player.getStat().getFloatStat(EnumStat.PLAYER_KILLED)).sum() + 0.5); 42 | } 43 | 44 | public int getPlayerCount() { 45 | return players.size(); 46 | } 47 | 48 | static class TeamType { 49 | private UhcGameColor color = UhcGameColor.WHITE; 50 | private UhcGamePlayer player; 51 | private String name = "Team Empty", teamName = "Team Empty"; 52 | 53 | public void setColor(UhcGameColor color) { 54 | this.color = color; 55 | player = null; 56 | teamName = name = "Team " + color.name; 57 | } 58 | 59 | public void setPlayer(UhcGamePlayer player) { 60 | this.player = player; 61 | color = UhcGameColor.randomColor(); 62 | teamName = player.getName(); 63 | name = "Team " + teamName; 64 | } 65 | 66 | public String getColorfulName() { 67 | return color.chatColor + name + Formatting.RESET; 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/task/TaskBroadcastData.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.task; 6 | 7 | import com.google.common.collect.Lists; 8 | import com.mojang.datafixers.util.Pair; 9 | import me.fallenbreath.tcuhc.UhcGameManager; 10 | import me.fallenbreath.tcuhc.UhcGamePlayer; 11 | import me.fallenbreath.tcuhc.UhcGamePlayer.EnumStat; 12 | import me.fallenbreath.tcuhc.task.Task.TaskTimer; 13 | import net.minecraft.world.GameMode; 14 | 15 | import java.util.List; 16 | 17 | public class TaskBroadcastData extends TaskTimer { 18 | private int round = 0; 19 | 20 | public TaskBroadcastData(int delay) { 21 | super(delay, 20); 22 | } 23 | 24 | private String getGraph(int len) { 25 | StringBuilder res = new StringBuilder(); 26 | for (int i = 0; i < len; i++) 27 | res.append(i % 2 == 0 ? "[" : "]"); 28 | return res.toString(); 29 | } 30 | 31 | @Override 32 | public void onTimer() { 33 | UhcGameManager gameManager = UhcGameManager.instance; 34 | if (round == 0) { 35 | for (UhcGamePlayer player : gameManager.getUhcPlayerManager().getAllPlayers()) 36 | player.getRealPlayer().ifPresent(playermp -> playermp.changeGameMode(GameMode.SPECTATOR)); 37 | } 38 | 39 | while (true) { 40 | float max = 0; 41 | EnumStat stat = EnumStat.values()[round]; 42 | List> stats = Lists.newArrayList(); 43 | for (UhcGamePlayer player : gameManager.getUhcPlayerManager().getCombatPlayers()) { 44 | float value = player.getStat().getFloatStat(stat); 45 | max = Math.max(max, value); 46 | stats.add(Pair.of(player, value)); 47 | } 48 | 49 | stats.sort((A, B) -> B.getSecond().compareTo(A.getSecond())); 50 | for (int i = 0; i < stats.size(); i++) { 51 | Pair pair = stats.get(i); 52 | if (pair.getSecond() == 0 || (i >= 8 && pair.getSecond() < stats.get(i - 1).getSecond())) { 53 | stats.subList(i, stats.size()).clear(); 54 | break; 55 | } 56 | } 57 | 58 | if (!stats.isEmpty()) { 59 | gameManager.broadcastMessage(stat.name + ":"); 60 | for (Pair pair : stats) { 61 | gameManager.broadcastMessage(String.format(" %s%-40s %7.2f %s", pair.getFirst().getTeam().getTeamColor().chatColor, 62 | getGraph((int) (40 * pair.getSecond() / max)), pair.getSecond(), pair.getFirst().getName())); 63 | } 64 | } 65 | 66 | if (++round == EnumStat.values().length) 67 | setCanceled(); 68 | else if (stats.isEmpty()) 69 | continue; 70 | 71 | break; 72 | } 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/worldgen/ore/OreFeatureMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.worldgen.ore; 2 | 3 | import me.fallenbreath.tcuhc.gen.feature.UhcFeatures; 4 | import net.minecraft.block.BlockState; 5 | import net.minecraft.util.math.BlockPos; 6 | import net.minecraft.world.gen.feature.OreFeature; 7 | import net.minecraft.world.gen.feature.OreFeatureConfig; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 12 | 13 | import java.util.Random; 14 | import java.util.function.Function; 15 | 16 | @Mixin(OreFeature.class) 17 | public abstract class OreFeatureMixin 18 | { 19 | @Inject(method = "shouldPlace", at = @At("HEAD"), cancellable = true) 20 | private static void uhcValuableOreNeverHidesInBlocks(BlockState state, Function posToState, Random random, OreFeatureConfig config, OreFeatureConfig.Target target, BlockPos.Mutable pos, CallbackInfoReturnable cir) 21 | { 22 | if (UhcFeatures.isValuableOreBlock(target.state.getBlock())) 23 | { 24 | if (!isValidPositionForValuableOre(posToState, pos)) 25 | { 26 | cir.setReturnValue(false); 27 | } 28 | } 29 | } 30 | 31 | @Inject( 32 | method = "shouldPlace", 33 | at = @At( 34 | value = "INVOKE", 35 | target = "Lnet/minecraft/world/gen/feature/OreFeature;isExposedToAir(Ljava/util/function/Function;Lnet/minecraft/util/math/BlockPos;)Z" 36 | ), 37 | cancellable = true 38 | ) 39 | private static void uhcValuableOreLovesToBeExposedToAir(BlockState state, Function posToState, Random random, OreFeatureConfig config, OreFeatureConfig.Target target, BlockPos.Mutable pos, CallbackInfoReturnable cir) 40 | { 41 | if (UhcFeatures.isValuableOreBlock(target.state.getBlock())) 42 | { 43 | if (random.nextFloat() < config.discardOnAirChance * 0.5) 44 | { 45 | cir.setReturnValue(true); 46 | } 47 | } 48 | } 49 | 50 | /** 51 | * Not using {@link net.minecraft.world.gen.feature.Feature#isExposedToAir} here since we scan more than adjacent 52 | * blocks 53 | */ 54 | private static boolean isValidPositionForValuableOre(Function posToState, BlockPos pos) 55 | { 56 | for (int x = -1; x <= 1; x++) 57 | { 58 | for (int y = -1; y <= 1; y++) 59 | { 60 | for (int z = -1; z <= 1; z++) 61 | { 62 | if (posToState.apply(pos.add(x, y, z)).isAir()) 63 | { 64 | return true; 65 | } 66 | } 67 | } 68 | } 69 | return false; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/core/MinecraftServerMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.core; 2 | 3 | import me.fallenbreath.tcuhc.UhcGameManager; 4 | import net.minecraft.server.MinecraftServer; 5 | import net.minecraft.server.world.ServerWorld; 6 | import net.minecraft.util.math.BlockPos; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | 12 | @Mixin(MinecraftServer.class) 13 | public abstract class MinecraftServerMixin 14 | { 15 | private UhcGameManager uhcGameManager; 16 | private boolean serverInited = false; 17 | 18 | @Inject(method = "", at = @At("TAIL")) 19 | private void constructUhcGameManager(CallbackInfo ci) 20 | { 21 | this.uhcGameManager = new UhcGameManager((MinecraftServer)(Object)this); 22 | } 23 | 24 | @Inject( 25 | method = "createWorlds", 26 | at = @At( 27 | value = "INVOKE", 28 | target = "Ljava/util/Map;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 29 | ordinal = 0, 30 | shift = At.Shift.AFTER 31 | ) 32 | ) 33 | private void setSpawnPosTo00(CallbackInfo ci) 34 | { 35 | ServerWorld world = this.uhcGameManager.getOverWorld(); 36 | BlockPos spawnPos = BlockPos.ORIGIN.up(world.getChunkManager().getChunkGenerator().getSpawnHeight(world)); 37 | float spawnAngle = world.getSpawnAngle(); 38 | world.setSpawnPos(spawnPos, spawnAngle); 39 | } 40 | 41 | @Inject( 42 | method = "runServer", 43 | at = @At( 44 | value = "INVOKE", 45 | target = "Lnet/minecraft/server/MinecraftServer;setFavicon(Lnet/minecraft/server/ServerMetadata;)V" 46 | ) 47 | ) 48 | private void postInitUhcGameManager(CallbackInfo ci) 49 | { 50 | this.uhcGameManager.onServerInited(); 51 | this.serverInited = true; 52 | } 53 | 54 | @Inject(method = "tick", at = @At(value = "HEAD")) 55 | private void tickDurationSamplingStart(CallbackInfo ci) 56 | { 57 | this.uhcGameManager.msptRecorder.startTick(); 58 | } 59 | 60 | @Inject( 61 | method = "runTasksTillTickEnd", 62 | at = @At( 63 | value = "INVOKE", 64 | target = "Lnet/minecraft/server/MinecraftServer;runTasks(Ljava/util/function/BooleanSupplier;)V" 65 | ) 66 | ) 67 | private void tickDurationSamplingEnd(CallbackInfo ci) 68 | { 69 | if (this.serverInited) 70 | { 71 | this.uhcGameManager.msptRecorder.endTick(); 72 | } 73 | } 74 | 75 | @Inject( 76 | method = "tick", 77 | at = @At( 78 | value = "CONSTANT", 79 | args = "stringValue=tallying" 80 | ) 81 | ) 82 | private void tickUhcGameManager(CallbackInfo ci) 83 | { 84 | this.uhcGameManager.tick(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/item/LivingEntityMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.item; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.mojang.datafixers.util.Pair; 5 | import net.minecraft.entity.LivingEntity; 6 | import net.minecraft.entity.effect.StatusEffect; 7 | import net.minecraft.entity.effect.StatusEffectInstance; 8 | import net.minecraft.entity.effect.StatusEffects; 9 | import net.minecraft.item.ItemStack; 10 | import net.minecraft.item.Items; 11 | import net.minecraft.world.World; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.Unique; 14 | import org.spongepowered.asm.mixin.injection.At; 15 | import org.spongepowered.asm.mixin.injection.Inject; 16 | import org.spongepowered.asm.mixin.injection.Redirect; 17 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 18 | 19 | import java.util.Iterator; 20 | import java.util.List; 21 | 22 | @Mixin(LivingEntity.class) 23 | public abstract class LivingEntityMixin 24 | { 25 | @Unique 26 | private int goldenAppleLevel; 27 | 28 | @Inject( 29 | method = "applyFoodEffects", 30 | at = @At( 31 | value = "INVOKE", 32 | target = "Ljava/util/List;iterator()Ljava/util/Iterator;" 33 | ) 34 | ) 35 | private void modifyEffects(ItemStack stack, World world, LivingEntity targetEntity, CallbackInfo ci) 36 | { 37 | if (stack.getItem() == Items.GOLDEN_APPLE && stack.getNbt() != null) 38 | { 39 | this.goldenAppleLevel = stack.getNbt().getInt("level"); 40 | } 41 | else 42 | { 43 | this.goldenAppleLevel = 0; 44 | } 45 | } 46 | 47 | @SuppressWarnings("ConstantConditions") 48 | @Redirect( 49 | method = "applyFoodEffects", 50 | at = @At( 51 | value = "INVOKE", 52 | target = "Ljava/util/List;iterator()Ljava/util/Iterator;" 53 | ) 54 | ) 55 | private Iterator> modifyIterator(List> list) 56 | { 57 | int level = this.goldenAppleLevel; 58 | if (level > 0) 59 | { 60 | List> newList = Lists.newArrayList(list); 61 | for (int i = 0; i < newList.size(); i++) 62 | { 63 | StatusEffectInstance effect = newList.get(i).getFirst(); 64 | float chance = newList.get(i).getSecond(); 65 | StatusEffectInstance newEffect = new StatusEffectInstance(effect); 66 | StatusEffect effectType = newEffect.getEffectType(); 67 | if (effectType == StatusEffects.REGENERATION) 68 | { 69 | ((StatusEffectInstanceAccessor)newEffect).setDuration((level + 1) * 20); 70 | } 71 | else if (effectType == StatusEffects.ABSORPTION) 72 | { 73 | ((StatusEffectInstanceAccessor)newEffect).setAmplifier(level - 1); 74 | } 75 | newList.set(i, Pair.of(newEffect, chance)); 76 | } 77 | return newList.iterator(); 78 | } 79 | return list.iterator(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/entity/SpectralArrowEntityMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.entity; 2 | 3 | import net.minecraft.block.BlockState; 4 | import net.minecraft.block.Blocks; 5 | import net.minecraft.entity.EntityType; 6 | import net.minecraft.entity.LivingEntity; 7 | import net.minecraft.entity.projectile.PersistentProjectileEntity; 8 | import net.minecraft.entity.projectile.SpectralArrowEntity; 9 | import net.minecraft.fluid.FluidState; 10 | import net.minecraft.util.hit.HitResult; 11 | import net.minecraft.util.math.BlockPos; 12 | import net.minecraft.world.World; 13 | import net.minecraft.world.explosion.Explosion; 14 | import org.spongepowered.asm.mixin.Intrinsic; 15 | import org.spongepowered.asm.mixin.Mixin; 16 | import org.spongepowered.asm.mixin.Unique; 17 | import org.spongepowered.asm.mixin.injection.At; 18 | import org.spongepowered.asm.mixin.injection.Inject; 19 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 20 | 21 | @Mixin(SpectralArrowEntity.class) 22 | public abstract class SpectralArrowEntityMixin extends PersistentProjectileEntity 23 | { 24 | protected SpectralArrowEntityMixin(EntityType entityType, World world) 25 | { 26 | super(entityType, world); 27 | } 28 | 29 | @Inject(method = "onHit", at = @At("TAIL")) 30 | private void onKill(LivingEntity target, CallbackInfo ci) 31 | { 32 | this.explode(); 33 | } 34 | 35 | @Intrinsic 36 | @Override 37 | protected void onCollision(HitResult hitResult) 38 | { 39 | if (hitResult.getType() == HitResult.Type.BLOCK && this.isCritical()) 40 | { 41 | this.updatePosition(hitResult.getPos().getX(), hitResult.getPos().getY(), hitResult.getPos().getZ()); 42 | this.explode(); 43 | } 44 | 45 | if (!this.isRemoved()) 46 | { 47 | super.onCollision(hitResult); 48 | } 49 | } 50 | 51 | @Unique 52 | private float getExplosionResistance(World world, BlockPos blockPos) 53 | { 54 | BlockState blockState = this.world.getBlockState(blockPos); 55 | FluidState fluidState = this.world.getFluidState(blockPos); 56 | return Math.max(blockState.getBlock().getBlastResistance(), fluidState.getBlastResistance()); 57 | } 58 | 59 | @Unique 60 | private void explode() 61 | { 62 | if (!this.isCritical() || this.isRemoved()) 63 | { 64 | return; 65 | } 66 | this.discard(); 67 | this.world.createExplosion(this, this.getPos().getX(), this.getPos().getY(), this.getPos().getZ(), 1.0F, Explosion.DestructionType.DESTROY); 68 | BlockPos arrowpos = new BlockPos(this.getPos()); 69 | if (getExplosionResistance(world, arrowpos) > 6.01f) 70 | { 71 | return; 72 | } 73 | for (int x = -1; x <= 1; x++) 74 | { 75 | for (int y = -2; y <= 1; y++) 76 | { 77 | for (int z = -1; z <= 1; z++) 78 | { 79 | BlockPos pos = arrowpos.add(x, y, z); 80 | if (getExplosionResistance(world, pos) < 6.01f) 81 | { 82 | this.world.setBlockState(pos, Blocks.AIR.getDefaultState()); 83 | } 84 | } 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /src/main/resources/tcuhc.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "me.fallenbreath.tcuhc.mixins", 5 | "compatibilityLevel": "JAVA_8", 6 | "mixins": [ 7 | "block.ChestBlockEntityMixin", 8 | "block.LootManagerMixin", 9 | "block.OreBlockMixin", 10 | "core.CommandManagerMixin", 11 | "core.LevelStorageMixin", 12 | "core.MinecraftServerAccessor", 13 | "core.MinecraftServerMixin", 14 | "core.PlayerManagerMixin", 15 | "core.SessionAccessor", 16 | "entity.AbstractMinecartEntityMixin", 17 | "entity.BoatEntityMixin", 18 | "entity.DrownedEntityMixin", 19 | "entity.EndCrystalEntityMixin", 20 | "entity.EntityCategoryMixin", 21 | "entity.EntityDamageSourceMixin", 22 | "entity.LivingEntityMixin", 23 | "entity.MobEntityAccessor", 24 | "entity.MobEntityMixin", 25 | "entity.PersistentProjectileEntityMixin", 26 | "entity.PlayerEntityMixin", 27 | "entity.PlayerInventoryMixin", 28 | "entity.ServerPlayerEntityMixin", 29 | "entity.ServerWorldMixin", 30 | "entity.SpectralArrowEntityMixin", 31 | "entity.StatusEffectInstanceMixin", 32 | "entity.TradeOffersEnchantBookFactoryMixin", 33 | "entity.VillagerEntityMixin", 34 | "entity.WitchEntityMixin", 35 | "feature.HorizontalConnectingBlockAccessor", 36 | "feature.structure.StructureFeatureAccessor", 37 | "feature.structure.StructuresConfigAccessor", 38 | "feature.structure.WeightedListAccessor", 39 | "item.AbsorptionStatusEffectMixin", 40 | "item.ChorusFruitMixin", 41 | "item.FlowerBlockMixin", 42 | "item.FoodComponentBuilderMixin", 43 | "item.ItemMixin", 44 | "item.ItemStackMixin", 45 | "item.LivingEntityMixin", 46 | "item.PlayerEntityMixin", 47 | "item.StatusEffectInstanceAccessor", 48 | "loot.ItemEntryAccessor", 49 | "loot.LootManagerAccessor", 50 | "loot.LootPoolMixin", 51 | "loot.LootTableMixin", 52 | "network.ServerPlayNetworkHandlerMixin", 53 | "recipe.RegistryMixin", 54 | "recipe.SynchronizeRecipesS2CPacketMixin", 55 | "task.PlayerListHeaderS2CPacketAccessor", 56 | "task.ServerChunkManagerAccessor", 57 | "util.SheepEntityAccessor", 58 | "worldgen.feature.BastionRemnantFeatureMixin", 59 | "worldgen.feature.ConfiguredStructureFeaturesMixin", 60 | "worldgen.feature.DefaultBiomeFeaturesMixin", 61 | "worldgen.feature.NetherFortressFeatureMixin", 62 | "worldgen.feature.StructureFeatureMixin", 63 | "worldgen.ore.DefaultBiomeFeaturesMixin", 64 | "worldgen.ore.OreFeatureMixin", 65 | "worldgen.ore.PlacedFeatureAccessor", 66 | "worldgen.ore.PlacedFeaturesMixin", 67 | "worldgen.structure.BuriedTreasureFeatureMixin", 68 | "worldgen.structure.ShipwreckFeatureMixin", 69 | "worldgen.structure.StructuresConfigMixin", 70 | "worldgen.world.CaveCarverMixin", 71 | "worldgen.world.NoiseColumnSamplerMixin", 72 | "worldgen.world.StructuresConfigMixin" 73 | ], 74 | "client": [ 75 | ], 76 | "injectors": { 77 | "defaultRequire": 1 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/worldgen/feature/ConfiguredStructureFeaturesMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.worldgen.feature; 2 | 3 | import me.fallenbreath.tcuhc.gen.structure.UhcStructures; 4 | import net.minecraft.util.registry.RegistryKey; 5 | import net.minecraft.world.biome.Biome; 6 | import net.minecraft.world.biome.BiomeKeys; 7 | import net.minecraft.world.gen.ProbabilityConfig; 8 | import net.minecraft.world.gen.feature.*; 9 | import org.spongepowered.asm.mixin.Final; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.Shadow; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 15 | import org.spongepowered.asm.mixin.injection.callback.LocalCapture; 16 | 17 | import java.util.Set; 18 | import java.util.function.BiConsumer; 19 | 20 | @Mixin(ConfiguredStructureFeatures.class) 21 | public abstract class ConfiguredStructureFeaturesMixin 22 | { 23 | @Shadow @Final private static ConfiguredStructureFeature> BASTION_REMNANT; 24 | 25 | @Shadow @Final private static ConfiguredStructureFeature> SHIPWRECK; 26 | 27 | @Shadow @Final private static ConfiguredStructureFeature> BURIED_TREASURE; 28 | 29 | @Shadow 30 | private static void register(BiConsumer, RegistryKey> registrar, ConfiguredStructureFeature feature, RegistryKey biome) 31 | { 32 | } 33 | 34 | @Shadow 35 | private static void register(BiConsumer, RegistryKey> registrar, ConfiguredStructureFeature feature, Set> biomes) 36 | { 37 | } 38 | 39 | @Inject(method = "registerAll", at = @At("TAIL"), locals = LocalCapture.CAPTURE_FAILHARD) 40 | private static void applyUhcTweaks( 41 | BiConsumer, RegistryKey> registrar, CallbackInfo ci, 42 | Set> deepOcean, Set> ocean, Set> beach, Set> river, 43 | Set> peak, Set> badland, Set> hill, Set> taiga, 44 | Set> jungle, Set> forest, Set> nether 45 | ) 46 | { 47 | // ======== Vanilla Structure tweaks ======== 48 | 49 | // allow BastionRemnant to generate in basalt deltas 50 | register(registrar, BASTION_REMNANT, BiomeKeys.BASALT_DELTAS); 51 | // allow ocean shipwecks and buried treasures to generate in rivers 52 | register(registrar, SHIPWRECK, river); 53 | register(registrar, BURIED_TREASURE, river); 54 | 55 | // ======== UHC Structures ======== 56 | UhcStructures.bindUhcStructureToBiomes((csf, key) -> register(registrar, csf, key), deepOcean, ocean, beach, river, peak, badland, hill, taiga, jungle, forest, nether); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/resources/data/tcuhc/loot_tables/ender_pyramid/chest.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "rolls": 1, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "name": "minecraft:diamond_sword", 10 | "weight": 2, 11 | "functions": [{"function": "minecraft:set_damage", "damage": {"type": "minecraft:uniform", "min": 0.5, "max": 0.8}}] 12 | }, 13 | { 14 | "type": "minecraft:item", 15 | "name": "minecraft:diamond_axe", 16 | "weight": 2, 17 | "functions": [{"function": "minecraft:set_damage", "damage": {"type": "minecraft:uniform", "min": 0.5, "max": 0.8}}] 18 | }, 19 | { 20 | "type": "minecraft:item", 21 | "name": "minecraft:diamond_pickaxe", 22 | "weight": 2, 23 | "functions": [{"function": "minecraft:set_damage", "damage": {"type": "minecraft:uniform", "min": 0.5, "max": 0.8}}] 24 | }, 25 | { 26 | "type": "minecraft:item", 27 | "name": "minecraft:diamond_shovel", 28 | "weight": 2, 29 | "functions": [{"function": "minecraft:set_damage", "damage": {"type": "minecraft:uniform", "min": 0.5, "max": 0.8}}] 30 | }, 31 | { 32 | "type": "minecraft:item", 33 | "name": "minecraft:diamond_hoe", 34 | "weight": 2, 35 | "functions": [{"function": "minecraft:set_damage", "damage": {"type": "minecraft:uniform", "min": 0.5, "max": 0.8}}] 36 | }, 37 | { 38 | "type": "minecraft:item", 39 | "name": "minecraft:diamond_helmet", 40 | "weight": 1, 41 | "functions": [{"function": "minecraft:set_damage", "damage": {"type": "minecraft:uniform", "min": 0.5, "max": 0.8}}] 42 | }, 43 | { 44 | "type": "minecraft:item", 45 | "name": "minecraft:diamond_chestplate", 46 | "weight": 1, 47 | "functions": [{"function": "minecraft:set_damage", "damage": {"type": "minecraft:uniform", "min": 0.5, "max": 0.8}}] 48 | }, 49 | { 50 | "type": "minecraft:item", 51 | "name": "minecraft:diamond_leggings", 52 | "weight": 1, 53 | "functions": [{"function": "minecraft:set_damage", "damage": {"type": "minecraft:uniform", "min": 0.5, "max": 0.8}}] 54 | }, 55 | { 56 | "type": "minecraft:item", 57 | "name": "minecraft:diamond_boots", 58 | "weight": 1, 59 | "functions": [{"function": "minecraft:set_damage", "damage": {"type": "minecraft:uniform", "min": 0.5, "max": 0.8}}] 60 | } 61 | ] 62 | }, 63 | { 64 | "rolls": 1, 65 | "entries": [ 66 | { 67 | "type": "minecraft:item", 68 | "name": "minecraft:book", 69 | "functions": [ 70 | { 71 | "function": "minecraft:enchant_with_levels", 72 | "levels": { 73 | "type": "minecraft:uniform", 74 | "min": 25, 75 | "max": 35 76 | }, 77 | "treasure": true 78 | } 79 | ] 80 | } 81 | ] 82 | } 83 | ] 84 | } -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/block/LootManagerMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.block; 2 | 3 | import com.google.common.collect.Lists; 4 | import me.fallenbreath.tcuhc.UhcGameManager; 5 | import me.fallenbreath.tcuhc.interfaces.LootPoolAccessor; 6 | import me.fallenbreath.tcuhc.interfaces.LootTableAccessor; 7 | import me.fallenbreath.tcuhc.mixins.loot.ItemEntryAccessor; 8 | import me.fallenbreath.tcuhc.util.LootTableUtil; 9 | import net.minecraft.block.Block; 10 | import net.minecraft.block.Blocks; 11 | import net.minecraft.block.LeavesBlock; 12 | import net.minecraft.item.Items; 13 | import net.minecraft.loot.LootManager; 14 | import net.minecraft.loot.LootPool; 15 | import net.minecraft.loot.LootTable; 16 | import net.minecraft.loot.entry.ItemEntry; 17 | import net.minecraft.loot.entry.LootPoolEntry; 18 | import net.minecraft.util.Identifier; 19 | import net.minecraft.util.registry.Registry; 20 | import org.apache.logging.log4j.Logger; 21 | import org.spongepowered.asm.mixin.Mixin; 22 | import org.spongepowered.asm.mixin.Shadow; 23 | import org.spongepowered.asm.mixin.injection.At; 24 | import org.spongepowered.asm.mixin.injection.Inject; 25 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 26 | 27 | import java.util.List; 28 | import java.util.Map; 29 | 30 | @Mixin(LootManager.class) 31 | public abstract class LootManagerMixin 32 | { 33 | @Shadow private Map tables; 34 | 35 | @Inject(method = "apply", at = @At("TAIL")) 36 | private void uhcBlockLootAdjust(CallbackInfo ci) 37 | { 38 | Logger logger = UhcGameManager.LOG; 39 | LootPool uhcAppleDrop = LootTableUtil.getUhcLootPool("apple"); 40 | LootPoolEntry uhcGlowStoneDrop = LootTableUtil.getUhcLootEntry("glowstone"); 41 | LootPoolEntry uhcLapisOreDrop = LootTableUtil.getUhcLootEntry("lapis_ore"); 42 | 43 | this.tables.forEach((id, table) -> { 44 | Block block = Registry.BLOCK.get(new Identifier(id.getNamespace(), id.getPath().replace("blocks/", ""))); 45 | LootTableAccessor tableAccessor = (LootTableAccessor)table; 46 | if (block instanceof LeavesBlock) 47 | { 48 | List lootPools = Lists.newArrayList(tableAccessor.getPools()); 49 | boolean modified = false; 50 | for (int i = 0; i < lootPools.size(); i++) 51 | { 52 | LootPoolEntry[] lootEntries = ((LootPoolAccessor)lootPools.get(i)).getEntries(); 53 | if (lootEntries.length == 1 && lootEntries[0] instanceof ItemEntry && ((ItemEntryAccessor)lootEntries[0]).getItem() == Items.APPLE) 54 | { 55 | lootPools.set(i, uhcAppleDrop); 56 | logger.info("Modified apple drop of {}", block); 57 | modified = true; 58 | } 59 | } 60 | if (!modified) 61 | { 62 | lootPools.add(uhcAppleDrop); 63 | logger.info("Appended apple drop to {}", block); 64 | } 65 | tableAccessor.setPools(lootPools.toArray(new LootPool[0])); 66 | } 67 | else if (block == Blocks.GLOWSTONE || block == Blocks.LAPIS_ORE || block == Blocks.DEEPSLATE_LAPIS_ORE) 68 | { 69 | if (tableAccessor.getPools().length == 1) 70 | { 71 | LootPoolEntry lootEntry = block == Blocks.GLOWSTONE ? uhcGlowStoneDrop : uhcLapisOreDrop; 72 | ((LootPoolAccessor)tableAccessor.getPools()[0]).setEntries(new LootPoolEntry[]{lootEntry}); 73 | } 74 | logger.info("Modified drop of {}", block); 75 | } 76 | }); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/gen/structure/HoneyWorkshopStructure.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.gen.structure; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.mojang.serialization.Codec; 5 | import me.fallenbreath.tcuhc.TcUhcMod; 6 | import me.fallenbreath.tcuhc.util.UhcRegistry; 7 | import net.minecraft.block.Block; 8 | import net.minecraft.block.Blocks; 9 | import net.minecraft.nbt.NbtCompound; 10 | import net.minecraft.structure.*; 11 | import net.minecraft.util.BlockRotation; 12 | import net.minecraft.util.Identifier; 13 | import net.minecraft.util.math.BlockBox; 14 | import net.minecraft.util.math.BlockPos; 15 | import net.minecraft.util.math.ChunkPos; 16 | import net.minecraft.world.Heightmap; 17 | import net.minecraft.world.ServerWorldAccess; 18 | import net.minecraft.world.StructureWorldAccess; 19 | import net.minecraft.world.gen.StructureAccessor; 20 | import net.minecraft.world.gen.chunk.ChunkGenerator; 21 | import net.minecraft.world.gen.feature.DefaultFeatureConfig; 22 | 23 | import java.util.List; 24 | import java.util.Random; 25 | 26 | public class HoneyWorkshopStructure extends SinglePieceLandStructure 27 | { 28 | private static final StructurePieceType PIECE_TYPE = UhcRegistry.registerStructurePieceType(Piece::new, "honey_workshop_piece"); 29 | 30 | private static final Identifier MAIN_TEMPLATE = TcUhcMod.id("honey_workshop/main"); 31 | private static final Identifier CHEST_LOOT_TABLE = TcUhcMod.id("honey_workshop/chest"); 32 | 33 | private static final List BASE_BLOCKS = ImmutableList.of(Blocks.STONE_BRICKS); 34 | private static final int FLOOR_HEIGHT = 0; 35 | 36 | public HoneyWorkshopStructure(Codec configCodec) 37 | { 38 | super(configCodec, StructureGeneratorFactory.simple(StructureGeneratorFactory.checkForBiomeOnTop(Heightmap.Type.WORLD_SURFACE_WG), HoneyWorkshopStructure::addPieces), HoneyWorkshopStructure::postGenerated); 39 | } 40 | 41 | private static void addPieces(StructurePiecesCollector collector, StructurePiecesGenerator.Context context) 42 | { 43 | BlockRotation rotation = BlockRotation.random(context.random()); 44 | collector.addPiece(new Piece(context.structureManager(), MAIN_TEMPLATE, shiftStartPosRandomly(context), rotation)); 45 | } 46 | 47 | private static void postGenerated(StructureWorldAccess world, StructureAccessor structureAccessor, ChunkGenerator chunkGenerator, Random random, BlockBox chunkBox, ChunkPos chunkPos, StructurePiecesList children) 48 | { 49 | fillBottomAirGapInAutoBox(world, random, chunkBox, children, BASE_BLOCKS, BASE_BLOCKS, FLOOR_HEIGHT); 50 | } 51 | 52 | private static class Piece extends SinglePieceLandStructure.Piece 53 | { 54 | public Piece(StructureManager manager, Identifier identifier, BlockPos pos, BlockRotation rotation) 55 | { 56 | super(PIECE_TYPE, manager, identifier, pos, rotation); 57 | } 58 | 59 | public Piece(StructureManager manager, NbtCompound nbt) 60 | { 61 | super(PIECE_TYPE, manager, nbt); 62 | } 63 | 64 | @Override 65 | protected void handleMetadata(String metadata, BlockPos pos, ServerWorldAccess world, Random random, BlockBox boundingBox) 66 | { 67 | if ("chest".equals(metadata)) 68 | { 69 | world.setBlockState(pos, Blocks.AIR.getDefaultState(), Block.NOTIFY_ALL); 70 | setChestLoot(world, pos.down(), random, CHEST_LOOT_TABLE); 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/util/ColorUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.util; 6 | 7 | import com.google.common.collect.ImmutableMap; 8 | import net.minecraft.block.Block; 9 | import net.minecraft.block.Blocks; 10 | import net.minecraft.util.DyeColor; 11 | 12 | public class ColorUtil 13 | { 14 | private static final ImmutableMap MAPPING = new ImmutableMap.Builder(). 15 | put(DyeColor.WHITE, new ColorfulBlocks(Blocks.WHITE_WOOL, Blocks.WHITE_STAINED_GLASS, Blocks.WHITE_STAINED_GLASS_PANE, Blocks.WHITE_CARPET)). 16 | put(DyeColor.ORANGE, new ColorfulBlocks(Blocks.ORANGE_WOOL, Blocks.ORANGE_STAINED_GLASS, Blocks.ORANGE_STAINED_GLASS_PANE, Blocks.ORANGE_CARPET)). 17 | put(DyeColor.MAGENTA, new ColorfulBlocks(Blocks.MAGENTA_WOOL, Blocks.MAGENTA_STAINED_GLASS, Blocks.MAGENTA_STAINED_GLASS_PANE, Blocks.MAGENTA_CARPET)). 18 | put(DyeColor.LIGHT_BLUE, new ColorfulBlocks(Blocks.LIGHT_BLUE_WOOL, Blocks.LIGHT_BLUE_STAINED_GLASS, Blocks.LIGHT_BLUE_STAINED_GLASS_PANE, Blocks.LIGHT_BLUE_CARPET)). 19 | put(DyeColor.YELLOW, new ColorfulBlocks(Blocks.YELLOW_WOOL, Blocks.YELLOW_STAINED_GLASS, Blocks.YELLOW_STAINED_GLASS_PANE, Blocks.YELLOW_CARPET)). 20 | put(DyeColor.LIME, new ColorfulBlocks(Blocks.LIME_WOOL, Blocks.LIME_STAINED_GLASS, Blocks.LIME_STAINED_GLASS_PANE, Blocks.LIME_CARPET)). 21 | put(DyeColor.PINK, new ColorfulBlocks(Blocks.PINK_WOOL, Blocks.PINK_STAINED_GLASS, Blocks.PINK_STAINED_GLASS_PANE, Blocks.PINK_CARPET)). 22 | put(DyeColor.GRAY, new ColorfulBlocks(Blocks.GRAY_WOOL, Blocks.GRAY_STAINED_GLASS, Blocks.GRAY_STAINED_GLASS_PANE, Blocks.GRAY_CARPET)). 23 | put(DyeColor.LIGHT_GRAY, new ColorfulBlocks(Blocks.LIGHT_GRAY_WOOL, Blocks.LIGHT_GRAY_STAINED_GLASS, Blocks.LIGHT_GRAY_STAINED_GLASS_PANE, Blocks.LIGHT_GRAY_CARPET)). 24 | put(DyeColor.CYAN, new ColorfulBlocks(Blocks.CYAN_WOOL, Blocks.CYAN_STAINED_GLASS, Blocks.CYAN_STAINED_GLASS_PANE, Blocks.CYAN_CARPET)). 25 | put(DyeColor.PURPLE, new ColorfulBlocks(Blocks.PURPLE_WOOL, Blocks.PURPLE_STAINED_GLASS, Blocks.PURPLE_STAINED_GLASS_PANE, Blocks.PURPLE_CARPET)). 26 | put(DyeColor.BLUE, new ColorfulBlocks(Blocks.BLUE_WOOL, Blocks.BLUE_STAINED_GLASS, Blocks.BLUE_STAINED_GLASS_PANE, Blocks.BLUE_CARPET)). 27 | put(DyeColor.BROWN, new ColorfulBlocks(Blocks.BROWN_WOOL, Blocks.BROWN_STAINED_GLASS, Blocks.BROWN_STAINED_GLASS_PANE, Blocks.BROWN_CARPET)). 28 | put(DyeColor.GREEN, new ColorfulBlocks(Blocks.GREEN_WOOL, Blocks.GREEN_STAINED_GLASS, Blocks.GREEN_STAINED_GLASS_PANE, Blocks.GREEN_CARPET)). 29 | put(DyeColor.RED, new ColorfulBlocks(Blocks.RED_WOOL, Blocks.RED_STAINED_GLASS, Blocks.RED_STAINED_GLASS_PANE, Blocks.RED_CARPET)). 30 | put(DyeColor.BLACK, new ColorfulBlocks(Blocks.BLACK_WOOL, Blocks.BLACK_STAINED_GLASS, Blocks.BLACK_STAINED_GLASS_PANE, Blocks.BLACK_CARPET)). 31 | build(); 32 | 33 | public static ColorfulBlocks fromColor(DyeColor color) 34 | { 35 | return MAPPING.get(color); 36 | } 37 | 38 | public static class ColorfulBlocks 39 | { 40 | public final Block wool; 41 | public final Block glass; 42 | public final Block glassPane; 43 | public final Block carpet; 44 | 45 | private ColorfulBlocks(Block wool, Block glass, Block glassPane, Block carpet) 46 | { 47 | this.wool = wool; 48 | this.glass = glass; 49 | this.glassPane = glassPane; 50 | this.carpet = carpet; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/entity/EndCrystalEntityMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.entity; 2 | 3 | import net.minecraft.entity.Entity; 4 | import net.minecraft.entity.EntityType; 5 | import net.minecraft.entity.damage.EntityDamageSource; 6 | import net.minecraft.entity.decoration.EndCrystalEntity; 7 | import net.minecraft.entity.player.PlayerEntity; 8 | import net.minecraft.sound.SoundCategory; 9 | import net.minecraft.sound.SoundEvents; 10 | import net.minecraft.util.math.BlockPos; 11 | import net.minecraft.world.World; 12 | import org.jetbrains.annotations.Nullable; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.Shadow; 15 | import org.spongepowered.asm.mixin.Unique; 16 | import org.spongepowered.asm.mixin.injection.At; 17 | import org.spongepowered.asm.mixin.injection.Inject; 18 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 19 | 20 | @Mixin(EndCrystalEntity.class) 21 | public abstract class EndCrystalEntityMixin extends Entity 22 | { 23 | @Unique 24 | private PlayerEntity target; 25 | 26 | @Unique 27 | private static final double MAX_RANGE_SQR = 32 * 32; 28 | 29 | @Unique 30 | private int attackCooldown; 31 | 32 | @Shadow 33 | public abstract void setBeamTarget(@Nullable BlockPos blockPos); 34 | 35 | public EndCrystalEntityMixin(EntityType type, World world) 36 | { 37 | super(type, world); 38 | } 39 | 40 | @Inject(method = "tick", at = @At("TAIL")) 41 | private void onTick(CallbackInfo ci) 42 | { 43 | if (!this.world.isClient()) 44 | { 45 | this.setBeamTarget(this.target == null ? null : new BlockPos(this.target.getPos().getX(), this.target.getPos().getY() - 0.5, this.target.getPos().getZ())); 46 | 47 | double distanceSqrToTarget = this.target == null ? MAX_RANGE_SQR : this.target.squaredDistanceTo(this); 48 | if (this.target != null && distanceSqrToTarget < MAX_RANGE_SQR && this.target.canSee(this)) // has valid target 49 | { 50 | this.attackCooldown--; 51 | if (this.attackCooldown <= 0) 52 | { 53 | float amount; 54 | if (distanceSqrToTarget < 8 * 8) 55 | { 56 | amount = 2.0F; 57 | this.attackCooldown = 25; 58 | } 59 | else if (distanceSqrToTarget < 16 * 16) 60 | { 61 | amount = 1.5F; 62 | this.attackCooldown = 28; 63 | } 64 | else 65 | { 66 | amount = 1.0F; 67 | this.attackCooldown = 30; 68 | } 69 | this.target.damage(new EntityDamageSource("mob", this), amount); 70 | } 71 | } 72 | else // no target 73 | { 74 | // reset 75 | this.target = null; 76 | this.attackCooldown = 40; 77 | 78 | if (this.age % 5 == 0) // search target every 5gt 79 | { 80 | double maxDistance = MAX_RANGE_SQR; 81 | for (PlayerEntity player : this.world.getNonSpectatingEntities(PlayerEntity.class, this.getBoundingBox().expand(32, 10, 32))) 82 | { 83 | if (player.isCreative() || player.isSpectator()) 84 | { 85 | continue; 86 | } 87 | 88 | double newdis = player.squaredDistanceTo(this); 89 | if (newdis < maxDistance && player.canSee(this)) 90 | { 91 | maxDistance = newdis; 92 | this.target = player; 93 | } 94 | } 95 | if (this.target != null) // target found 96 | { 97 | this.target.playSound(SoundEvents.ENTITY_GUARDIAN_ATTACK, SoundCategory.HOSTILE, 1.0F, 1.0F); 98 | } 99 | } 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/gen/structure/EnderPyramidStructure.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.gen.structure; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.mojang.serialization.Codec; 5 | import me.fallenbreath.tcuhc.TcUhcMod; 6 | import me.fallenbreath.tcuhc.util.UhcRegistry; 7 | import net.minecraft.block.Block; 8 | import net.minecraft.block.Blocks; 9 | import net.minecraft.nbt.NbtCompound; 10 | import net.minecraft.structure.*; 11 | import net.minecraft.util.BlockRotation; 12 | import net.minecraft.util.Identifier; 13 | import net.minecraft.util.math.BlockBox; 14 | import net.minecraft.util.math.BlockPos; 15 | import net.minecraft.util.math.ChunkPos; 16 | import net.minecraft.world.Heightmap; 17 | import net.minecraft.world.ServerWorldAccess; 18 | import net.minecraft.world.StructureWorldAccess; 19 | import net.minecraft.world.gen.StructureAccessor; 20 | import net.minecraft.world.gen.chunk.ChunkGenerator; 21 | import net.minecraft.world.gen.feature.DefaultFeatureConfig; 22 | 23 | import java.util.List; 24 | import java.util.Random; 25 | 26 | public class EnderPyramidStructure extends SinglePieceLandStructure 27 | { 28 | private static final StructurePieceType PIECE_TYPE = UhcRegistry.registerStructurePieceType(Piece::new, "ender_pyramid_piece"); 29 | 30 | private static final Identifier MAIN_TEMPLATE = TcUhcMod.id("ender_pyramid/main"); 31 | private static final Identifier CHEST_LOOT_TABLE = TcUhcMod.id("ender_pyramid/chest"); 32 | private static final List BASE_BLOCKS = ImmutableList.of( 33 | Blocks.STONE_BRICKS, Blocks.CRACKED_STONE_BRICKS, Blocks.MOSSY_STONE_BRICKS, 34 | Blocks.COBBLESTONE, Blocks.COBBLESTONE, Blocks.INFESTED_COBBLESTONE, Blocks.MOSSY_COBBLESTONE 35 | ); 36 | 37 | public EnderPyramidStructure(Codec configCodec) 38 | { 39 | super(configCodec, StructureGeneratorFactory.simple(StructureGeneratorFactory.checkForBiomeOnTop(Heightmap.Type.WORLD_SURFACE_WG), EnderPyramidStructure::addPieces), EnderPyramidStructure::postGenerated); 40 | } 41 | 42 | private static void addPieces(StructurePiecesCollector collector, StructurePiecesGenerator.Context context) 43 | { 44 | BlockRotation rotation = BlockRotation.random(context.random()); 45 | collector.addPiece(new Piece(context.structureManager(), MAIN_TEMPLATE, shiftStartPosRandomly(context), rotation)); 46 | } 47 | 48 | private static void postGenerated(StructureWorldAccess world, StructureAccessor structureAccessor, ChunkGenerator chunkGenerator, Random random, BlockBox chunkBox, ChunkPos chunkPos, StructurePiecesList children) 49 | { 50 | fillBottomAirGap(world, random, chunkBox, children, (pos, blockState) -> BASE_BLOCKS.contains(blockState.getBlock()), rnd -> BASE_BLOCKS.get(random.nextInt(BASE_BLOCKS.size())).getDefaultState(), 0); 51 | } 52 | 53 | private static class Piece extends SinglePieceLandStructure.Piece 54 | { 55 | public Piece(StructureManager manager, Identifier identifier, BlockPos pos, BlockRotation rotation) 56 | { 57 | super(PIECE_TYPE, manager, identifier, pos, rotation); 58 | } 59 | 60 | public Piece(StructureManager manager, NbtCompound nbt) 61 | { 62 | super(PIECE_TYPE, manager, nbt); 63 | } 64 | 65 | @Override 66 | protected void handleMetadata(String metadata, BlockPos pos, ServerWorldAccess world, Random random, BlockBox boundingBox) 67 | { 68 | if ("chest".equals(metadata)) 69 | { 70 | world.setBlockState(pos, Blocks.AIR.getDefaultState(), Block.NOTIFY_ALL); 71 | setChestLoot(world, pos.up(), random, CHEST_LOOT_TABLE); 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/item/ItemStackMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.item; 2 | 3 | import me.fallenbreath.tcuhc.UhcGameManager; 4 | import me.fallenbreath.tcuhc.UhcGamePlayer; 5 | import me.fallenbreath.tcuhc.util.PlayerItems; 6 | import me.fallenbreath.tcuhc.util.Position; 7 | import net.minecraft.block.BlockState; 8 | import net.minecraft.block.Blocks; 9 | import net.minecraft.entity.player.PlayerEntity; 10 | import net.minecraft.item.ItemStack; 11 | import net.minecraft.item.ItemUsageContext; 12 | import net.minecraft.server.network.ServerPlayerEntity; 13 | import net.minecraft.server.world.ServerWorld; 14 | import net.minecraft.sound.SoundCategory; 15 | import net.minecraft.sound.SoundEvents; 16 | import net.minecraft.text.Text; 17 | import net.minecraft.util.ActionResult; 18 | import net.minecraft.util.Formatting; 19 | import net.minecraft.util.math.BlockPos; 20 | import net.minecraft.util.math.Vec3d; 21 | import net.minecraft.world.World; 22 | import org.spongepowered.asm.mixin.Mixin; 23 | import org.spongepowered.asm.mixin.injection.At; 24 | import org.spongepowered.asm.mixin.injection.Inject; 25 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 26 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 27 | 28 | @Mixin(ItemStack.class) 29 | public abstract class ItemStackMixin 30 | { 31 | @Inject( 32 | method = "postMine", 33 | at = @At( 34 | value = "INVOKE", 35 | target = "Lnet/minecraft/entity/player/PlayerEntity;incrementStat(Lnet/minecraft/stat/Stat;)V" 36 | ) 37 | ) 38 | private void onPlayerMinedBlock(World world, BlockState state, BlockPos pos, PlayerEntity miner, CallbackInfo ci) 39 | { 40 | if (miner instanceof ServerPlayerEntity) 41 | { 42 | if (state.getBlock() == Blocks.DIAMOND_ORE || state.getBlock() == Blocks.DEEPSLATE_DIAMOND_ORE) 43 | { 44 | UhcGameManager.instance.getUhcPlayerManager().getGamePlayer(miner).getStat().addStat(UhcGamePlayer.EnumStat.DIAMOND_FOUND, 1); 45 | } 46 | } 47 | } 48 | 49 | @Inject( 50 | method = "useOnBlock", 51 | at = @At( 52 | value = "INVOKE", 53 | target = "Lnet/minecraft/item/ItemStack;getItem()Lnet/minecraft/item/Item;" 54 | ), 55 | cancellable = true 56 | ) 57 | private void moralRespawnPlayerLogic(ItemUsageContext context, CallbackInfoReturnable cir) 58 | { 59 | ItemStack self = (ItemStack)(Object)this; 60 | if (context.getWorld() instanceof ServerWorld && PlayerItems.isMoralItem(self)) 61 | { 62 | BlockPos blockPos = context.getBlockPos(); 63 | BlockState blockState = context.getWorld().getBlockState(blockPos); 64 | if (blockState.getBlock() == Blocks.WITHER_SKELETON_SKULL || blockState.getBlock() == Blocks.WITHER_SKELETON_WALL_SKULL) 65 | { 66 | String playerName = PlayerItems.getMoralOwner(self); 67 | Vec3d vec3d = Vec3d.ofBottomCenter(blockPos); 68 | Position respawnPos = new Position(vec3d, context.getWorld().getRegistryKey(), 0.0F, 0.0F); 69 | if (UhcGameManager.instance.getUhcPlayerManager().resurrectPlayerUsingMoral(playerName, respawnPos)) 70 | { 71 | self.decrement(1); 72 | context.getWorld().removeBlock(blockPos, false); 73 | context.getWorld().playSound(null, vec3d.getX(), vec3d.getY(), vec3d.getZ(), SoundEvents.ITEM_TOTEM_USE, SoundCategory.PLAYERS, 1.0F, 1.0F); 74 | cir.setReturnValue(ActionResult.CONSUME); 75 | } 76 | else 77 | { 78 | PlayerEntity player = context.getPlayer(); 79 | if (player != null) 80 | { 81 | player.sendMessage(Text.of(Formatting.RED + "You cannot resurrect " + playerName + " now."), false); 82 | } 83 | } 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/entity/ServerPlayerEntityMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.entity; 2 | 3 | import com.mojang.authlib.GameProfile; 4 | import me.fallenbreath.tcuhc.UhcGameManager; 5 | import me.fallenbreath.tcuhc.UhcGamePlayer; 6 | import net.minecraft.entity.Entity; 7 | import net.minecraft.entity.damage.DamageSource; 8 | import net.minecraft.entity.player.PlayerEntity; 9 | import net.minecraft.server.network.ServerPlayerEntity; 10 | import net.minecraft.util.math.BlockPos; 11 | import net.minecraft.world.World; 12 | import org.spongepowered.asm.mixin.Intrinsic; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.Shadow; 15 | import org.spongepowered.asm.mixin.injection.At; 16 | import org.spongepowered.asm.mixin.injection.Inject; 17 | import org.spongepowered.asm.mixin.injection.ModifyVariable; 18 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 19 | 20 | import static me.fallenbreath.tcuhc.helpers.ServerPlayerEntityHelper.doSpectateCheck; 21 | 22 | @Mixin(ServerPlayerEntity.class) 23 | public abstract class ServerPlayerEntityMixin extends PlayerEntity 24 | { 25 | @Shadow private int joinInvulnerabilityTicks; 26 | 27 | @Shadow private Entity cameraEntity; 28 | 29 | @Shadow public abstract boolean isSpectator(); 30 | private Entity previousCameraEntity; 31 | 32 | public ServerPlayerEntityMixin(World world, BlockPos pos, float yaw, GameProfile profile) 33 | { 34 | super(world, pos, yaw, profile); 35 | } 36 | 37 | @Inject(method = "", at = @At("TAIL")) 38 | private void modifyInvulnerableDuration( CallbackInfo ci) 39 | { 40 | // TC Plugin: modified invulnerable time from 60gt to 20gt 41 | this.joinInvulnerabilityTicks = 20; 42 | } 43 | 44 | @Inject( 45 | method = "onDeath", 46 | at = @At( 47 | value = "FIELD", 48 | target = "Lnet/minecraft/stat/Stats;DEATHS:Lnet/minecraft/util/Identifier;" 49 | ) 50 | ) 51 | private void onPlayerDeath(DamageSource cause, CallbackInfo ci) 52 | { 53 | Entity sourceEntity = cause.getSource(); 54 | if (!(sourceEntity instanceof PlayerEntity)) sourceEntity = cause.getAttacker(); 55 | if (!(sourceEntity instanceof PlayerEntity)) sourceEntity = this.getAttacker(); 56 | if (sourceEntity instanceof PlayerEntity) 57 | { 58 | UhcGameManager.instance.getUhcPlayerManager().getGamePlayer((PlayerEntity)sourceEntity).getStat().addStat(UhcGamePlayer.EnumStat.PLAYER_KILLED, 1); 59 | } 60 | // TC Plugin: Player Death Hook 61 | UhcGameManager.instance.onPlayerDeath((ServerPlayerEntity) (Object) this, cause); 62 | } 63 | 64 | @ModifyVariable(method = "setCameraEntity", at = @At("STORE"), ordinal = 1) 65 | private Entity returnNullToAlwaysEnterIf(Entity entity2) 66 | { 67 | this.previousCameraEntity = entity2; 68 | return null; 69 | } 70 | 71 | @Inject( 72 | method = "setCameraEntity", 73 | at = @At( 74 | value = "FIELD", 75 | target = "Lnet/minecraft/server/network/ServerPlayerEntity;cameraEntity:Lnet/minecraft/entity/Entity;", 76 | ordinal = 1 77 | ) 78 | ) 79 | private void modifyCameraEntity(CallbackInfo ci) 80 | { 81 | if (doSpectateCheck.get() && this.isSpectator()) 82 | { 83 | this.cameraEntity = UhcGameManager.instance.onPlayerSpectate((ServerPlayerEntity) (Object) this, this.cameraEntity, this.previousCameraEntity); 84 | } 85 | // Regular calls are always with it true 86 | doSpectateCheck.set(true); 87 | } 88 | 89 | @Intrinsic 90 | @Override 91 | public void heal(float healAmount) 92 | { 93 | float health = this.getHealth(); 94 | super.heal(healAmount); 95 | UhcGameManager.instance.getUhcPlayerManager().getGamePlayer(this).getStat().addStat(UhcGamePlayer.EnumStat.HEALTH_HEALED, getHealth() - health); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/util/UhcRegistry.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.util; 2 | 3 | import com.google.common.collect.Sets; 4 | import com.mojang.serialization.Codec; 5 | import me.fallenbreath.tcuhc.TcUhcMod; 6 | import me.fallenbreath.tcuhc.mixins.feature.structure.StructureFeatureAccessor; 7 | import net.minecraft.recipe.Recipe; 8 | import net.minecraft.recipe.RecipeSerializer; 9 | import net.minecraft.structure.StructurePieceType; 10 | import net.minecraft.util.math.intprovider.IntProvider; 11 | import net.minecraft.util.math.intprovider.IntProviderType; 12 | import net.minecraft.util.registry.BuiltinRegistries; 13 | import net.minecraft.util.registry.Registry; 14 | import net.minecraft.world.gen.GenerationStep; 15 | import net.minecraft.world.gen.feature.*; 16 | 17 | import java.util.Set; 18 | 19 | public class UhcRegistry 20 | { 21 | private static final Set> RECIPE_SERIALIZERS = Sets.newLinkedHashSet(); 22 | 23 | public static Set> getRecipeSerializers() 24 | { 25 | return RECIPE_SERIALIZERS; 26 | } 27 | 28 | /** 29 | * Like net.minecraft.world.gen.feature.Feature#register(java.lang.String, net.minecraft.world.gen.feature.Feature) 30 | */ 31 | public static > F registerFeature(String name, F feature) 32 | { 33 | return Registry.register(Registry.FEATURE, TcUhcMod.id(name), feature); 34 | } 35 | 36 | /** 37 | * Like {@link net.minecraft.world.gen.feature.ConfiguredFeatures#register} 38 | */ 39 | public static ConfiguredFeature registerConfiguredFeature(String name, ConfiguredFeature configuredFeature) 40 | { 41 | return Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, TcUhcMod.id(name), configuredFeature); 42 | } 43 | 44 | /** 45 | * Like {@link net.minecraft.world.gen.feature.PlacedFeatures#register} 46 | */ 47 | public static PlacedFeature registerPlacedFeature(String name, PlacedFeature placedFeature) 48 | { 49 | return Registry.register(BuiltinRegistries.PLACED_FEATURE, TcUhcMod.id(name), placedFeature); 50 | } 51 | 52 | /** 53 | * Like net.minecraft.world.gen.feature.StructureFeature#register 54 | */ 55 | public static > F registerStructure(String name, F structureFeature, GenerationStep.Feature step) 56 | { 57 | StructureFeature.STRUCTURES.put(name, structureFeature); 58 | StructureFeatureAccessor.getSTRUCTURE_TO_GENERATION_STEP().put(structureFeature, step); 59 | return Registry.register(Registry.STRUCTURE_FEATURE, TcUhcMod.id(name), structureFeature); 60 | } 61 | 62 | /** 63 | * Like net.minecraft.world.gen.feature.ConfiguredStructureFeatures#register 64 | */ 65 | public static > ConfiguredStructureFeature registerConfiguredStructure(String name, ConfiguredStructureFeature configuredStructureFeature) 66 | { 67 | return BuiltinRegistries.add(BuiltinRegistries.CONFIGURED_STRUCTURE_FEATURE, TcUhcMod.id(name), configuredStructureFeature); 68 | } 69 | 70 | /** 71 | * Like net.minecraft.structure.StructurePieceType#register(net.minecraft.structure.StructurePieceType.ManagerAware, java.lang.String) 72 | */ 73 | public static StructurePieceType registerStructurePieceType(StructurePieceType.ManagerAware structurePieceType, String name) 74 | { 75 | return Registry.register(Registry.STRUCTURE_PIECE, TcUhcMod.id(name), structurePieceType); 76 | } 77 | 78 | /** 79 | * Like net.minecraft.recipe.RecipeSerializer#register(java.lang.String, net.minecraft.recipe.RecipeSerializer) 80 | */ 81 | public static , T extends Recipe> S registerRecipeSerializer(String name, S serializer) 82 | { 83 | RECIPE_SERIALIZERS.add(serializer); 84 | return Registry.register(Registry.RECIPE_SERIALIZER, TcUhcMod.id(name), serializer); 85 | } 86 | 87 | /** 88 | * Like {@link net.minecraft.util.math.intprovider.IntProviderType} 89 | */ 90 | public static

IntProviderType

registerIntProviderType(String name, Codec

codec) 91 | { 92 | return Registry.register(Registry.INT_PROVIDER_TYPE, TcUhcMod.id(name), () -> codec); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/mixins/network/ServerPlayNetworkHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.mixins.network; 2 | 3 | import me.fallenbreath.tcuhc.UhcGameManager; 4 | import me.fallenbreath.tcuhc.helpers.ServerPlayerEntityHelper; 5 | import net.minecraft.entity.Entity; 6 | import net.minecraft.network.MessageType; 7 | import net.minecraft.network.packet.c2s.play.SpectatorTeleportC2SPacket; 8 | import net.minecraft.server.PlayerManager; 9 | import net.minecraft.server.filter.TextStream; 10 | import net.minecraft.server.network.ServerPlayNetworkHandler; 11 | import net.minecraft.server.network.ServerPlayerEntity; 12 | import net.minecraft.server.world.ServerWorld; 13 | import net.minecraft.text.Text; 14 | import org.spongepowered.asm.mixin.Mixin; 15 | import org.spongepowered.asm.mixin.Shadow; 16 | import org.spongepowered.asm.mixin.Unique; 17 | import org.spongepowered.asm.mixin.injection.At; 18 | import org.spongepowered.asm.mixin.injection.Inject; 19 | import org.spongepowered.asm.mixin.injection.Redirect; 20 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 21 | import org.spongepowered.asm.mixin.injection.callback.LocalCapture; 22 | 23 | import java.util.Iterator; 24 | import java.util.UUID; 25 | import java.util.function.Function; 26 | 27 | @Mixin(ServerPlayNetworkHandler.class) 28 | public abstract class ServerPlayNetworkHandlerMixin 29 | { 30 | @Shadow public ServerPlayerEntity player; 31 | 32 | @Unique 33 | private boolean observe; 34 | 35 | @Unique 36 | private Entity entityToSpectate; 37 | 38 | @Inject( 39 | method = "onSpectatorTeleport", 40 | at = @At( 41 | value = "INVOKE", 42 | target = "Lnet/minecraft/server/network/ServerPlayerEntity;teleport(Lnet/minecraft/server/world/ServerWorld;DDDFF)V" 43 | ), 44 | locals = LocalCapture.CAPTURE_FAILHARD 45 | ) 46 | private void spectatorHook1(SpectatorTeleportC2SPacket packet, CallbackInfo ci, Iterator var2, ServerWorld serverWorld, Entity entity) 47 | { 48 | Entity lastSpectateTarget = player.getCameraEntity(); 49 | this.entityToSpectate = UhcGameManager.instance.onPlayerSpectate(player, entity, lastSpectateTarget); 50 | this.observe = UhcGameManager.instance.onPlayerSpectate(player, player, lastSpectateTarget) == player; 51 | 52 | ServerPlayerEntityHelper.doSpectateCheck.set(false); 53 | this.player.setCameraEntity(null); 54 | this.player.stopRiding(); 55 | } 56 | 57 | @Redirect( 58 | method = "onSpectatorTeleport", 59 | at = @At( 60 | value = "INVOKE", 61 | target = "Lnet/minecraft/server/network/ServerPlayerEntity;teleport(Lnet/minecraft/server/world/ServerWorld;DDDFF)V" 62 | ) 63 | ) 64 | private void modifyTeleportTarget(ServerPlayerEntity playerEntity, ServerWorld targetWorld, double x, double y, double z, float yaw, float pitch) 65 | { 66 | Entity entity = this.entityToSpectate; 67 | playerEntity.teleport(targetWorld, entity.getX(), entity.getY(), entity.getZ(), entity.getYaw(), entity.getPitch()); 68 | } 69 | 70 | @Inject( 71 | method = "onSpectatorTeleport", 72 | at = @At( 73 | value = "INVOKE", 74 | target = "Lnet/minecraft/server/network/ServerPlayerEntity;teleport(Lnet/minecraft/server/world/ServerWorld;DDDFF)V", 75 | shift = At.Shift.AFTER 76 | ) 77 | ) 78 | private void spectatorHook2(CallbackInfo ci) 79 | { 80 | if (!this.observe) 81 | { 82 | ServerPlayerEntityHelper.doSpectateCheck.set(false); 83 | this.player.setCameraEntity(this.observe ? null : this.entityToSpectate); 84 | } 85 | } 86 | 87 | @Redirect( 88 | method = "handleMessage", 89 | at = @At( 90 | value = "INVOKE", 91 | target = "Lnet/minecraft/server/PlayerManager;broadcast(Lnet/minecraft/text/Text;Ljava/util/function/Function;Lnet/minecraft/network/MessageType;Ljava/util/UUID;)V" 92 | ) 93 | ) 94 | private void optioalChatting(PlayerManager playerManager, Text serverMessage, Function playerMessageFactory, MessageType playerMessageType, UUID sender, /* parent method parameters -> */ TextStream.Message message) 95 | { 96 | String string = message.getFiltered(); 97 | if (UhcGameManager.instance.onPlayerChat(player, string)) 98 | { 99 | playerManager.broadcast(serverMessage, playerMessageFactory, playerMessageType, sender); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/task/TaskTitleCountDown.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.task; 6 | 7 | import me.fallenbreath.tcuhc.UhcGameManager; 8 | import me.fallenbreath.tcuhc.task.Task.TaskTimer; 9 | import me.fallenbreath.tcuhc.util.TitleUtil; 10 | import net.minecraft.advancement.AdvancementProgress; 11 | import net.minecraft.enchantment.Enchantments; 12 | import net.minecraft.entity.EquipmentSlot; 13 | import net.minecraft.entity.effect.StatusEffectInstance; 14 | import net.minecraft.entity.effect.StatusEffects; 15 | import net.minecraft.item.DyeableItem; 16 | import net.minecraft.item.ItemStack; 17 | import net.minecraft.item.Items; 18 | import net.minecraft.nbt.NbtByte; 19 | import net.minecraft.potion.PotionUtil; 20 | import net.minecraft.server.network.ServerPlayerEntity; 21 | import net.minecraft.stat.Stats; 22 | import net.minecraft.text.LiteralText; 23 | import net.minecraft.util.DyeColor; 24 | import net.minecraft.util.Formatting; 25 | import net.minecraft.world.GameMode; 26 | 27 | import java.util.Collections; 28 | 29 | public class TaskTitleCountDown extends TaskTimer { 30 | 31 | private int count; 32 | 33 | public TaskTitleCountDown(int init, int delay, int interval) { 34 | super(delay, interval); 35 | count = init; 36 | } 37 | 38 | @Override 39 | public void onTimer() { 40 | TitleUtil.sendTitleToAllPlayers(Formatting.GOLD + String.valueOf(--count), null); 41 | if (count == 0) this.setCanceled(); 42 | } 43 | 44 | @Override 45 | public void onFinish() { 46 | TitleUtil.sendTitleToAllPlayers("Game Started !", "Enjoy Yourself !"); 47 | UhcGameManager.instance.getUhcPlayerManager().getCombatPlayers().forEach(player -> player.addTask(new TaskFindPlayer(player) { 48 | @SuppressWarnings("ConstantConditions") 49 | @Override 50 | public void onFindPlayer(ServerPlayerEntity player) { 51 | player.changeGameMode(GameMode.SURVIVAL); 52 | player.setInvulnerable(false); 53 | player.clearStatusEffects(); 54 | UhcGameManager.instance.getUhcPlayerManager().resetHealthAndFood(player); 55 | player.resetStat(Stats.CUSTOM.getOrCreateStat(Stats.TIME_SINCE_REST)); // no free phantom 56 | player.addStatusEffect(new StatusEffectInstance(StatusEffects.RESISTANCE, 200, 4)); // 10s Resistance V 57 | // revoke all advancements 58 | player.getServer().getAdvancementLoader().getAdvancements().forEach(advancement -> { 59 | AdvancementProgress advancementProgress = player.getAdvancementTracker().getProgress(advancement); 60 | if (advancementProgress.isAnyObtained()) { 61 | for(String string : advancementProgress.getObtainedCriteria()) { 62 | player.getAdvancementTracker().revokeCriterion(advancement, string); 63 | } 64 | } 65 | }); 66 | 67 | // give invisibility and shiny potion to player for ghost mode 68 | switch (UhcGameManager.getGameMode()) { 69 | case GHOST: 70 | this.getGamePlayer().addGhostModeEffect(); 71 | ItemStack shinyPotion = new ItemStack(Items.SPLASH_POTION).setCustomName(new LiteralText("Splash Shiny Potion")); 72 | PotionUtil.setCustomPotionEffects(shinyPotion, Collections.singleton(new StatusEffectInstance(StatusEffects.GLOWING, 200, 0))); 73 | player.getInventory().insertStack(shinyPotion); 74 | break; 75 | case KING: 76 | if (this.getGamePlayer().isKing()) { 77 | DyeColor dyeColor = this.getGamePlayer().getTeam().getTeamColor().dyeColor; 78 | ItemStack kingsHelmet = new ItemStack(Items.LEATHER_HELMET).setCustomName(new LiteralText(String.format("%s crown", dyeColor.getName()))); 79 | kingsHelmet.getOrCreateNbt().put("KingsCrown", NbtByte.of((byte)1)); 80 | kingsHelmet.getOrCreateNbt().put("Unbreakable", NbtByte.of((byte)1)); 81 | ((DyeableItem)Items.LEATHER_HELMET).setColor(kingsHelmet, dyeColor.getMapColor().color); 82 | kingsHelmet.addEnchantment(Enchantments.PROTECTION, 6); 83 | kingsHelmet.addEnchantment(Enchantments.BINDING_CURSE, 1); 84 | kingsHelmet.addEnchantment(Enchantments.VANISHING_CURSE, 1); 85 | player.equipStack(EquipmentSlot.HEAD, kingsHelmet); 86 | } 87 | break; 88 | } 89 | } 90 | })); 91 | if (UhcGameManager.getGameMode() == UhcGameManager.EnumMode.KING) { 92 | UhcGameManager.instance.addTask(new TaskKingEffectField()); 93 | } 94 | UhcGameManager.instance.addTask(new TaskScoreboard()); 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/util/SpawnPlatform.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.util; 6 | 7 | import me.fallenbreath.tcuhc.UhcGameManager; 8 | import me.fallenbreath.tcuhc.task.TaskSpawnPlatformProtect; 9 | import net.minecraft.block.BlockState; 10 | import net.minecraft.block.Blocks; 11 | import net.minecraft.util.DyeColor; 12 | import net.minecraft.util.math.BlockPos; 13 | import net.minecraft.world.Heightmap; 14 | import net.minecraft.world.World; 15 | 16 | import java.util.Random; 17 | 18 | public class SpawnPlatform { 19 | private static final int DEFAULT_HEIGHT = 160; 20 | public static int height = DEFAULT_HEIGHT; 21 | private static BlockPos[] hexagonPos; 22 | 23 | private static void sampleTerrainHeight(UhcGameManager gameManager, World world) { 24 | UhcWorldData uhcWorldData = gameManager.getWorldData(); 25 | if (uhcWorldData.isSpawnPlatformHeightValid()) { 26 | height = uhcWorldData.spawnPlatformHeight; 27 | } 28 | else { 29 | height = DEFAULT_HEIGHT; 30 | final int sampleWidth = 40; 31 | for (int x = -sampleWidth; x <= sampleWidth; x++) 32 | for (int z = -sampleWidth; z <= sampleWidth; z++) 33 | { 34 | int y = world.getTopY(Heightmap.Type.MOTION_BLOCKING, x, z); 35 | height = Math.max(height, Math.min(y + 64, world.getTopY() - 16)); 36 | } 37 | uhcWorldData.spawnPlatformHeight = height; 38 | uhcWorldData.save(); 39 | } 40 | UhcGameManager.LOG.info("Set spawn platform height to y" + height); 41 | } 42 | 43 | public static void generatePlatform(UhcGameManager gameManager, World world) { 44 | sampleTerrainHeight(gameManager, world); 45 | generateHexagonPos(); 46 | generateHexagon(world, hexagonPos[0], DyeColor.BLUE); 47 | generateHexagon(world, hexagonPos[1], DyeColor.RED); 48 | generateHexagon(world, hexagonPos[2], DyeColor.BLUE); 49 | generateHexagon(world, hexagonPos[3], DyeColor.BLUE); 50 | generateHexagon(world, hexagonPos[4], DyeColor.BLUE); 51 | generateHexagon(world, hexagonPos[5], DyeColor.RED); 52 | generateHexagon(world, hexagonPos[6], DyeColor.RED); 53 | gameManager.addTask(new TaskSpawnPlatformProtect(gameManager)); 54 | } 55 | 56 | private static void generateHexagon(World world, BlockPos pos, DyeColor color) { 57 | for (int x = pos.getX() - 5; x <= pos.getX() + 6; x++) 58 | for (int z = pos.getZ() - 6; z <= pos.getZ() + 6; z++) { 59 | int dx = Math.min(x - pos.getX() + 5, pos.getX() + 6 - x); 60 | int dz = Math.min(z - pos.getZ() + 6, pos.getZ() + 6 - z); 61 | if (dx / 2.0f + dz < 2.1f) 62 | continue; 63 | if (Math.abs(x - pos.getX()) < 2 && Math.abs(z - pos.getZ()) < 2) { 64 | world.setBlockState(new BlockPos(x, pos.getY(), z), Blocks.SEA_LANTERN.getDefaultState(), 2); 65 | } else 66 | world.setBlockState(new BlockPos(x, pos.getY(), z), 67 | ColorUtil.fromColor(color).wool.getDefaultState(), 2); 68 | world.setBlockState(new BlockPos(x, pos.getY() + 1, z), 69 | ColorUtil.fromColor(color).carpet.getDefaultState(), 2); 70 | } 71 | } 72 | 73 | public static void generateSafePlatform(World world) { 74 | BlockState block = Blocks.BARRIER.getDefaultState(); 75 | for (int x = -25; x <= 25; x++) 76 | for (int z = -25; z <= 25; z++) { 77 | if (x == -25 || x == 25 || z == -25 || z == 25) 78 | for (int y = height + 1; y <= height + 4; y++) 79 | world.setBlockState(new BlockPos(x, y, z), block, 2); 80 | if (world.isAir(new BlockPos(x, height, z))) 81 | world.setBlockState(new BlockPos(x, height, z), block, 2); 82 | } 83 | } 84 | 85 | public static void destroyPlatform(World world) { 86 | for (int x = -30; x <= 30; x++) 87 | for (int z = -30; z <= 30; z++) 88 | for (int y = height + 5; y >= height; y--) 89 | world.setBlockState(new BlockPos(x, y, z), Blocks.AIR.getDefaultState(), 2); 90 | } 91 | 92 | public static BlockPos getRandomSpawnPosition(Random rand) { 93 | BlockPos res = hexagonPos[rand.nextInt(hexagonPos.length)]; 94 | return res.add(new BlockPos(rand.nextInt(7) - 3, 0, rand.nextInt(7) - 3)); 95 | } 96 | 97 | private static void generateHexagonPos() { 98 | hexagonPos = new BlockPos[7]; 99 | hexagonPos[0] = new BlockPos(0, height, 0); 100 | hexagonPos[1] = new BlockPos(14, height, 0); 101 | hexagonPos[2] = new BlockPos(-14, height, 0); 102 | hexagonPos[3] = new BlockPos(7, height, 12); 103 | hexagonPos[4] = new BlockPos(7, height, -12); 104 | hexagonPos[5] = new BlockPos(-7, height, 12); 105 | hexagonPos[6] = new BlockPos(-7, height, -12); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/gen/structure/VillainHouseStructure.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.gen.structure; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.mojang.serialization.Codec; 5 | import me.fallenbreath.tcuhc.TcUhcMod; 6 | import me.fallenbreath.tcuhc.util.UhcRegistry; 7 | import net.minecraft.block.*; 8 | import net.minecraft.entity.EntityType; 9 | import net.minecraft.nbt.NbtCompound; 10 | import net.minecraft.structure.*; 11 | import net.minecraft.util.BlockRotation; 12 | import net.minecraft.util.Identifier; 13 | import net.minecraft.util.math.BlockBox; 14 | import net.minecraft.util.math.BlockPos; 15 | import net.minecraft.util.math.ChunkPos; 16 | import net.minecraft.world.Heightmap; 17 | import net.minecraft.world.ServerWorldAccess; 18 | import net.minecraft.world.StructureWorldAccess; 19 | import net.minecraft.world.gen.StructureAccessor; 20 | import net.minecraft.world.gen.chunk.ChunkGenerator; 21 | import net.minecraft.world.gen.feature.DefaultFeatureConfig; 22 | 23 | import java.util.List; 24 | import java.util.Random; 25 | 26 | public class VillainHouseStructure extends SinglePieceLandStructure 27 | { 28 | private static final StructurePieceType PIECE_TYPE = UhcRegistry.registerStructurePieceType(Piece::new, "villain_house_piece"); 29 | 30 | private static final Identifier MAIN_TEMPLATE = TcUhcMod.id("villain_house/main"); 31 | private static final Identifier CHEST_LOOT_TABLE = TcUhcMod.id("villain_house/chest"); 32 | 33 | private static final List BASE_BLOCKS = ImmutableList.of(Blocks.STONE_BRICKS, Blocks.STONE_BRICKS, Blocks.STONE, Blocks.ANDESITE); 34 | private static final int FLOOR_HEIGHT = 1; 35 | 36 | public VillainHouseStructure(Codec configCodec) 37 | { 38 | super(configCodec, StructureGeneratorFactory.simple(VillainHouseStructure::canGenerate, VillainHouseStructure::addPieces), VillainHouseStructure::postGenerated); 39 | } 40 | 41 | private static boolean canGenerate(StructureGeneratorFactory.Context context) 42 | { 43 | return context.isBiomeValid(Heightmap.Type.WORLD_SURFACE_WG) && isBiomeValidInChunk(context) && isSurroundingFlat(context, Heightmap.Type.WORLD_SURFACE_WG, 5, 3); 44 | } 45 | 46 | private static void addPieces(StructurePiecesCollector collector, StructurePiecesGenerator.Context context) 47 | { 48 | BlockRotation rotation = BlockRotation.random(context.random()); 49 | collector.addPiece(new Piece(context.structureManager(), MAIN_TEMPLATE, shiftStartPosRandomly(context), rotation)); 50 | } 51 | 52 | private static void postGenerated(StructureWorldAccess world, StructureAccessor structureAccessor, ChunkGenerator chunkGenerator, Random random, BlockBox chunkBox, ChunkPos chunkPos, StructurePiecesList children) 53 | { 54 | fillBottomAirGapInAutoBox(world, random, chunkBox, children, BASE_BLOCKS, BASE_BLOCKS, FLOOR_HEIGHT); 55 | } 56 | 57 | private static class Piece extends SinglePieceLandStructure.YOffsetPiece 58 | { 59 | private static final List> VILLAINS = ImmutableList.of(EntityType.WITCH, EntityType.VINDICATOR, EntityType.PILLAGER); 60 | 61 | public Piece(StructureManager manager, Identifier identifier, BlockPos pos, BlockRotation rotation) 62 | { 63 | super(PIECE_TYPE, manager, identifier, pos, rotation, FLOOR_HEIGHT); 64 | } 65 | 66 | public Piece(StructureManager manager, NbtCompound nbt) 67 | { 68 | super(PIECE_TYPE, manager, nbt); 69 | } 70 | 71 | @Override 72 | protected void handleMetadata(String metadata, BlockPos pos, ServerWorldAccess world, Random random, BlockBox boundingBox) 73 | { 74 | switch (metadata) 75 | { 76 | case "villain": 77 | world.setBlockState(pos, Blocks.AIR.getDefaultState(), Block.NOTIFY_ALL); 78 | for (int i = 0; i < 2; i++) 79 | { 80 | this.placeEntity(VILLAINS.get(random.nextInt(VILLAINS.size())), pos, world, random); 81 | } 82 | break; 83 | case "chest": 84 | world.setBlockState(pos, Blocks.AIR.getDefaultState(), Block.NOTIFY_ALL); 85 | BlockPos chestPos = pos.down(); 86 | BlockState chestBlock = world.getBlockState(chestPos); 87 | if (random.nextInt(2) == 0) 88 | { 89 | if (chestBlock.getBlock() == Blocks.CHEST) 90 | { 91 | world.setBlockState(chestPos, Blocks.ENDER_CHEST.getDefaultState().with(EnderChestBlock.FACING, chestBlock.get(ChestBlock.FACING)), Block.NOTIFY_ALL); 92 | } 93 | } 94 | else 95 | { 96 | setChestLoot(world, chestPos, random, CHEST_LOOT_TABLE); 97 | } 98 | break; 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/gen/structure/PlainCottageStructure.java: -------------------------------------------------------------------------------- 1 | package me.fallenbreath.tcuhc.gen.structure; 2 | 3 | import com.mojang.serialization.Codec; 4 | import me.fallenbreath.tcuhc.TcUhcMod; 5 | import me.fallenbreath.tcuhc.util.UhcRegistry; 6 | import net.minecraft.block.Block; 7 | import net.minecraft.block.Blocks; 8 | import net.minecraft.entity.EntityType; 9 | import net.minecraft.nbt.NbtCompound; 10 | import net.minecraft.structure.*; 11 | import net.minecraft.util.BlockRotation; 12 | import net.minecraft.util.Identifier; 13 | import net.minecraft.util.math.BlockBox; 14 | import net.minecraft.util.math.BlockPos; 15 | import net.minecraft.util.math.ChunkPos; 16 | import net.minecraft.world.Heightmap; 17 | import net.minecraft.world.ServerWorldAccess; 18 | import net.minecraft.world.StructureWorldAccess; 19 | import net.minecraft.world.gen.StructureAccessor; 20 | import net.minecraft.world.gen.chunk.ChunkGenerator; 21 | import net.minecraft.world.gen.feature.DefaultFeatureConfig; 22 | 23 | import java.util.Random; 24 | 25 | public class PlainCottageStructure extends SinglePieceLandStructure 26 | { 27 | private static final StructurePieceType PIECE_TYPE = UhcRegistry.registerStructurePieceType(Piece::new, "plain_cottage_piece"); 28 | 29 | private static final Identifier MAIN_TEMPLATE = TcUhcMod.id("plain_cottage/main"); 30 | private static final Identifier CHEST_LOOT_TABLE = TcUhcMod.id("plain_cottage/chest"); 31 | 32 | private static final int FLOOR_HEIGHT = 1; 33 | 34 | public PlainCottageStructure(Codec configCodec) 35 | { 36 | super(configCodec, StructureGeneratorFactory.simple(PlainCottageStructure::canGenerate, PlainCottageStructure::addPieces), PlainCottageStructure::postGenerated); 37 | } 38 | 39 | private static boolean canGenerate(StructureGeneratorFactory.Context context) 40 | { 41 | return context.isBiomeValid(Heightmap.Type.WORLD_SURFACE_WG) && isBiomeValidInChunk(context) && isSurroundingFlat(context, Heightmap.Type.WORLD_SURFACE_WG, 7, 3); 42 | } 43 | 44 | private static void addPieces(StructurePiecesCollector collector, StructurePiecesGenerator.Context context) 45 | { 46 | BlockRotation rotation = BlockRotation.random(context.random()); 47 | collector.addPiece(new Piece(context, MAIN_TEMPLATE, shiftStartPosRandomly(context), rotation)); 48 | } 49 | 50 | private static void postGenerated(StructureWorldAccess world, StructureAccessor structureAccessor, ChunkGenerator chunkGenerator, Random random, BlockBox chunkBox, ChunkPos chunkPos, StructurePiecesList children) 51 | { 52 | fillBottomAirGap(world, random, chunkBox, children, (pos, state) -> !state.isAir(), pos -> Blocks.DIRT.getDefaultState(), FLOOR_HEIGHT); 53 | } 54 | 55 | private static class Piece extends SinglePieceLandStructure.YOffsetPiece 56 | { 57 | private static final int CHEST_AMOUNT = 3; 58 | private final int bonusChestIndex; 59 | private int chestCounter = 0; 60 | 61 | public Piece(StructurePiecesGenerator.Context context, Identifier identifier, BlockPos pos, BlockRotation rotation) 62 | { 63 | super(PIECE_TYPE, context.structureManager(), identifier, pos, rotation, FLOOR_HEIGHT); 64 | this.bonusChestIndex = context.random().nextInt(CHEST_AMOUNT) + 1; 65 | } 66 | 67 | public Piece(StructureManager manager, NbtCompound nbt) 68 | { 69 | super(PIECE_TYPE, manager, nbt); 70 | this.bonusChestIndex = nbt.getInt("BonusChestIndex"); 71 | } 72 | 73 | @Override 74 | protected void writeNbt(StructureContext context, NbtCompound nbt) 75 | { 76 | super.writeNbt(context, nbt); 77 | nbt.putInt("BonusChestIndex", this.bonusChestIndex); 78 | } 79 | 80 | @Override 81 | protected void handleMetadata(String metadata, BlockPos pos, ServerWorldAccess world, Random random, BlockBox boundingBox) 82 | { 83 | EntityType entityType = null; 84 | int amount = 1; 85 | switch (metadata) 86 | { 87 | case "horse": 88 | entityType = random.nextInt(2) == 0 ? EntityType.HORSE : EntityType.DONKEY; 89 | break; 90 | case "chicken": 91 | entityType = EntityType.CHICKEN; 92 | amount = random.nextInt(2) + 3; 93 | break; 94 | case "chest": 95 | this.chestCounter++; 96 | world.setBlockState(pos, Blocks.AIR.getDefaultState(), Block.NOTIFY_ALL); 97 | if (this.chestCounter == this.bonusChestIndex) 98 | { 99 | setChestLoot(world, pos.down(), random, CHEST_LOOT_TABLE); 100 | } 101 | break; 102 | } 103 | if (entityType != null) 104 | { 105 | world.setBlockState(pos, Blocks.AIR.getDefaultState(), Block.NOTIFY_ALL); 106 | for (int i = 0; i < amount; i++) 107 | { 108 | this.placeEntity(entityType, pos.down(), world, random); 109 | } 110 | } 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/task/TaskScoreboard.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.task; 6 | 7 | import me.fallenbreath.tcuhc.UhcGameManager; 8 | import me.fallenbreath.tcuhc.UhcGamePlayer; 9 | import me.fallenbreath.tcuhc.options.Options; 10 | import me.fallenbreath.tcuhc.task.Task.TaskTimer; 11 | import net.minecraft.network.packet.s2c.play.PlayerSpawnPositionS2CPacket; 12 | import net.minecraft.scoreboard.Scoreboard; 13 | import net.minecraft.scoreboard.ScoreboardCriterion; 14 | import net.minecraft.scoreboard.ScoreboardObjective; 15 | import net.minecraft.scoreboard.ScoreboardPlayerScore; 16 | import net.minecraft.server.network.ServerPlayerEntity; 17 | import net.minecraft.text.LiteralText; 18 | 19 | public class TaskScoreboard extends TaskTimer { 20 | 21 | private final int borderStart, borderEnd; 22 | private final int gameTime, startTime, endTime, netherTime, caveTime; 23 | 24 | public static final String scoreName = "time"; 25 | public static final String displayName = "UHC Game"; 26 | public static final String[] lines = { "Time Remaining:", "Border Radius:", "Nether Close:", "Cave Close:" }; 27 | 28 | private Scoreboard scoreboard; 29 | private ScoreboardObjective objective; 30 | 31 | public TaskScoreboard() { 32 | super(0, 20); 33 | 34 | Options options = UhcGameManager.instance.getOptions(); 35 | borderStart = options.getIntegerOptionValue("borderStart"); 36 | borderEnd = options.getIntegerOptionValue("borderEnd"); 37 | gameTime = options.getIntegerOptionValue("gameTime"); 38 | startTime = options.getIntegerOptionValue("borderStartTime"); 39 | endTime = options.getIntegerOptionValue("borderEndTime"); 40 | netherTime = options.getIntegerOptionValue("netherCloseTime"); 41 | caveTime = options.getIntegerOptionValue("caveCloseTime"); 42 | 43 | scoreboard = UhcGameManager.instance.getMainScoreboard(); 44 | if ((objective = scoreboard.getObjective(scoreName)) == null) { 45 | objective = scoreboard.addObjective(scoreName, ScoreboardCriterion.DUMMY, new LiteralText(displayName), ScoreboardCriterion.RenderType.INTEGER); 46 | } 47 | scoreboard.setObjectiveSlot(1, objective); 48 | scoreboard.getPlayerScore(lines[0], objective).setScore(gameTime); 49 | scoreboard.getPlayerScore(lines[1], objective).setScore(borderStart / 2); 50 | scoreboard.getPlayerScore(lines[2], objective).setScore(netherTime); 51 | scoreboard.getPlayerScore(lines[3], objective).setScore(caveTime); 52 | 53 | UhcGameManager.instance.addTask(new TaskNetherCave()); 54 | } 55 | 56 | private int getBorderPosition() { 57 | return (int) UhcGameManager.instance.getOverWorld().getWorldBorder().getSize(); 58 | } 59 | 60 | @Override 61 | public void onTimer() { 62 | if (this.hasFinished() || !UhcGameManager.instance.isGamePlaying()) this.setCanceled(); 63 | ScoreboardPlayerScore score = scoreboard.getPlayerScore(lines[0], objective); 64 | int timeRemaining = score.getScore(); 65 | score.setScore(timeRemaining - 1); 66 | if (timeRemaining == gameTime - startTime) { 67 | UhcGameManager.instance.addTask(new TaskBorderReminder()); 68 | } 69 | scoreboard.getPlayerScore(lines[1], objective).setScore(getBorderPosition() / 2); 70 | 71 | score = scoreboard.getPlayerScore(lines[2], objective); 72 | if (score.getScore() > 0) 73 | score.setScore(Math.max(0, score.getScore() - 1)); 74 | else scoreboard.resetPlayerScore(lines[2], objective); 75 | 76 | score = scoreboard.getPlayerScore(lines[3], objective); 77 | if (score.getScore() > 0) 78 | score.setScore(Math.max(0, score.getScore() - 1)); 79 | else scoreboard.resetPlayerScore(lines[3], objective); 80 | 81 | if (timeRemaining % 60 == 0) updateCompassRotation(); 82 | } 83 | 84 | private void updateCompassRotation() { 85 | for (UhcGamePlayer player : UhcGameManager.instance.getUhcPlayerManager().getCombatPlayers()) { 86 | if (player.isAlive()) { 87 | if (player.getRealPlayer().isPresent()) { 88 | ServerPlayerEntity playermp = player.getRealPlayer().get(); 89 | ServerPlayerEntity target = null; 90 | for (UhcGamePlayer tmpTarget : UhcGameManager.instance.getUhcPlayerManager().getCombatPlayers()) { 91 | if (tmpTarget.isAlive() && player.getTeam() != tmpTarget.getTeam() && tmpTarget.getRealPlayer().isPresent()) { 92 | if (target == null || playermp.squaredDistanceTo(target) > playermp.squaredDistanceTo(tmpTarget.getRealPlayer().get())) 93 | target = tmpTarget.getRealPlayer().get(); 94 | } 95 | } 96 | if (target != null) 97 | playermp.networkHandler.sendPacket(new PlayerSpawnPositionS2CPacket(target.getBlockPos(), 0)); 98 | } 99 | } 100 | } 101 | } 102 | 103 | public static void hideScoreboard() { 104 | UhcGameManager.instance.getMainScoreboard().setObjectiveSlot(1, null); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/options/OptionType.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc.options; 6 | 7 | import java.lang.reflect.InvocationTargetException; 8 | import java.lang.reflect.Method; 9 | 10 | public abstract class OptionType { 11 | 12 | protected Object value; 13 | 14 | public abstract String getIncString(); 15 | public abstract String getDecString(); 16 | public abstract void applyInc(); 17 | public abstract void applyDec(); 18 | public abstract void setValue(Object nvalue); 19 | public abstract void setStringValue(String nvalue); 20 | public Object getValue() { return value; } 21 | public String getStringValue() { return getValue().toString(); } 22 | 23 | @Override 24 | public String toString() { 25 | return getStringValue(); 26 | } 27 | 28 | static abstract class NumbericType extends OptionType { 29 | 30 | protected T min, max, step; 31 | private String inc, dec; 32 | 33 | public NumbericType(T min, T max, T step) { 34 | this.min = min; 35 | this.max = max; 36 | this.step = step; 37 | inc = "+ " + step; 38 | dec = "- " + step; 39 | } 40 | 41 | @Override public String getIncString() { return inc; } 42 | @Override public String getDecString() { return dec; } 43 | 44 | } 45 | 46 | public static class IntegerType extends NumbericType { 47 | 48 | public IntegerType(int min, int max, int step) { 49 | super(min, max, step); 50 | value = 0; 51 | } 52 | @Override public void applyInc() { value = Math.min(max, (int) value + step); } 53 | @Override public void applyDec() { value = Math.max(min, (int) value - step); } 54 | @Override public void setValue(Object nvalue) { value = Math.min(max, Math.max(min, (int) nvalue)); } 55 | @Override public void setStringValue(String nvalue) { setValue(Integer.parseInt(nvalue)); } 56 | 57 | } 58 | 59 | public static class FloatType extends NumbericType { 60 | 61 | public FloatType(float min, float max, float step) { 62 | super(min, max, step); 63 | value = 0.0f; 64 | } 65 | @Override public void applyInc() { value = Math.min(max, (float) value + step); } 66 | @Override public void applyDec() { value = Math.max(min, (float) value - step); } 67 | @Override public void setValue(Object nvalue) { value = Math.min(max, Math.max(min, (float) nvalue)); } 68 | @Override public void setStringValue(String nvalue) { setValue(Float.parseFloat(nvalue)); } 69 | 70 | } 71 | 72 | public static class BooleanType extends OptionType { 73 | 74 | public BooleanType() { 75 | value = false; 76 | } 77 | @Override public String getIncString() { return "true"; } 78 | @Override public String getDecString() { return "false"; } 79 | @Override public void applyInc() { value = true; } 80 | @Override public void applyDec() { value = false; } 81 | @Override public void setValue(Object nvalue) { value = (boolean) nvalue; } 82 | @Override public void setStringValue(String nvalue) { setValue(Boolean.parseBoolean(nvalue)); } 83 | 84 | } 85 | 86 | public static class EnumType extends OptionType { 87 | 88 | private final Class enumClass; 89 | private Object[] enums; 90 | 91 | private Method getMethod(Class clazz, String func, Class ... params) { 92 | try { 93 | return clazz.getMethod(func, params); 94 | } catch (IllegalArgumentException | NoSuchMethodException | SecurityException e) { 95 | e.printStackTrace(); 96 | } 97 | return null; 98 | } 99 | 100 | private Object invokeMethod(Method method, Object obj, Object ... params) { 101 | try { 102 | return method.invoke(obj, params); 103 | } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { 104 | e.printStackTrace(); 105 | } 106 | return null; 107 | } 108 | 109 | public EnumType(Class enums) { 110 | enumClass = enums; 111 | this.enums = (Object[]) invokeMethod(getMethod(enums, "values"), null); 112 | value = 0; 113 | } 114 | @Override public String getIncString() { return enums[((int) value + 1) % enums.length].toString(); } 115 | @Override public String getDecString() { return enums[((int) value + enums.length - 1) % enums.length].toString(); } 116 | @Override public void applyInc() { value = ((int) value + 1) % enums.length; } 117 | @Override public void applyDec() { value = ((int) value + enums.length - 1) % enums.length; } 118 | @Override public void setValue(Object nvalue) { 119 | for (int i = 0; i < enums.length; i++) { 120 | if (enums[i].equals(nvalue)) { 121 | value = i; 122 | break; 123 | } 124 | } 125 | } 126 | @Override public Object getValue() { return enums[(int) value]; } 127 | @Override public void setStringValue(String nvalue) { setValue(invokeMethod(getMethod(enumClass, "valueOf", String.class), null, nvalue)); } 128 | 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/me/fallenbreath/tcuhc/UhcGamePlayer.java: -------------------------------------------------------------------------------- 1 | /* 2 | From Gamepiaynmo: https://github.com/Gamepiaynmo/TC-UHC 3 | */ 4 | 5 | package me.fallenbreath.tcuhc; 6 | 7 | import com.google.common.collect.Maps; 8 | import me.fallenbreath.tcuhc.options.Options; 9 | import me.fallenbreath.tcuhc.task.Taskable; 10 | import me.fallenbreath.tcuhc.util.Position; 11 | import net.minecraft.entity.effect.StatusEffectInstance; 12 | import net.minecraft.entity.effect.StatusEffects; 13 | import net.minecraft.entity.player.PlayerEntity; 14 | import net.minecraft.server.network.ServerPlayerEntity; 15 | import org.jetbrains.annotations.Nullable; 16 | 17 | import java.util.Map; 18 | import java.util.Optional; 19 | import java.util.UUID; 20 | 21 | public class UhcGamePlayer extends Taskable { 22 | 23 | private static final UhcPlayerManager playerManager = UhcGameManager.instance.getUhcPlayerManager(); 24 | 25 | private final UUID playerUUID; 26 | private final String playerName; 27 | 28 | protected boolean isAlive; 29 | private UhcGameTeam team; 30 | @Nullable 31 | private UhcGameColor colorSelected = null; 32 | 33 | protected int deathTime; 34 | @Nullable 35 | private Position deathPos = null; 36 | private final PlayerStatistics statistics = new PlayerStatistics(); 37 | 38 | private int borderReminder; 39 | 40 | public UhcGamePlayer(ServerPlayerEntity realPlayer) { 41 | playerUUID = realPlayer.getUuid(); 42 | playerName = realPlayer.getEntityName(); 43 | isAlive = true; 44 | } 45 | 46 | public UhcGameTeam getTeam() { return team; } 47 | protected void setTeam(UhcGameTeam team) { this.team = team; } 48 | public int getDeathTime() { return deathTime; } 49 | @Nullable 50 | public Position getDeathPos() { return deathPos; } 51 | public void resetDeathPos() { this.deathPos = null; } 52 | public void setColorSelected(@Nullable UhcGameColor color) { colorSelected = color; } 53 | public Optional getColorSelected() { return Optional.ofNullable(colorSelected); } 54 | public String getName() { return playerName; } 55 | public boolean isAlive() { return isAlive; } 56 | public PlayerStatistics getStat() { return statistics; } 57 | 58 | public boolean isSamePlayer(PlayerEntity player) { 59 | return player != null && playerUUID.equals(player.getUuid()); 60 | } 61 | 62 | public boolean isKing() { 63 | return this.getTeam() != null && this.getTeam().getKing() == this; 64 | } 65 | 66 | public void setDead(int curTime) { 67 | if (isAlive) { 68 | isAlive = false; 69 | deathTime = curTime; 70 | deathPos = getRealPlayer().map(player -> new Position(player.getPos(), player.getWorld().getRegistryKey(), player.getYaw(), player.getPitch())).orElse(null); 71 | statistics.setStat(EnumStat.ALIVE_TIME, Options.instance.getIntegerOptionValue("gameTime") - deathTime); 72 | } 73 | } 74 | 75 | public void tick() { 76 | this.updateTasks(); 77 | if (borderReminder > 0) borderReminder--; 78 | } 79 | 80 | public boolean borderRemindCooldown() { 81 | if (borderReminder == 0) { 82 | borderReminder = 200; 83 | return true; 84 | } else return false; 85 | } 86 | 87 | public Optional getRealPlayer() { 88 | return playerManager.getPlayerByUUID(playerUUID); 89 | } 90 | 91 | public void addGhostModeEffect() { 92 | this.getRealPlayer().ifPresent(player -> player.addStatusEffect(new StatusEffectInstance(StatusEffects.INVISIBILITY, Integer.MAX_VALUE, 0, true, false))); 93 | } 94 | 95 | public enum EnumStat { 96 | PLAYER_KILLED("Player Killed"), 97 | ENTITY_KILLED("Entity Killed"), 98 | DAMAGE_TAKEN("Damage Taken"), 99 | DAMAGE_BLOCKED("Damage Blocked"), 100 | DAMAGE_DEALT("Damage Dealt"), 101 | DAMAGE_BEING_BLOCKED("Damage Being Blocked"), 102 | FRIENDLY_FIRE("Friendly Fire"), 103 | CHEST_FOUND("Chest Found"), 104 | EMPTY_CHEST_FOUND("Empty Chest Found"), 105 | DIAMOND_FOUND("Diamond Found"), 106 | HEALTH_HEALED("Health Healed"), 107 | GOLDEN_APPLE_EATEN("Golden Apple Eaten"), 108 | ALIVE_TIME("Alive Time"); 109 | 110 | public final String name; 111 | 112 | EnumStat(String name) { 113 | this.name = name; 114 | } 115 | } 116 | 117 | public static class PlayerStatistics { 118 | 119 | private final Map stats = Maps.newEnumMap(EnumStat.class); 120 | 121 | public PlayerStatistics() { 122 | clear(); 123 | } 124 | 125 | public void clear() { 126 | for (EnumStat stat : EnumStat.values()) { 127 | stats.put(stat, 0.0f); 128 | } 129 | } 130 | 131 | public void addStat(EnumStat stat, float value) { 132 | if (UhcGameManager.instance.isGamePlaying()) 133 | stats.put(stat, stats.get(stat) + value); 134 | } 135 | 136 | public void setStat(EnumStat stat, float value) { 137 | if (UhcGameManager.instance.isGamePlaying()) 138 | stats.put(stat, value); 139 | } 140 | 141 | public float getFloatStat(EnumStat stat) { 142 | return stats.get(stat); 143 | } 144 | } 145 | 146 | } 147 | --------------------------------------------------------------------------------