├── src ├── generated │ └── resources │ │ ├── data │ │ └── origins │ │ │ ├── powers │ │ │ ├── like_water.json │ │ │ ├── scare_creepers.json │ │ │ ├── water_breathing.json │ │ │ ├── aquatic.json │ │ │ ├── conduit_power_on_land.json │ │ │ ├── arthropod.json │ │ │ ├── arcane_skin.json │ │ │ ├── no_cobweb_slowdown.json │ │ │ ├── cat_vision.json │ │ │ ├── burning_wrath.json │ │ │ ├── aerial_combatant.json │ │ │ ├── air_from_potions.json │ │ │ ├── burn_in_daylight.json │ │ │ ├── water_vision.json │ │ │ ├── carnivore.json │ │ │ └── aqua_affinity.json │ │ │ └── tags │ │ │ └── blocks │ │ │ └── cobwebs.json │ │ └── .cache │ │ └── cache └── main │ ├── resources │ ├── data │ │ └── origins │ │ │ ├── tags │ │ │ ├── items │ │ │ │ ├── ignore_diet.json │ │ │ │ ├── shields.json │ │ │ │ ├── ranged_weapons.json │ │ │ │ └── meat.json │ │ │ └── blocks │ │ │ │ ├── unphasable.json │ │ │ │ └── natural_stone.json │ │ │ ├── powers │ │ │ ├── translucent.json │ │ │ ├── elytra.json │ │ │ ├── velvet_paws.json │ │ │ ├── end_spawn.json │ │ │ ├── fire_immunity.json │ │ │ ├── ender_particles.json │ │ │ ├── flame_particles.json │ │ │ ├── hotblooded.json │ │ │ ├── fall_immunity.json │ │ │ ├── like_air.json │ │ │ ├── nether_spawn.json │ │ │ ├── invisibility.json │ │ │ ├── strong_arms.json │ │ │ ├── webbing.json │ │ │ ├── no_shield.json │ │ │ ├── hunger_over_time.json │ │ │ ├── more_exhaustion.json │ │ │ ├── fresh_air.json │ │ │ ├── fragile.json │ │ │ ├── natural_armor.json │ │ │ ├── tailwind.json │ │ │ ├── nine_lives.json │ │ │ ├── shulker_inventory.json │ │ │ ├── swim_speed.json │ │ │ ├── extra_reach.json │ │ │ ├── sprint_jump.json │ │ │ ├── phantomize.json │ │ │ ├── damage_from_snowballs.json │ │ │ ├── launch_into_air.json │ │ │ ├── lay_eggs.json │ │ │ ├── strong_arms_break_speed.json │ │ │ ├── throw_ender_pearl.json │ │ │ ├── damage_from_potions.json │ │ │ ├── more_kinetic_damage.json │ │ │ ├── light_armor.json │ │ │ ├── phasing.json │ │ │ ├── claustrophobia.json │ │ │ ├── pumpkin_hate.json │ │ │ ├── water_vulnerability.json │ │ │ ├── vegetarian.json │ │ │ ├── slow_falling.json │ │ │ ├── weak_arms.json │ │ │ ├── climbing.json │ │ │ ├── phantomize_overlay.json │ │ │ └── master_of_webs.json │ │ │ ├── origins │ │ │ ├── human.json │ │ │ ├── arachnid.json │ │ │ ├── avian.json │ │ │ ├── elytrian.json │ │ │ ├── shulk.json │ │ │ ├── enderian.json │ │ │ ├── feline.json │ │ │ ├── merling.json │ │ │ ├── phantom.json │ │ │ └── blazeborn.json │ │ │ ├── badges │ │ │ ├── active.json │ │ │ └── toggle.json │ │ │ └── origin_layers │ │ │ └── origin.json │ ├── pack.mcmeta │ ├── origins_icon.png │ ├── assets │ │ └── origins │ │ │ ├── icon.png │ │ │ ├── blockstates │ │ │ └── temporary_cobweb.json │ │ │ ├── textures │ │ │ ├── gui │ │ │ │ ├── badge │ │ │ │ │ ├── info.png │ │ │ │ │ ├── star.png │ │ │ │ │ ├── active.png │ │ │ │ │ ├── recipe.png │ │ │ │ │ ├── toggle.png │ │ │ │ │ └── arrow_up.png │ │ │ │ ├── resource_bar.png │ │ │ │ ├── choose_origin.png │ │ │ │ ├── extra_inventory.png │ │ │ │ ├── tooltip │ │ │ │ │ └── recipe_tooltip.png │ │ │ │ └── community │ │ │ │ │ ├── huang │ │ │ │ │ ├── resource_bar_01.png │ │ │ │ │ └── resource_bar_02.png │ │ │ │ │ └── spiderkolo │ │ │ │ │ ├── resource_bar_01.png │ │ │ │ │ ├── resource_bar_02.png │ │ │ │ │ ├── resource_bar_03.png │ │ │ │ │ └── resource_bar_points_01.png │ │ │ └── item │ │ │ │ └── orb_of_origin.png │ │ │ └── models │ │ │ └── item │ │ │ └── orb_of_origin.json │ ├── origins.mixins.json │ └── META-INF │ │ └── mods.toml │ └── java │ └── io │ └── github │ ├── apace100 │ └── origins │ │ ├── util │ │ ├── Constants.java │ │ ├── InventoryType.java │ │ ├── DebugInfo.java │ │ ├── PowerKeyManager.java │ │ ├── ChoseOriginCriterion.java │ │ └── OriginLootCondition.java │ │ ├── registry │ │ ├── ModDamageSources.java │ │ ├── ModItems.java │ │ ├── ModTags.java │ │ ├── ModEnchantments.java │ │ ├── ModLoot.java │ │ ├── ModEntities.java │ │ └── ModBlocks.java │ │ ├── power │ │ ├── OriginsEntityConditions.java │ │ ├── OriginsPowerTypes.java │ │ └── OriginsCallbackPower.java │ │ ├── mixin │ │ ├── ScreenAccessor.java │ │ ├── ConduitOnLandMixin.java │ │ ├── forge │ │ │ └── ModifyPlayerSpawnPowerMixin.java │ │ ├── WaterVisibilityMixin.java │ │ ├── NoCobwebSlowdownMixin.java │ │ ├── LikeWaterMixin.java │ │ ├── SelectionInvulnerabilityMixin.java │ │ ├── WaterBreathingMixin.java │ │ └── ScareCreepersMixin.java │ │ ├── data │ │ ├── OriginsDataTypes.java │ │ └── CompatibilityDataTypes.java │ │ ├── origin │ │ ├── Impact.java │ │ ├── OriginUpgrade.java │ │ ├── OriginLayers.java │ │ ├── OriginRegistry.java │ │ └── OriginLayer.java │ │ ├── networking │ │ └── ModPackets.java │ │ ├── enchantment │ │ └── WaterProtectionEnchantment.java │ │ ├── badge │ │ ├── SpriteBadge.java │ │ ├── Badge.java │ │ ├── BadgeFactories.java │ │ ├── TooltipBadge.java │ │ ├── BadgeFactory.java │ │ ├── KeybindBadge.java │ │ └── CraftingRecipeBadge.java │ │ ├── component │ │ └── OriginComponent.java │ │ ├── content │ │ ├── TemporaryCobwebBlock.java │ │ └── OrbOfOriginItem.java │ │ ├── command │ │ ├── LayerArgumentType.java │ │ └── OriginArgumentType.java │ │ ├── screen │ │ ├── tooltip │ │ │ └── CraftingRecipeTooltipComponent.java │ │ └── WaitForNextLayerScreen.java │ │ ├── OriginsClient.java │ │ ├── entity │ │ └── EnderianPearlEntity.java │ │ └── Origins.java │ └── edwinmindcraft │ └── origins │ ├── api │ ├── package-info.java │ ├── data │ │ ├── package-info.java │ │ └── PartialGuiTitle.java │ ├── util │ │ ├── package-info.java │ │ └── JsonUtils.java │ ├── origin │ │ ├── package-info.java │ │ ├── IOriginCallbackPower.java │ │ ├── GuiTitle.java │ │ └── OriginUpgrade.java │ ├── registry │ │ ├── package-info.java │ │ ├── OriginsDynamicRegistries.java │ │ └── OriginsBuiltinRegistries.java │ ├── capabilities │ │ └── package-info.java │ ├── event │ │ └── AutoBadgeEvent.java │ └── OriginsAPI.java │ ├── client │ ├── OriginsClientUtils.java │ ├── OriginsClient.java │ └── OriginsClientEventHandler.java │ ├── data │ ├── tag │ │ ├── OriginsItemTags.java │ │ └── OriginsBlockTags.java │ ├── generator │ │ └── OriginsBlockTagProvider.java │ └── OriginsData.java │ └── common │ ├── power │ ├── configuration │ │ ├── WaterVisionConfiguration.java │ │ ├── NoSlowdownConfiguration.java │ │ └── OriginsCallbackConfiguration.java │ ├── NoSlowdownPower.java │ └── WaterVisionPower.java │ ├── network │ ├── C2SAcknowledgeOrigins.java │ ├── S2COpenOriginScreen.java │ ├── S2CSynchronizeBadges.java │ ├── S2CConfirmOrigin.java │ ├── S2CSynchronizeOrigin.java │ ├── C2SChooseRandomOrigin.java │ └── C2SChooseOrigin.java │ ├── condition │ ├── configuration │ │ └── OriginConfiguration.java │ └── OriginCondition.java │ ├── data │ ├── LayerLoader.java │ └── OriginLoader.java │ ├── OriginsConfigs.java │ ├── registry │ └── OriginRegisters.java │ └── OriginsCommon.java ├── .gitignore ├── README.md └── LICENSE /src/generated/resources/data/origins/powers/like_water.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:like_water" 3 | } -------------------------------------------------------------------------------- /src/generated/resources/data/origins/powers/scare_creepers.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:scare_creepers" 3 | } -------------------------------------------------------------------------------- /src/generated/resources/data/origins/powers/water_breathing.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:water_breathing" 3 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/tags/items/ignore_diet.json: -------------------------------------------------------------------------------- 1 | { 2 | "replace": false, 3 | "values": [] 4 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/translucent.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:model_color", 3 | "alpha": 0.5 4 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/elytra.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:elytra_flight", 3 | "render_elytra": true 4 | } -------------------------------------------------------------------------------- /src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": "Origins Resources", 4 | "pack_format": 8 5 | } 6 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/velvet_paws.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:prevent_game_event", 3 | "event": "minecraft:step" 4 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/tags/items/shields.json: -------------------------------------------------------------------------------- 1 | { 2 | "replace": false, 3 | "values": [ 4 | "minecraft:shield" 5 | ] 6 | } -------------------------------------------------------------------------------- /src/main/resources/origins_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwinMindcraft/origins-architectury/HEAD/src/main/resources/origins_icon.png -------------------------------------------------------------------------------- /src/generated/resources/data/origins/powers/aquatic.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": "aquatic", 3 | "hidden": true, 4 | "type": "apoli:entity_group" 5 | } -------------------------------------------------------------------------------- /src/generated/resources/data/origins/powers/conduit_power_on_land.json: -------------------------------------------------------------------------------- 1 | { 2 | "hidden": true, 3 | "type": "origins:conduit_power_on_land" 4 | } -------------------------------------------------------------------------------- /src/generated/resources/data/origins/powers/arthropod.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": "arthropod", 3 | "hidden": true, 4 | "type": "apoli:entity_group" 5 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/origins/human.json: -------------------------------------------------------------------------------- 1 | { 2 | "icon": { 3 | "item": "minecraft:player_head" 4 | }, 5 | "order": 0, 6 | "impact": 0 7 | } -------------------------------------------------------------------------------- /src/main/resources/assets/origins/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwinMindcraft/origins-architectury/HEAD/src/main/resources/assets/origins/icon.png -------------------------------------------------------------------------------- /src/main/resources/data/origins/badges/active.json: -------------------------------------------------------------------------------- 1 | { 2 | "sprite": "origins:textures/gui/badge/active.png", 3 | "text": "origins.gui.badge.active" 4 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/badges/toggle.json: -------------------------------------------------------------------------------- 1 | { 2 | "sprite": "origins:textures/gui/badge/toggle.png", 3 | "text": "origins.gui.badge.toggle" 4 | } -------------------------------------------------------------------------------- /src/generated/resources/data/origins/powers/arcane_skin.json: -------------------------------------------------------------------------------- 1 | { 2 | "red": 0.5, 3 | "green": 0.5, 4 | "alpha": 0.7, 5 | "type": "apoli:model_color" 6 | } -------------------------------------------------------------------------------- /src/generated/resources/data/origins/powers/no_cobweb_slowdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "tag": "origins:cobwebs", 3 | "hidden": true, 4 | "type": "origins:no_slowdown" 5 | } -------------------------------------------------------------------------------- /src/main/resources/assets/origins/blockstates/temporary_cobweb.json: -------------------------------------------------------------------------------- 1 | { 2 | "variants": { 3 | "": { "model": "minecraft:block/cobweb" } 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/end_spawn.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:modify_player_spawn", 3 | "dimension": "the_end", 4 | "spawn_strategy": "center" 5 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/fire_immunity.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:invulnerability", 3 | "damage_condition": { 4 | "type": "origins:fire" 5 | } 6 | } -------------------------------------------------------------------------------- /src/generated/resources/data/origins/tags/blocks/cobwebs.json: -------------------------------------------------------------------------------- 1 | { 2 | "replace": false, 3 | "values": [ 4 | "minecraft:cobweb", 5 | "origins:temporary_cobweb" 6 | ] 7 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/ender_particles.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:particle", 3 | "particle": "minecraft:portal", 4 | "frequency": 4, 5 | "hidden": true 6 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/flame_particles.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:particle", 3 | "particle": "minecraft:flame", 4 | "frequency": 4, 5 | "hidden": true 6 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/hotblooded.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:effect_immunity", 3 | "effects": [ 4 | "minecraft:poison", 5 | "minecraft:hunger" 6 | ] 7 | } -------------------------------------------------------------------------------- /src/main/resources/assets/origins/textures/gui/badge/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwinMindcraft/origins-architectury/HEAD/src/main/resources/assets/origins/textures/gui/badge/info.png -------------------------------------------------------------------------------- /src/main/resources/assets/origins/textures/gui/badge/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwinMindcraft/origins-architectury/HEAD/src/main/resources/assets/origins/textures/gui/badge/star.png -------------------------------------------------------------------------------- /src/main/resources/assets/origins/models/item/orb_of_origin.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "item/generated", 3 | "textures": { 4 | "layer0": "origins:item/orb_of_origin" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/origins/textures/gui/badge/active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwinMindcraft/origins-architectury/HEAD/src/main/resources/assets/origins/textures/gui/badge/active.png -------------------------------------------------------------------------------- /src/main/resources/assets/origins/textures/gui/badge/recipe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwinMindcraft/origins-architectury/HEAD/src/main/resources/assets/origins/textures/gui/badge/recipe.png -------------------------------------------------------------------------------- /src/main/resources/assets/origins/textures/gui/badge/toggle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwinMindcraft/origins-architectury/HEAD/src/main/resources/assets/origins/textures/gui/badge/toggle.png -------------------------------------------------------------------------------- /src/main/resources/assets/origins/textures/gui/resource_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwinMindcraft/origins-architectury/HEAD/src/main/resources/assets/origins/textures/gui/resource_bar.png -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/fall_immunity.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:invulnerability", 3 | "damage_condition": { 4 | "type": "origins:name", 5 | "name": "fall" 6 | } 7 | } -------------------------------------------------------------------------------- /src/main/resources/assets/origins/textures/gui/badge/arrow_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwinMindcraft/origins-architectury/HEAD/src/main/resources/assets/origins/textures/gui/badge/arrow_up.png -------------------------------------------------------------------------------- /src/main/resources/assets/origins/textures/gui/choose_origin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwinMindcraft/origins-architectury/HEAD/src/main/resources/assets/origins/textures/gui/choose_origin.png -------------------------------------------------------------------------------- /src/main/resources/assets/origins/textures/gui/extra_inventory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwinMindcraft/origins-architectury/HEAD/src/main/resources/assets/origins/textures/gui/extra_inventory.png -------------------------------------------------------------------------------- /src/main/resources/assets/origins/textures/item/orb_of_origin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwinMindcraft/origins-architectury/HEAD/src/main/resources/assets/origins/textures/item/orb_of_origin.png -------------------------------------------------------------------------------- /src/main/resources/data/origins/tags/items/ranged_weapons.json: -------------------------------------------------------------------------------- 1 | { 2 | "replace": false, 3 | "values": [ 4 | "minecraft:bow", 5 | "minecraft:crossbow", 6 | "minecraft:trident" 7 | ] 8 | } -------------------------------------------------------------------------------- /src/main/resources/assets/origins/textures/gui/tooltip/recipe_tooltip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwinMindcraft/origins-architectury/HEAD/src/main/resources/assets/origins/textures/gui/tooltip/recipe_tooltip.png -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/like_air.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:attribute_modify_transfer", 3 | "class": "modify_air_speed", 4 | "attribute": "minecraft:generic.movement_speed", 5 | "multiplier": 1 6 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/nether_spawn.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:modify_player_spawn", 3 | "dimension": "the_nether", 4 | "dimension_distance_multiplier": 0.125, 5 | "spawn_strategy": "center" 6 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/invisibility.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:invisibility", 3 | "render_armor": true, 4 | "condition": { 5 | "type": "origins:power_active", 6 | "power": "*:phantomize" 7 | } 8 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/strong_arms.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:modify_harvest", 3 | "allow": true, 4 | "block_condition": { 5 | "type": "origins:in_tag", 6 | "tag": "origins:natural_stone" 7 | } 8 | } -------------------------------------------------------------------------------- /src/main/resources/assets/origins/textures/gui/community/huang/resource_bar_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwinMindcraft/origins-architectury/HEAD/src/main/resources/assets/origins/textures/gui/community/huang/resource_bar_01.png -------------------------------------------------------------------------------- /src/main/resources/assets/origins/textures/gui/community/huang/resource_bar_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwinMindcraft/origins-architectury/HEAD/src/main/resources/assets/origins/textures/gui/community/huang/resource_bar_02.png -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/webbing.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:cooldown", 3 | "cooldown": 120, 4 | "hud_render": { 5 | "sprite_location": "origins:textures/gui/resource_bar.png", 6 | "bar_index": 5 7 | } 8 | } -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/util/Constants.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.util; 2 | 3 | public class Constants { 4 | 5 | public static final int[] LIGHT_ARMOR_MAX_PROTECTION = new int[] {1, 4, 5, 2}; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/no_shield.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:prevent_item_use", 3 | "item_condition": { 4 | "type": "origins:ingredient", 5 | "ingredient": { 6 | "tag": "origins:shields" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/tags/blocks/unphasable.json: -------------------------------------------------------------------------------- 1 | { 2 | "replace": false, 3 | "values": [ 4 | "minecraft:barrier", 5 | "minecraft:bedrock", 6 | "minecraft:crying_obsidian", 7 | "minecraft:obsidian" 8 | ] 9 | } -------------------------------------------------------------------------------- /src/main/resources/assets/origins/textures/gui/community/spiderkolo/resource_bar_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwinMindcraft/origins-architectury/HEAD/src/main/resources/assets/origins/textures/gui/community/spiderkolo/resource_bar_01.png -------------------------------------------------------------------------------- /src/main/resources/assets/origins/textures/gui/community/spiderkolo/resource_bar_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwinMindcraft/origins-architectury/HEAD/src/main/resources/assets/origins/textures/gui/community/spiderkolo/resource_bar_02.png -------------------------------------------------------------------------------- /src/main/resources/assets/origins/textures/gui/community/spiderkolo/resource_bar_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwinMindcraft/origins-architectury/HEAD/src/main/resources/assets/origins/textures/gui/community/spiderkolo/resource_bar_03.png -------------------------------------------------------------------------------- /src/generated/resources/data/origins/powers/cat_vision.json: -------------------------------------------------------------------------------- 1 | { 2 | "strength": 0.4, 3 | "condition": { 4 | "fluid": "minecraft:water", 5 | "inverted": true, 6 | "type": "apoli:submerged_in" 7 | }, 8 | "type": "apoli:night_vision" 9 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/hunger_over_time.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:exhaust", 3 | "interval": 20, 4 | "exhaustion": 0.812, 5 | "condition": { 6 | "type": "origins:power_active", 7 | "power": "*:phantomize" 8 | } 9 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/more_exhaustion.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:modify_exhaustion", 3 | "modifier": { 4 | "name": "Extra exhaustion from large appetite", 5 | "value": 0.6, 6 | "operation": "multiply_base" 7 | } 8 | } -------------------------------------------------------------------------------- /src/main/resources/assets/origins/textures/gui/community/spiderkolo/resource_bar_points_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwinMindcraft/origins-architectury/HEAD/src/main/resources/assets/origins/textures/gui/community/spiderkolo/resource_bar_points_01.png -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/fresh_air.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:prevent_sleep", 3 | "block_condition": { 4 | "type": "origins:height", 5 | "comparison": "<", 6 | "compare_to": 86 7 | }, 8 | "message": "origins.avian_sleep_fail" 9 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/fragile.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:attribute", 3 | "modifier": { 4 | "name": "Fragile health reduction", 5 | "attribute": "minecraft:generic.max_health", 6 | "value": -6.0, 7 | "operation": "addition" 8 | } 9 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/natural_armor.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:attribute", 3 | "modifier": { 4 | "name": "Natural Armor health bonus", 5 | "attribute": "minecraft:generic.armor", 6 | "value": 8.0, 7 | "operation": "addition" 8 | } 9 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/tailwind.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:attribute", 3 | "modifier": { 4 | "name": "Tailwind speed bonus", 5 | "attribute": "minecraft:generic.movement_speed", 6 | "value": 0.2, 7 | "operation": "multiply_base" 8 | } 9 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/nine_lives.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:attribute", 3 | "modifier": { 4 | "name": "Nine lives health reduction", 5 | "attribute": "minecraft:generic.max_health", 6 | "value": -2.0, 7 | "operation": "addition" 8 | } 9 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/shulker_inventory.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:inventory", 3 | "title": "container.shulker_inventory_power", 4 | "drop_on_death": false, 5 | "key": { 6 | "key": "key.origins.primary_active", 7 | "continuous": false 8 | } 9 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/swim_speed.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:attribute", 3 | "modifier": { 4 | "attribute": "additionalentityattributes:water_speed", 5 | "name": "Additional swim speed", 6 | "value": 1.5, 7 | "operation": "multiply_base" 8 | } 9 | } -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/api/package-info.java: -------------------------------------------------------------------------------- 1 | @MethodsReturnNonnullByDefault 2 | @ParametersAreNonnullByDefault 3 | package io.github.edwinmindcraft.origins.api; 4 | 5 | import net.minecraft.MethodsReturnNonnullByDefault; 6 | 7 | import javax.annotation.ParametersAreNonnullByDefault; -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/extra_reach.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:attribute", 3 | "modifiers": [ 4 | { 5 | "name": "Extra Reach block reach", 6 | "attribute": "forge:reach_distance", 7 | "value": 1.5, 8 | "operation": "addition" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /src/generated/resources/data/origins/powers/burning_wrath.json: -------------------------------------------------------------------------------- 1 | { 2 | "modifier": { 3 | "name": "Additional damage while on fire", 4 | "value": 3.0, 5 | "operation": "addition" 6 | }, 7 | "condition": { 8 | "type": "apoli:on_fire" 9 | }, 10 | "type": "apoli:modify_damage_dealt" 11 | } -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/api/data/package-info.java: -------------------------------------------------------------------------------- 1 | @MethodsReturnNonnullByDefault 2 | @ParametersAreNonnullByDefault 3 | package io.github.edwinmindcraft.origins.api.data; 4 | 5 | import net.minecraft.MethodsReturnNonnullByDefault; 6 | 7 | import javax.annotation.ParametersAreNonnullByDefault; -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/api/util/package-info.java: -------------------------------------------------------------------------------- 1 | @MethodsReturnNonnullByDefault 2 | @ParametersAreNonnullByDefault 3 | package io.github.edwinmindcraft.origins.api.util; 4 | 5 | import net.minecraft.MethodsReturnNonnullByDefault; 6 | 7 | import javax.annotation.ParametersAreNonnullByDefault; -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/sprint_jump.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:modify_jump", 3 | "modifier": { 4 | "name": "Bonus jump force while sprinting", 5 | "value": 0.5, 6 | "operation": "multiply_base" 7 | }, 8 | "condition": { 9 | "type": "origins:sprinting" 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 | # fabric 28 | 29 | run/ 30 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/api/origin/package-info.java: -------------------------------------------------------------------------------- 1 | @MethodsReturnNonnullByDefault 2 | @ParametersAreNonnullByDefault 3 | package io.github.edwinmindcraft.origins.api.origin; 4 | 5 | import net.minecraft.MethodsReturnNonnullByDefault; 6 | 7 | import javax.annotation.ParametersAreNonnullByDefault; -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/api/registry/package-info.java: -------------------------------------------------------------------------------- 1 | @MethodsReturnNonnullByDefault 2 | @ParametersAreNonnullByDefault 3 | package io.github.edwinmindcraft.origins.api.registry; 4 | 5 | import net.minecraft.MethodsReturnNonnullByDefault; 6 | 7 | import javax.annotation.ParametersAreNonnullByDefault; -------------------------------------------------------------------------------- /src/main/resources/data/origins/origins/arachnid.json: -------------------------------------------------------------------------------- 1 | { 2 | "powers": [ 3 | "origins:climbing", 4 | "origins:master_of_webs", 5 | "origins:carnivore", 6 | "origins:fragile", 7 | "origins:arthropod" 8 | ], 9 | "icon": { 10 | "item": "minecraft:cobweb" 11 | }, 12 | "order": 1, 13 | "impact": 1 14 | } -------------------------------------------------------------------------------- /src/generated/resources/data/origins/powers/aerial_combatant.json: -------------------------------------------------------------------------------- 1 | { 2 | "modifier": { 3 | "name": "Extra damage while fall flying", 4 | "value": 1.0, 5 | "operation": "multiply_base" 6 | }, 7 | "condition": { 8 | "type": "apoli:fall_flying" 9 | }, 10 | "type": "apoli:modify_damage_dealt" 11 | } -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/api/capabilities/package-info.java: -------------------------------------------------------------------------------- 1 | @MethodsReturnNonnullByDefault 2 | @ParametersAreNonnullByDefault 3 | package io.github.edwinmindcraft.origins.api.capabilities; 4 | 5 | import net.minecraft.MethodsReturnNonnullByDefault; 6 | 7 | import javax.annotation.ParametersAreNonnullByDefault; -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/phantomize.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:toggle", 3 | "key": { 4 | "key": "key.origins.primary_active", 5 | "continuous": false 6 | }, 7 | "retain_state": false, 8 | "condition": { 9 | "type": "apoli:food_level", 10 | "comparison": ">", 11 | "compare_to": 6 12 | } 13 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/origins/avian.json: -------------------------------------------------------------------------------- 1 | { 2 | "powers": [ 3 | "origins:slow_falling", 4 | "origins:fresh_air", 5 | "origins:like_air", 6 | "origins:tailwind", 7 | "origins:lay_eggs", 8 | "origins:vegetarian" 9 | ], 10 | "icon": { 11 | "item": "minecraft:feather" 12 | }, 13 | "order": 0, 14 | "impact": 1 15 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/tags/blocks/natural_stone.json: -------------------------------------------------------------------------------- 1 | { 2 | "replace": false, 3 | "values": [ 4 | "#minecraft:base_stone_overworld", 5 | "#minecraft:base_stone_nether", 6 | "minecraft:sandstone", 7 | "minecraft:smooth_sandstone", 8 | "minecraft:red_sandstone", 9 | "minecraft:smooth_red_sandstone" 10 | ] 11 | } -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/registry/ModDamageSources.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.registry; 2 | 3 | import net.minecraft.world.damagesource.DamageSource; 4 | 5 | public class ModDamageSources { 6 | 7 | public static final DamageSource NO_WATER_FOR_GILLS = new DamageSource("no_water_for_gills").bypassArmor().bypassMagic(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/resources/data/origins/origins/elytrian.json: -------------------------------------------------------------------------------- 1 | { 2 | "powers": [ 3 | "origins:elytra", 4 | "origins:launch_into_air", 5 | "origins:aerial_combatant", 6 | "origins:light_armor", 7 | "origins:claustrophobia", 8 | "origins:more_kinetic_damage" 9 | ], 10 | "icon": { 11 | "item": "minecraft:elytra" 12 | }, 13 | "order": 3, 14 | "impact": 1 15 | } -------------------------------------------------------------------------------- /src/generated/resources/data/origins/powers/air_from_potions.json: -------------------------------------------------------------------------------- 1 | { 2 | "item_condition": { 3 | "ingredient": { 4 | "item": "minecraft:potion" 5 | }, 6 | "type": "apoli:ingredient" 7 | }, 8 | "entity_action": { 9 | "value": 60, 10 | "type": "apoli:gain_air" 11 | }, 12 | "hidden": true, 13 | "type": "apoli:action_on_item_use" 14 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/origins/shulk.json: -------------------------------------------------------------------------------- 1 | { 2 | "powers": [ 3 | "origins:shulker_inventory", 4 | "origins:natural_armor", 5 | "origins:strong_arms", 6 | "origins:strong_arms_break_speed", 7 | "origins:no_shield", 8 | "origins:more_exhaustion" 9 | ], 10 | "icon": { 11 | "item": "minecraft:shulker_shell" 12 | }, 13 | "order": 4, 14 | "impact": 1 15 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/origins/enderian.json: -------------------------------------------------------------------------------- 1 | { 2 | "powers": [ 3 | "origins:throw_ender_pearl", 4 | "origins:water_vulnerability", 5 | "origins:pumpkin_hate", 6 | "origins:extra_reach", 7 | "origins:ender_particles", 8 | "origins:damage_from_potions" 9 | ], 10 | "icon": { 11 | "item": "minecraft:ender_pearl" 12 | }, 13 | "order": 1, 14 | "impact": 2 15 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/origins/feline.json: -------------------------------------------------------------------------------- 1 | { 2 | "powers": [ 3 | "origins:fall_immunity", 4 | "origins:sprint_jump", 5 | "origins:velvet_paws", 6 | "origins:nine_lives", 7 | "origins:weak_arms", 8 | "origins:scare_creepers", 9 | "origins:cat_vision" 10 | ], 11 | "icon": { 12 | "item": "minecraft:orange_wool" 13 | }, 14 | "order": 0, 15 | "impact": 2 16 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/damage_from_snowballs.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:modify_damage_taken", 3 | "modifier": { 4 | "name": "Snowball damage taken like Blazes", 5 | "value": 3, 6 | "operation": "addition" 7 | }, 8 | "damage_condition": { 9 | "type": "origins:projectile", 10 | "projectile": "minecraft:snowball" 11 | }, 12 | "hidden": true 13 | } -------------------------------------------------------------------------------- /src/generated/resources/data/origins/powers/burn_in_daylight.json: -------------------------------------------------------------------------------- 1 | { 2 | "interval": 20, 3 | "burn_duration": 6, 4 | "condition": { 5 | "conditions": [ 6 | { 7 | "type": "apoli:exposed_to_sun" 8 | }, 9 | { 10 | "inverted": true, 11 | "type": "apoli:invisible" 12 | } 13 | ], 14 | "type": "apoli:and" 15 | }, 16 | "type": "apoli:burn" 17 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/launch_into_air.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:launch", 3 | "cooldown": 600, 4 | "hud_render": { 5 | "sprite_location": "origins:textures/gui/resource_bar.png", 6 | "bar_index": 4 7 | }, 8 | "sound": "minecraft:entity.parrot.fly", 9 | "speed": 2, 10 | "key": { 11 | "key": "key.origins.primary_active", 12 | "continuous": true 13 | } 14 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/origins/merling.json: -------------------------------------------------------------------------------- 1 | { 2 | "powers": [ 3 | "origins:water_breathing", 4 | "origins:water_vision", 5 | "origins:aqua_affinity", 6 | "origins:swim_speed", 7 | "origins:like_water", 8 | "origins:aquatic", 9 | "origins:conduit_power_on_land", 10 | "origins:air_from_potions" 11 | ], 12 | "icon": { 13 | "item": "minecraft:cod" 14 | }, 15 | "order": 0, 16 | "impact": 3 17 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/origins/phantom.json: -------------------------------------------------------------------------------- 1 | { 2 | "powers": [ 3 | "origins:phantomize", 4 | "origins:translucent", 5 | "origins:phasing", 6 | "origins:invisibility", 7 | "origins:burn_in_daylight", 8 | "origins:hunger_over_time", 9 | "origins:fragile", 10 | "origins:phantomize_overlay" 11 | ], 12 | "icon": { 13 | "item": "minecraft:phantom_membrane" 14 | }, 15 | "order": 2, 16 | "impact": 3 17 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/origins/blazeborn.json: -------------------------------------------------------------------------------- 1 | { 2 | "powers": [ 3 | "origins:fire_immunity", 4 | "origins:nether_spawn", 5 | "origins:burning_wrath", 6 | "origins:hotblooded", 7 | "origins:water_vulnerability", 8 | "origins:flame_particles", 9 | "origins:damage_from_snowballs", 10 | "origins:damage_from_potions" 11 | ], 12 | "icon": { 13 | "item": "minecraft:blaze_powder" 14 | }, 15 | "order": 1, 16 | "impact": 3 17 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/lay_eggs.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:action_on_wake_up", 3 | "entity_action": { 4 | "type": "origins:and", 5 | "actions": [ 6 | { 7 | "type": "origins:give", 8 | "stack": { 9 | "item": "minecraft:egg" 10 | } 11 | }, 12 | { 13 | "type": "origins:play_sound", 14 | "sound": "minecraft:entity.chicken.egg" 15 | } 16 | ] 17 | } 18 | } -------------------------------------------------------------------------------- /src/generated/resources/data/origins/powers/water_vision.json: -------------------------------------------------------------------------------- 1 | { 2 | "vision": { 3 | "condition": { 4 | "power": "*:*_toggle", 5 | "type": "apoli:power_active" 6 | }, 7 | "type": "origins:water_vision" 8 | }, 9 | "toggle": { 10 | "active_by_default": true, 11 | "condition": { 12 | "fluid": "minecraft:water", 13 | "type": "apoli:submerged_in" 14 | }, 15 | "type": "apoli:toggle_night_vision" 16 | }, 17 | "type": "apoli:multiple" 18 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/strong_arms_break_speed.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:modify_break_speed", 3 | "block_condition": { 4 | "type": "origins:in_tag", 5 | "tag": "origins:natural_stone" 6 | }, 7 | "condition": { 8 | "type": "origins:using_effective_tool", 9 | "inverted": true 10 | }, 11 | "modifier": { 12 | "name": "Strong Arms stone break speed bonus", 13 | "value": 0.06, 14 | "operation": "addition" 15 | }, 16 | "hidden": true 17 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/throw_ender_pearl.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:fire_projectile", 3 | "cooldown": 30, 4 | "hud_render": { 5 | "sprite_location": "origins:textures/gui/resource_bar.png", 6 | "bar_index": 6 7 | }, 8 | "entity_type": "origins:enderian_pearl", 9 | "sound": "minecraft:entity.ender_pearl.throw", 10 | "speed": 1.5, 11 | "divergence": 1, 12 | "key": { 13 | "key": "key.origins.primary_active", 14 | "continuous": false 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/damage_from_potions.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:action_on_item_use", 3 | "hidden": true, 4 | "item_condition": { 5 | "type": "origins:ingredient", 6 | "ingredient": { 7 | "item": "minecraft:potion" 8 | } 9 | }, 10 | "entity_action": { 11 | "type": "origins:damage", 12 | "amount": 2, 13 | "source": { 14 | "name": "hurt_by_water", 15 | "unblockable": true, 16 | "bypasses_armor": true 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/client/OriginsClientUtils.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.client; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.world.entity.player.Player; 5 | import net.minecraft.world.level.Level; 6 | 7 | public class OriginsClientUtils { 8 | public static Level getClientLevel() { 9 | return Minecraft.getInstance().level; 10 | } 11 | 12 | public static Player getClientPlayer() { 13 | return Minecraft.getInstance().player; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/more_kinetic_damage.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:modify_damage_taken", 3 | "modifier": { 4 | "name": "More kinetic damage taken", 5 | "value": 0.5, 6 | "operation": "multiply_base" 7 | }, 8 | "damage_condition": { 9 | "type": "origins:or", 10 | "conditions": [ 11 | { 12 | "type": "origins:name", 13 | "name": "fall" 14 | }, 15 | { 16 | "type": "origins:name", 17 | "name": "flyIntoWall" 18 | } 19 | ] 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/light_armor.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:restrict_armor", 3 | "head": { 4 | "type": "origins:armor_value", 5 | "comparison": ">", 6 | "compare_to": 2 7 | }, 8 | "chest": { 9 | "type": "origins:armor_value", 10 | "comparison": ">", 11 | "compare_to": 5 12 | }, 13 | "legs": { 14 | "type": "origins:armor_value", 15 | "comparison": ">", 16 | "compare_to": 4 17 | }, 18 | "feet": { 19 | "type": "origins:armor_value", 20 | "comparison": ">", 21 | "compare_to": 1 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/registry/ModItems.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.registry; 2 | 3 | import io.github.apace100.origins.content.OrbOfOriginItem; 4 | import io.github.edwinmindcraft.origins.common.registry.OriginRegisters; 5 | import net.minecraft.world.item.Item; 6 | import net.minecraftforge.registries.RegistryObject; 7 | 8 | public class ModItems { 9 | 10 | public static final RegistryObject ORB_OF_ORIGIN = OriginRegisters.ITEMS.register("orb_of_origin", OrbOfOriginItem::new); 11 | 12 | public static void register() {} 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/client/OriginsClient.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.client; 2 | 3 | import net.minecraftforge.api.distmarker.Dist; 4 | import net.minecraftforge.api.distmarker.OnlyIn; 5 | 6 | import java.util.concurrent.atomic.AtomicBoolean; 7 | 8 | @OnlyIn(Dist.CLIENT) 9 | public class OriginsClient { 10 | public static final AtomicBoolean AWAITING_DISPLAY = new AtomicBoolean(); 11 | public static final AtomicBoolean OPEN_NEXT_LAYER = new AtomicBoolean(); 12 | public static boolean SHOW_DIRT_BACKGROUND = false; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/resources/data/origins/origin_layers/origin.json: -------------------------------------------------------------------------------- 1 | { 2 | "replace": false, 3 | "order": 0, 4 | "enabled": true, 5 | "origins": [ 6 | "origins:arachnid", 7 | "origins:avian", 8 | "origins:blazeborn", 9 | "origins:elytrian", 10 | "origins:enderian", 11 | "origins:feline", 12 | "origins:human", 13 | "origins:merling", 14 | "origins:phantom", 15 | "origins:shulk" 16 | ], 17 | "allow_random": true, 18 | "exclude_random": [ 19 | "origins:human" 20 | ], 21 | "allow_random_unchoosable": false, 22 | "hidden": false 23 | } -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/power/OriginsEntityConditions.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.power; 2 | 3 | import io.github.edwinmindcraft.origins.common.condition.OriginCondition; 4 | import io.github.edwinmindcraft.origins.common.registry.OriginRegisters; 5 | import net.minecraftforge.registries.RegistryObject; 6 | 7 | public class OriginsEntityConditions { 8 | 9 | public static final RegistryObject ORIGIN = OriginRegisters.ENTITY_CONDITIONS.register("origin", OriginCondition::new); 10 | 11 | public static void register() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/phasing.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:phasing", 3 | "blacklist": true, 4 | "render_type": "blindness", 5 | "view_distance": 10, 6 | "block_condition": { 7 | "type": "origins:in_tag", 8 | "tag": "origins:unphasable" 9 | }, 10 | "phase_down_condition": { 11 | "type": "origins:and", 12 | "conditions": [ 13 | { 14 | "type": "origins:sneaking" 15 | }, 16 | { 17 | "type": "origins:on_block" 18 | } 19 | ] 20 | }, 21 | "condition": { 22 | "type": "origins:power_active", 23 | "power": "*:phantomize" 24 | } 25 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Origins (Forge) 2 | 3 | This is the repository for the source of the unofficial forge port of the Origins mod. 4 | 5 | ## Resources 6 | Datapacks: Origins forge is supposed to be fully compatible with fabric datapacks, if you want more information, please 7 | visit [the official wiki](https://origins.readthedocs.io/) written for fabric. 8 | 9 | ## Building from source 10 | 11 | The code to build the repository has moved to [here](https://github.com/EdwinMindcraft/origins-forge). 12 | 13 | ### Disclaimer: 14 | The project doesn't allow for the creation of a unified build yet, which is why there isn't a release 15 | with the new bugfixes. -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/mixin/ScreenAccessor.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.mixin; 2 | 3 | import com.mojang.blaze3d.vertex.PoseStack; 4 | import net.minecraft.client.gui.screens.Screen; 5 | import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.gen.Invoker; 8 | 9 | import java.util.List; 10 | 11 | @Mixin(Screen.class) 12 | public interface ScreenAccessor { 13 | 14 | @Invoker("renderTooltipInternal") 15 | void invokeRenderTooltipFromComponents(PoseStack matrices, List components, int x, int y); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/origins.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8.4", 4 | "package": "io.github.apace100.origins.mixin", 5 | "compatibilityLevel": "JAVA_17", 6 | "mixins": [ 7 | "ConduitOnLandMixin", 8 | "LikeWaterMixin", 9 | "NoCobwebSlowdownMixin", 10 | "ScareCreepersMixin", 11 | "SelectionInvulnerabilityMixin", 12 | "WaterBreathingMixin$CanBreatheInWater", 13 | "WaterBreathingMixin$UpdateAir", 14 | "forge.ModifyPlayerSpawnPowerMixin" 15 | ], 16 | "client": [ 17 | "ScreenAccessor", 18 | "WaterVisibilityMixin" 19 | ], 20 | "refmap": "origins.refmap.json", 21 | "injectors": { 22 | "defaultRequire": 1 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/data/tag/OriginsItemTags.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.data.tag; 2 | 3 | import io.github.apace100.origins.Origins; 4 | import net.minecraft.tags.ItemTags; 5 | import net.minecraft.tags.TagKey; 6 | import net.minecraft.world.item.Item; 7 | 8 | public class OriginsItemTags { 9 | private static TagKey tag(String path) { 10 | return ItemTags.create(Origins.identifier(path)); 11 | } 12 | 13 | public static final TagKey MEAT = tag("meat"); 14 | public static final TagKey IGNORE_DIET = tag("ignore_diet"); 15 | public static final TagKey RANGED_WEAPONS = tag("ranged_weapons"); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/claustrophobia.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:stacking_status_effect", 3 | "min_stacks": -20, 4 | "max_stacks": 361, 5 | "duration_per_stack": 10, 6 | "effects": [ 7 | { 8 | "effect": "minecraft:weakness", 9 | "is_ambient": true, 10 | "show_particles": false, 11 | "show_icon": true 12 | }, 13 | { 14 | "effect": "minecraft:slowness", 15 | "is_ambient": true, 16 | "show_particles": false, 17 | "show_icon": true 18 | } 19 | ], 20 | "condition": { 21 | "type": "origins:block_collision", 22 | "offset_x": 0, 23 | "offset_y": 1, 24 | "offset_z": 0 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/common/power/configuration/WaterVisionConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.common.power.configuration; 2 | 3 | import com.mojang.serialization.Codec; 4 | import io.github.edwinmindcraft.apoli.api.IDynamicFeatureConfiguration; 5 | import io.github.edwinmindcraft.calio.api.network.CalioCodecHelper; 6 | 7 | public record WaterVisionConfiguration(float strength) implements IDynamicFeatureConfiguration { 8 | public static final Codec CODEC = CalioCodecHelper.optionalField(CalioCodecHelper.FLOAT, "strength", 1.0F).xmap(WaterVisionConfiguration::new, WaterVisionConfiguration::strength).codec(); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/data/tag/OriginsBlockTags.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.data.tag; 2 | 3 | import io.github.apace100.origins.Origins; 4 | import net.minecraft.tags.BlockTags; 5 | import net.minecraft.tags.TagKey; 6 | import net.minecraft.world.level.block.Block; 7 | 8 | public class OriginsBlockTags { 9 | private static TagKey tag(String path) { 10 | return BlockTags.create(Origins.identifier(path)); 11 | } 12 | 13 | public static final TagKey COBWEBS = tag("cobwebs"); 14 | public static final TagKey UNPHASABLE = tag("unphasable"); 15 | public static final TagKey NATURAL_STONE = tag("natural_stone"); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/pumpkin_hate.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:multiple", 3 | "prevent_eating": { 4 | "type": "origins:prevent_item_use", 5 | "item_condition": { 6 | "type": "origins:ingredient", 7 | "ingredient": { 8 | "item": "minecraft:pumpkin_pie" 9 | } 10 | } 11 | }, 12 | "prevent_seeing": { 13 | "type": "origins:prevent_entity_render", 14 | "entity_condition": { 15 | "type": "origins:equipped_item", 16 | "equipment_slot": "head", 17 | "item_condition": { 18 | "type": "origins:ingredient", 19 | "ingredient": { 20 | "item": "minecraft:carved_pumpkin" 21 | } 22 | } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/tags/items/meat.json: -------------------------------------------------------------------------------- 1 | { 2 | "replace": false, 3 | "values": [ 4 | "minecraft:rotten_flesh", 5 | "minecraft:cod", 6 | "minecraft:tropical_fish", 7 | "minecraft:pufferfish", 8 | "minecraft:salmon", 9 | "minecraft:beef", 10 | "minecraft:porkchop", 11 | "minecraft:mutton", 12 | "minecraft:chicken", 13 | "minecraft:rabbit", 14 | "minecraft:cooked_chicken", 15 | "minecraft:cooked_rabbit", 16 | "minecraft:rabbit_stew", 17 | "minecraft:cooked_porkchop", 18 | "minecraft:cooked_cod", 19 | "minecraft:cooked_beef", 20 | "minecraft:cooked_mutton", 21 | "minecraft:cooked_salmon", 22 | "minecraft:spider_eye" 23 | ] 24 | } -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/util/InventoryType.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.util; 2 | 3 | import net.minecraft.world.inventory.MenuType; 4 | 5 | public enum InventoryType { 6 | THREE_BY_THREE(MenuType.GENERIC_3x3), 7 | NINE_BY_ONE(MenuType.GENERIC_9x1), 8 | NINE_BY_TWO(MenuType.GENERIC_9x2), 9 | NINE_BY_THREE(MenuType.GENERIC_9x3), 10 | NINE_BY_FOUR(MenuType.GENERIC_9x4), 11 | NINE_BY_FIVE(MenuType.GENERIC_9x5), 12 | NINE_BY_SIX(MenuType.GENERIC_9x6); 13 | 14 | private final MenuType type; 15 | 16 | InventoryType(MenuType type) { 17 | this.type = type; 18 | } 19 | 20 | public MenuType getType() { 21 | return this.type; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/data/OriginsDataTypes.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.data; 2 | 3 | import io.github.apace100.calio.data.SerializableDataType; 4 | import io.github.apace100.origins.origin.Impact; 5 | import io.github.apace100.origins.origin.OriginUpgrade; 6 | 7 | import java.util.List; 8 | 9 | public final class OriginsDataTypes { 10 | 11 | public static final SerializableDataType IMPACT = SerializableDataType.enumValue(Impact.class); 12 | 13 | public static final SerializableDataType UPGRADE = new SerializableDataType<>(OriginUpgrade.class, OriginUpgrade.CODEC); 14 | 15 | public static final SerializableDataType> UPGRADES = SerializableDataType.list(UPGRADE); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/water_vulnerability.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:damage_over_time", 3 | "interval": 20, 4 | "onset_delay": 1, 5 | "damage": 2, 6 | "damage_easy": 1, 7 | "damage_source": { 8 | "name": "hurt_by_water", 9 | "unblockable": true, 10 | "bypasses_armor": true 11 | }, 12 | "protection_enchantment": "origins:water_protection", 13 | "protection_effectiveness": 1.0, 14 | "condition": { 15 | "type": "origins:or", 16 | "conditions": [ 17 | { 18 | "type": "origins:fluid_height", 19 | "fluid": "minecraft:water", 20 | "comparison": ">", 21 | "compare_to": 0.0 22 | }, 23 | { 24 | "type": "origins:in_rain" 25 | } 26 | ] 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/registry/ModTags.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.registry; 2 | 3 | import io.github.edwinmindcraft.origins.data.tag.OriginsBlockTags; 4 | import io.github.edwinmindcraft.origins.data.tag.OriginsItemTags; 5 | import net.minecraft.tags.TagKey; 6 | import net.minecraft.world.item.Item; 7 | import net.minecraft.world.level.block.Block; 8 | 9 | public class ModTags { 10 | 11 | public static final TagKey MEAT = OriginsItemTags.MEAT; 12 | public static final TagKey UNPHASABLE = OriginsBlockTags.UNPHASABLE; 13 | public static final TagKey NATURAL_STONE = OriginsBlockTags.NATURAL_STONE; 14 | public static final TagKey RANGED_WEAPONS = OriginsItemTags.RANGED_WEAPONS; 15 | 16 | public static void register() { } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/vegetarian.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:prevent_item_use", 3 | "item_condition": { 4 | "type": "origins:and", 5 | "conditions": [ 6 | { 7 | "type": "origins:or", 8 | "conditions": [ 9 | { 10 | "type": "origins:ingredient", 11 | "ingredient": { 12 | "tag": "origins:meat" 13 | } 14 | }, 15 | { 16 | "type": "origins:meat" 17 | } 18 | ] 19 | }, 20 | { 21 | "type": "origins:food" 22 | }, 23 | { 24 | "type": "origins:ingredient", 25 | "ingredient": { 26 | "tag": "origins:ignore_diet" 27 | }, 28 | "inverted": true 29 | } 30 | ] 31 | } 32 | } -------------------------------------------------------------------------------- /src/generated/resources/data/origins/powers/carnivore.json: -------------------------------------------------------------------------------- 1 | { 2 | "item_condition": { 3 | "conditions": [ 4 | { 5 | "conditions": [ 6 | { 7 | "ingredient": { 8 | "tag": "origins:meat" 9 | }, 10 | "type": "apoli:ingredient" 11 | }, 12 | { 13 | "type": "apoli:meat" 14 | } 15 | ], 16 | "inverted": true, 17 | "type": "apoli:or" 18 | }, 19 | { 20 | "type": "apoli:food" 21 | }, 22 | { 23 | "ingredient": { 24 | "tag": "origins:ignore_diet" 25 | }, 26 | "inverted": true, 27 | "type": "apoli:ingredient" 28 | } 29 | ], 30 | "type": "apoli:and" 31 | }, 32 | "type": "apoli:prevent_item_use" 33 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/slow_falling.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "apoli:modify_falling", 3 | "velocity": 0.01, 4 | "take_fall_damage": false, 5 | "condition": { 6 | "type": "origins:or", 7 | "conditions": [ 8 | { 9 | "type": "origins:and", 10 | "conditions": [ 11 | { 12 | "type": "origins:sneaking" 13 | }, 14 | { 15 | "type": "origins:fall_flying" 16 | } 17 | ] 18 | }, 19 | { 20 | "type": "origins:and", 21 | "conditions": [ 22 | { 23 | "type": "origins:sneaking", 24 | "inverted": true 25 | }, 26 | { 27 | "type": "origins:fall_flying", 28 | "inverted": true 29 | } 30 | ] 31 | } 32 | ] 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/api/registry/OriginsDynamicRegistries.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.api.registry; 2 | 3 | import io.github.edwinmindcraft.origins.api.OriginsAPI; 4 | import io.github.edwinmindcraft.origins.api.origin.Origin; 5 | import io.github.edwinmindcraft.origins.api.origin.OriginLayer; 6 | import net.minecraft.core.Registry; 7 | import net.minecraft.resources.ResourceKey; 8 | import net.minecraft.resources.ResourceLocation; 9 | 10 | public class OriginsDynamicRegistries { 11 | public static final ResourceKey> ORIGINS_REGISTRY = ResourceKey.createRegistryKey(new ResourceLocation(OriginsAPI.MODID, "origins")); 12 | public static final ResourceKey> LAYERS_REGISTRY = ResourceKey.createRegistryKey(new ResourceLocation(OriginsAPI.MODID, "layers")); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/weak_arms.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:modify_break_speed", 3 | "modifier": { 4 | "name": "Unbreakable natural stone", 5 | "value": -1, 6 | "operation": "multiply_total" 7 | }, 8 | "block_condition": { 9 | "type": "origins:and", 10 | "conditions": [ 11 | { 12 | "type": "origins:in_tag", 13 | "tag": "origins:natural_stone" 14 | }, 15 | { 16 | "type": "origins:adjacent", 17 | "adjacent_condition": { 18 | "type": "origins:in_tag", 19 | "tag": "origins:natural_stone" 20 | }, 21 | "comparison": ">", 22 | "compare_to": 2 23 | } 24 | ] 25 | }, 26 | "condition": { 27 | "type": "origins:status_effect", 28 | "effect": "minecraft:strength", 29 | "inverted": true 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/api/registry/OriginsBuiltinRegistries.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.api.registry; 2 | 3 | import io.github.apace100.origins.Origins; 4 | import io.github.apace100.origins.badge.BadgeFactory; 5 | import io.github.edwinmindcraft.origins.api.origin.Origin; 6 | import net.minecraft.core.Registry; 7 | import net.minecraft.resources.ResourceKey; 8 | import net.minecraftforge.registries.IForgeRegistry; 9 | 10 | import java.util.function.Supplier; 11 | 12 | public class OriginsBuiltinRegistries { 13 | public static final ResourceKey> BADGE_FACTORY_KEY = ResourceKey.createRegistryKey(Origins.identifier("badge_factory")); 14 | 15 | public static Supplier> ORIGINS; 16 | public static Supplier> BADGE_FACTORIES; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/registry/ModEnchantments.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.registry; 2 | 3 | import io.github.apace100.origins.enchantment.WaterProtectionEnchantment; 4 | import io.github.edwinmindcraft.origins.common.registry.OriginRegisters; 5 | import net.minecraft.world.entity.EquipmentSlot; 6 | import net.minecraft.world.item.enchantment.Enchantment; 7 | import net.minecraft.world.item.enchantment.EnchantmentCategory; 8 | import net.minecraftforge.registries.RegistryObject; 9 | 10 | public class ModEnchantments { 11 | 12 | public static final RegistryObject WATER_PROTECTION = OriginRegisters.ENCHANTMENTS.register("water_protection", () -> new WaterProtectionEnchantment(Enchantment.Rarity.RARE, EnchantmentCategory.ARMOR, new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET})); 13 | 14 | public static void register() {} 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/api/origin/IOriginCallbackPower.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.api.origin; 2 | 3 | import io.github.edwinmindcraft.apoli.api.IDynamicFeatureConfiguration; 4 | import io.github.edwinmindcraft.apoli.api.power.configuration.ConfiguredPower; 5 | import io.github.edwinmindcraft.apoli.api.power.factory.PowerFactory; 6 | import net.minecraft.world.entity.Entity; 7 | 8 | public interface IOriginCallbackPower { 9 | @SuppressWarnings("unchecked") 10 | static > void onChosen(ConfiguredPower power, Entity living, boolean isOrb) { 11 | if (power.getFactory() instanceof IOriginCallbackPower) 12 | ((IOriginCallbackPower) power.getFactory()).onChosen(power.getConfiguration(), living, isOrb); 13 | } 14 | 15 | void onChosen(T configuration, Entity entity, boolean isOrb); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/data/CompatibilityDataTypes.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.data; 2 | 3 | import io.github.apace100.calio.data.SerializableDataType; 4 | import io.github.apace100.calio.data.SerializableDataTypes; 5 | import net.minecraft.world.item.Item; 6 | import net.minecraft.world.item.ItemStack; 7 | 8 | public final class CompatibilityDataTypes { 9 | 10 | 11 | public static final SerializableDataType ITEM_OR_ITEM_STACK = new SerializableDataType<>(ItemStack.class, 12 | SerializableDataTypes.ITEM_STACK::send, SerializableDataTypes.ITEM_STACK::receive, jsonElement -> { 13 | if(jsonElement.isJsonPrimitive() && jsonElement.getAsJsonPrimitive().isString()) { 14 | Item item = SerializableDataTypes.ITEM.read(jsonElement); 15 | return new ItemStack(item); 16 | } 17 | return SerializableDataTypes.ITEM_STACK.read(jsonElement); 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/common/power/NoSlowdownPower.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.common.power; 2 | 3 | import io.github.apace100.origins.power.OriginsPowerTypes; 4 | import io.github.edwinmindcraft.apoli.api.component.IPowerContainer; 5 | import io.github.edwinmindcraft.apoli.api.power.factory.PowerFactory; 6 | import io.github.edwinmindcraft.origins.common.power.configuration.NoSlowdownConfiguration; 7 | import net.minecraft.world.entity.Entity; 8 | import net.minecraft.world.level.block.state.BlockState; 9 | 10 | public class NoSlowdownPower extends PowerFactory { 11 | public static boolean isActive(Entity player, BlockState state) { 12 | return IPowerContainer.getPowers(player, OriginsPowerTypes.NO_SLOWDOWN.get()).stream().anyMatch(x -> x.getConfiguration().test(state)); 13 | } 14 | 15 | 16 | public NoSlowdownPower() { 17 | super(NoSlowdownConfiguration.CODEC); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/common/network/C2SAcknowledgeOrigins.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.common.network; 2 | 3 | import io.github.edwinmindcraft.origins.api.capabilities.IOriginContainer; 4 | import net.minecraft.network.FriendlyByteBuf; 5 | import net.minecraftforge.network.NetworkEvent; 6 | 7 | import java.util.function.Supplier; 8 | 9 | public class C2SAcknowledgeOrigins { 10 | public static C2SAcknowledgeOrigins decode(FriendlyByteBuf buf) { 11 | return new C2SAcknowledgeOrigins(); 12 | } 13 | 14 | public C2SAcknowledgeOrigins() { 15 | 16 | } 17 | 18 | public void encode(FriendlyByteBuf buf) { 19 | 20 | } 21 | 22 | public void handle(Supplier contextSupplier) { 23 | contextSupplier.get().enqueueWork(() -> IOriginContainer.get(contextSupplier.get().getSender()).ifPresent(IOriginContainer::validateSynchronization)); 24 | contextSupplier.get().setPacketHandled(true); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/mixin/ConduitOnLandMixin.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.mixin; 2 | 3 | import io.github.apace100.origins.power.OriginsPowerTypes; 4 | import io.github.edwinmindcraft.apoli.api.component.IPowerContainer; 5 | import net.minecraft.world.entity.player.Player; 6 | import net.minecraft.world.level.block.entity.ConduitBlockEntity; 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(ConduitBlockEntity.class) 12 | public class ConduitOnLandMixin { 13 | 14 | @Redirect(method = "applyEffects", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;isInWaterOrRain()Z")) 15 | private static boolean allowConduitPowerOnLand(Player playerEntity) { 16 | return playerEntity.isInWaterOrRain() || IPowerContainer.hasPower(playerEntity, OriginsPowerTypes.CONDUIT_POWER_ON_LAND.get()); 17 | } 18 | } -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/registry/ModLoot.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.registry; 2 | 3 | import io.github.apace100.origins.Origins; 4 | import io.github.apace100.origins.util.OriginLootCondition; 5 | import net.minecraft.core.Registry; 6 | import net.minecraft.world.level.storage.loot.Serializer; 7 | import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; 8 | import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType; 9 | 10 | public class ModLoot { 11 | public static final LootItemConditionType ORIGIN_LOOT_CONDITION = registerLootCondition("origin", new OriginLootCondition.Serializer()); 12 | 13 | private static LootItemConditionType registerLootCondition(String path, Serializer serializer) { 14 | return Registry.register(Registry.LOOT_CONDITION_TYPE, Origins.identifier(path), new LootItemConditionType(serializer)); 15 | } 16 | 17 | public static void register() {} 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/data/generator/OriginsBlockTagProvider.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.data.generator; 2 | 3 | import io.github.apace100.origins.Origins; 4 | import io.github.apace100.origins.registry.ModBlocks; 5 | import io.github.edwinmindcraft.origins.data.tag.OriginsBlockTags; 6 | import net.minecraft.data.DataGenerator; 7 | import net.minecraft.data.tags.BlockTagsProvider; 8 | import net.minecraft.world.level.block.Blocks; 9 | import net.minecraftforge.common.data.ExistingFileHelper; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | public class OriginsBlockTagProvider extends BlockTagsProvider { 13 | public OriginsBlockTagProvider(DataGenerator generator, @Nullable ExistingFileHelper existingFileHelper) { 14 | super(generator, Origins.MODID, existingFileHelper); 15 | } 16 | 17 | @Override 18 | protected void addTags() { 19 | this.tag(OriginsBlockTags.COBWEBS).add(Blocks.COBWEB).add(ModBlocks.TEMPORARY_COBWEB.get()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/api/origin/GuiTitle.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.api.origin; 2 | 3 | import com.mojang.serialization.Codec; 4 | import com.mojang.serialization.codecs.RecordCodecBuilder; 5 | import io.github.edwinmindcraft.calio.api.network.CalioCodecHelper; 6 | import io.github.edwinmindcraft.calio.api.network.OptionalFuncs; 7 | import net.minecraft.network.chat.Component; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | public record GuiTitle(@Nullable Component view, @Nullable Component choose) { 11 | public static final GuiTitle DEFAULT = new GuiTitle(null, null); 12 | 13 | public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( 14 | CalioCodecHelper.COMPONENT_CODEC.optionalFieldOf("view_origin").forGetter(OptionalFuncs.opt(GuiTitle::view)), 15 | CalioCodecHelper.COMPONENT_CODEC.optionalFieldOf("choose_origin").forGetter(OptionalFuncs.opt(GuiTitle::choose)) 16 | ).apply(instance, OptionalFuncs.of(GuiTitle::new))); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/api/origin/OriginUpgrade.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.api.origin; 2 | 3 | import com.mojang.serialization.Codec; 4 | import com.mojang.serialization.MapCodec; 5 | import com.mojang.serialization.codecs.RecordCodecBuilder; 6 | import io.github.edwinmindcraft.calio.api.network.CalioCodecHelper; 7 | import net.minecraft.resources.ResourceLocation; 8 | 9 | public record OriginUpgrade(ResourceLocation advancement, ResourceLocation origin, String announcement) { 10 | public static final MapCodec MAP_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( 11 | ResourceLocation.CODEC.fieldOf("condition").forGetter(OriginUpgrade::advancement), 12 | ResourceLocation.CODEC.fieldOf("origin").forGetter(OriginUpgrade::origin), 13 | CalioCodecHelper.optionalField(Codec.STRING, "announcement", "").forGetter(OriginUpgrade::announcement) 14 | ).apply(instance, OriginUpgrade::new)); 15 | 16 | public static final Codec CODEC = MAP_CODEC.codec(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/common/power/WaterVisionPower.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.common.power; 2 | 3 | import io.github.apace100.origins.power.OriginsPowerTypes; 4 | import io.github.edwinmindcraft.apoli.api.component.IPowerContainer; 5 | import io.github.edwinmindcraft.apoli.api.power.factory.PowerFactory; 6 | import io.github.edwinmindcraft.origins.common.power.configuration.WaterVisionConfiguration; 7 | import net.minecraft.world.entity.LivingEntity; 8 | 9 | import java.util.Optional; 10 | 11 | public class WaterVisionPower extends PowerFactory { 12 | public static Optional getWaterVisionStrength(LivingEntity living) { 13 | if (!OriginsPowerTypes.WATER_VISION.isPresent()) 14 | return Optional.empty(); 15 | return IPowerContainer.getPowers(living, OriginsPowerTypes.WATER_VISION.get()).stream().map(x -> x.getConfiguration().strength()).max(Float::compareTo); 16 | } 17 | 18 | public WaterVisionPower() { 19 | super(WaterVisionConfiguration.CODEC); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/common/condition/configuration/OriginConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.common.condition.configuration; 2 | 3 | import com.mojang.serialization.Codec; 4 | import com.mojang.serialization.codecs.RecordCodecBuilder; 5 | import io.github.edwinmindcraft.apoli.api.IDynamicFeatureConfiguration; 6 | import io.github.edwinmindcraft.calio.api.network.CalioCodecHelper; 7 | import net.minecraft.resources.ResourceLocation; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import java.util.Optional; 11 | 12 | public record OriginConfiguration(ResourceLocation origin, 13 | @Nullable ResourceLocation layer) implements IDynamicFeatureConfiguration { 14 | public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( 15 | ResourceLocation.CODEC.fieldOf("origin").forGetter(OriginConfiguration::origin), 16 | CalioCodecHelper.optionalField(ResourceLocation.CODEC, "layer").forGetter(x -> Optional.ofNullable(x.layer())) 17 | ).apply(instance, (o, l) -> new OriginConfiguration(o, l.orElse(null)))); 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 apace100 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/mods.toml: -------------------------------------------------------------------------------- 1 | modLoader="javafml" 2 | loaderVersion="[39,)" 3 | license="MIT" 4 | issueTrackerURL="https://github.com/EdwinMindcraft/origins-architectury/issues" 5 | 6 | [[mods]] 7 | modId="origins" 8 | version="${version}" 9 | displayName="Origins" 10 | logoFile= "origins_icon.png" 11 | authors="Apace" 12 | description=''' 13 | This mod adds several origins with passive abilities to the game, which you can choose from at the beginning of the game. 14 | ''' 15 | 16 | [[dependencies.origins]] 17 | modId="forge" 18 | mandatory=true 19 | versionRange="${forge_requirements}" 20 | ordering="NONE" 21 | side="BOTH" 22 | 23 | [[dependencies.origins]] 24 | modId="minecraft" 25 | mandatory=true 26 | versionRange="[${mc_version}]" 27 | ordering="NONE" 28 | side="BOTH" 29 | 30 | [[dependencies.origins]] 31 | modId="calio" 32 | mandatory=true 33 | versionRange="[1.18.1-1.4,)" 34 | ordering="NONE" 35 | side="BOTH" 36 | 37 | [[dependencies.origins]] 38 | modId="apoli" 39 | mandatory=true 40 | versionRange="[1.18.1-2.2,)" 41 | ordering="NONE" 42 | side="BOTH" -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/mixin/forge/ModifyPlayerSpawnPowerMixin.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.mixin.forge; 2 | 3 | import io.github.edwinmindcraft.apoli.common.power.ModifyPlayerSpawnPower; 4 | import io.github.edwinmindcraft.apoli.common.power.configuration.ModifyPlayerSpawnConfiguration; 5 | import io.github.edwinmindcraft.origins.api.origin.IOriginCallbackPower; 6 | import net.minecraft.world.entity.Entity; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.Shadow; 10 | 11 | @Mixin(ModifyPlayerSpawnPower.class) 12 | public abstract class ModifyPlayerSpawnPowerMixin implements IOriginCallbackPower { 13 | @Shadow(remap = false) 14 | public abstract void teleportToModifiedSpawn(ModifyPlayerSpawnConfiguration configuration, Entity entity); 15 | 16 | @Override 17 | public void onChosen(@NotNull ModifyPlayerSpawnConfiguration configuration, @NotNull Entity living, boolean isOrb) { 18 | if (!isOrb) //This is IMO a better way to do this. 19 | this.teleportToModifiedSpawn(configuration, living); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/common/network/S2COpenOriginScreen.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.common.network; 2 | 3 | import io.github.edwinmindcraft.origins.client.OriginsClient; 4 | import net.minecraft.network.FriendlyByteBuf; 5 | import net.minecraftforge.api.distmarker.Dist; 6 | import net.minecraftforge.fml.DistExecutor; 7 | import net.minecraftforge.network.NetworkEvent; 8 | 9 | import java.util.function.Supplier; 10 | 11 | public record S2COpenOriginScreen(boolean showDirtBackground) { 12 | public static S2COpenOriginScreen decode(FriendlyByteBuf buf) { 13 | return new S2COpenOriginScreen(buf.readBoolean()); 14 | } 15 | 16 | public void encode(FriendlyByteBuf buf) { 17 | buf.writeBoolean(this.showDirtBackground()); 18 | } 19 | 20 | public void handle(Supplier contextSupplier) { 21 | contextSupplier.get().enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { 22 | OriginsClient.AWAITING_DISPLAY.set(true); 23 | OriginsClient.SHOW_DIRT_BACKGROUND = this.showDirtBackground(); 24 | })); 25 | contextSupplier.get().setPacketHandled(true); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/registry/ModEntities.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.registry; 2 | 3 | import io.github.apace100.origins.Origins; 4 | import io.github.apace100.origins.entity.EnderianPearlEntity; 5 | import io.github.edwinmindcraft.origins.common.registry.OriginRegisters; 6 | import net.minecraft.world.entity.Entity; 7 | import net.minecraft.world.entity.EntityType; 8 | import net.minecraft.world.entity.MobCategory; 9 | import net.minecraftforge.registries.RegistryObject; 10 | 11 | import java.util.function.Supplier; 12 | 13 | public class ModEntities { 14 | 15 | public static final RegistryObject> ENDERIAN_PEARL = register("enderian_pearl", () -> EntityType.Builder.of(EnderianPearlEntity::new, MobCategory.MISC).sized(0.25F, 0.25F).sized(0.25F, 0.25F).clientTrackingRange(4).updateInterval(10)); 16 | 17 | private static RegistryObject> register(String name, Supplier> builder) { 18 | return OriginRegisters.ENTITY_TYPES.register(name, () -> builder.get().build(Origins.MODID + ":" + name)); 19 | } 20 | 21 | public static void register() {} 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/data/OriginsData.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.data; 2 | 3 | import io.github.edwinmindcraft.origins.data.generator.OriginsBlockTagProvider; 4 | import io.github.edwinmindcraft.origins.data.generator.OriginsPowerProvider; 5 | import net.minecraft.data.DataGenerator; 6 | import net.minecraftforge.common.data.ExistingFileHelper; 7 | import net.minecraftforge.eventbus.api.IEventBus; 8 | import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; 9 | import net.minecraftforge.forge.event.lifecycle.GatherDataEvent; 10 | 11 | public class OriginsData { 12 | public static void initialize() { 13 | IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus(); 14 | bus.addListener(OriginsData::gatherData); 15 | } 16 | 17 | private static void gatherData(GatherDataEvent event) { 18 | DataGenerator generator = event.getGenerator(); 19 | ExistingFileHelper existingFileHelper = event.getExistingFileHelper(); 20 | if (event.includeServer()) { 21 | generator.addProvider(new OriginsBlockTagProvider(generator, existingFileHelper)); 22 | generator.addProvider(new OriginsPowerProvider(generator, existingFileHelper)); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/util/DebugInfo.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.util; 2 | 3 | import io.github.apace100.origins.Origins; 4 | import io.github.edwinmindcraft.apoli.api.ApoliAPI; 5 | import io.github.edwinmindcraft.origins.api.OriginsAPI; 6 | 7 | public class DebugInfo { 8 | 9 | public static void printRegistrySizes(String at) { 10 | printInfo(new String[]{ 11 | "Registry Size at " + at, 12 | "Origins: " + OriginsAPI.getOriginsRegistry().keySet().size(), 13 | "Layers: " + OriginsAPI.getLayersRegistry().keySet().size(), 14 | "Powers: " + ApoliAPI.getPowers().keySet().size() 15 | }); 16 | } 17 | 18 | private static void printInfo(String[] lines) { 19 | int longest = 0; 20 | for (int i = 0; i < lines.length; i++) { 21 | if (lines[i].length() > longest) 22 | longest = lines[i].length(); 23 | lines[i] = "| " + lines[i]; 24 | } 25 | String border = "+" + "-".repeat(Math.max(0, longest + 2)) + "+"; 26 | Origins.LOGGER.info(border); 27 | for (int i = 0; i < lines.length; i++) { 28 | while (lines[i].length() < longest + 3) 29 | lines[i] += " "; 30 | lines[i] += "|"; 31 | Origins.LOGGER.info(lines[i]); 32 | } 33 | Origins.LOGGER.info(border); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/mixin/WaterVisibilityMixin.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.mixin; 2 | 3 | import com.mojang.authlib.GameProfile; 4 | import io.github.edwinmindcraft.origins.common.power.WaterVisionPower; 5 | import net.minecraft.client.multiplayer.ClientLevel; 6 | import net.minecraft.client.player.AbstractClientPlayer; 7 | import net.minecraft.client.player.LocalPlayer; 8 | import net.minecraftforge.api.distmarker.Dist; 9 | import net.minecraftforge.api.distmarker.OnlyIn; 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 | @OnlyIn(Dist.CLIENT) 16 | @Mixin(LocalPlayer.class) 17 | public abstract class WaterVisibilityMixin extends AbstractClientPlayer { 18 | 19 | public WaterVisibilityMixin(ClientLevel world, GameProfile profile) { 20 | super(world, profile); 21 | } 22 | 23 | @Inject(at = @At("HEAD"), method = "getWaterVision", cancellable = true) 24 | private void getUnderwaterVisibility(CallbackInfoReturnable info) { 25 | WaterVisionPower.getWaterVisionStrength(this).ifPresent(info::setReturnValue); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/generated/resources/data/origins/powers/aqua_affinity.json: -------------------------------------------------------------------------------- 1 | { 2 | "underwater": { 3 | "modifier": { 4 | "name": "Unnamed attribute modifier", 5 | "value": 4.0, 6 | "operation": "multiply_total" 7 | }, 8 | "condition": { 9 | "conditions": [ 10 | { 11 | "fluid": "minecraft:water", 12 | "type": "apoli:submerged_in" 13 | }, 14 | { 15 | "comparison": "==", 16 | "compare_to": 0, 17 | "enchantment": "minecraft:aqua_affinity", 18 | "type": "apoli:enchantment" 19 | } 20 | ], 21 | "type": "apoli:and" 22 | }, 23 | "type": "apoli:modify_break_speed" 24 | }, 25 | "ungrounded": { 26 | "modifier": { 27 | "name": "Unnamed attribute modifier", 28 | "value": 4.0, 29 | "operation": "multiply_total" 30 | }, 31 | "condition": { 32 | "conditions": [ 33 | { 34 | "comparison": ">", 35 | "compare_to": 0.0, 36 | "fluid": "minecraft:water", 37 | "type": "apoli:fluid_height" 38 | }, 39 | { 40 | "inverted": true, 41 | "type": "apoli:on_block" 42 | } 43 | ], 44 | "type": "apoli:and" 45 | }, 46 | "type": "apoli:modify_break_speed" 47 | }, 48 | "type": "apoli:multiple" 49 | } -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/common/power/configuration/NoSlowdownConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.common.power.configuration; 2 | 3 | import com.mojang.serialization.Codec; 4 | import io.github.edwinmindcraft.apoli.api.IDynamicFeatureConfiguration; 5 | import net.minecraft.core.Registry; 6 | import net.minecraft.tags.TagKey; 7 | import net.minecraft.world.level.block.Block; 8 | import net.minecraft.world.level.block.state.BlockState; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | import java.util.Optional; 12 | 13 | /** 14 | * Another take on the "no_cobweb_slowdown" power that doesn't need to 15 | * work for powder snow and sweet berry bushes. 16 | * If {@link #blocks()} is null, this will prevent slowdown from all sources. 17 | */ 18 | public record NoSlowdownConfiguration(@Nullable TagKey blocks) implements IDynamicFeatureConfiguration { 19 | //FIXME As this is a non-standard power, move it to a list. 20 | public static final Codec CODEC = TagKey.hashedCodec(Registry.BLOCK_REGISTRY).optionalFieldOf("tag") 21 | .xmap(x -> new NoSlowdownConfiguration(x.orElse(null)), x -> Optional.ofNullable(x.blocks())).codec(); 22 | 23 | public boolean test(BlockState state) { 24 | return this.blocks() == null || state.is(this.blocks()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/origin/Impact.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.origin; 2 | 3 | import net.minecraft.ChatFormatting; 4 | import net.minecraft.network.chat.TranslatableComponent; 5 | 6 | public enum Impact { 7 | 8 | NONE(0, "none", ChatFormatting.GRAY), 9 | LOW(1, "low", ChatFormatting.GREEN), 10 | MEDIUM(2, "medium", ChatFormatting.YELLOW), 11 | HIGH(3, "high", ChatFormatting.RED); 12 | 13 | private final int impactValue; 14 | private final String translationKey; 15 | private final ChatFormatting textStyle; 16 | 17 | Impact(int impactValue, String translationKey, ChatFormatting textStyle) { 18 | this.translationKey = "origins.gui.impact." + translationKey; 19 | this.impactValue = impactValue; 20 | this.textStyle = textStyle; 21 | } 22 | 23 | public int getImpactValue() { 24 | return this.impactValue; 25 | } 26 | 27 | public String getTranslationKey() { 28 | return this.translationKey; 29 | } 30 | 31 | public ChatFormatting getTextStyle() { 32 | return this.textStyle; 33 | } 34 | 35 | public TranslatableComponent getTextComponent() { 36 | return (TranslatableComponent)new TranslatableComponent(this.getTranslationKey()).withStyle(this.getTextStyle()); 37 | } 38 | 39 | public static Impact getByValue(int impactValue) { 40 | return Impact.values()[impactValue]; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/climbing.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:multiple", 3 | "toggle": { 4 | "type": "origins:toggle", 5 | "key": { 6 | "key": "key.origins.primary_active", 7 | "continuous": false 8 | } 9 | }, 10 | "climbing": { 11 | "type": "origins:climbing", 12 | "hold_condition": { 13 | "type": "origins:and", 14 | "conditions": [ 15 | { 16 | "type": "origins:or", 17 | "conditions": [ 18 | { 19 | "type": "origins:block_collision", 20 | "offset_x": 0.01, 21 | "offset_z": 0.01, 22 | "offset_y": 0 23 | }, 24 | { 25 | "type": "origins:block_collision", 26 | "offset_x": -0.01, 27 | "offset_z": -0.01, 28 | "offset_y": 0 29 | } 30 | ] 31 | }, 32 | { 33 | "type": "origins:power_active", 34 | "power": "*:*_toggle" 35 | } 36 | ] 37 | }, 38 | "condition": { 39 | "type": "origins:and", 40 | "conditions": [ 41 | { 42 | "type": "origins:collided_horizontally" 43 | }, 44 | { 45 | "type": "origins:power_active", 46 | "power": "*:*_toggle" 47 | } 48 | ] 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/origin/OriginUpgrade.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.origin; 2 | 3 | import com.mojang.serialization.Codec; 4 | import net.minecraft.resources.ResourceLocation; 5 | 6 | public class OriginUpgrade { 7 | 8 | public static final Codec CODEC = io.github.edwinmindcraft.origins.api.origin.OriginUpgrade.MAP_CODEC.xmap(OriginUpgrade::new, OriginUpgrade::getWrapped).codec(); 9 | 10 | private final io.github.edwinmindcraft.origins.api.origin.OriginUpgrade wrapped; 11 | 12 | public OriginUpgrade(ResourceLocation advancementCondition, ResourceLocation upgradeToOrigin, String announcement) { 13 | this(new io.github.edwinmindcraft.origins.api.origin.OriginUpgrade(advancementCondition, upgradeToOrigin, announcement)); 14 | } 15 | 16 | public OriginUpgrade(io.github.edwinmindcraft.origins.api.origin.OriginUpgrade wrapped) { 17 | this.wrapped = wrapped; 18 | } 19 | 20 | public io.github.edwinmindcraft.origins.api.origin.OriginUpgrade getWrapped() { 21 | return this.wrapped; 22 | } 23 | 24 | public ResourceLocation getAdvancementCondition() { 25 | return this.wrapped.advancement(); 26 | } 27 | 28 | public ResourceLocation getUpgradeToOrigin() { 29 | return this.wrapped.origin(); 30 | } 31 | 32 | public String getAnnouncement() { 33 | return this.wrapped.announcement(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/networking/ModPackets.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.networking; 2 | 3 | import io.github.apace100.origins.Origins; 4 | import net.minecraft.resources.ResourceLocation; 5 | 6 | public class ModPackets { 7 | 8 | 9 | public static final ResourceLocation OPEN_ORIGIN_SCREEN = new ResourceLocation(Origins.MODID, "open_origin_screen"); 10 | public static final ResourceLocation CHOOSE_ORIGIN = new ResourceLocation(Origins.MODID, "choose_origin"); 11 | public static final ResourceLocation USE_ACTIVE_POWERS = new ResourceLocation(Origins.MODID, "use_active_powers"); 12 | public static final ResourceLocation ORIGIN_LIST = new ResourceLocation(Origins.MODID, "origin_list"); 13 | public static final ResourceLocation LAYER_LIST = new ResourceLocation(Origins.MODID, "layer_list"); 14 | public static final ResourceLocation POWER_LIST = new ResourceLocation(Origins.MODID, "power_list"); 15 | public static final ResourceLocation CHOOSE_RANDOM_ORIGIN = new ResourceLocation(Origins.MODID, "choose_random_origin"); 16 | public static final ResourceLocation CONFIRM_ORIGIN = Origins.identifier("confirm_origin"); 17 | public static final ResourceLocation PLAYER_LANDED = Origins.identifier("player_landed"); 18 | public static final ResourceLocation BADGE_LIST = Origins.identifier("badge_list"); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/enchantment/WaterProtectionEnchantment.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.enchantment; 2 | 3 | import net.minecraft.world.entity.EquipmentSlot; 4 | import net.minecraft.world.item.enchantment.Enchantment; 5 | import net.minecraft.world.item.enchantment.EnchantmentCategory; 6 | import net.minecraft.world.item.enchantment.ProtectionEnchantment; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | public class WaterProtectionEnchantment extends Enchantment { 10 | 11 | public WaterProtectionEnchantment(Rarity weight, EnchantmentCategory type, EquipmentSlot[] slotTypes) { 12 | super(weight, type, slotTypes); 13 | } 14 | 15 | public int getMinCost(int level) { 16 | return 8 + level * 5; 17 | } 18 | 19 | public int getMaxCost(int level) { 20 | return this.getMinCost(level) + 8; 21 | } 22 | 23 | public boolean isTreasureOnly() { 24 | return true; 25 | } 26 | 27 | public int getMaxLevel() { 28 | return 4; 29 | } 30 | 31 | @Override 32 | protected boolean checkCompatibility(@NotNull Enchantment other) { 33 | if(other == this || ((other instanceof ProtectionEnchantment && !(((ProtectionEnchantment)other).type == ProtectionEnchantment.Type.FALL)))) { 34 | return false; 35 | } 36 | return super.checkCompatibility(other); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/badge/SpriteBadge.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.badge; 2 | 3 | import io.github.apace100.calio.data.SerializableData; 4 | import io.github.edwinmindcraft.apoli.api.power.configuration.ConfiguredPower; 5 | import net.minecraft.client.gui.Font; 6 | import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; 7 | import net.minecraft.resources.ResourceLocation; 8 | import net.minecraftforge.api.distmarker.Dist; 9 | import net.minecraftforge.api.distmarker.OnlyIn; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | public record SpriteBadge(ResourceLocation spriteId) implements Badge { 15 | 16 | public SpriteBadge(SerializableData.Instance instance) { 17 | this(instance.getId("sprite")); 18 | } 19 | 20 | @Override 21 | public boolean hasTooltip() { 22 | return false; 23 | } 24 | 25 | @Override 26 | @OnlyIn(Dist.CLIENT) 27 | public List getTooltipComponents(ConfiguredPower powerType, int widthLimit, float time, Font textRenderer) { 28 | return new ArrayList<>(); 29 | } 30 | 31 | @Override 32 | public SerializableData.Instance toData(SerializableData.Instance instance) { 33 | instance.set("sprite", this.spriteId); 34 | return instance; 35 | } 36 | 37 | @Override 38 | public BadgeFactory getBadgeFactory() { 39 | return BadgeFactories.SPRITE.get(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/mixin/NoCobwebSlowdownMixin.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.mixin; 2 | 3 | import io.github.edwinmindcraft.origins.common.power.NoSlowdownPower; 4 | import net.minecraft.commands.CommandSource; 5 | import net.minecraft.world.Nameable; 6 | import net.minecraft.world.entity.EntityType; 7 | import net.minecraft.world.entity.LivingEntity; 8 | import net.minecraft.world.entity.player.Player; 9 | import net.minecraft.world.level.Level; 10 | import net.minecraft.world.level.block.WebBlock; 11 | import net.minecraft.world.level.block.state.BlockState; 12 | import net.minecraft.world.phys.Vec3; 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(Player.class) 19 | public abstract class NoCobwebSlowdownMixin extends LivingEntity implements Nameable, CommandSource { 20 | protected NoCobwebSlowdownMixin(EntityType entityType, Level world) { 21 | super(entityType, world); 22 | } 23 | 24 | @Inject(at = @At("HEAD"), method = "makeStuckInBlock", cancellable = true) 25 | public void slowMovement(BlockState state, Vec3 multiplier, CallbackInfo info) { 26 | if (state.getBlock() instanceof WebBlock && NoSlowdownPower.isActive(this, state)) 27 | info.cancel(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/generated/resources/.cache/cache: -------------------------------------------------------------------------------- 1 | a72819651522f7fb669be4cb476289f4d80e46b6 data/origins/powers/aerial_combatant.json 2 | b56133f07251b478f5a67be881bf1bb6d7017e10 data/origins/powers/air_from_potions.json 3 | 306f1e7902048b43a743f7c721ff159cdebedf47 data/origins/powers/aqua_affinity.json 4 | 81c9c5823c30c55d28315ece2784a23dff9c1f2c data/origins/powers/aquatic.json 5 | f6b0d0c140f8fdc14c1a1e9a49282b08be6ac363 data/origins/powers/arcane_skin.json 6 | 186c777df6c4bb4a4a424c285dbe637564bd17ae data/origins/powers/arthropod.json 7 | da642697cc9536b65af8434ea44f2d07f7492438 data/origins/powers/burn_in_daylight.json 8 | 272b0e6a4130618763ee1fc1906969d07386cf6f data/origins/powers/burning_wrath.json 9 | 63361f799f6d964f5896290beeef17257a55e453 data/origins/powers/carnivore.json 10 | aa1c2d947df20c9c156c1a07fcc52f3d8c1f8948 data/origins/powers/cat_vision.json 11 | f583ab8292cc588d3c717f272b32e394b8e4f141 data/origins/powers/conduit_power_on_land.json 12 | 9d2017e3f0fff84a108211bae97075ace49dd220 data/origins/powers/like_water.json 13 | 90c5554d8410e012209b3e2ed41ad28efc6cfe98 data/origins/powers/no_cobweb_slowdown.json 14 | bbfd19e806576c77eb52b7a8e7a40913c8c6510a data/origins/powers/scare_creepers.json 15 | 107d3c49e278304ec2fd837710bf8b36d4175d4d data/origins/powers/water_breathing.json 16 | c5f77217c27187c3adfce52d4dcb4844c06cddc8 data/origins/powers/water_vision.json 17 | 0242bb4e8b8e60a094ef34c5f5c5c4c108ea89ed data/origins/tags/blocks/cobwebs.json 18 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/common/condition/OriginCondition.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.common.condition; 2 | 3 | import io.github.edwinmindcraft.apoli.api.power.factory.EntityCondition; 4 | import io.github.edwinmindcraft.origins.api.OriginsAPI; 5 | import io.github.edwinmindcraft.origins.api.capabilities.IOriginContainer; 6 | import io.github.edwinmindcraft.origins.api.origin.OriginLayer; 7 | import io.github.edwinmindcraft.origins.common.condition.configuration.OriginConfiguration; 8 | import net.minecraft.world.entity.Entity; 9 | import net.minecraftforge.registries.ForgeRegistryEntry; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | public class OriginCondition extends EntityCondition { 13 | public OriginCondition() { 14 | super(OriginConfiguration.CODEC); 15 | } 16 | 17 | @Override 18 | public boolean check(@NotNull OriginConfiguration configuration, @NotNull Entity entity) { 19 | return IOriginContainer.get(entity).resolve().map(container -> { 20 | if (configuration.layer() != null) { 21 | OriginLayer layer = OriginsAPI.getLayersRegistry().get(configuration.layer()); 22 | return layer != null && configuration.origin().equals(container.getOrigin(layer).getRegistryName()); 23 | } 24 | return container.getOrigins().values().stream().map(ForgeRegistryEntry::getRegistryName).anyMatch(configuration.origin()::equals); 25 | }).orElse(false); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/origin/OriginLayers.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.origin; 2 | 3 | import com.google.common.collect.ImmutableSet; 4 | import io.github.edwinmindcraft.origins.api.OriginsAPI; 5 | import net.minecraft.resources.ResourceLocation; 6 | 7 | import java.util.Collection; 8 | import java.util.Map; 9 | import java.util.concurrent.ConcurrentHashMap; 10 | 11 | /** 12 | * @deprecated Use {@link OriginsAPI#getLayersRegistry()} where possible instead. 13 | */ 14 | @Deprecated 15 | public class OriginLayers { 16 | 17 | private static final Map CACHE_MAP = new ConcurrentHashMap<>(); 18 | 19 | public static OriginLayer getLayer(ResourceLocation id) { 20 | return OriginsAPI.getLayersRegistry().getOptional(id).map(OriginLayer::new).orElse(null); 21 | } 22 | 23 | public static Collection getLayers() { 24 | return OriginsAPI.getLayersRegistry().stream().map(OriginLayer::new).collect(ImmutableSet.toImmutableSet()); 25 | } 26 | 27 | public static int size() { 28 | return OriginsAPI.getLayersRegistry().keySet().size(); 29 | } 30 | 31 | public static void clear() { 32 | CACHE_MAP.clear(); 33 | } 34 | 35 | /** 36 | * @deprecated Dead code. 37 | */ 38 | @Deprecated 39 | public static void add(OriginLayer layer) {} 40 | 41 | public static OriginLayer get(io.github.edwinmindcraft.origins.api.origin.OriginLayer layer) { 42 | return CACHE_MAP.computeIfAbsent(layer, OriginLayer::new); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/badge/Badge.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.badge; 2 | 3 | import io.github.apace100.apoli.power.PowerType; 4 | import io.github.apace100.calio.data.SerializableData; 5 | import io.github.apace100.calio.registry.DataObject; 6 | import io.github.apace100.calio.registry.DataObjectFactory; 7 | import io.github.edwinmindcraft.apoli.api.power.configuration.ConfiguredPower; 8 | import net.minecraft.client.gui.Font; 9 | import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; 10 | import net.minecraft.network.FriendlyByteBuf; 11 | import net.minecraft.resources.ResourceLocation; 12 | import net.minecraftforge.api.distmarker.Dist; 13 | import net.minecraftforge.api.distmarker.OnlyIn; 14 | 15 | import java.util.List; 16 | 17 | public interface Badge extends DataObject { 18 | 19 | ResourceLocation spriteId(); 20 | 21 | boolean hasTooltip(); 22 | 23 | @OnlyIn(Dist.CLIENT) 24 | List getTooltipComponents(ConfiguredPower powerType, int widthLimit, float time, Font textRenderer); 25 | 26 | SerializableData.Instance toData(SerializableData.Instance instance); 27 | 28 | BadgeFactory getBadgeFactory(); 29 | 30 | @Override 31 | default DataObjectFactory getFactory() { 32 | return this.getBadgeFactory(); 33 | } 34 | 35 | default void writeBuf(FriendlyByteBuf buf) { 36 | DataObjectFactory factory = this.getFactory(); 37 | buf.writeResourceLocation(this.getBadgeFactory().id()); 38 | factory.getData().write(buf, factory.toData(this)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/component/OriginComponent.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.component; 2 | 3 | import io.github.apace100.origins.origin.Origin; 4 | import io.github.apace100.origins.origin.OriginLayer; 5 | import io.github.edwinmindcraft.origins.api.capabilities.IOriginContainer; 6 | import net.minecraft.world.entity.player.Player; 7 | 8 | import java.util.HashMap; 9 | 10 | @SuppressWarnings("deprecation") 11 | public interface OriginComponent { 12 | 13 | boolean hasOrigin(OriginLayer layer); 14 | 15 | boolean hasAllOrigins(); 16 | 17 | HashMap getOrigins(); 18 | 19 | Origin getOrigin(OriginLayer layer); 20 | 21 | boolean hadOriginBefore(); 22 | 23 | void setOrigin(OriginLayer layer, Origin origin); 24 | 25 | void sync(); 26 | 27 | @Deprecated(forRemoval = true) 28 | default void onPowersRead() {} 29 | 30 | static void sync(Player player) { 31 | IOriginContainer.get(player).ifPresent(IOriginContainer::synchronize); 32 | } 33 | 34 | static void onChosen(Player player, boolean hadOriginBefore) { 35 | IOriginContainer.get(player).ifPresent(x -> x.onChosen(hadOriginBefore)); 36 | } 37 | 38 | static void partialOnChosen(Player player, boolean hadOriginBefore, Origin origin) { 39 | IOriginContainer.get(player).ifPresent(x -> x.onChosen(origin.getWrapped(), hadOriginBefore)); 40 | } 41 | 42 | default boolean checkAutoChoosingLayers(Player player, boolean includeDefaults) { 43 | return IOriginContainer.get(player).map(x -> x.checkAutoChoosingLayers(includeDefaults)).orElse(false); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/mixin/LikeWaterMixin.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.mixin; 2 | 3 | import io.github.apace100.origins.power.OriginsPowerTypes; 4 | import io.github.edwinmindcraft.apoli.api.component.IPowerContainer; 5 | import net.minecraft.world.entity.Entity; 6 | import net.minecraft.world.entity.EntityType; 7 | import net.minecraft.world.entity.LivingEntity; 8 | import net.minecraft.world.level.Level; 9 | import net.minecraft.world.phys.Vec3; 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(LivingEntity.class) 15 | public abstract class LikeWaterMixin extends Entity { 16 | 17 | public LikeWaterMixin(EntityType type, Level world) { 18 | super(type, world); 19 | } 20 | 21 | @Redirect(method = "travel", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;getFluidFallingAdjustedMovement(DZLnet/minecraft/world/phys/Vec3;)Lnet/minecraft/world/phys/Vec3;")) 22 | public Vec3 method_26317Proxy(LivingEntity entity, double d, boolean bl, Vec3 vec3d) { 23 | Vec3 oldReturn = entity.getFluidFallingAdjustedMovement(d, bl, vec3d); 24 | if(IPowerContainer.hasPower(entity, OriginsPowerTypes.LIKE_WATER.get())) { 25 | if (Math.abs(vec3d.y - d / 16.0D) < 0.025D) { 26 | return new Vec3(oldReturn.x, 0, oldReturn.z); 27 | } 28 | } 29 | return entity.getFluidFallingAdjustedMovement(d, bl, vec3d); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/registry/ModBlocks.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.registry; 2 | 3 | import io.github.apace100.origins.content.TemporaryCobwebBlock; 4 | import io.github.edwinmindcraft.origins.common.registry.OriginRegisters; 5 | import net.minecraft.world.item.BlockItem; 6 | import net.minecraft.world.item.CreativeModeTab; 7 | import net.minecraft.world.item.Item; 8 | import net.minecraft.world.level.block.Block; 9 | import net.minecraft.world.level.block.state.BlockBehaviour; 10 | import net.minecraft.world.level.material.Material; 11 | import net.minecraftforge.registries.RegistryObject; 12 | 13 | import java.util.function.Supplier; 14 | 15 | public class ModBlocks { 16 | 17 | public static final RegistryObject TEMPORARY_COBWEB = register("temporary_cobweb", () -> new TemporaryCobwebBlock(BlockBehaviour.Properties.of(Material.WEB).noCollission().requiresCorrectToolForDrops().strength(4.0F)), false); 18 | 19 | public static void register() { 20 | } 21 | 22 | private static RegistryObject register(String blockName, Supplier block) { 23 | return register(blockName, block, true); 24 | } 25 | 26 | private static RegistryObject register(String blockName, Supplier block, boolean withBlockItem) { 27 | RegistryObject register = OriginRegisters.BLOCKS.register(blockName, block); 28 | if (withBlockItem) 29 | OriginRegisters.ITEMS.register(blockName, () -> new BlockItem(register.get(), new Item.Properties().tab(CreativeModeTab.TAB_MISC))); 30 | return register; 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/api/event/AutoBadgeEvent.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.api.event; 2 | 3 | import io.github.apace100.apoli.integration.PowerLoadEvent; 4 | import io.github.apace100.origins.badge.Badge; 5 | import io.github.edwinmindcraft.apoli.api.power.configuration.ConfiguredPower; 6 | import net.minecraft.resources.ResourceLocation; 7 | import net.minecraftforge.eventbus.api.Event; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | /** 13 | * Callback which is called when a power hasn't got any badges from json and was expecting a fallback
14 | * Badge fallbacks can be added on this callback.
15 | * The callback is not informing whether the power is a subpower,
16 | * as all badges from subpowers will be merged to the main power on {@link PowerLoadEvent.Post}.
17 | * All created badges should be added to the provided list.
18 | */ 19 | public class AutoBadgeEvent extends Event { 20 | private final ResourceLocation registryName; 21 | private final ConfiguredPower power; 22 | private final List badges; 23 | 24 | public AutoBadgeEvent(ResourceLocation registryName, ConfiguredPower power, List badges) { 25 | this.registryName = registryName; 26 | this.power = power; 27 | this.badges = badges; 28 | } 29 | 30 | public ResourceLocation getRegistryName() { 31 | return this.registryName; 32 | } 33 | 34 | public ConfiguredPower getPower() { 35 | return this.power; 36 | } 37 | 38 | public List getBadges() { 39 | return this.badges; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/power/OriginsPowerTypes.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.power; 2 | 3 | import io.github.edwinmindcraft.apoli.common.power.DummyPower; 4 | import io.github.edwinmindcraft.origins.common.power.NoSlowdownPower; 5 | import io.github.edwinmindcraft.origins.common.power.WaterVisionPower; 6 | import io.github.edwinmindcraft.origins.common.registry.OriginRegisters; 7 | import net.minecraftforge.registries.RegistryObject; 8 | 9 | public class OriginsPowerTypes { 10 | 11 | public static final RegistryObject LIKE_WATER = OriginRegisters.POWER_FACTORIES.register("like_water", DummyPower::new); 12 | public static final RegistryObject WATER_BREATHING = OriginRegisters.POWER_FACTORIES.register("water_breathing", DummyPower::new); 13 | public static final RegistryObject SCARE_CREEPERS = OriginRegisters.POWER_FACTORIES.register("scare_creepers", DummyPower::new); 14 | public static final RegistryObject WATER_VISION = OriginRegisters.POWER_FACTORIES.register("water_vision", WaterVisionPower::new); 15 | public static final RegistryObject NO_SLOWDOWN = OriginRegisters.POWER_FACTORIES.register("no_slowdown", NoSlowdownPower::new); 16 | public static final RegistryObject CONDUIT_POWER_ON_LAND = OriginRegisters.POWER_FACTORIES.register("conduit_power_on_land", DummyPower::new); 17 | public static final RegistryObject ACTION_ON_CALLBACK = OriginRegisters.POWER_FACTORIES.register("action_on_callback", OriginsCallbackPower::new); 18 | 19 | public static void register() {} 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/util/PowerKeyManager.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.util; 2 | 3 | import io.github.apace100.apoli.power.PowerTypeRegistry; 4 | import io.github.edwinmindcraft.apoli.api.ApoliAPI; 5 | import io.github.edwinmindcraft.apoli.api.power.configuration.ConfiguredPower; 6 | import net.minecraft.core.Holder; 7 | import net.minecraft.core.Registry; 8 | import net.minecraft.resources.ResourceLocation; 9 | 10 | import java.util.HashMap; 11 | 12 | public class PowerKeyManager { 13 | 14 | private static final HashMap KEY_CACHE = new HashMap<>(); 15 | 16 | public static void clearCache() { 17 | KEY_CACHE.clear(); 18 | } 19 | 20 | public static String getKeyIdentifier(ResourceLocation powerId) { 21 | if (KEY_CACHE.containsKey(powerId)) { 22 | return KEY_CACHE.get(powerId); 23 | } 24 | String key = getKeyFromPower(powerId); 25 | KEY_CACHE.put(powerId, key); 26 | return key; 27 | } 28 | 29 | private static String getKeyFromPower(ResourceLocation powerId) { 30 | if (PowerTypeRegistry.contains(powerId)) { 31 | Registry> powers = ApoliAPI.getPowers(); 32 | ConfiguredPower powerType = powers.get(powerId); 33 | if (powerType == null) 34 | return ""; 35 | return powerType.getKey(null) 36 | .map(key -> key.key().equals("none") ? "key.origins.primary_active" : key.key()) 37 | .or(() -> powerType.getContainedPowers().values().stream().filter(Holder::isBound).map(Holder::value).map(x -> getKeyFromPower(x.getRegistryName())).filter(x -> !x.isBlank()).findFirst()) 38 | .orElse(""); 39 | } 40 | return ""; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/content/TemporaryCobwebBlock.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.content; 2 | 3 | import net.minecraft.core.BlockPos; 4 | import net.minecraft.server.level.ServerLevel; 5 | import net.minecraft.world.level.BlockGetter; 6 | import net.minecraft.world.level.Level; 7 | import net.minecraft.world.level.block.Blocks; 8 | import net.minecraft.world.level.block.WebBlock; 9 | import net.minecraft.world.level.block.state.BlockBehaviour; 10 | import net.minecraft.world.level.block.state.BlockState; 11 | import net.minecraft.world.phys.shapes.CollisionContext; 12 | import net.minecraft.world.phys.shapes.Shapes; 13 | import net.minecraft.world.phys.shapes.VoxelShape; 14 | import org.jetbrains.annotations.NotNull; 15 | 16 | import java.util.Random; 17 | 18 | public class TemporaryCobwebBlock extends WebBlock { 19 | 20 | public TemporaryCobwebBlock(BlockBehaviour.Properties settings) { 21 | super(settings); 22 | } 23 | 24 | @Override 25 | @Deprecated 26 | public void tick(@NotNull BlockState state, ServerLevel world, @NotNull BlockPos pos, @NotNull Random random) { 27 | if (!world.isClientSide) 28 | world.setBlockAndUpdate(pos, Blocks.AIR.defaultBlockState()); 29 | } 30 | 31 | @Override 32 | @NotNull 33 | public VoxelShape getShape(@NotNull BlockState state, @NotNull BlockGetter world, @NotNull BlockPos pos, @NotNull CollisionContext context) { 34 | return Shapes.empty(); 35 | } 36 | 37 | @Override 38 | @NotNull 39 | public VoxelShape getCollisionShape(@NotNull BlockState state, @NotNull BlockGetter world, @NotNull BlockPos pos, @NotNull CollisionContext context) { 40 | return Shapes.empty(); 41 | } 42 | 43 | @Override 44 | public void onPlace(@NotNull BlockState state, Level worldIn, @NotNull BlockPos pos, @NotNull BlockState oldState, boolean isMoving) { 45 | worldIn.scheduleTick(pos, this, 60); 46 | } 47 | } -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/common/network/S2CSynchronizeBadges.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.common.network; 2 | 3 | import com.google.common.collect.HashMultimap; 4 | import com.google.common.collect.Multimap; 5 | import io.github.apace100.origins.badge.Badge; 6 | import io.github.apace100.origins.badge.BadgeManager; 7 | import net.minecraft.network.FriendlyByteBuf; 8 | import net.minecraft.resources.ResourceLocation; 9 | import net.minecraftforge.network.NetworkEvent; 10 | 11 | import java.util.Collection; 12 | import java.util.Map; 13 | import java.util.function.Supplier; 14 | 15 | public record S2CSynchronizeBadges(Multimap badges) { 16 | public static S2CSynchronizeBadges decode(FriendlyByteBuf buf) { 17 | Multimap badges = HashMultimap.create(); 18 | int size = buf.readVarInt(); 19 | for (int i = 0; i < size; i++) { 20 | ResourceLocation rl = buf.readResourceLocation(); 21 | int count = buf.readVarInt(); 22 | for (int j = 0; j < count; j++) 23 | badges.put(rl, BadgeManager.REGISTRY.receiveDataObject(buf)); 24 | } 25 | return new S2CSynchronizeBadges(badges); 26 | } 27 | 28 | public void encode(FriendlyByteBuf buf) { 29 | Map> map = this.badges().asMap(); 30 | buf.writeVarInt(map.size()); 31 | for (Map.Entry> entry : map.entrySet()) { 32 | buf.writeResourceLocation(entry.getKey()); 33 | buf.writeVarInt(entry.getValue().size()); 34 | for (Badge badge : entry.getValue()) 35 | BadgeManager.REGISTRY.writeDataObject(buf, badge); 36 | } 37 | } 38 | 39 | public void handle(Supplier contextSupplier) { 40 | contextSupplier.get().enqueueWork(() -> { 41 | BadgeManager.clear(); 42 | this.badges.forEach(BadgeManager::putPowerBadge); 43 | }); 44 | contextSupplier.get().setPacketHandled(true); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/mixin/SelectionInvulnerabilityMixin.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.mixin; 2 | 3 | import io.github.apace100.origins.Origins; 4 | import io.github.edwinmindcraft.calio.common.CalioConfig; 5 | import io.github.edwinmindcraft.origins.api.OriginsAPI; 6 | import io.github.edwinmindcraft.origins.api.capabilities.IOriginContainer; 7 | import net.minecraft.resources.ResourceLocation; 8 | import net.minecraft.world.damagesource.DamageSource; 9 | import net.minecraft.world.entity.Entity; 10 | import net.minecraft.world.entity.player.Player; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 15 | 16 | import java.util.stream.Collectors; 17 | 18 | @Mixin(Entity.class) 19 | public abstract class SelectionInvulnerabilityMixin { 20 | @Inject(at = @At("HEAD"), method = "isInvulnerableTo", cancellable = true) 21 | private void makeOriginInvulnerable(DamageSource damageSource, CallbackInfoReturnable cir) { 22 | if (!damageSource.isBypassInvul()) { 23 | Entity entity = (Entity) (Object) this; 24 | IOriginContainer.get(entity).ifPresent(container -> { 25 | if (!container.hasAllOrigins()) { 26 | cir.setReturnValue(true); 27 | if (CalioConfig.COMMON.logging.get()) { 28 | String s = OriginsAPI.getActiveLayers().stream() 29 | .filter(x -> !container.hasOrigin(x) && !x.empty((Player) entity)) 30 | .map(layer -> "\"%s\" (Eligible: %s)".formatted(layer.getRegistryName(), layer.origins((Player) entity).stream().map(ResourceLocation::toString).collect(Collectors.joining(",")))) 31 | .collect(Collectors.joining(",")); 32 | Origins.LOGGER.info("Player {} took damage while missing origins for layers: {0}", s); 33 | } 34 | } 35 | }); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/badge/BadgeFactories.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.badge; 2 | 3 | import io.github.apace100.calio.data.SerializableData; 4 | import io.github.apace100.calio.data.SerializableDataTypes; 5 | import io.github.apace100.origins.Origins; 6 | import io.github.edwinmindcraft.origins.common.registry.OriginRegisters; 7 | import net.minecraftforge.registries.RegistryObject; 8 | 9 | import java.util.function.Function; 10 | 11 | public final class BadgeFactories { 12 | 13 | public static final RegistryObject SPRITE = register("sprite", 14 | new SerializableData() 15 | .add("sprite", SerializableDataTypes.IDENTIFIER), 16 | SpriteBadge::new); 17 | 18 | public static final RegistryObject TOOLTIP = register("tooltip", 19 | new SerializableData() 20 | .add("sprite", SerializableDataTypes.IDENTIFIER) 21 | .add("text", SerializableDataTypes.TEXT), 22 | TooltipBadge::new); 23 | 24 | // Added mostly for backwards-compatibility as the default factory. 25 | public static final RegistryObject KEYBIND = register("keybind", 26 | new SerializableData() 27 | .add("sprite", SerializableDataTypes.IDENTIFIER) 28 | .add("text", SerializableDataTypes.STRING), 29 | KeybindBadge::new); 30 | 31 | public static final RegistryObject CRAFTING_RECIPE = register("crafting_recipe", 32 | new SerializableData() 33 | .add("sprite", SerializableDataTypes.IDENTIFIER) 34 | .add("recipe", SerializableDataTypes.RECIPE) 35 | .add("prefix", SerializableDataTypes.TEXT, null) 36 | .add("suffix", SerializableDataTypes.TEXT, null), 37 | CraftingRecipeBadge::new); 38 | 39 | public static void bootstrap() {} 40 | 41 | private static RegistryObject register(String name, SerializableData data, Function factory) { 42 | return OriginRegisters.BADGE_FACTORIES.register(name, () -> new BadgeFactory(Origins.identifier(name), data, factory)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/command/LayerArgumentType.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.command; 2 | 3 | import com.mojang.brigadier.StringReader; 4 | import com.mojang.brigadier.arguments.ArgumentType; 5 | import com.mojang.brigadier.context.CommandContext; 6 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 7 | import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; 8 | import com.mojang.brigadier.suggestion.Suggestions; 9 | import com.mojang.brigadier.suggestion.SuggestionsBuilder; 10 | import io.github.edwinmindcraft.origins.api.OriginsAPI; 11 | import io.github.edwinmindcraft.origins.api.origin.OriginLayer; 12 | import net.minecraft.commands.CommandSourceStack; 13 | import net.minecraft.commands.SharedSuggestionProvider; 14 | import net.minecraft.network.chat.TranslatableComponent; 15 | import net.minecraft.resources.ResourceLocation; 16 | 17 | import java.util.concurrent.CompletableFuture; 18 | 19 | public class LayerArgumentType implements ArgumentType { 20 | public static final DynamicCommandExceptionType LAYER_NOT_FOUND = new DynamicCommandExceptionType((p_208663_0_) -> new TranslatableComponent("commands.origin.layer_not_found", p_208663_0_)); 21 | 22 | public static LayerArgumentType layer() { 23 | return new LayerArgumentType(); 24 | } 25 | 26 | public ResourceLocation parse(StringReader p_parse_1_) throws CommandSyntaxException { 27 | return ResourceLocation.read(p_parse_1_); 28 | } 29 | 30 | public static OriginLayer getLayer(CommandContext context, String argumentName) throws CommandSyntaxException { 31 | ResourceLocation id = context.getArgument(argumentName, ResourceLocation.class); 32 | OriginLayer layer = OriginsAPI.getLayersRegistry().get(id); 33 | if (layer == null) 34 | throw LAYER_NOT_FOUND.create(id); 35 | return layer; 36 | } 37 | 38 | @Override 39 | public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { 40 | return SharedSuggestionProvider.suggestResource(OriginsAPI.getLayersRegistry().keySet(), builder); 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/mixin/WaterBreathingMixin.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.mixin; 2 | 3 | import io.github.apace100.origins.power.OriginsPowerTypes; 4 | import io.github.edwinmindcraft.apoli.api.component.IPowerContainer; 5 | import net.minecraft.tags.TagKey; 6 | import net.minecraft.world.entity.Entity; 7 | import net.minecraft.world.entity.EntityType; 8 | import net.minecraft.world.entity.LivingEntity; 9 | import net.minecraft.world.entity.player.Player; 10 | import net.minecraft.world.level.Level; 11 | import net.minecraft.world.level.material.Fluid; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.Inject; 15 | import org.spongepowered.asm.mixin.injection.Redirect; 16 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 17 | 18 | public final class WaterBreathingMixin { 19 | 20 | @Mixin(LivingEntity.class) 21 | public static abstract class CanBreatheInWater extends Entity { 22 | 23 | public CanBreatheInWater(EntityType type, Level world) { 24 | super(type, world); 25 | } 26 | 27 | @Inject(at = @At("HEAD"), method = "canBreatheUnderwater", cancellable = true) 28 | public void doWaterBreathing(CallbackInfoReturnable info) { 29 | if (IPowerContainer.hasPower(this, OriginsPowerTypes.WATER_BREATHING.get())) 30 | info.setReturnValue(true); 31 | } 32 | } 33 | 34 | @Mixin(Player.class) 35 | public static abstract class UpdateAir extends LivingEntity { 36 | 37 | protected UpdateAir(EntityType entityType, Level world) { 38 | super(entityType, world); 39 | } 40 | 41 | @Redirect(at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;isEyeInFluid(Lnet/minecraft/tags/TagKey;)Z"), method = "turtleHelmetTick") 42 | public boolean isSubmergedInProxy(Player player, TagKey fluidTag) { 43 | boolean submerged = this.isEyeInFluid(fluidTag); 44 | return IPowerContainer.hasPower(this, OriginsPowerTypes.WATER_BREATHING.get()) != submerged; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/power/OriginsCallbackPower.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.power; 2 | 3 | import io.github.edwinmindcraft.apoli.api.power.configuration.ConfiguredEntityAction; 4 | import io.github.edwinmindcraft.apoli.api.power.factory.PowerFactory; 5 | import io.github.edwinmindcraft.origins.api.origin.IOriginCallbackPower; 6 | import io.github.edwinmindcraft.origins.common.power.configuration.OriginsCallbackConfiguration; 7 | import net.minecraft.world.entity.Entity; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | public class OriginsCallbackPower extends PowerFactory implements IOriginCallbackPower { 11 | public OriginsCallbackPower() { 12 | super(OriginsCallbackConfiguration.CODEC); 13 | } 14 | 15 | @Override 16 | protected void onGained(@NotNull OriginsCallbackConfiguration configuration, @NotNull Entity player) { 17 | ConfiguredEntityAction.execute(configuration.entityActionGained(), player); 18 | } 19 | 20 | @Override 21 | protected void onLost(@NotNull OriginsCallbackConfiguration configuration, @NotNull Entity player) { 22 | ConfiguredEntityAction.execute(configuration.entityActionLost(), player); 23 | } 24 | 25 | @Override 26 | protected void onAdded(@NotNull OriginsCallbackConfiguration configuration, @NotNull Entity player) { 27 | ConfiguredEntityAction.execute(configuration.entityActionAdded(), player); 28 | } 29 | 30 | @Override 31 | protected void onRemoved(@NotNull OriginsCallbackConfiguration configuration, @NotNull Entity player) { 32 | ConfiguredEntityAction.execute(configuration.entityActionRemoved(), player); 33 | } 34 | 35 | @Override 36 | protected void onRespawn(@NotNull OriginsCallbackConfiguration configuration, @NotNull Entity player) { 37 | ConfiguredEntityAction.execute(configuration.entityActionRespawned(), player); 38 | } 39 | 40 | @Override 41 | public void onChosen(@NotNull OriginsCallbackConfiguration configuration, @NotNull Entity entity, boolean isOrb) { 42 | if (!isOrb || configuration.onOrb()) 43 | ConfiguredEntityAction.execute(configuration.entityActionChosen(), entity); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/common/power/configuration/OriginsCallbackConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.common.power.configuration; 2 | 3 | import com.mojang.serialization.Codec; 4 | import com.mojang.serialization.codecs.RecordCodecBuilder; 5 | import io.github.edwinmindcraft.apoli.api.IDynamicFeatureConfiguration; 6 | import io.github.edwinmindcraft.apoli.api.power.configuration.ConfiguredEntityAction; 7 | import io.github.edwinmindcraft.calio.api.network.CalioCodecHelper; 8 | import net.minecraft.core.Holder; 9 | 10 | public record OriginsCallbackConfiguration(Holder> entityActionRespawned, 11 | Holder> entityActionRemoved, 12 | Holder> entityActionGained, 13 | Holder> entityActionLost, 14 | Holder> entityActionAdded, 15 | Holder> entityActionChosen, 16 | boolean onOrb) implements IDynamicFeatureConfiguration { 17 | public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( 18 | ConfiguredEntityAction.optional("entity_action_respawned").forGetter(OriginsCallbackConfiguration::entityActionRespawned), 19 | ConfiguredEntityAction.optional("entity_action_removed").forGetter(OriginsCallbackConfiguration::entityActionRemoved), 20 | ConfiguredEntityAction.optional("entity_action_gained").forGetter(OriginsCallbackConfiguration::entityActionGained), 21 | ConfiguredEntityAction.optional("entity_action_lost").forGetter(OriginsCallbackConfiguration::entityActionLost), 22 | ConfiguredEntityAction.optional("entity_action_added").forGetter(OriginsCallbackConfiguration::entityActionAdded), 23 | ConfiguredEntityAction.optional("entity_action_chosen").forGetter(OriginsCallbackConfiguration::entityActionChosen), 24 | CalioCodecHelper.optionalField(CalioCodecHelper.BOOL, "execute_chosen_when_orb", true).forGetter(OriginsCallbackConfiguration::onOrb) 25 | ).apply(instance, OriginsCallbackConfiguration::new)); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/mixin/ScareCreepersMixin.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.mixin; 2 | 3 | 4 | import io.github.apace100.origins.power.OriginsPowerTypes; 5 | import io.github.edwinmindcraft.apoli.api.component.IPowerContainer; 6 | import net.minecraft.world.entity.EntitySelector; 7 | import net.minecraft.world.entity.EntityType; 8 | import net.minecraft.world.entity.ai.goal.AvoidEntityGoal; 9 | import net.minecraft.world.entity.ai.goal.Goal; 10 | import net.minecraft.world.entity.ai.goal.GoalSelector; 11 | import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; 12 | import net.minecraft.world.entity.monster.Creeper; 13 | import net.minecraft.world.entity.monster.Monster; 14 | import net.minecraft.world.entity.player.Player; 15 | import net.minecraft.world.level.Level; 16 | import org.spongepowered.asm.mixin.Mixin; 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 | 22 | @Mixin(Creeper.class) 23 | public abstract class ScareCreepersMixin extends Monster { 24 | protected ScareCreepersMixin(EntityType entityType, Level world) { 25 | super(entityType, world); 26 | } 27 | 28 | @Inject(at = @At("TAIL"), method = "registerGoals") 29 | private void addGoals(CallbackInfo info) { 30 | Goal goal = new AvoidEntityGoal<>(this, Player.class, e -> IPowerContainer.hasPower(e, OriginsPowerTypes.SCARE_CREEPERS.get()), 6.0F, 1.0D, 1.2D, EntitySelector.NO_CREATIVE_OR_SPECTATOR::test); 31 | this.goalSelector.addGoal(3, goal); 32 | } 33 | 34 | @Redirect(at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/ai/goal/GoalSelector;addGoal(ILnet/minecraft/world/entity/ai/goal/Goal;)V", ordinal = 8), method = "registerGoals") 35 | private void redirectTargetGoal(GoalSelector goalSelector, int priority, Goal goal) { 36 | Goal newGoal = new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, e -> !IPowerContainer.hasPower(e, OriginsPowerTypes.SCARE_CREEPERS.get())); 37 | goalSelector.addGoal(priority, newGoal); 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/util/ChoseOriginCriterion.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.util; 2 | 3 | import com.google.gson.JsonObject; 4 | import com.google.gson.JsonPrimitive; 5 | import io.github.apace100.origins.Origins; 6 | import io.github.edwinmindcraft.origins.api.origin.Origin; 7 | import net.minecraft.advancements.critereon.*; 8 | import net.minecraft.resources.ResourceLocation; 9 | import net.minecraft.server.level.ServerPlayer; 10 | import net.minecraft.util.GsonHelper; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.Objects; 14 | 15 | public class ChoseOriginCriterion extends SimpleCriterionTrigger { 16 | 17 | public static final ChoseOriginCriterion INSTANCE = new ChoseOriginCriterion(); 18 | 19 | private static final ResourceLocation ID = new ResourceLocation(Origins.MODID, "chose_origin"); 20 | 21 | @Override 22 | protected @NotNull Conditions createInstance(@NotNull JsonObject obj, EntityPredicate.@NotNull Composite playerPredicate, @NotNull DeserializationContext predicateDeserializer) { 23 | ResourceLocation id = ResourceLocation.tryParse(GsonHelper.getAsString(obj, "origin")); 24 | return new Conditions(playerPredicate, id); 25 | } 26 | 27 | public void trigger(ServerPlayer player, Origin origin) { 28 | this.trigger(player, (conditions -> conditions.matches(origin))); 29 | } 30 | 31 | @Override 32 | public @NotNull ResourceLocation getId() { 33 | return ID; 34 | } 35 | 36 | public static class Conditions extends AbstractCriterionTriggerInstance { 37 | private final ResourceLocation originId; 38 | 39 | public Conditions(EntityPredicate.Composite player, ResourceLocation originId) { 40 | super(ChoseOriginCriterion.ID, player); 41 | this.originId = originId; 42 | } 43 | 44 | public boolean matches(Origin origin) { 45 | return Objects.equals(origin.getRegistryName(), this.originId); 46 | } 47 | 48 | public @NotNull JsonObject serializeToJson(@NotNull SerializationContext predicateSerializer) { 49 | JsonObject jsonObject = super.serializeToJson(predicateSerializer); 50 | jsonObject.add("origin", new JsonPrimitive(this.originId.toString())); 51 | return jsonObject; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/common/network/S2CConfirmOrigin.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.common.network; 2 | 3 | import io.github.apace100.origins.Origins; 4 | import io.github.edwinmindcraft.origins.api.OriginsAPI; 5 | import io.github.edwinmindcraft.origins.api.capabilities.IOriginContainer; 6 | import io.github.edwinmindcraft.origins.api.origin.Origin; 7 | import io.github.edwinmindcraft.origins.api.origin.OriginLayer; 8 | import io.github.edwinmindcraft.origins.client.OriginsClient; 9 | import io.github.edwinmindcraft.origins.client.OriginsClientUtils; 10 | import net.minecraft.network.FriendlyByteBuf; 11 | import net.minecraft.resources.ResourceLocation; 12 | import net.minecraft.world.entity.player.Player; 13 | import net.minecraftforge.api.distmarker.Dist; 14 | import net.minecraftforge.fml.DistExecutor; 15 | import net.minecraftforge.network.NetworkEvent; 16 | 17 | import java.util.function.Supplier; 18 | 19 | public record S2CConfirmOrigin(ResourceLocation layer, ResourceLocation origin) { 20 | 21 | public static S2CConfirmOrigin decode(FriendlyByteBuf buf) { 22 | return new S2CConfirmOrigin(buf.readResourceLocation(), buf.readResourceLocation()); 23 | } 24 | 25 | public void encode(FriendlyByteBuf buf) { 26 | buf.writeResourceLocation(this.layer()); 27 | buf.writeResourceLocation(this.origin()); 28 | } 29 | 30 | public void handle(Supplier contextSupplier) { 31 | contextSupplier.get().enqueueWork(() -> { 32 | Player player = DistExecutor.safeCallWhenOn(Dist.CLIENT, () -> OriginsClientUtils::getClientPlayer); 33 | if (player == null) return; 34 | OriginLayer layer = OriginsAPI.getLayersRegistry().get(this.layer()); 35 | Origin origin = OriginsAPI.getOriginsRegistry().get(this.origin()); 36 | if (layer == null || origin == null) { 37 | Origins.LOGGER.warn("Received invalid confirmation: {} ({}): {} ({})", this.layer(), layer, this.origin(), origin); 38 | return; 39 | } 40 | IOriginContainer.get(player).ifPresent(x -> x.setOrigin(layer, origin)); 41 | DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> OriginsClient.OPEN_NEXT_LAYER.set(true)); 42 | }); 43 | contextSupplier.get().setPacketHandled(true); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/badge/TooltipBadge.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.badge; 2 | 3 | import io.github.apace100.apoli.power.PowerType; 4 | import io.github.apace100.calio.data.SerializableData; 5 | import io.github.edwinmindcraft.apoli.api.power.configuration.ConfiguredPower; 6 | import net.minecraft.client.gui.Font; 7 | import net.minecraft.client.gui.screens.inventory.tooltip.ClientTextTooltip; 8 | import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; 9 | import net.minecraft.network.chat.Component; 10 | import net.minecraft.resources.ResourceLocation; 11 | import net.minecraft.util.FormattedCharSequence; 12 | import net.minecraftforge.api.distmarker.Dist; 13 | import net.minecraftforge.api.distmarker.OnlyIn; 14 | 15 | import java.util.LinkedList; 16 | import java.util.List; 17 | 18 | public record TooltipBadge(ResourceLocation spriteId, Component text) implements Badge { 19 | 20 | public TooltipBadge(SerializableData.Instance instance) { 21 | this(instance.getId("sprite"), instance.get("text")); 22 | } 23 | 24 | @Override 25 | public boolean hasTooltip() { 26 | return true; 27 | } 28 | 29 | @OnlyIn(Dist.CLIENT) 30 | public static void addLines(List tooltips, Component text, Font textRenderer, int widthLimit) { 31 | if (textRenderer.width(text) > widthLimit) { 32 | for (FormattedCharSequence orderedText : textRenderer.split(text, widthLimit)) { 33 | tooltips.add(new ClientTextTooltip(orderedText)); 34 | } 35 | } else { 36 | tooltips.add(new ClientTextTooltip(text.getVisualOrderText())); 37 | } 38 | } 39 | 40 | @Override 41 | @OnlyIn(Dist.CLIENT) 42 | public List getTooltipComponents(ConfiguredPower powerType, int widthLimit, float time, Font textRenderer) { 43 | List tooltips = new LinkedList<>(); 44 | addLines(tooltips, this.text, textRenderer, widthLimit); 45 | return tooltips; 46 | } 47 | 48 | @Override 49 | public SerializableData.Instance toData(SerializableData.Instance instance) { 50 | instance.set("sprite", this.spriteId); 51 | instance.set("text", this.text); 52 | return instance; 53 | } 54 | 55 | @Override 56 | public BadgeFactory getBadgeFactory() { 57 | return BadgeFactories.TOOLTIP.get(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/phantomize_overlay.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "apoli:multiple", 3 | "hidden": true, 4 | "green": { 5 | "type": "apoli:overlay", 6 | "hidden": true, 7 | "texture": "minecraft:textures/misc/nausea.png", 8 | "red": 0.2, 9 | "green": 0.4, 10 | "blue": 0.2, 11 | "strength": 0.7, 12 | "draw_mode": "nausea", 13 | "draw_phase": "above_hud", 14 | "visible_in_third_person": true, 15 | "hide_with_hud": true, 16 | "condition": { 17 | "type": "apoli:and", 18 | "conditions": [ 19 | { 20 | "type": "apoli:power_active", 21 | "power": "origins:phantomize" 22 | }, 23 | { 24 | "type": "apoli:food_level", 25 | "comparison": ">", 26 | "compare_to": 10 27 | } 28 | ] 29 | } 30 | }, 31 | "orange": { 32 | "type": "apoli:overlay", 33 | "hidden": true, 34 | "texture": "minecraft:textures/misc/nausea.png", 35 | "red": 0.3, 36 | "green": 0.3, 37 | "blue": 0.2, 38 | "strength": 0.7, 39 | "draw_mode": "nausea", 40 | "draw_phase": "above_hud", 41 | "visible_in_third_person": true, 42 | "hide_with_hud": true, 43 | "condition": { 44 | "type": "apoli:and", 45 | "conditions": [ 46 | { 47 | "type": "apoli:power_active", 48 | "power": "origins:phantomize" 49 | }, 50 | { 51 | "type": "apoli:food_level", 52 | "comparison": "<=", 53 | "compare_to": 10 54 | }, 55 | { 56 | "type": "apoli:food_level", 57 | "comparison": ">", 58 | "compare_to": 8 59 | } 60 | ] 61 | } 62 | }, 63 | "red": { 64 | "type": "apoli:overlay", 65 | "hidden": true, 66 | "texture": "minecraft:textures/misc/nausea.png", 67 | "red": 0.4, 68 | "green": 0.2, 69 | "blue": 0.2, 70 | "strength": 0.7, 71 | "draw_mode": "nausea", 72 | "draw_phase": "above_hud", 73 | "visible_in_third_person": true, 74 | "hide_with_hud": true, 75 | "condition": { 76 | "type": "apoli:and", 77 | "conditions": [ 78 | { 79 | "type": "apoli:power_active", 80 | "power": "origins:phantomize" 81 | }, 82 | { 83 | "type": "apoli:food_level", 84 | "comparison": "<=", 85 | "compare_to": 8 86 | } 87 | ] 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/badge/BadgeFactory.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.badge; 2 | 3 | import com.mojang.serialization.Codec; 4 | import io.github.apace100.calio.data.SerializableData; 5 | import io.github.apace100.calio.registry.DataObjectFactory; 6 | import net.minecraft.resources.ResourceLocation; 7 | import net.minecraftforge.registries.ForgeRegistryEntry; 8 | 9 | import java.util.Objects; 10 | import java.util.function.Function; 11 | 12 | //FORGE: Properly back factories with a forge registry. 13 | public final class BadgeFactory extends ForgeRegistryEntry implements DataObjectFactory { 14 | private final ResourceLocation id; 15 | private final SerializableData data; 16 | private final Function factory; 17 | private final Codec codec; 18 | 19 | public BadgeFactory(ResourceLocation id, SerializableData data, Function factory) { 20 | this.id = id; 21 | this.data = data; 22 | this.factory = factory; 23 | //TODO: Full codec backing for badges. 24 | this.codec = data.xmap(factory, x -> x.toData(this.data().new Instance())).codec(); 25 | } 26 | 27 | public Codec getCodec() { 28 | return this.codec; 29 | } 30 | 31 | @Override 32 | public SerializableData getData() { 33 | return this.data; 34 | } 35 | 36 | @Override 37 | public Badge fromData(SerializableData.Instance instance) { 38 | return this.factory().apply(instance); 39 | } 40 | 41 | @Override 42 | public SerializableData.Instance toData(Badge badge) { 43 | return badge.toData(this.data.new Instance()); 44 | } 45 | 46 | public ResourceLocation id() { 47 | return this.id; 48 | } 49 | 50 | public SerializableData data() { 51 | return this.data; 52 | } 53 | 54 | public Function factory() { 55 | return this.factory; 56 | } 57 | 58 | @Override 59 | public boolean equals(Object obj) { 60 | if (obj == this) return true; 61 | if (obj == null || obj.getClass() != this.getClass()) return false; 62 | var that = (BadgeFactory) obj; 63 | return Objects.equals(this.id, that.id) && 64 | Objects.equals(this.data, that.data) && 65 | Objects.equals(this.factory, that.factory); 66 | } 67 | 68 | @Override 69 | public int hashCode() { 70 | return Objects.hash(this.id, this.data, this.factory); 71 | } 72 | 73 | @Override 74 | public String toString() { 75 | return "BadgeFactory[" + 76 | "id=" + this.id + ", " + 77 | "data=" + this.data + ", " + 78 | "factory=" + this.factory + ']'; 79 | } 80 | } -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/common/data/LayerLoader.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.common.data; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import com.google.gson.JsonElement; 6 | import com.mojang.serialization.DataResult; 7 | import io.github.apace100.origins.Origins; 8 | import io.github.edwinmindcraft.calio.api.registry.DynamicEntryFactory; 9 | import io.github.edwinmindcraft.calio.api.registry.DynamicEntryValidator; 10 | import io.github.edwinmindcraft.calio.api.registry.ICalioDynamicRegistryManager; 11 | import io.github.edwinmindcraft.origins.api.data.PartialGuiTitle; 12 | import io.github.edwinmindcraft.origins.api.data.PartialLayer; 13 | import io.github.edwinmindcraft.origins.api.origin.ConditionedOrigin; 14 | import io.github.edwinmindcraft.origins.api.origin.OriginLayer; 15 | import net.minecraft.resources.ResourceLocation; 16 | import org.jetbrains.annotations.NotNull; 17 | 18 | import java.util.List; 19 | import java.util.Optional; 20 | import java.util.stream.Stream; 21 | 22 | public enum LayerLoader implements DynamicEntryValidator, DynamicEntryFactory { 23 | INSTANCE; 24 | 25 | private static final Gson GSON = new GsonBuilder().setPrettyPrinting() 26 | .registerTypeAdapter(PartialLayer.class, PartialLayer.Serializer.INSTANCE) 27 | .registerTypeAdapter(PartialGuiTitle.class, PartialGuiTitle.Serializer.INSTANCE) 28 | .registerTypeAdapter(ConditionedOrigin.class, ConditionedOrigin.Serializer.INSTANCE) 29 | .create(); 30 | 31 | @Override 32 | public OriginLayer accept(@NotNull ResourceLocation resourceLocation, List list) { 33 | Optional reduce = list.stream().flatMap(x -> { 34 | try { 35 | return Stream.of(GSON.fromJson(x, PartialLayer.class)); 36 | } catch (Exception e) { 37 | Origins.LOGGER.error("There was a problem reading Origin layer file {} (skipping): {}: {}", resourceLocation, e.getClass(), e.getMessage(), e); 38 | return Stream.empty(); 39 | } 40 | }).sorted(PartialLayer.LOADING_COMPARATOR).reduce(PartialLayer::merge); 41 | if (reduce.isPresent()) 42 | return reduce.get().create(resourceLocation); 43 | Origins.LOGGER.error("All instances of layer {} failed to load. Skipped", resourceLocation); 44 | return null; 45 | } 46 | 47 | @Override 48 | public @NotNull DataResult validate(@NotNull ResourceLocation resourceLocation, @NotNull OriginLayer originLayer, @NotNull ICalioDynamicRegistryManager manager) { 49 | return DataResult.success(originLayer.cleanup(manager)); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/common/network/S2CSynchronizeOrigin.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.common.network; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | import io.github.edwinmindcraft.origins.api.OriginsAPI; 5 | import io.github.edwinmindcraft.origins.client.OriginsClientUtils; 6 | import io.github.edwinmindcraft.origins.common.OriginsCommon; 7 | import io.github.edwinmindcraft.origins.common.capabilities.OriginContainer; 8 | import net.minecraft.network.FriendlyByteBuf; 9 | import net.minecraft.resources.ResourceLocation; 10 | import net.minecraft.world.entity.Entity; 11 | import net.minecraft.world.level.Level; 12 | import net.minecraftforge.api.distmarker.Dist; 13 | import net.minecraftforge.fml.DistExecutor; 14 | import net.minecraftforge.network.NetworkEvent; 15 | import net.minecraftforge.network.PacketDistributor; 16 | 17 | import java.util.Map; 18 | import java.util.function.Supplier; 19 | 20 | public record S2CSynchronizeOrigin(int entity, Map origins, boolean hadAllOrigins) { 21 | 22 | public void encode(FriendlyByteBuf buf) { 23 | buf.writeInt(this.entity()); 24 | buf.writeVarInt(this.origins().size()); 25 | this.origins().forEach((layer, origin) -> { 26 | buf.writeResourceLocation(layer); 27 | buf.writeResourceLocation(origin); 28 | }); 29 | buf.writeBoolean(this.hadAllOrigins()); 30 | } 31 | 32 | public static S2CSynchronizeOrigin decode(FriendlyByteBuf buf) { 33 | int entity = buf.readInt(); 34 | int size = buf.readVarInt(); 35 | ImmutableMap.Builder builder = ImmutableMap.builder(); 36 | for (int i = 0; i < size; i++) { 37 | builder.put(buf.readResourceLocation(), buf.readResourceLocation()); 38 | } 39 | boolean hadAll = buf.readBoolean(); 40 | return new S2CSynchronizeOrigin(entity, builder.build(), hadAll); 41 | } 42 | 43 | public void handle(Supplier contextSupplier) { 44 | contextSupplier.get().enqueueWork(() -> { 45 | Level level = DistExecutor.safeCallWhenOn(Dist.CLIENT, () -> OriginsClientUtils::getClientLevel); 46 | if (level == null) return; 47 | Entity entity = level.getEntity(this.entity()); 48 | if (entity == null) return; 49 | entity.getCapability(OriginsAPI.ORIGIN_CONTAINER).ifPresent(x -> { 50 | if (x instanceof OriginContainer container) { 51 | container.acceptSynchronization(this.origins(), this.hadAllOrigins()); 52 | OriginsCommon.CHANNEL.send(PacketDistributor.SERVER.noArg(), new C2SAcknowledgeOrigins()); 53 | } 54 | }); 55 | }); 56 | contextSupplier.get().setPacketHandled(true); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/command/OriginArgumentType.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.command; 2 | 3 | import com.mojang.brigadier.StringReader; 4 | import com.mojang.brigadier.arguments.ArgumentType; 5 | import com.mojang.brigadier.context.CommandContext; 6 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 7 | import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; 8 | import com.mojang.brigadier.suggestion.Suggestions; 9 | import com.mojang.brigadier.suggestion.SuggestionsBuilder; 10 | import io.github.edwinmindcraft.origins.api.OriginsAPI; 11 | import io.github.edwinmindcraft.origins.api.origin.Origin; 12 | import io.github.edwinmindcraft.origins.api.origin.OriginLayer; 13 | import net.minecraft.commands.CommandSourceStack; 14 | import net.minecraft.commands.SharedSuggestionProvider; 15 | import net.minecraft.network.chat.TranslatableComponent; 16 | import net.minecraft.resources.ResourceLocation; 17 | 18 | import java.util.LinkedList; 19 | import java.util.List; 20 | import java.util.concurrent.CompletableFuture; 21 | 22 | public class OriginArgumentType implements ArgumentType { 23 | public static final DynamicCommandExceptionType ORIGIN_NOT_FOUND = new DynamicCommandExceptionType((p_208663_0_) -> new TranslatableComponent("commands.origin.origin_not_found", p_208663_0_)); 24 | 25 | public static OriginArgumentType origin() { 26 | return new OriginArgumentType(); 27 | } 28 | 29 | public ResourceLocation parse(StringReader p_parse_1_) throws CommandSyntaxException { 30 | return ResourceLocation.read(p_parse_1_); 31 | } 32 | 33 | public static Origin getOrigin(CommandContext context, String argumentName) throws CommandSyntaxException { 34 | ResourceLocation id = context.getArgument(argumentName, ResourceLocation.class); 35 | Origin origin = OriginsAPI.getOriginsRegistry().get(id); 36 | if (origin == null) 37 | throw ORIGIN_NOT_FOUND.create(id); 38 | return origin; 39 | } 40 | 41 | @Override 42 | public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { 43 | OriginLayer layer = null; 44 | try { 45 | layer = context.getArgument("layer", OriginLayer.class); 46 | } catch (Exception e) { 47 | // no-op :) 48 | } 49 | if (layer != null) { 50 | List ids = new LinkedList<>(layer.origins()); 51 | ids.add(Origin.EMPTY.getRegistryName()); 52 | return SharedSuggestionProvider.suggestResource(ids.stream(), builder); 53 | } else { 54 | return SharedSuggestionProvider.suggestResource(OriginsAPI.getOriginsRegistry().keySet(), builder); 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/api/util/JsonUtils.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.api.util; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.google.gson.JsonArray; 5 | import com.google.gson.JsonElement; 6 | import com.google.gson.JsonObject; 7 | import com.google.gson.JsonParseException; 8 | import net.minecraft.ResourceLocationException; 9 | import net.minecraft.resources.ResourceLocation; 10 | import net.minecraft.util.GsonHelper; 11 | 12 | import java.util.List; 13 | import java.util.Optional; 14 | import java.util.function.BiFunction; 15 | import java.util.function.Function; 16 | import java.util.stream.Collector; 17 | import java.util.stream.IntStream; 18 | import java.util.stream.Stream; 19 | 20 | public class JsonUtils { 21 | public static Optional getOptional(JsonObject root, String name, BiFunction function) { 22 | if (root.has(name)) 23 | return Optional.of(function.apply(root, name)); 24 | return Optional.empty(); 25 | } 26 | 27 | public static List getOptionalList(JsonObject root, String name, BiFunction conversion) { 28 | Optional optional = getOptional(root, name, GsonHelper::getAsJsonArray); 29 | if (optional.isEmpty()) 30 | return ImmutableList.of(); 31 | ImmutableList.Builder builder = ImmutableList.builder(); 32 | JsonArray arr = optional.get(); 33 | for (int i = 0; i < arr.size(); i++) 34 | builder.add(conversion.apply(arr.get(i), "%s[%d]".formatted(name, i))); 35 | return builder.build(); 36 | } 37 | 38 | public static List getIdentifierList(JsonObject root, String name) { 39 | return getOptionalList(root, name, (jsonElement, s) -> { 40 | String s1 = GsonHelper.convertToString(jsonElement, s); 41 | try { 42 | return new ResourceLocation(s1); 43 | } catch (ResourceLocationException t) { 44 | throw new JsonParseException(s1 + " isn't a valid identifier at: " + s, t); 45 | } 46 | }); 47 | } 48 | 49 | public static Collector toJsonArray() { 50 | return Collector.of(JsonArray::new, JsonArray::add, (array, array2) -> { 51 | array.addAll(array2); 52 | return array; 53 | }); 54 | } 55 | 56 | public static Stream stream(JsonArray array) { 57 | return IntStream.range(0, array.size()).mapToObj(array::get); 58 | } 59 | 60 | public static Function rethrow(Function input, String message) { 61 | return t -> { 62 | try { 63 | return input.apply(t); 64 | } catch (Throwable th) { 65 | throw new JsonParseException(message, th); 66 | } 67 | }; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/screen/tooltip/CraftingRecipeTooltipComponent.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.screen.tooltip; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | import com.mojang.blaze3d.vertex.PoseStack; 5 | import io.github.apace100.origins.Origins; 6 | import net.minecraft.client.gui.Font; 7 | import net.minecraft.client.gui.Gui; 8 | import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; 9 | import net.minecraft.client.renderer.entity.ItemRenderer; 10 | import net.minecraft.core.NonNullList; 11 | import net.minecraft.resources.ResourceLocation; 12 | import net.minecraft.world.item.ItemStack; 13 | import net.minecraftforge.api.distmarker.Dist; 14 | import net.minecraftforge.api.distmarker.OnlyIn; 15 | import org.jetbrains.annotations.NotNull; 16 | 17 | /** 18 | * A {@link ClientTooltipComponent} used for {@link io.github.apace100.origins.badge.CraftingRecipeBadge} 19 | * Draws a snapshot of a 3x3 crafting recipe in the tooltip 20 | */ 21 | @OnlyIn(Dist.CLIENT) 22 | public class CraftingRecipeTooltipComponent implements ClientTooltipComponent { 23 | private final NonNullList inputs; 24 | private final ItemStack output; 25 | private static final ResourceLocation TEXTURE = Origins.identifier("textures/gui/tooltip/recipe_tooltip.png"); 26 | 27 | public CraftingRecipeTooltipComponent(NonNullList inputs, ItemStack output) { 28 | this.inputs = inputs; 29 | this.output = output; 30 | } 31 | 32 | @Override 33 | public int getHeight() { 34 | return 68; 35 | } 36 | 37 | @Override 38 | public int getWidth(@NotNull Font pFont) { 39 | return 130; 40 | } 41 | 42 | @Override 43 | public void renderImage(@NotNull Font pFont, int pMouseX, int pMouseY, @NotNull PoseStack pPoseStack, @NotNull ItemRenderer pItemRenderer, int pBlitOffset) { 44 | this.drawBackGround(pPoseStack, pMouseX, pMouseY, pBlitOffset); 45 | for (int column = 0; column < 3; ++column) { 46 | for (int row = 0; row < 3; ++row) { 47 | int index = column + row * 3; 48 | int slotX = pMouseX + 8 + column * 18; 49 | int slotY = pMouseY + 8 + row * 18; 50 | ItemStack stack = this.inputs.get(index); 51 | pItemRenderer.renderAndDecorateItem(stack, slotX, slotY, index); 52 | pItemRenderer.renderGuiItemDecorations(pFont, stack, slotX, slotY); 53 | } 54 | } 55 | pItemRenderer.renderAndDecorateItem(this.output, pMouseX + 101, pMouseY + 25, 10); 56 | } 57 | 58 | public void drawBackGround(PoseStack matrices, int x, int y, int z) { 59 | RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); 60 | RenderSystem.setShaderTexture(0, TEXTURE); 61 | Gui.blit(matrices, x, y, z, 0, 0, 130, 86, 256, 256); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/client/OriginsClientEventHandler.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.client; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import io.github.apace100.origins.Origins; 5 | import io.github.apace100.origins.screen.ChooseOriginScreen; 6 | import io.github.apace100.origins.screen.ViewOriginScreen; 7 | import io.github.apace100.origins.screen.WaitForNextLayerScreen; 8 | import io.github.apace100.origins.util.PowerKeyManager; 9 | import io.github.edwinmindcraft.calio.api.event.CalioDynamicRegistryEvent; 10 | import io.github.edwinmindcraft.origins.api.OriginsAPI; 11 | import io.github.edwinmindcraft.origins.api.capabilities.IOriginContainer; 12 | import io.github.edwinmindcraft.origins.api.origin.OriginLayer; 13 | import net.minecraft.client.Minecraft; 14 | import net.minecraftforge.api.distmarker.Dist; 15 | import net.minecraftforge.event.TickEvent; 16 | import net.minecraftforge.eventbus.api.SubscribeEvent; 17 | import net.minecraftforge.fml.common.Mod; 18 | 19 | import java.util.List; 20 | 21 | import static io.github.apace100.origins.OriginsClient.viewCurrentOriginKeybind; 22 | 23 | @Mod.EventBusSubscriber(value = Dist.CLIENT, modid = Origins.MODID) 24 | public class OriginsClientEventHandler { 25 | 26 | @SubscribeEvent 27 | public static void renderTick(TickEvent.RenderTickEvent event) { 28 | if (event.phase == TickEvent.Phase.START) { 29 | Minecraft instance = Minecraft.getInstance(); 30 | if (OriginsClient.AWAITING_DISPLAY.get() && instance.screen == null && instance.player != null) { 31 | IOriginContainer.get(instance.player).ifPresent(container -> { 32 | List layers = OriginsAPI.getActiveLayers().stream().filter(x -> !container.hasOrigin(x)).sorted(OriginLayer::compareTo).toList(); 33 | if (layers.size() > 0) { 34 | instance.setScreen(new ChooseOriginScreen(ImmutableList.copyOf(layers), 0, OriginsClient.SHOW_DIRT_BACKGROUND)); 35 | OriginsClient.AWAITING_DISPLAY.set(false); 36 | } 37 | }); 38 | } 39 | 40 | if (OriginsClient.OPEN_NEXT_LAYER.get()) { 41 | if (instance.screen instanceof WaitForNextLayerScreen screen) 42 | screen.openSelection(); 43 | } 44 | } 45 | } 46 | 47 | @SubscribeEvent 48 | public static void onKeyPressed(TickEvent.ClientTickEvent event) { 49 | if (event.phase == TickEvent.Phase.START) { 50 | while (viewCurrentOriginKeybind.consumeClick()) { 51 | if (!(Minecraft.getInstance().screen instanceof ViewOriginScreen)) { 52 | Minecraft.getInstance().setScreen(new ViewOriginScreen()); 53 | } 54 | } 55 | } 56 | } 57 | 58 | @SubscribeEvent 59 | public static void onCalioRegistryClear(CalioDynamicRegistryEvent.Reload event) { 60 | PowerKeyManager.clearCache(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/badge/KeybindBadge.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.badge; 2 | 3 | import io.github.apace100.apoli.power.PowerType; 4 | import io.github.apace100.calio.data.SerializableData; 5 | import io.github.apace100.origins.util.PowerKeyManager; 6 | import io.github.edwinmindcraft.apoli.api.power.configuration.ConfiguredPower; 7 | import net.minecraft.client.KeyMapping; 8 | import net.minecraft.client.gui.Font; 9 | import net.minecraft.client.gui.screens.inventory.tooltip.ClientTextTooltip; 10 | import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; 11 | import net.minecraft.network.chat.Component; 12 | import net.minecraft.network.chat.TextComponent; 13 | import net.minecraft.network.chat.TranslatableComponent; 14 | import net.minecraft.resources.ResourceLocation; 15 | import net.minecraft.util.FormattedCharSequence; 16 | import net.minecraftforge.api.distmarker.Dist; 17 | import net.minecraftforge.api.distmarker.OnlyIn; 18 | 19 | import java.util.LinkedList; 20 | import java.util.List; 21 | 22 | public record KeybindBadge(ResourceLocation spriteId, String text) implements Badge { 23 | 24 | public KeybindBadge(SerializableData.Instance instance) { 25 | this(instance.getId("sprite"), instance.get("text")); 26 | } 27 | 28 | @Override 29 | public boolean hasTooltip() { 30 | return true; 31 | } 32 | 33 | @OnlyIn(Dist.CLIENT) 34 | public static void addLines(List tooltips, Component text, Font textRenderer, int widthLimit) { 35 | if (textRenderer.width(text) > widthLimit) { 36 | for (FormattedCharSequence orderedText : textRenderer.split(text, widthLimit)) { 37 | tooltips.add(new ClientTextTooltip(orderedText)); 38 | } 39 | } else { 40 | tooltips.add(new ClientTextTooltip(text.getVisualOrderText())); 41 | } 42 | } 43 | 44 | @Override 45 | @OnlyIn(Dist.CLIENT) 46 | public List getTooltipComponents(ConfiguredPower powerType, int widthLimit, float time, Font textRenderer) { 47 | List tooltips = new LinkedList<>(); 48 | Component keyText; 49 | keyText = new TextComponent("[") 50 | .append(KeyMapping.createNameSupplier(PowerKeyManager.getKeyIdentifier(powerType.getRegistryName())).get()) 51 | .append(new TextComponent("]")); 52 | addLines(tooltips, new TranslatableComponent(this.text, keyText), textRenderer, widthLimit); 53 | return tooltips; 54 | } 55 | 56 | @Override 57 | public SerializableData.Instance toData(SerializableData.Instance instance) { 58 | instance.set("sprite", this.spriteId); 59 | instance.set("text", this.text); 60 | return instance; 61 | } 62 | 63 | @Override 64 | public BadgeFactory getBadgeFactory() { 65 | return BadgeFactories.KEYBIND.get(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/api/data/PartialGuiTitle.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.api.data; 2 | 3 | import com.google.gson.*; 4 | import io.github.edwinmindcraft.origins.api.origin.GuiTitle; 5 | import net.minecraft.network.chat.TranslatableComponent; 6 | import net.minecraft.resources.ResourceLocation; 7 | import net.minecraft.util.GsonHelper; 8 | import org.jetbrains.annotations.Contract; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | import java.lang.reflect.Type; 13 | 14 | public record PartialGuiTitle(@Nullable String view, 15 | @Nullable String choose) { 16 | 17 | @NotNull 18 | public GuiTitle create(@NotNull ResourceLocation identifier) { 19 | return new GuiTitle( 20 | this.view() != null ? new TranslatableComponent(!this.view().isEmpty() ? this.view() : "layer.%s.%s.view_origin.name".formatted(identifier.getNamespace(), identifier.getPath())) : null, 21 | this.choose() != null ? new TranslatableComponent(!this.choose().isEmpty() ? this.choose() : "layer.%s.%s.choose_origin.name".formatted(identifier.getNamespace(), identifier.getPath())) : null 22 | ); 23 | } 24 | 25 | @Nullable 26 | @Contract("null, null -> null; null, _ -> param2; _, null -> param1") 27 | public static PartialGuiTitle merge(@Nullable PartialGuiTitle self, @Nullable PartialGuiTitle other) { 28 | if (other == null) return self; 29 | if (self == null) return other; 30 | return new PartialGuiTitle( 31 | other.view() != null ? other.view() : self.view(), 32 | other.choose() != null ? other.choose() : self.choose() 33 | ); 34 | } 35 | 36 | public enum Serializer implements JsonSerializer, JsonDeserializer { 37 | INSTANCE; 38 | 39 | @Override 40 | public PartialGuiTitle deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 41 | if (json.isJsonObject()) 42 | return new PartialGuiTitle(null, null); 43 | JsonObject guiTitleObj = json.getAsJsonObject(); 44 | String view = null; 45 | String choose = null; 46 | if (guiTitleObj.has("view_origin")) { 47 | view = GsonHelper.getAsString(guiTitleObj, "view_origin", ""); 48 | } 49 | if (guiTitleObj.has("choose_origin")) { 50 | choose = GsonHelper.getAsString(guiTitleObj, "choose_origin", ""); 51 | } 52 | return new PartialGuiTitle(view, choose); 53 | } 54 | 55 | @Override 56 | public JsonElement serialize(PartialGuiTitle src, Type typeOfSrc, JsonSerializationContext context) { 57 | JsonObject object = new JsonObject(); 58 | if (src.view() != null) object.addProperty("view_origin", src.view()); 59 | if (src.choose() != null) object.addProperty("choose_origin", src.choose()); 60 | return object; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/screen/WaitForNextLayerScreen.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.screen; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.mojang.blaze3d.vertex.PoseStack; 5 | import io.github.edwinmindcraft.origins.api.capabilities.IOriginContainer; 6 | import io.github.edwinmindcraft.origins.api.origin.OriginLayer; 7 | import net.minecraft.client.Minecraft; 8 | import net.minecraft.client.gui.screens.Screen; 9 | import net.minecraft.network.chat.TextComponent; 10 | import net.minecraft.world.entity.player.Player; 11 | import net.minecraftforge.common.util.LazyOptional; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | import java.util.List; 15 | import java.util.Objects; 16 | 17 | public class WaitForNextLayerScreen extends Screen { 18 | 19 | private final List layerList; 20 | private final int currentLayerIndex; 21 | private final boolean showDirtBackground; 22 | private final int maxSelection; 23 | 24 | protected WaitForNextLayerScreen(List layerList, int currentLayerIndex, boolean showDirtBackground) { 25 | super(TextComponent.EMPTY); 26 | this.layerList = ImmutableList.copyOf(layerList); 27 | this.currentLayerIndex = currentLayerIndex; 28 | this.showDirtBackground = showDirtBackground; 29 | Player player = Minecraft.getInstance().player; 30 | OriginLayer currentLayer = layerList.get(currentLayerIndex); 31 | this.maxSelection = currentLayer.getOriginOptionCount(Objects.requireNonNull(player)); 32 | } 33 | 34 | public void openSelection() { 35 | int index = this.currentLayerIndex + 1; 36 | Player player = Minecraft.getInstance().player; 37 | LazyOptional iOriginContainerLazyOptional = IOriginContainer.get(player); 38 | if (!iOriginContainerLazyOptional.isPresent()) { 39 | Minecraft.getInstance().setScreen(null); 40 | return; 41 | } 42 | IOriginContainer component = iOriginContainerLazyOptional.orElseThrow(RuntimeException::new); 43 | while (index < this.layerList.size()) { 44 | if (!component.hasOrigin(this.layerList.get(index)) && this.layerList.get(index).origins(Objects.requireNonNull(player)).size() > 0) { 45 | Minecraft.getInstance().setScreen(new ChooseOriginScreen(this.layerList, index, this.showDirtBackground)); 46 | return; 47 | } 48 | index++; 49 | } 50 | Minecraft.getInstance().setScreen(null); 51 | } 52 | 53 | @Override 54 | public void render(@NotNull PoseStack matrices, int mouseX, int mouseY, float delta) { 55 | if (this.maxSelection == 0) { 56 | this.openSelection(); 57 | return; 58 | } 59 | this.renderBackground(matrices); 60 | } 61 | 62 | @Override 63 | public void renderBackground(@NotNull PoseStack matrices, int vOffset) { 64 | if (this.showDirtBackground) { 65 | super.renderDirtBackground(vOffset); 66 | } else { 67 | super.renderBackground(matrices, vOffset); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/resources/data/origins/powers/master_of_webs.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:multiple", 3 | "webbing": { 4 | "entity_action": { 5 | "block_action": { 6 | "condition": { 7 | "type": "apoli:replaceable" 8 | }, 9 | "if_action": { 10 | "block": "origins:temporary_cobweb", 11 | "type": "apoli:set_block" 12 | }, 13 | "type": "apoli:if_else" 14 | }, 15 | "type": "apoli:block_action_at" 16 | }, 17 | "cooldown": 200, 18 | "hud_render": { 19 | "bar_index": 5, 20 | "sprite_location": "origins:textures/gui/resource_bar.png" 21 | }, 22 | "type": "apoli:target_action_on_hit" 23 | }, 24 | "no_slowdown": { 25 | "tag": "origins:cobwebs", 26 | "type": "origins:no_slowdown" 27 | }, 28 | "climbing": { 29 | "hold_condition": { 30 | "power": "origins:master_of_webs_climbing", 31 | "type": "apoli:power_active" 32 | }, 33 | "conditions": [ 34 | { 35 | "conditions": [ 36 | { 37 | "block_condition": { 38 | "tag": "origins:cobwebs", 39 | "type": "apoli:in_tag" 40 | }, 41 | "type": "apoli:in_block_anywhere" 42 | }, 43 | { 44 | "power": "origins:climbing_toggle", 45 | "type": "apoli:power_active" 46 | } 47 | ], 48 | "type": "apoli:and" 49 | } 50 | ], 51 | "type": "apoli:climbing" 52 | }, 53 | "punch_through": { 54 | "block_condition": { 55 | "tag": "origins:cobwebs", 56 | "type": "apoli:in_tag" 57 | }, 58 | "conditions": [ 59 | { 60 | "inverted": true, 61 | "type": "apoli:sneaking" 62 | } 63 | ], 64 | "type": "apoli:prevent_block_selection" 65 | }, 66 | "sense": { 67 | "entity_condition": { 68 | "conditions": [ 69 | { 70 | "block_condition": { 71 | "tag": "origins:cobwebs", 72 | "type": "apoli:in_tag" 73 | }, 74 | "type": "apoli:in_block_anywhere" 75 | }, 76 | { 77 | "group": "arthropod", 78 | "inverted": true, 79 | "type": "apoli:entity_group" 80 | } 81 | ], 82 | "type": "apoli:and" 83 | }, 84 | "type": "apoli:entity_glow" 85 | }, 86 | "web_crafting": { 87 | "type": "origins:recipe", 88 | "recipe": { 89 | "id": "origins:master_of_webs/web_crafting", 90 | "type": "minecraft:crafting_shapeless", 91 | "ingredients": [ 92 | { 93 | "item": "minecraft:string" 94 | }, 95 | { 96 | "item": "minecraft:string" 97 | } 98 | ], 99 | "result": { 100 | "item": "minecraft:cobweb" 101 | } 102 | } 103 | } 104 | } -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/common/data/OriginLoader.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.common.data; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import com.google.gson.JsonElement; 6 | import com.mojang.serialization.DataResult; 7 | import io.github.apace100.origins.Origins; 8 | import io.github.edwinmindcraft.calio.api.network.CalioCodecHelper; 9 | import io.github.edwinmindcraft.calio.api.registry.DynamicEntryFactory; 10 | import io.github.edwinmindcraft.calio.api.registry.DynamicEntryValidator; 11 | import io.github.edwinmindcraft.calio.api.registry.ICalioDynamicRegistryManager; 12 | import io.github.edwinmindcraft.origins.api.data.PartialOrigin; 13 | import io.github.edwinmindcraft.origins.api.origin.Origin; 14 | import io.github.edwinmindcraft.origins.api.origin.OriginUpgrade; 15 | import io.github.edwinmindcraft.origins.common.OriginsConfigs; 16 | import net.minecraft.resources.ResourceLocation; 17 | import org.jetbrains.annotations.NotNull; 18 | import org.jetbrains.annotations.Nullable; 19 | 20 | import java.util.Comparator; 21 | import java.util.List; 22 | import java.util.Optional; 23 | import java.util.stream.Stream; 24 | 25 | public enum OriginLoader implements DynamicEntryValidator, DynamicEntryFactory { 26 | INSTANCE; 27 | 28 | private static final Comparator LOADING_ORDER = Comparator.comparingInt(PartialOrigin::loadingOrder); 29 | 30 | private static final Gson GSON = new GsonBuilder().setPrettyPrinting() 31 | .registerTypeAdapter(PartialOrigin.class, PartialOrigin.Serializer.INSTANCE) 32 | .registerTypeAdapter(OriginUpgrade.class, CalioCodecHelper.jsonAdapter(OriginUpgrade.CODEC)) 33 | .create(); 34 | 35 | @Override 36 | public @Nullable Origin accept(@NotNull ResourceLocation id, @NotNull List list) { 37 | Optional origin = list.stream().flatMap(x -> { 38 | try { 39 | return Stream.of(GSON.fromJson(x, PartialOrigin.class)); 40 | } catch (Exception e) { 41 | Origins.LOGGER.error("There was a problem reading Origin file " + id + " (skipping): " + e.getMessage()); 42 | return Stream.empty(); 43 | } 44 | }).max(LOADING_ORDER).map(x -> x.create(id)); 45 | if (origin.isPresent()) 46 | return origin.get(); 47 | Origins.LOGGER.error("All instances of origin {} failed to load. Skipped", id); 48 | return null; 49 | } 50 | 51 | @Override 52 | public @NotNull DataResult validate(@NotNull ResourceLocation resourceLocation, @NotNull Origin origin, @NotNull ICalioDynamicRegistryManager iCalioDynamicRegistryManager) { 53 | Origin cleanup = origin.cleanup(iCalioDynamicRegistryManager); 54 | if (origin.getPowers().size() > cleanup.getPowers().size()) 55 | Origins.LOGGER.error("Removed {} missing powers from {}", origin.getPowers().size() - cleanup.getPowers().size(), resourceLocation); 56 | return DataResult.success(cleanup); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/common/OriginsConfigs.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.common; 2 | 3 | import com.electronwill.nightconfig.core.Config; 4 | import com.google.common.collect.ImmutableList; 5 | import io.github.edwinmindcraft.origins.api.origin.Origin; 6 | import net.minecraft.resources.ResourceLocation; 7 | import net.minecraftforge.common.ForgeConfigSpec; 8 | import org.apache.commons.lang3.tuple.Pair; 9 | 10 | public class OriginsConfigs { 11 | public static class Server { 12 | public Server(ForgeConfigSpec.Builder builder) {} 13 | } 14 | 15 | public static class Client { 16 | public Client(ForgeConfigSpec.Builder builder) {} 17 | } 18 | 19 | public static class Common { 20 | 21 | private final ForgeConfigSpec.ConfigValue origins; 22 | 23 | public Common(ForgeConfigSpec.Builder builder) { 24 | //Remove validation. 25 | this.origins = builder.define(ImmutableList.of("origins"), Config::inMemory, x -> x instanceof Config, Config.class); 26 | } 27 | 28 | public boolean isOriginEnabled(ResourceLocation origin) { 29 | return this.origins.get().getOrElse(ImmutableList.of(origin.toString(), "enabled"), true); 30 | } 31 | 32 | public boolean isPowerEnabled(ResourceLocation origin, ResourceLocation power) { 33 | return this.origins.get().getOrElse(ImmutableList.of(origin.toString(), power.toString()), true); 34 | } 35 | 36 | public boolean updateOriginList(Iterable origins) { 37 | boolean changed = false; 38 | for (Origin origin : origins) { 39 | ResourceLocation registryName = origin.getRegistryName(); 40 | if (origin.isSpecial() || registryName == null) //Ignore special origins 41 | continue; 42 | if (this.origins.get().add(ImmutableList.of(registryName.toString(), "enabled"), true)) 43 | changed = true; 44 | for (ResourceLocation power : origin.getPowers()) { 45 | if (this.origins.get().add(ImmutableList.of(registryName.toString(), power.toString()), true)) { 46 | changed = true; 47 | } 48 | } 49 | } 50 | return changed; 51 | } 52 | } 53 | 54 | public static final ForgeConfigSpec COMMON_SPECS; 55 | public static final ForgeConfigSpec CLIENT_SPECS; 56 | public static final ForgeConfigSpec SERVER_SPECS; 57 | 58 | public static final Common COMMON; 59 | public static final Client CLIENT; 60 | public static final Server SERVER; 61 | 62 | static { 63 | Pair common = new ForgeConfigSpec.Builder().configure(Common::new); 64 | Pair client = new ForgeConfigSpec.Builder().configure(Client::new); 65 | Pair server = new ForgeConfigSpec.Builder().configure(Server::new); 66 | COMMON_SPECS = common.getRight(); 67 | CLIENT_SPECS = client.getRight(); 68 | SERVER_SPECS = server.getRight(); 69 | COMMON = common.getLeft(); 70 | CLIENT = client.getLeft(); 71 | SERVER = server.getLeft(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/api/OriginsAPI.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.api; 2 | 3 | import io.github.edwinmindcraft.calio.api.CalioAPI; 4 | import io.github.edwinmindcraft.origins.api.capabilities.IOriginContainer; 5 | import io.github.edwinmindcraft.origins.api.origin.Origin; 6 | import io.github.edwinmindcraft.origins.api.origin.OriginLayer; 7 | import io.github.edwinmindcraft.origins.api.registry.OriginsDynamicRegistries; 8 | import net.minecraft.core.Registry; 9 | import net.minecraft.resources.ResourceLocation; 10 | import net.minecraft.server.MinecraftServer; 11 | import net.minecraftforge.common.capabilities.Capability; 12 | import net.minecraftforge.common.capabilities.CapabilityManager; 13 | import net.minecraftforge.common.capabilities.CapabilityToken; 14 | import org.apache.commons.lang3.Validate; 15 | 16 | import java.util.List; 17 | import java.util.concurrent.ConcurrentHashMap; 18 | 19 | public class OriginsAPI { 20 | private static final ConcurrentHashMap POWER_SOURCE_CACHE = new ConcurrentHashMap<>(); 21 | public static final String MODID = "origins"; 22 | 23 | public static final Capability ORIGIN_CONTAINER = CapabilityManager.get(new CapabilityToken<>() {}); 24 | 25 | public static Registry getOriginsRegistry(MinecraftServer server) { 26 | return CalioAPI.getDynamicRegistries(server).get(OriginsDynamicRegistries.ORIGINS_REGISTRY); 27 | } 28 | 29 | public static Registry getOriginsRegistry() { 30 | return CalioAPI.getDynamicRegistries().get(OriginsDynamicRegistries.ORIGINS_REGISTRY); 31 | } 32 | 33 | public static Registry getLayersRegistry(MinecraftServer server) { 34 | return CalioAPI.getDynamicRegistries(server).get(OriginsDynamicRegistries.LAYERS_REGISTRY); 35 | } 36 | 37 | public static Registry getLayersRegistry() { 38 | return CalioAPI.getDynamicRegistries().get(OriginsDynamicRegistries.LAYERS_REGISTRY); 39 | } 40 | 41 | public static List getActiveLayers() { 42 | return getLayersRegistry().stream().filter(OriginLayer::enabled).sorted().toList(); 43 | } 44 | 45 | public static ResourceLocation getPowerSource(Origin origin) { 46 | var registryName = origin.getRegistryName(); 47 | Validate.notNull(registryName, "Unregistered origins cannot provide powers."); 48 | return POWER_SOURCE_CACHE.computeIfAbsent(registryName, OriginsAPI::createPowerSource); 49 | } 50 | 51 | public static ResourceLocation getPowerSource(ResourceLocation origin) { 52 | Validate.notNull(origin, "Unregistered origins cannot provide powers."); 53 | return POWER_SOURCE_CACHE.computeIfAbsent(origin, OriginsAPI::createPowerSource); 54 | } 55 | 56 | private static ResourceLocation createPowerSource(ResourceLocation key) { 57 | //Fabric command compat. 58 | //If this were up to me, the power source would've been :origins/ 59 | return new ResourceLocation(key.getNamespace(), key.getPath()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/OriginsClient.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins; 2 | 3 | import com.mojang.blaze3d.platform.InputConstants; 4 | import io.github.apace100.apoli.ApoliClient; 5 | import io.github.apace100.origins.registry.ModBlocks; 6 | import io.github.apace100.origins.registry.ModEntities; 7 | import net.minecraft.client.KeyMapping; 8 | import net.minecraft.client.renderer.ItemBlockRenderTypes; 9 | import net.minecraft.client.renderer.RenderType; 10 | import net.minecraft.client.renderer.entity.ThrownItemRenderer; 11 | import net.minecraftforge.api.distmarker.Dist; 12 | import net.minecraftforge.api.distmarker.OnlyIn; 13 | import net.minecraftforge.client.ClientRegistry; 14 | import net.minecraftforge.client.event.EntityRenderersEvent; 15 | import net.minecraftforge.eventbus.api.IEventBus; 16 | import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; 17 | import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; 18 | import org.lwjgl.glfw.GLFW; 19 | 20 | @OnlyIn(Dist.CLIENT) 21 | public class OriginsClient { 22 | 23 | public static KeyMapping usePrimaryActivePowerKeybind; 24 | public static KeyMapping useSecondaryActivePowerKeybind; 25 | public static KeyMapping viewCurrentOriginKeybind; 26 | 27 | public static boolean isServerRunningOrigins = false; 28 | 29 | public static void initialize() { 30 | 31 | usePrimaryActivePowerKeybind = new KeyMapping("key.origins.primary_active", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_G, "category." + Origins.MODID); 32 | useSecondaryActivePowerKeybind = new KeyMapping("key.origins.secondary_active", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_UNKNOWN, "category." + Origins.MODID); 33 | viewCurrentOriginKeybind = new KeyMapping("key.origins.view_origin", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_O, "category." + Origins.MODID); 34 | 35 | ApoliClient.registerPowerKeybinding("key.origins.primary_active", usePrimaryActivePowerKeybind); 36 | ApoliClient.registerPowerKeybinding("key.origins.secondary_active", useSecondaryActivePowerKeybind); 37 | ApoliClient.registerPowerKeybinding("primary", usePrimaryActivePowerKeybind); 38 | ApoliClient.registerPowerKeybinding("secondary", useSecondaryActivePowerKeybind); 39 | 40 | // "none" is the default key used when none is specified. 41 | ApoliClient.registerPowerKeybinding("none", usePrimaryActivePowerKeybind); 42 | IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus(); 43 | bus.addListener(OriginsClient::clientSetup); 44 | bus.addListener(OriginsClient::entityRenderers); 45 | } 46 | 47 | public static void clientSetup(FMLClientSetupEvent event) { 48 | event.enqueueWork(() -> ItemBlockRenderTypes.setRenderLayer(ModBlocks.TEMPORARY_COBWEB.get(), RenderType.cutout())); 49 | 50 | ClientRegistry.registerKeyBinding(usePrimaryActivePowerKeybind); 51 | ClientRegistry.registerKeyBinding(useSecondaryActivePowerKeybind); 52 | ClientRegistry.registerKeyBinding(viewCurrentOriginKeybind); 53 | } 54 | 55 | public static void entityRenderers(EntityRenderersEvent.RegisterRenderers event) { 56 | event.registerEntityRenderer(ModEntities.ENDERIAN_PEARL.get(), ThrownItemRenderer::new); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/common/network/C2SChooseRandomOrigin.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.common.network; 2 | 3 | import io.github.apace100.origins.Origins; 4 | import io.github.apace100.origins.component.OriginComponent; 5 | import io.github.edwinmindcraft.origins.api.OriginsAPI; 6 | import io.github.edwinmindcraft.origins.api.capabilities.IOriginContainer; 7 | import io.github.edwinmindcraft.origins.api.origin.Origin; 8 | import io.github.edwinmindcraft.origins.api.origin.OriginLayer; 9 | import io.github.edwinmindcraft.origins.common.OriginsCommon; 10 | import net.minecraft.network.FriendlyByteBuf; 11 | import net.minecraft.resources.ResourceLocation; 12 | import net.minecraft.server.level.ServerPlayer; 13 | import net.minecraftforge.network.NetworkEvent; 14 | import net.minecraftforge.network.PacketDistributor; 15 | 16 | import java.util.Optional; 17 | import java.util.function.Supplier; 18 | 19 | public record C2SChooseRandomOrigin(ResourceLocation layer) { 20 | public static C2SChooseRandomOrigin decode(FriendlyByteBuf buf) { 21 | return new C2SChooseRandomOrigin(buf.readResourceLocation()); 22 | } 23 | 24 | public void encode(FriendlyByteBuf buf) { 25 | buf.writeResourceLocation(this.layer()); 26 | } 27 | 28 | public void handle(Supplier contextSupplier) { 29 | contextSupplier.get().enqueueWork(() -> { 30 | ServerPlayer sender = contextSupplier.get().getSender(); 31 | if (sender == null) return; 32 | IOriginContainer.get(sender).ifPresent(container -> { 33 | OriginLayer layer = OriginsAPI.getLayersRegistry().get(this.layer()); 34 | if (layer == null) { 35 | Origins.LOGGER.warn("Player {} tried to select a random origin for missing layer {}", sender.getScoreboardName(), this.layer()); 36 | return; 37 | } 38 | if (container.hasAllOrigins() || container.hasOrigin(layer)) { 39 | Origins.LOGGER.warn("Player {} tried to choose origin for layer {} while having one already.", sender.getScoreboardName(), this.layer()); 40 | return; 41 | } 42 | Optional selected = layer.selectRandom(sender); 43 | if (!layer.allowRandom() || selected.isEmpty()) { 44 | Origins.LOGGER.warn("Player {} tried to choose a random Origin for layer {}, which is not allowed!", sender.getScoreboardName(), this.layer()); 45 | container.setOrigin(layer, Origin.EMPTY); 46 | return; 47 | } 48 | Origin origin = selected.get(); 49 | boolean hadOriginBefore = container.hadAllOrigins(); 50 | boolean hadAllOrigins = container.hasAllOrigins(); 51 | container.setOrigin(layer, origin); 52 | container.checkAutoChoosingLayers(false); 53 | container.synchronize(); 54 | if (container.hasAllOrigins() && !hadAllOrigins) 55 | OriginComponent.onChosen(sender, hadOriginBefore); 56 | Origins.LOGGER.info("Player {} was randomly assigned the following Origin: \"{}\" for layer: {}", sender.getScoreboardName(), origin.getRegistryName(), this.layer()); 57 | OriginsCommon.CHANNEL.send(PacketDistributor.PLAYER.with(() -> sender), new S2CConfirmOrigin(this.layer(), origin.getRegistryName())); 58 | }); 59 | }); 60 | contextSupplier.get().setPacketHandled(true); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/common/network/C2SChooseOrigin.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.common.network; 2 | 3 | import io.github.apace100.origins.Origins; 4 | import io.github.apace100.origins.component.OriginComponent; 5 | import io.github.edwinmindcraft.origins.api.OriginsAPI; 6 | import io.github.edwinmindcraft.origins.api.capabilities.IOriginContainer; 7 | import io.github.edwinmindcraft.origins.api.origin.Origin; 8 | import io.github.edwinmindcraft.origins.api.origin.OriginLayer; 9 | import io.github.edwinmindcraft.origins.common.OriginsCommon; 10 | import net.minecraft.network.FriendlyByteBuf; 11 | import net.minecraft.resources.ResourceLocation; 12 | import net.minecraft.server.level.ServerPlayer; 13 | import net.minecraftforge.network.NetworkEvent; 14 | import net.minecraftforge.network.PacketDistributor; 15 | 16 | import java.util.function.Supplier; 17 | 18 | public record C2SChooseOrigin(ResourceLocation layer, ResourceLocation origin) { 19 | 20 | public static C2SChooseOrigin decode(FriendlyByteBuf buf) { 21 | return new C2SChooseOrigin(buf.readResourceLocation(), buf.readResourceLocation()); 22 | } 23 | 24 | public void encode(FriendlyByteBuf buf) { 25 | buf.writeResourceLocation(this.layer()); 26 | buf.writeResourceLocation(this.origin()); 27 | } 28 | 29 | public void handle(Supplier contextSupplier) { 30 | contextSupplier.get().enqueueWork(() -> { 31 | ServerPlayer sender = contextSupplier.get().getSender(); 32 | if (sender == null) return; 33 | IOriginContainer.get(sender).ifPresent(container -> { 34 | OriginLayer layer = OriginsAPI.getLayersRegistry().get(this.layer()); 35 | if (layer == null) { 36 | Origins.LOGGER.warn("Player {} tried to select an origin for missing layer {}", sender.getScoreboardName(), this.layer()); 37 | return; 38 | } 39 | if (container.hasAllOrigins() || container.hasOrigin(layer)) { 40 | Origins.LOGGER.warn("Player {} tried to choose origin for layer {} while having one already.", sender.getScoreboardName(), this.layer()); 41 | return; 42 | } 43 | Origin origin = OriginsAPI.getOriginsRegistry().get(this.origin()); 44 | if (origin == null) { 45 | Origins.LOGGER.warn("Player {} chose unknown origin: {} for layer {}", sender.getScoreboardName(), this.origin(), this.layer()); 46 | return; 47 | } 48 | if (!origin.isChoosable() || !layer.contains(this.origin(), sender)) { 49 | Origins.LOGGER.warn("Player {} tried to choose invalid origin: {} for layer: {}", sender.getScoreboardName(), this.origin(), this.layer()); 50 | container.setOrigin(layer, Origin.EMPTY); 51 | } else { 52 | boolean hadOriginBefore = container.hadAllOrigins(); 53 | boolean hadAllOrigins = container.hasAllOrigins(); 54 | container.setOrigin(layer, origin); 55 | container.checkAutoChoosingLayers(false); 56 | if (container.hasAllOrigins() && !hadAllOrigins) { 57 | OriginComponent.onChosen(sender, hadOriginBefore); 58 | } 59 | } 60 | container.synchronize(); 61 | OriginsCommon.CHANNEL.send(PacketDistributor.PLAYER.with(() -> sender), new S2CConfirmOrigin(this.layer(), this.origin())); 62 | }); 63 | }); 64 | contextSupplier.get().setPacketHandled(true); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/common/registry/OriginRegisters.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.common.registry; 2 | 3 | import io.github.apace100.origins.Origins; 4 | import io.github.apace100.origins.badge.BadgeFactories; 5 | import io.github.apace100.origins.badge.BadgeFactory; 6 | import io.github.apace100.origins.badge.BadgeManager; 7 | import io.github.edwinmindcraft.apoli.api.power.factory.EntityCondition; 8 | import io.github.edwinmindcraft.apoli.api.power.factory.PowerFactory; 9 | import io.github.edwinmindcraft.apoli.api.registry.ApoliRegistries; 10 | import io.github.edwinmindcraft.origins.api.origin.Origin; 11 | import io.github.edwinmindcraft.origins.api.registry.OriginsBuiltinRegistries; 12 | import io.github.edwinmindcraft.origins.api.registry.OriginsDynamicRegistries; 13 | import net.minecraft.world.entity.EntityType; 14 | import net.minecraft.world.item.Item; 15 | import net.minecraft.world.item.enchantment.Enchantment; 16 | import net.minecraft.world.level.block.Block; 17 | import net.minecraftforge.eventbus.api.IEventBus; 18 | import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; 19 | import net.minecraftforge.registries.DeferredRegister; 20 | import net.minecraftforge.registries.ForgeRegistries; 21 | import net.minecraftforge.registries.RegistryBuilder; 22 | import net.minecraftforge.registries.RegistryObject; 23 | 24 | public class OriginRegisters { 25 | public static final DeferredRegister> POWER_FACTORIES = DeferredRegister.create(ApoliRegistries.POWER_FACTORY_KEY, Origins.MODID); 26 | public static final DeferredRegister ORIGINS = DeferredRegister.create(OriginsDynamicRegistries.ORIGINS_REGISTRY, Origins.MODID); 27 | public static final DeferredRegister BADGE_FACTORIES = DeferredRegister.create(OriginsBuiltinRegistries.BADGE_FACTORY_KEY, Origins.MODID); 28 | public static final DeferredRegister> ENTITY_TYPES = DeferredRegister.create(ForgeRegistries.ENTITIES, Origins.MODID); 29 | public static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, Origins.MODID); 30 | public static final DeferredRegister BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, Origins.MODID); 31 | public static final DeferredRegister ENCHANTMENTS = DeferredRegister.create(ForgeRegistries.ENCHANTMENTS, Origins.MODID); 32 | public static final DeferredRegister> ENTITY_CONDITIONS = DeferredRegister.create(ApoliRegistries.ENTITY_CONDITION_KEY, Origins.MODID); 33 | 34 | public static final RegistryObject EMPTY = ORIGINS.register("empty", () -> Origin.EMPTY); 35 | 36 | public static void register() { 37 | IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus(); 38 | OriginsBuiltinRegistries.ORIGINS = ORIGINS.makeRegistry(Origin.class, () -> new RegistryBuilder().setDefaultKey(Origins.identifier("empty"))); 39 | OriginsBuiltinRegistries.BADGE_FACTORIES = BADGE_FACTORIES.makeRegistry(BadgeFactory.class, RegistryBuilder::new); 40 | 41 | POWER_FACTORIES.register(bus); 42 | ORIGINS.register(bus); 43 | ENTITY_TYPES.register(bus); 44 | ITEMS.register(bus); 45 | BLOCKS.register(bus); 46 | ENCHANTMENTS.register(bus); 47 | ENTITY_CONDITIONS.register(bus); 48 | BADGE_FACTORIES.register(bus); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/util/OriginLootCondition.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.util; 2 | 3 | import com.google.gson.JsonDeserializationContext; 4 | import com.google.gson.JsonObject; 5 | import com.google.gson.JsonSerializationContext; 6 | import io.github.apace100.origins.registry.ModLoot; 7 | import io.github.edwinmindcraft.origins.api.capabilities.IOriginContainer; 8 | import net.minecraft.resources.ResourceLocation; 9 | import net.minecraft.util.GsonHelper; 10 | import net.minecraft.world.entity.Entity; 11 | import net.minecraft.world.level.storage.loot.LootContext; 12 | import net.minecraft.world.level.storage.loot.parameters.LootContextParams; 13 | import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; 14 | import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType; 15 | import org.jetbrains.annotations.NotNull; 16 | import org.jetbrains.annotations.Nullable; 17 | 18 | public class OriginLootCondition implements LootItemCondition { 19 | private final ResourceLocation origin; 20 | @Nullable 21 | private final ResourceLocation layer; 22 | 23 | private OriginLootCondition(ResourceLocation origin) { 24 | this(origin, null); 25 | } 26 | 27 | private OriginLootCondition(ResourceLocation origin, @Nullable ResourceLocation layer) { 28 | this.origin = origin; 29 | this.layer = layer; 30 | } 31 | 32 | public @NotNull LootItemConditionType getType() { 33 | return ModLoot.ORIGIN_LOOT_CONDITION; 34 | } 35 | 36 | public boolean test(LootContext lootContext) { 37 | Entity entity = lootContext.getParamOrNull(LootContextParams.THIS_ENTITY); 38 | if (entity == null) return false; 39 | return IOriginContainer.get(entity) 40 | .map(container -> container 41 | .getOrigins().entrySet().stream() 42 | .anyMatch(entry -> (this.layer == null || this.layer.equals(entry.getKey().getRegistryName())) && this.origin.equals(entry.getValue().getRegistryName()))).orElse(false); 43 | } 44 | 45 | public static LootItemCondition.Builder builder(String originId) { 46 | return builder(new ResourceLocation(originId)); 47 | } 48 | 49 | public static LootItemCondition.Builder builder(ResourceLocation origin) { 50 | return () -> new OriginLootCondition(origin); 51 | } 52 | 53 | public static LootItemCondition.Builder builder(String originId, String layerId) { 54 | return builder(new ResourceLocation(originId), new ResourceLocation(layerId)); 55 | } 56 | 57 | public static LootItemCondition.Builder builder(ResourceLocation origin, ResourceLocation layer) { 58 | return () -> new OriginLootCondition(origin, layer); 59 | } 60 | 61 | public static class Serializer implements net.minecraft.world.level.storage.loot.Serializer { 62 | public void serialize(JsonObject jsonObject, OriginLootCondition originLootCondition, @NotNull JsonSerializationContext jsonSerializationContext) { 63 | jsonObject.addProperty("origin", originLootCondition.origin.toString()); 64 | if (originLootCondition.layer != null) { 65 | jsonObject.addProperty("layer", originLootCondition.layer.toString()); 66 | } 67 | } 68 | 69 | public @NotNull OriginLootCondition deserialize(@NotNull JsonObject jsonObject, @NotNull JsonDeserializationContext jsonDeserializationContext) { 70 | ResourceLocation origin = new ResourceLocation(GsonHelper.getAsString(jsonObject, "origin")); 71 | if (jsonObject.has("layer")) { 72 | ResourceLocation layer = new ResourceLocation(GsonHelper.getAsString(jsonObject, "layer")); 73 | return new OriginLootCondition(origin, layer); 74 | } 75 | return new OriginLootCondition(origin); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/badge/CraftingRecipeBadge.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.badge; 2 | 3 | import io.github.apace100.calio.data.SerializableData; 4 | import io.github.apace100.origins.screen.tooltip.CraftingRecipeTooltipComponent; 5 | import io.github.edwinmindcraft.apoli.api.power.configuration.ConfiguredPower; 6 | import net.minecraft.ChatFormatting; 7 | import net.minecraft.client.Minecraft; 8 | import net.minecraft.client.gui.Font; 9 | import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; 10 | import net.minecraft.core.NonNullList; 11 | import net.minecraft.network.chat.Component; 12 | import net.minecraft.network.chat.TextComponent; 13 | import net.minecraft.resources.ResourceLocation; 14 | import net.minecraft.util.Mth; 15 | import net.minecraft.world.inventory.CraftingContainer; 16 | import net.minecraft.world.item.ItemStack; 17 | import net.minecraft.world.item.crafting.Ingredient; 18 | import net.minecraft.world.item.crafting.Recipe; 19 | import net.minecraftforge.api.distmarker.Dist; 20 | import net.minecraftforge.api.distmarker.OnlyIn; 21 | 22 | import javax.annotation.Nullable; 23 | import java.util.LinkedList; 24 | import java.util.List; 25 | 26 | public record CraftingRecipeBadge(ResourceLocation spriteId, 27 | Recipe recipe, 28 | @Nullable Component prefix, 29 | @Nullable Component suffix) implements Badge { 30 | 31 | public CraftingRecipeBadge(SerializableData.Instance instance) { 32 | this(instance.getId("sprite"), 33 | instance.get("recipe"), 34 | instance.get("prefix"), 35 | instance.get("suffix")); 36 | } 37 | 38 | @Override 39 | public boolean hasTooltip() { 40 | return true; 41 | } 42 | 43 | public NonNullList peekInputs(float time) { 44 | int seed = Mth.floor(time / 30); 45 | NonNullList inputs = NonNullList.withSize(9, ItemStack.EMPTY); 46 | List ingredients = this.recipe.getIngredients(); 47 | for (int index = 0; index < ingredients.size(); ++index) { 48 | ItemStack[] stacks = ingredients.get(index).getItems(); 49 | if (stacks.length > 0) inputs.set(index, stacks[seed % stacks.length].copy()); 50 | } 51 | return inputs; 52 | } 53 | 54 | @Override 55 | @OnlyIn(Dist.CLIENT) 56 | public List getTooltipComponents(ConfiguredPower powerType, int widthLimit, float time, Font textRenderer) { 57 | List tooltips = new LinkedList<>(); 58 | if (Minecraft.getInstance().options.advancedItemTooltips) { 59 | Component recipeIdText = new TextComponent(this.recipe.getId().toString()).withStyle(ChatFormatting.DARK_GRAY); 60 | widthLimit = Math.max(130, textRenderer.width(recipeIdText)); 61 | if (this.prefix != null) TooltipBadge.addLines(tooltips, this.prefix, textRenderer, widthLimit); 62 | tooltips.add(new CraftingRecipeTooltipComponent(this.peekInputs(time), this.recipe.getResultItem().copy())); 63 | if (this.suffix != null) TooltipBadge.addLines(tooltips, this.suffix, textRenderer, widthLimit); 64 | TooltipBadge.addLines(tooltips, recipeIdText, textRenderer, widthLimit); 65 | } else { 66 | widthLimit = 130; 67 | if (this.prefix != null) TooltipBadge.addLines(tooltips, this.prefix, textRenderer, widthLimit); 68 | tooltips.add(new CraftingRecipeTooltipComponent(this.peekInputs(time), this.recipe.getResultItem().copy())); 69 | if (this.suffix != null) TooltipBadge.addLines(tooltips, this.suffix, textRenderer, widthLimit); 70 | } 71 | return tooltips; 72 | } 73 | 74 | @Override 75 | public SerializableData.Instance toData(SerializableData.Instance instance) { 76 | instance.set("sprite", this.spriteId); 77 | instance.set("recipe", this.recipe); 78 | instance.set("prefix", this.prefix); 79 | instance.set("suffix", this.suffix); 80 | return instance; 81 | } 82 | 83 | @Override 84 | public BadgeFactory getBadgeFactory() { 85 | return BadgeFactories.CRAFTING_RECIPE.get(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/entity/EnderianPearlEntity.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.entity; 2 | 3 | import io.github.apace100.origins.registry.ModEntities; 4 | import net.minecraft.core.particles.ParticleTypes; 5 | import net.minecraft.network.protocol.Packet; 6 | import net.minecraft.server.level.ServerPlayer; 7 | import net.minecraft.world.damagesource.DamageSource; 8 | import net.minecraft.world.entity.Entity; 9 | import net.minecraft.world.entity.EntityType; 10 | import net.minecraft.world.entity.LivingEntity; 11 | import net.minecraft.world.entity.projectile.ThrownEnderpearl; 12 | import net.minecraft.world.item.Item; 13 | import net.minecraft.world.item.Items; 14 | import net.minecraft.world.level.Level; 15 | import net.minecraft.world.level.gameevent.GameEvent; 16 | import net.minecraft.world.phys.BlockHitResult; 17 | import net.minecraft.world.phys.EntityHitResult; 18 | import net.minecraft.world.phys.HitResult; 19 | import net.minecraftforge.event.ForgeEventFactory; 20 | import net.minecraftforge.event.entity.EntityTeleportEvent; 21 | import net.minecraftforge.network.NetworkHooks; 22 | import org.jetbrains.annotations.NotNull; 23 | 24 | public class EnderianPearlEntity extends ThrownEnderpearl { 25 | public EnderianPearlEntity(EntityType entityType, Level world) { 26 | super(entityType, world); 27 | } 28 | 29 | public EnderianPearlEntity(EntityType entityType, LivingEntity owner, Level world) { 30 | super(entityType, world); 31 | this.setPos(owner.getX(), owner.getEyeY() - 0.1D, owner.getZ()); 32 | this.setOwner(owner); 33 | } 34 | 35 | public EnderianPearlEntity(Level world, LivingEntity owner) { 36 | this(ModEntities.ENDERIAN_PEARL.get(), owner, world); 37 | } 38 | 39 | @Override 40 | protected void onHitEntity(@NotNull EntityHitResult entityHitResult) {} 41 | 42 | protected @NotNull Item getDefaultItem() { 43 | return Items.ENDER_PEARL; 44 | } 45 | 46 | protected void onHit(HitResult result) { 47 | HitResult.Type type = result.getType(); 48 | if (type == HitResult.Type.ENTITY) 49 | this.onHitEntity((EntityHitResult) result); 50 | else if (type == HitResult.Type.BLOCK) 51 | this.onHitBlock((BlockHitResult) result); 52 | 53 | if (type != HitResult.Type.MISS) 54 | this.gameEvent(GameEvent.PROJECTILE_LAND, this.getOwner()); 55 | 56 | 57 | for (int i = 0; i < 32; ++i) { 58 | this.level.addParticle(ParticleTypes.PORTAL, this.getX(), this.getY() + this.random.nextDouble() * 2.0D, this.getZ(), this.random.nextGaussian(), 0.0D, this.random.nextGaussian()); 59 | } 60 | 61 | if (!this.level.isClientSide && !this.isRemoved()) { 62 | Entity entity = this.getOwner(); 63 | if (entity instanceof ServerPlayer serverplayer) { 64 | //Origins: No damage from enderian pearls. 65 | //Origins: Disable Endermite spawning. 66 | if (serverplayer.connection.getConnection().isConnected() && serverplayer.level == this.level && !serverplayer.isSleeping()) { 67 | EntityTeleportEvent.EnderPearl event = ForgeEventFactory.onEnderPearlLand(serverplayer, this.getX(), this.getY(), this.getZ(), this, 0.0F); 68 | if (!event.isCanceled()) { 69 | if (entity.isPassenger()) 70 | serverplayer.dismountTo(this.getX(), this.getY(), this.getZ()); 71 | else 72 | entity.teleportTo(this.getX(), this.getY(), this.getZ()); 73 | 74 | entity.teleportTo(event.getTargetX(), event.getTargetY(), event.getTargetZ()); 75 | entity.fallDistance = 0.0F; 76 | if (event.getAttackDamage() > 0) 77 | entity.hurt(DamageSource.FALL, event.getAttackDamage()); 78 | } 79 | } 80 | } else if (entity != null) { 81 | entity.teleportTo(this.getX(), this.getY(), this.getZ()); 82 | entity.fallDistance = 0.0F; 83 | } 84 | 85 | this.discard(); 86 | } 87 | } 88 | 89 | @Override 90 | public @NotNull Packet getAddEntityPacket() { 91 | return NetworkHooks.getEntitySpawningPacket(this); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/origin/OriginRegistry.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.origin; 2 | 3 | import io.github.edwinmindcraft.origins.api.OriginsAPI; 4 | import net.minecraft.resources.ResourceKey; 5 | import net.minecraft.resources.ResourceLocation; 6 | 7 | import java.util.Iterator; 8 | import java.util.Map; 9 | import java.util.concurrent.ConcurrentHashMap; 10 | import java.util.stream.Stream; 11 | 12 | @Deprecated 13 | public class OriginRegistry { 14 | 15 | private static final Map CACHE_MAP = new ConcurrentHashMap<>(); 16 | 17 | @Deprecated 18 | public static Origin register(Origin origin) { 19 | return register(origin.getIdentifier(), origin); 20 | } 21 | 22 | @Deprecated 23 | public static Origin register(ResourceLocation id, Origin origin) { 24 | return origin; 25 | } 26 | 27 | @Deprecated 28 | protected static Origin update(ResourceLocation id, Origin origin) { 29 | return register(id, origin); 30 | } 31 | 32 | public static int size() { 33 | return OriginsAPI.getOriginsRegistry().keySet().size(); 34 | } 35 | 36 | public static Stream identifiers() { 37 | return OriginsAPI.getOriginsRegistry().keySet().stream(); 38 | } 39 | 40 | public static Iterable> entries() { 41 | return () -> { 42 | Iterator, io.github.edwinmindcraft.origins.api.origin.Origin>> iterator = OriginsAPI.getOriginsRegistry().entrySet().iterator(); 43 | return new Iterator<>() { 44 | @Override 45 | public boolean hasNext() { 46 | return iterator.hasNext(); 47 | } 48 | 49 | @Override 50 | public Map.Entry next() { 51 | Map.Entry, io.github.edwinmindcraft.origins.api.origin.Origin> next = iterator.next(); 52 | return new Map.Entry<>() { 53 | @Override 54 | public ResourceLocation getKey() { 55 | return next.getKey().location(); 56 | } 57 | 58 | @Override 59 | public Origin getValue() { 60 | return get(next.getValue()); 61 | } 62 | 63 | @Override 64 | public Origin setValue(Origin value) { 65 | return null; 66 | } 67 | }; 68 | } 69 | }; 70 | }; 71 | } 72 | 73 | public static Iterable values() { 74 | return () -> { 75 | Iterator iterator = OriginsAPI.getOriginsRegistry().iterator(); 76 | return new Iterator<>() { 77 | @Override 78 | public boolean hasNext() { 79 | return iterator.hasNext(); 80 | } 81 | 82 | @Override 83 | public Origin next() { 84 | return get(iterator.next()); 85 | } 86 | }; 87 | }; 88 | } 89 | 90 | public static Origin get(ResourceLocation id) { 91 | return OriginsAPI.getOriginsRegistry().getOptional(id).map(OriginRegistry::get) 92 | .orElseThrow(() -> new IllegalArgumentException("Could not get origin from id '" + id.toString() + "', as it was not registered!")); 93 | } 94 | 95 | public static Origin get(io.github.edwinmindcraft.origins.api.origin.Origin origin) { 96 | return CACHE_MAP.computeIfAbsent(origin, o -> new Origin(() -> o)); 97 | } 98 | 99 | public static boolean contains(ResourceLocation id) { 100 | return OriginsAPI.getOriginsRegistry().containsKey(id); 101 | } 102 | 103 | public static boolean contains(Origin origin) { 104 | return contains(origin.getIdentifier()); 105 | } 106 | 107 | public static void clear() { 108 | CACHE_MAP.clear(); 109 | } 110 | 111 | public static void reset() { 112 | clear(); 113 | } 114 | 115 | public static void remove(ResourceLocation id) { 116 | throw new UnsupportedOperationException("Remove origins by cancelling a registration event."); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/Origins.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.google.gson.JsonObject; 5 | import com.google.gson.JsonPrimitive; 6 | import io.github.apace100.apoli.power.PowerType; 7 | import io.github.apace100.apoli.util.NamespaceAlias; 8 | import io.github.apace100.origins.command.LayerArgumentType; 9 | import io.github.apace100.origins.command.OriginArgumentType; 10 | import io.github.apace100.origins.origin.Origin; 11 | import io.github.apace100.origins.power.OriginsEntityConditions; 12 | import io.github.apace100.origins.power.OriginsPowerTypes; 13 | import io.github.apace100.origins.registry.*; 14 | import io.github.apace100.origins.util.ChoseOriginCriterion; 15 | import io.github.edwinmindcraft.origins.api.OriginsAPI; 16 | import io.github.edwinmindcraft.origins.common.OriginsCommon; 17 | import io.github.edwinmindcraft.origins.common.OriginsConfigs; 18 | import io.github.edwinmindcraft.origins.data.OriginsData; 19 | import net.minecraft.advancements.CriteriaTriggers; 20 | import net.minecraft.commands.synchronization.ArgumentTypes; 21 | import net.minecraft.commands.synchronization.EmptyArgumentSerializer; 22 | import net.minecraft.resources.ResourceLocation; 23 | import net.minecraftforge.api.distmarker.Dist; 24 | import net.minecraftforge.fml.DistExecutor; 25 | import net.minecraftforge.fml.ModLoadingContext; 26 | import net.minecraftforge.fml.common.Mod; 27 | import net.minecraftforge.fml.config.ModConfig; 28 | import org.apache.logging.log4j.LogManager; 29 | import org.apache.logging.log4j.Logger; 30 | 31 | @Mod(Origins.MODID) 32 | public class Origins { 33 | 34 | public static final String MODID = OriginsAPI.MODID; 35 | public static String VERSION = ""; 36 | public static final Logger LOGGER = LogManager.getLogger(Origins.class); 37 | 38 | public static ServerConfig config = new ServerConfig(); 39 | //private static ConfigSerializer configSerializer; 40 | 41 | public Origins() { 42 | VERSION = ModLoadingContext.get().getActiveContainer().getModInfo().getVersion().toString(); 43 | LOGGER.info("Origins " + VERSION + " is initializing. Have fun!"); 44 | ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, OriginsConfigs.COMMON_SPECS); 45 | ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, OriginsConfigs.CLIENT_SPECS); 46 | ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, OriginsConfigs.SERVER_SPECS); 47 | //AutoConfig.register(ServerConfig.class, OriginsConfigSerializer::new); 48 | //config = AutoConfig.getConfigHolder(ServerConfig.class).getConfig(); 49 | 50 | NamespaceAlias.addAlias(MODID, "apoli"); 51 | 52 | OriginsPowerTypes.register(); 53 | OriginsEntityConditions.register(); 54 | 55 | ModBlocks.register(); 56 | ModItems.register(); 57 | ModTags.register(); 58 | ModEnchantments.register(); 59 | ModEntities.register(); 60 | Origin.init(); 61 | 62 | OriginsCommon.initialize(); 63 | OriginsData.initialize(); 64 | 65 | DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> OriginsClient::initialize); 66 | NamespaceAlias.addAlias("origins", "apoli"); 67 | 68 | CriteriaTriggers.register(ChoseOriginCriterion.INSTANCE); 69 | ArgumentTypes.register("origins:origin", OriginArgumentType.class, new EmptyArgumentSerializer<>(OriginArgumentType::origin)); 70 | ArgumentTypes.register("origins:layer", LayerArgumentType.class, new EmptyArgumentSerializer<>(LayerArgumentType::layer)); 71 | } 72 | 73 | public static ResourceLocation identifier(String path) { 74 | return new ResourceLocation(Origins.MODID, path); 75 | } 76 | 77 | public static class ServerConfig { 78 | 79 | public boolean isOriginDisabled(ResourceLocation originId) { 80 | return !OriginsConfigs.COMMON.isOriginEnabled(originId); 81 | } 82 | 83 | public boolean isPowerDisabled(ResourceLocation originId, ResourceLocation powerId) { 84 | return !OriginsConfigs.COMMON.isPowerEnabled(originId, powerId); 85 | } 86 | 87 | public boolean addToConfig(Origin origin) { 88 | return OriginsConfigs.COMMON.updateOriginList(ImmutableList.of(origin.getWrapped())); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/origin/OriginLayer.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.origin; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import net.minecraft.network.chat.TranslatableComponent; 5 | import net.minecraft.resources.ResourceLocation; 6 | import net.minecraft.world.entity.player.Player; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | 11 | /** 12 | * Use {@link io.github.edwinmindcraft.origins.api.origin.OriginLayer} where possible instead. 13 | */ 14 | @Deprecated 15 | public class OriginLayer implements Comparable { 16 | private final io.github.edwinmindcraft.origins.api.origin.OriginLayer wrapped; 17 | 18 | public OriginLayer(io.github.edwinmindcraft.origins.api.origin.OriginLayer wrapped) {this.wrapped = wrapped;} 19 | 20 | public String getOrCreateTranslationKey() { 21 | return this.wrapped.name() instanceof TranslatableComponent tc ? tc.getKey() : ""; 22 | } 23 | 24 | public io.github.edwinmindcraft.origins.api.origin.OriginLayer getWrapped() { 25 | return this.wrapped; 26 | } 27 | 28 | public String getTranslationKey() { 29 | return this.getOrCreateTranslationKey(); 30 | } 31 | 32 | public String getMissingOriginNameTranslationKey() { 33 | return this.wrapped.missingName() instanceof TranslatableComponent tc ? tc.getKey() : ""; 34 | } 35 | 36 | public String getMissingOriginDescriptionTranslationKey() { 37 | return this.wrapped.missingDescription() instanceof TranslatableComponent tc ? tc.getKey() : ""; 38 | } 39 | 40 | public String getTitleViewOriginTranslationKey() { 41 | return this.wrapped.title().view() instanceof TranslatableComponent tc ? tc.getKey() : ""; 42 | } 43 | 44 | public boolean shouldOverrideViewOriginTitle() { 45 | return this.wrapped.title().view() != null; 46 | } 47 | 48 | public String getTitleChooseOriginTranslationKey() { 49 | return this.wrapped.title().choose() instanceof TranslatableComponent tc ? tc.getKey() : ""; 50 | } 51 | 52 | public boolean shouldOverrideChooseOriginTitle() { 53 | return this.wrapped.title().choose() != null; 54 | } 55 | 56 | public ResourceLocation getIdentifier() { 57 | return this.wrapped.getRegistryName(); 58 | } 59 | 60 | public boolean isEnabled() { 61 | return this.wrapped.enabled(); 62 | } 63 | 64 | public boolean hasDefaultOrigin() { 65 | return this.wrapped.hasDefaultOrigin(); 66 | } 67 | 68 | public ResourceLocation getDefaultOrigin() { 69 | return this.wrapped.defaultOrigin(); 70 | } 71 | 72 | public boolean shouldAutoChoose() { 73 | return this.wrapped.autoChoose(); 74 | } 75 | 76 | public List getOrigins() { 77 | return ImmutableList.copyOf(this.wrapped.origins()); 78 | } 79 | 80 | public List getOrigins(Player playerEntity) { 81 | return ImmutableList.copyOf(this.wrapped.origins(playerEntity)); 82 | } 83 | 84 | public int getOriginOptionCount(Player playerEntity) { 85 | return this.wrapped.getOriginOptionCount(playerEntity); 86 | } 87 | 88 | public boolean contains(Origin origin) { 89 | return this.wrapped.contains(origin.getIdentifier()); 90 | } 91 | 92 | public boolean contains(Origin origin, Player playerEntity) { 93 | return this.wrapped.contains(origin.getIdentifier(), playerEntity); 94 | } 95 | 96 | public boolean isRandomAllowed() { 97 | return this.wrapped.allowRandom(); 98 | } 99 | 100 | public boolean isHidden() { 101 | return this.wrapped.hidden(); 102 | } 103 | 104 | public List getRandomOrigins(Player playerEntity) { 105 | return this.wrapped.randomOrigins(playerEntity); 106 | } 107 | 108 | @Override 109 | public int hashCode() { 110 | return this.wrapped.hashCode(); 111 | } 112 | 113 | @Override 114 | public boolean equals(Object obj) { 115 | if (obj == this) { 116 | return true; 117 | } else if (!(obj instanceof OriginLayer)) { 118 | return false; 119 | } else { 120 | return Objects.equals(this.wrapped.getRegistryName(), ((OriginLayer) obj).wrapped.getRegistryName()); 121 | } 122 | } 123 | 124 | @Override 125 | public int compareTo(OriginLayer o) { 126 | return this.wrapped.compareTo(o.wrapped); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/main/java/io/github/edwinmindcraft/origins/common/OriginsCommon.java: -------------------------------------------------------------------------------- 1 | package io.github.edwinmindcraft.origins.common; 2 | 3 | import io.github.apace100.calio.Calio; 4 | import io.github.apace100.origins.Origins; 5 | import io.github.apace100.origins.badge.BadgeFactories; 6 | import io.github.apace100.origins.badge.BadgeManager; 7 | import io.github.apace100.origins.power.OriginsPowerTypes; 8 | import io.github.apace100.origins.registry.ModLoot; 9 | import io.github.edwinmindcraft.origins.api.capabilities.IOriginContainer; 10 | import io.github.edwinmindcraft.origins.common.network.*; 11 | import io.github.edwinmindcraft.origins.common.registry.OriginRegisters; 12 | import net.minecraft.network.FriendlyByteBuf; 13 | import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; 14 | import net.minecraftforge.eventbus.api.IEventBus; 15 | import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; 16 | import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; 17 | import net.minecraftforge.network.NetworkDirection; 18 | import net.minecraftforge.network.NetworkRegistry; 19 | import net.minecraftforge.network.simple.SimpleChannel; 20 | 21 | import java.util.function.Function; 22 | 23 | public class OriginsCommon { 24 | private static final String NETWORK_VERSION = "1.1"; 25 | 26 | public static final SimpleChannel CHANNEL = NetworkRegistry.newSimpleChannel(Origins.identifier("network"), () -> NETWORK_VERSION, NETWORK_VERSION::equals, NETWORK_VERSION::equals); 27 | 28 | private static Function withLogging(Function original) { 29 | return buf -> { 30 | T apply = original.apply(buf); 31 | if (Calio.isDebugMode()) 32 | Origins.LOGGER.info("Received packet: {}", apply); 33 | return apply; 34 | }; 35 | } 36 | 37 | private static void initializeNetwork() { 38 | int message = 0; 39 | CHANNEL.messageBuilder(S2CSynchronizeOrigin.class, message++, NetworkDirection.PLAY_TO_CLIENT) 40 | .encoder(S2CSynchronizeOrigin::encode).decoder(withLogging(S2CSynchronizeOrigin::decode)) 41 | .consumer(S2CSynchronizeOrigin::handle).add(); 42 | CHANNEL.messageBuilder(S2COpenOriginScreen.class, message++, NetworkDirection.PLAY_TO_CLIENT) 43 | .encoder(S2COpenOriginScreen::encode).decoder(withLogging(S2COpenOriginScreen::decode)) 44 | .consumer(S2COpenOriginScreen::handle).add(); 45 | CHANNEL.messageBuilder(S2CConfirmOrigin.class, message++, NetworkDirection.PLAY_TO_CLIENT) 46 | .encoder(S2CConfirmOrigin::encode).decoder(withLogging(S2CConfirmOrigin::decode)) 47 | .consumer(S2CConfirmOrigin::handle).add(); 48 | CHANNEL.messageBuilder(S2CSynchronizeBadges.class, message++, NetworkDirection.PLAY_TO_CLIENT) 49 | .encoder(S2CSynchronizeBadges::encode).decoder(withLogging(S2CSynchronizeBadges::decode)) 50 | .consumer(S2CSynchronizeBadges::handle).add(); 51 | 52 | CHANNEL.messageBuilder(C2SChooseRandomOrigin.class, message++, NetworkDirection.PLAY_TO_SERVER) 53 | .encoder(C2SChooseRandomOrigin::encode).decoder(withLogging(C2SChooseRandomOrigin::decode)) 54 | .consumer(C2SChooseRandomOrigin::handle).add(); 55 | CHANNEL.messageBuilder(C2SChooseOrigin.class, message++, NetworkDirection.PLAY_TO_SERVER) 56 | .encoder(C2SChooseOrigin::encode).decoder(withLogging(C2SChooseOrigin::decode)) 57 | .consumer(C2SChooseOrigin::handle).add(); 58 | CHANNEL.messageBuilder(C2SAcknowledgeOrigins.class, message++, NetworkDirection.PLAY_TO_SERVER) 59 | .encoder(C2SAcknowledgeOrigins::encode).decoder(withLogging(C2SAcknowledgeOrigins::decode)) 60 | .consumer(C2SAcknowledgeOrigins::handle).add(); 61 | 62 | Origins.LOGGER.debug("Registered {} packets", message); 63 | } 64 | 65 | public static void initialize() { 66 | IEventBus mod = FMLJavaModLoadingContext.get().getModEventBus(); 67 | OriginRegisters.register(); 68 | OriginsPowerTypes.register(); 69 | BadgeFactories.bootstrap(); 70 | BadgeManager.init(); 71 | mod.addListener(OriginsCommon::registerCapabilities); 72 | mod.addListener(OriginsCommon::commonSetup); 73 | } 74 | 75 | public static void registerCapabilities(RegisterCapabilitiesEvent event) { 76 | event.register(IOriginContainer.class); 77 | } 78 | 79 | public static void commonSetup(FMLCommonSetupEvent event) { 80 | initializeNetwork(); 81 | event.enqueueWork(ModLoot::register); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/io/github/apace100/origins/content/OrbOfOriginItem.java: -------------------------------------------------------------------------------- 1 | package io.github.apace100.origins.content; 2 | 3 | import io.github.edwinmindcraft.origins.api.OriginsAPI; 4 | import io.github.edwinmindcraft.origins.api.capabilities.IOriginContainer; 5 | import io.github.edwinmindcraft.origins.api.origin.Origin; 6 | import io.github.edwinmindcraft.origins.api.origin.OriginLayer; 7 | import io.github.edwinmindcraft.origins.common.OriginsCommon; 8 | import io.github.edwinmindcraft.origins.common.network.S2COpenOriginScreen; 9 | import net.minecraft.ChatFormatting; 10 | import net.minecraft.nbt.CompoundTag; 11 | import net.minecraft.nbt.ListTag; 12 | import net.minecraft.nbt.Tag; 13 | import net.minecraft.network.chat.Component; 14 | import net.minecraft.network.chat.TranslatableComponent; 15 | import net.minecraft.resources.ResourceLocation; 16 | import net.minecraft.server.level.ServerPlayer; 17 | import net.minecraft.world.InteractionHand; 18 | import net.minecraft.world.InteractionResultHolder; 19 | import net.minecraft.world.entity.player.Player; 20 | import net.minecraft.world.item.*; 21 | import net.minecraft.world.level.Level; 22 | import net.minecraftforge.network.PacketDistributor; 23 | import org.jetbrains.annotations.NotNull; 24 | import org.jetbrains.annotations.Nullable; 25 | 26 | import java.util.HashMap; 27 | import java.util.List; 28 | import java.util.Map; 29 | import java.util.Objects; 30 | 31 | public class OrbOfOriginItem extends Item { 32 | 33 | public OrbOfOriginItem() { 34 | super(new Item.Properties().stacksTo(1).tab(CreativeModeTab.TAB_MISC).rarity(Rarity.RARE)); 35 | } 36 | 37 | @Override 38 | @NotNull 39 | public InteractionResultHolder use(@NotNull Level level, @NotNull Player player, @NotNull InteractionHand hand) { 40 | ItemStack stack = player.getItemInHand(hand); 41 | if (!level.isClientSide()) { 42 | IOriginContainer.get(player).ifPresent(container -> { 43 | Map targets = this.getTargets(stack); 44 | if (targets.size() > 0) { 45 | for (Map.Entry target : targets.entrySet()) { 46 | container.setOrigin(target.getKey(), target.getValue()); 47 | } 48 | } else { 49 | for (OriginLayer layer : OriginsAPI.getActiveLayers()) { 50 | container.setOrigin(layer, Origin.EMPTY); 51 | } 52 | } 53 | if (player instanceof ServerPlayer sp) { 54 | container.checkAutoChoosingLayers(false); 55 | PacketDistributor.PacketTarget target = PacketDistributor.PLAYER.with(() -> sp); 56 | OriginsCommon.CHANNEL.send(target, container.getSynchronizationPacket()); 57 | OriginsCommon.CHANNEL.send(target, new S2COpenOriginScreen(false)); 58 | container.synchronize(); 59 | } 60 | }); 61 | } 62 | if (!player.isCreative()) { 63 | stack.shrink(1); 64 | } 65 | return InteractionResultHolder.consume(stack); 66 | } 67 | 68 | @Override 69 | public void appendHoverText(@NotNull ItemStack stack, @Nullable Level level, @NotNull List components, @NotNull TooltipFlag flags) { 70 | Map targets = this.getTargets(stack); 71 | for (Map.Entry entry : targets.entrySet()) { 72 | if (entry.getValue() == Origin.EMPTY) 73 | components.add(new TranslatableComponent("item.origins.orb_of_origin.layer_generic", entry.getKey().name()).withStyle(ChatFormatting.GRAY)); 74 | else 75 | components.add(new TranslatableComponent("item.origins.orb_of_origin.layer_specific", entry.getKey().name(), entry.getValue().getName()).withStyle(ChatFormatting.GRAY)); 76 | } 77 | } 78 | 79 | private Map getTargets(ItemStack stack) { 80 | Map targets = new HashMap<>(); 81 | if (!stack.hasTag()) { 82 | return targets; 83 | } 84 | CompoundTag nbt = Objects.requireNonNull(stack.getTag()); 85 | ListTag targetList = nbt.getList("Targets", Tag.TAG_COMPOUND); 86 | for (Tag nbtElement : targetList) { 87 | CompoundTag targetNbt = (CompoundTag) nbtElement; 88 | if (targetNbt.contains("Layer", Tag.TAG_STRING)) { 89 | try { 90 | ResourceLocation id = new ResourceLocation(targetNbt.getString("Layer")); 91 | OriginLayer layer = OriginsAPI.getLayersRegistry().get(id); 92 | if (layer == null) continue; 93 | Origin origin = Origin.EMPTY; 94 | if (targetNbt.contains("Origin", Tag.TAG_STRING)) { 95 | ResourceLocation originId = new ResourceLocation(targetNbt.getString("Origin")); 96 | origin = OriginsAPI.getOriginsRegistry().get(originId); 97 | } 98 | if (origin == null || origin.getRegistryName() == null) 99 | continue; 100 | if (layer.enabled() && (layer.contains(origin.getRegistryName()) || origin.isSpecial())) { 101 | targets.put(layer, origin); 102 | } 103 | } catch (Exception e) { 104 | // no op 105 | } 106 | } 107 | } 108 | return targets; 109 | } 110 | } 111 | --------------------------------------------------------------------------------