Initial commit
This commit is contained in:
commit
cd0af5a1d3
2557 files changed
+271980
No files matched your search
@@ -0,0 +1,153 @@
|
||||
plugins {
|
||||
id "com.github.johnrengelman.shadow" version "7.1.2"
|
||||
}
|
||||
|
||||
architectury {
|
||||
platformSetupLoomIde()
|
||||
fabric()
|
||||
}
|
||||
|
||||
configurations {
|
||||
common
|
||||
shadowCommon
|
||||
compileClasspath.extendsFrom common
|
||||
runtimeClasspath.extendsFrom common
|
||||
developmentFabric.extendsFrom common
|
||||
}
|
||||
|
||||
dependencies {
|
||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||
mappings loom.officialMojangMappings()
|
||||
|
||||
modImplementation "net.fabricmc:fabric-loader:${project.fabric_loader_version}"
|
||||
modApi "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}"
|
||||
modImplementation "software.bernie.geckolib:geckolib-fabric-${project.minecraft_version}:${project.geckolib_version}"
|
||||
compileOnly("curse.maven:intapi-${project.intapi_curseforge_id}:${project.intapi_curseforge_file_id_neoforge}")
|
||||
compileOnly("curse.maven:create-${project.create_curseforge_id_neoforge}:${project.create_curseforge_file_id_neoforge}")
|
||||
compileOnly("curse.maven:marvel-${project.marvel_curseforge_id}:${project.marvel_curseforge_file_id}")
|
||||
compileOnly("curse.maven:stellaris-${project.stellaris_curseforge_id}:${project.stellaris_curseforge_file_id}")
|
||||
compileOnly("curse.maven:aperture-${project.aperture_curseforge_id}:${project.aperture_curseforge_file_id}")
|
||||
compileOnly("curse.maven:inventory_pets-${project.inventory_pets_curseforge_id}:${project.inventory_pets_curseforge_file_id}")
|
||||
compileOnly("curse.maven:cataclysm-${project.cataclysm_curseforge_id}:${project.cataclysm_curseforge_file_id}")
|
||||
compileOnly("curse.maven:iaf-${project.iaf_curseforge_id}:${project.iaf_curseforge_file_id}")
|
||||
compileOnly("curse.maven:backpack-${project.backpack_curseforge_id}:${project.backpack_curseforge_file_id}")
|
||||
compileOnly("curse.maven:regions_unexplored-${project.regions_unexplored_curseforge_id}:${project.regions_unexplored_curseforge_file_id}")
|
||||
compileOnly(files("$rootDir/infinite_dimensions_jars/infinity-2.7.1+1.21.1-neoforge.jar"))
|
||||
compileOnly(files("$rootDir/infinite_dimensions_jars/infinity-2.7.1+1.21.1-neoforge-sources.jar"))
|
||||
compileOnly(files("$rootDir/infinite_dimensions_jars/gravity-api-1.0.7-1.20.1.jar"))
|
||||
compileOnly(files("$rootDir/infinite_dimensions_jars/Cloro's Gravity Gun Mod (Release 1.3.1).jar"))
|
||||
compileOnly(files("$rootDir/infinite_dimensions_jars/VanillaBackport-neoforge-1.21.1-1.1.7.6.jar"))
|
||||
compileOnly(files("$rootDir/infinite_dimensions_jars/soul-fire-d-neoforge-1.21-6.1.0.jar"))
|
||||
compileOnly(files("$rootDir/infinite_dimensions_jars/prometheus-neoforge-1.21-1.2.5.jar"))
|
||||
compileOnly(files("$rootDir/infinite_dimensions_jars/cloth-config-15.0.140-fabric.jar"))
|
||||
compileOnly(files("$rootDir/infinite_dimensions_jars/sable-neoforge-1.21.1-2.0.3.jar"))
|
||||
|
||||
annotationProcessor "org.spongepowered:mixin:0.8.7:processor"
|
||||
common(project(path: ':common', configuration: 'namedElements')) { transitive false }
|
||||
shadowCommon(project(path: ':common', configuration: 'namedElements')) { transitive false }
|
||||
}
|
||||
|
||||
loom {
|
||||
mixin {
|
||||
useLegacyMixinAp = true
|
||||
defaultRefmapName = "antarchy.refmap.json"
|
||||
}
|
||||
|
||||
mods {
|
||||
"${mod_id}" {
|
||||
sourceSet sourceSets.main
|
||||
sourceSet project(':common').sourceSets.main
|
||||
}
|
||||
}
|
||||
|
||||
runs {
|
||||
configureEach {
|
||||
runDir('run')
|
||||
ideConfigGenerated(true)
|
||||
}
|
||||
|
||||
client {
|
||||
client()
|
||||
setConfigName('Fabric Client')
|
||||
}
|
||||
|
||||
server {
|
||||
server()
|
||||
setConfigName('Fabric Server')
|
||||
programArg('--nogui')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named('compileJava', JavaCompile) {
|
||||
source(project(':common').sourceSets.main.allJava)
|
||||
}
|
||||
|
||||
tasks.named('javadoc', Javadoc).configure {
|
||||
source(project(':common').sourceSets.main.allJava)
|
||||
}
|
||||
|
||||
tasks.named('sourcesJar', Jar) {
|
||||
from(project(':common').sourceSets.main.allSource)
|
||||
exclude "antarchy-common.mixins.json"
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
exclude 'architectury.common.json'
|
||||
configurations = [project.configurations.shadowCommon]
|
||||
archiveClassifier.set('dev-shadow')
|
||||
}
|
||||
|
||||
remapJar {
|
||||
injectAccessWidener = true
|
||||
input.set shadowJar.archiveFile
|
||||
dependsOn shadowJar
|
||||
archiveClassifier.set(null)
|
||||
}
|
||||
|
||||
jar {
|
||||
archiveClassifier.set('dev')
|
||||
}
|
||||
|
||||
components.java {
|
||||
withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
|
||||
skip()
|
||||
}
|
||||
}
|
||||
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
inputs.property "minecraft_version", project.minecraft_version
|
||||
inputs.property "fabric_loader_version", project.fabric_loader_version
|
||||
inputs.property "mod_id", project.mod_id
|
||||
inputs.property "mod_name", project.mod_name
|
||||
inputs.property "mod_description", project.mod_description
|
||||
inputs.property "mod_author", project.mod_author
|
||||
inputs.property "license", project.license
|
||||
inputs.property "homepage_url", project.homepage_url
|
||||
inputs.property "issues_url", project.issues_url
|
||||
inputs.property "sources_url", project.sources_url
|
||||
inputs.property "logo_fabric", project.logo_fabric
|
||||
|
||||
from(project(':common').sourceSets.main.resources) {
|
||||
exclude "antarchy-common.mixins.json"
|
||||
}
|
||||
|
||||
filesMatching("fabric.mod.json") {
|
||||
expand(
|
||||
version: project.version,
|
||||
minecraft_version: project.minecraft_version,
|
||||
fabric_loader_version: project.fabric_loader_version,
|
||||
mod_id: project.mod_id,
|
||||
mod_name: project.mod_name,
|
||||
mod_description: project.mod_description,
|
||||
mod_author: project.mod_author,
|
||||
license: project.license,
|
||||
homepage_url: project.homepage_url,
|
||||
issues_url: project.issues_url,
|
||||
sources_url: project.sources_url,
|
||||
logo_fabric: project.logo_fabric
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
package com.craisinlord.antarchy.fabric;
|
||||
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class AntarchyConfigModuleFabric {
|
||||
private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();
|
||||
private static final Path CONFIG_DIR = FabricLoader.getInstance()
|
||||
.getConfigDir()
|
||||
.resolve(Antarchy.MODID);
|
||||
private static final Path LEGACY_CONFIG_PATH = CONFIG_DIR.resolve("antarchy.json");
|
||||
private static final Map<String, SettingBinding> SETTINGS = buildBindings();
|
||||
|
||||
private AntarchyConfigModuleFabric() {
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
JsonObject legacy = readConfig(LEGACY_CONFIG_PATH);
|
||||
Map<ConfigSection, JsonObject> loaded = new LinkedHashMap<>();
|
||||
Map<ConfigSection, JsonObject> normalized = new LinkedHashMap<>();
|
||||
|
||||
for (ConfigSection section : ConfigSection.values()) {
|
||||
loaded.put(section, readConfig(section.path));
|
||||
normalized.put(section, new JsonObject());
|
||||
}
|
||||
|
||||
for (Map.Entry<String, SettingBinding> entry : SETTINGS.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
SettingBinding binding = entry.getValue();
|
||||
JsonObject loadedSection = loaded.get(binding.section);
|
||||
JsonElement element = loadedSection != null ? loadedSection.get(key) : null;
|
||||
if (element == null && legacy != null) {
|
||||
element = legacy.get(key);
|
||||
}
|
||||
Object value = binding.readValue(element);
|
||||
binding.apply(value);
|
||||
normalized.get(binding.section).add(key, binding.toJson(value));
|
||||
}
|
||||
|
||||
for (Map.Entry<ConfigSection, JsonObject> entry : normalized.entrySet()) {
|
||||
writeConfig(entry.getKey().path, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private static JsonObject readConfig(Path path) {
|
||||
if (!Files.exists(path)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try (Reader reader = Files.newBufferedReader(path)) {
|
||||
JsonElement parsed = JsonParser.parseReader(reader);
|
||||
if (parsed.isJsonObject()) {
|
||||
return parsed.getAsJsonObject();
|
||||
}
|
||||
Antarchy.LOGGER.warn("Fabric config at {} is not a JSON object, using defaults", path);
|
||||
} catch (IOException | JsonParseException e) {
|
||||
Antarchy.LOGGER.warn("Failed to read Fabric config at {}, using defaults", path, e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void writeConfig(Path path, JsonObject root) {
|
||||
try {
|
||||
Files.createDirectories(path.getParent());
|
||||
try (Writer writer = Files.newBufferedWriter(path)) {
|
||||
GSON.toJson(root, writer);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Antarchy.LOGGER.warn("Failed to write Fabric config at {}", path, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, SettingBinding> buildBindings() {
|
||||
Map<String, Method> getters = new LinkedHashMap<>();
|
||||
for (Method method : AntarchySettings.class.getMethods()) {
|
||||
if (!isPublicStatic(method) || method.getParameterCount() != 0 || method.getReturnType() == Void.TYPE) {
|
||||
continue;
|
||||
}
|
||||
getters.put(method.getName(), method);
|
||||
}
|
||||
|
||||
return Arrays.stream(AntarchySettings.class.getMethods())
|
||||
.filter(AntarchyConfigModuleFabric::isPublicStatic)
|
||||
.filter(method -> method.getName().startsWith("set"))
|
||||
.filter(method -> method.getParameterCount() == 1)
|
||||
.sorted(Comparator.comparing(Method::getName))
|
||||
.collect(LinkedHashMap::new, (bindings, setter) -> {
|
||||
String propertyName = decapitalize(setter.getName().substring(3));
|
||||
Method getter = getters.get(propertyName);
|
||||
if (getter == null) {
|
||||
return;
|
||||
}
|
||||
if (!isSupported(setter.getParameterTypes()[0], getter.getReturnType())) {
|
||||
return;
|
||||
}
|
||||
bindings.put(propertyName, new SettingBinding(propertyName, getter, setter, ConfigSection.forProperty(propertyName)));
|
||||
}, Map::putAll);
|
||||
}
|
||||
|
||||
private static boolean isPublicStatic(Method method) {
|
||||
int modifiers = method.getModifiers();
|
||||
return java.lang.reflect.Modifier.isPublic(modifiers) && java.lang.reflect.Modifier.isStatic(modifiers);
|
||||
}
|
||||
|
||||
private static boolean isSupported(Class<?> setterType, Class<?> getterType) {
|
||||
if (setterType == boolean.class || setterType == int.class || setterType == double.class || setterType == float.class) {
|
||||
return getterType == setterType;
|
||||
}
|
||||
return setterType == String.class && ResourceKey.class.isAssignableFrom(getterType);
|
||||
}
|
||||
|
||||
private static String decapitalize(String value) {
|
||||
if (value.isEmpty()) {
|
||||
return value;
|
||||
}
|
||||
return Character.toLowerCase(value.charAt(0)) + value.substring(1);
|
||||
}
|
||||
|
||||
private enum ConfigSection {
|
||||
MOBS("antarchy_mobs.json"),
|
||||
TOOLS("antarchy_tools.json"),
|
||||
MISC("antarchy_misc.json");
|
||||
|
||||
private final Path path;
|
||||
|
||||
ConfigSection(String fileName) {
|
||||
this.path = CONFIG_DIR.resolve(fileName);
|
||||
}
|
||||
|
||||
private static ConfigSection forProperty(String name) {
|
||||
if (isMiscSetting(name)) {
|
||||
return MISC;
|
||||
}
|
||||
if (isToolSetting(name)) {
|
||||
return TOOLS;
|
||||
}
|
||||
return MOBS;
|
||||
}
|
||||
|
||||
private static boolean isMiscSetting(String name) {
|
||||
return name.equals("disableInfinityBookPortalCreation")
|
||||
|| name.equals("rainbowAntsLeadToInfinityDimensions")
|
||||
|| name.equals("hushweedSporeLifetimeSeconds")
|
||||
|| name.equals("elythiaFireflyParticlesEnabled")
|
||||
|| name.equals("duplicatorTreeEnabled")
|
||||
|| name.equals("glowingTorchflowers")
|
||||
|| name.equals("glowVinesUnderLeaves")
|
||||
|| name.equals("entitySpecificFireOverlayEnabled")
|
||||
|| name.equals("dreamSandEnabled")
|
||||
|| name.startsWith("dreamSand")
|
||||
|| name.equals("ichorWitherEnabled")
|
||||
|| name.startsWith("diamondMinecart");
|
||||
}
|
||||
|
||||
private static boolean isToolSetting(String name) {
|
||||
return name.equals("sizeChangingRaysEnabled")
|
||||
|| name.startsWith("sizeRay")
|
||||
|| name.equals("shrinkingPotionDelta")
|
||||
|| name.equals("growthPotionDelta")
|
||||
|| name.startsWith("ultimate")
|
||||
|| name.startsWith("battleAxe")
|
||||
|| name.startsWith("bigBertha")
|
||||
|| name.startsWith("scorpionWhip")
|
||||
|| name.startsWith("bloodCrystal")
|
||||
|| name.startsWith("nightmareHelmet")
|
||||
|| name.startsWith("nightmareChestplate")
|
||||
|| name.startsWith("nightmareLeggings")
|
||||
|| name.startsWith("nightmareBoots")
|
||||
|| name.startsWith("nightmareArmorDreadAura")
|
||||
|| name.startsWith("nightmareSword")
|
||||
|| name.startsWith("basiliskDagger")
|
||||
|| name.startsWith("squidzooka")
|
||||
|| name.equals("invertProjectilesFromInvertedPlayers")
|
||||
|| name.startsWith("gravityGun")
|
||||
|| name.equals("potentNyxiteInvertedDurationSeconds")
|
||||
|| name.equals("corneaEarNightVisionSeconds")
|
||||
|| name.startsWith("mogglesVision")
|
||||
|| name.equals("ductTapeRepairPercentPerUse")
|
||||
|| name.startsWith("fallenKingCrown");
|
||||
}
|
||||
}
|
||||
|
||||
private static final class SettingBinding {
|
||||
private final String name;
|
||||
private final Method getter;
|
||||
private final Method setter;
|
||||
private final Class<?> setterType;
|
||||
private final ConfigSection section;
|
||||
|
||||
private SettingBinding(String name, Method getter, Method setter, ConfigSection section) {
|
||||
this.name = name;
|
||||
this.getter = getter;
|
||||
this.setter = setter;
|
||||
this.setterType = setter.getParameterTypes()[0];
|
||||
this.section = section;
|
||||
}
|
||||
|
||||
private Object readValue(JsonElement element) {
|
||||
Object defaultValue = getCurrentValue();
|
||||
if (element == null || element.isJsonNull()) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
try {
|
||||
if (setterType == boolean.class) {
|
||||
return element.getAsBoolean();
|
||||
}
|
||||
if (setterType == int.class) {
|
||||
return element.getAsInt();
|
||||
}
|
||||
if (setterType == double.class) {
|
||||
return element.getAsDouble();
|
||||
}
|
||||
if (setterType == float.class) {
|
||||
return element.getAsFloat();
|
||||
}
|
||||
if (setterType == String.class) {
|
||||
return element.getAsString();
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
Antarchy.LOGGER.warn("Invalid Fabric config value for {}, using default", name, e);
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private void apply(Object value) {
|
||||
try {
|
||||
setter.invoke(null, value);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new IllegalStateException("Failed to apply config value for " + name, e);
|
||||
}
|
||||
}
|
||||
|
||||
private JsonElement toJson(Object value) {
|
||||
return GSON.toJsonTree(value);
|
||||
}
|
||||
|
||||
private Object getCurrentValue() {
|
||||
try {
|
||||
Object value = getter.invoke(null);
|
||||
if (setterType == String.class && value instanceof ResourceKey<?> resourceKey) {
|
||||
return resourceKey.location().toString();
|
||||
}
|
||||
return value;
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new IllegalStateException("Failed to read config default for " + name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.craisinlord.antarchy.fabric;
|
||||
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import com.craisinlord.antarchy.content.item.BloodCrystalShardItem;
|
||||
import com.craisinlord.antarchy.fabric.network.AntarchyFabricNetworking;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
|
||||
public final class AntarchyFabric implements ModInitializer {
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
AntarchyFabricNetworking.register();
|
||||
AntarchyConfigModuleFabric.init();
|
||||
AntarchyFabricContent.register();
|
||||
AntarchyFabricEvents.register();
|
||||
BloodglassManager.register();
|
||||
Antarchy.init();
|
||||
BloodCrystalShardItem.SYNC_BLOODGLASS = BloodglassManager::syncBloodglass;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,177 @@
|
||||
package com.craisinlord.antarchy.fabric;
|
||||
|
||||
import com.craisinlord.antarchy.content.entity.ReverieEntity;
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||
import com.craisinlord.antarchy.content.block.DuctTapeBlock;
|
||||
import com.craisinlord.antarchy.content.block.PotentNyxiteBlock;
|
||||
import com.craisinlord.antarchy.content.entity.MissileSquidEntity;
|
||||
import com.craisinlord.antarchy.content.entity.kraken.KrakenEntity;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityTransition;
|
||||
import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.block.ComposterBlock;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.tags.FluidTags;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.MobSpawnType;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class AntarchyFabricEvents {
|
||||
private static final AntarchyGravityTransition INVERTED_CLEAR_TRANSITION = new AntarchyGravityTransition(12);
|
||||
private static final Set<UUID> invertedPlayers = new HashSet<>();
|
||||
|
||||
private AntarchyFabricEvents() {
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
ComposterBlock.COMPOSTABLES.put(AntarchyFabricContent.UMBRAL_MOSS_BLOCK.get().asItem(), 0.65f);
|
||||
ComposterBlock.COMPOSTABLES.put(AntarchyFabricContent.UMBRAL_MOSS_CARPET.get().asItem(), 0.3f);
|
||||
ComposterBlock.COMPOSTABLES.put(AntarchyFabricContent.HUSHWEED.get().asItem(), 0.65f);
|
||||
ComposterBlock.COMPOSTABLES.put(AntarchyFabricContent.CORNEA_EAR.get(), 0.65f);
|
||||
|
||||
ServerLivingEntityEvents.AFTER_DEATH.register((entity, damageSource) -> {
|
||||
if (entity instanceof ServerPlayer sp) {
|
||||
BloodglassManager.handleDeath(sp);
|
||||
}
|
||||
if (!(entity instanceof MissileSquidEntity)) {
|
||||
return;
|
||||
}
|
||||
if (!(entity.level() instanceof ServerLevel serverLevel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BlockPos deathPos = entity.blockPosition();
|
||||
if (AntarchySettings.krakenSquidSpawnEnabled() && serverLevel.random.nextInt(100) == 0) {
|
||||
spawnKrakens(serverLevel, deathPos, 1);
|
||||
}
|
||||
if (AntarchySettings.krakenMassSpawnEnabled() && serverLevel.random.nextInt(100) == 0) {
|
||||
spawnKrakens(serverLevel, deathPos, 10);
|
||||
}
|
||||
});
|
||||
|
||||
ServerTickEvents.END_SERVER_TICK.register(server -> {
|
||||
Set<UUID> activeThisTick = new HashSet<>();
|
||||
for (ServerLevel level : server.getAllLevels()) {
|
||||
tickInvertedPlayers(level, activeThisTick);
|
||||
tickDuctTapePlayers(level);
|
||||
tickIchorPlayers(level);
|
||||
tickBloodglassRecharge(level);
|
||||
}
|
||||
invertedPlayers.retainAll(activeThisTick);
|
||||
});
|
||||
}
|
||||
|
||||
private static void spawnKrakens(ServerLevel level, BlockPos origin, int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
BlockPos spawnPos = findKrakenSpawnPos(level, origin);
|
||||
KrakenEntity kraken = AntarchyObjects.KRAKEN.get().create(level);
|
||||
if (kraken == null) {
|
||||
continue;
|
||||
}
|
||||
kraken.moveTo(spawnPos.getX() + 0.5D, spawnPos.getY() + 1.0D, spawnPos.getZ() + 0.5D,
|
||||
level.random.nextFloat() * 360.0F, 0.0F);
|
||||
kraken.finalizeSpawn(level, level.getCurrentDifficultyAt(spawnPos), MobSpawnType.EVENT, null);
|
||||
level.addFreshEntity(kraken);
|
||||
}
|
||||
}
|
||||
|
||||
private static BlockPos findKrakenSpawnPos(ServerLevel level, BlockPos origin) {
|
||||
for (int attempt = 0; attempt < 20; attempt++) {
|
||||
BlockPos candidate = origin.offset(
|
||||
level.random.nextInt(33) - 16,
|
||||
level.random.nextInt(9) - 4,
|
||||
level.random.nextInt(33) - 16
|
||||
);
|
||||
if (level.getFluidState(candidate).is(FluidTags.WATER)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return origin.above(3);
|
||||
}
|
||||
|
||||
private static void tickInvertedPlayers(ServerLevel level, Set<UUID> activeThisTick) {
|
||||
for (Player player : level.players()) {
|
||||
LivingEntity livingEntity = player;
|
||||
|
||||
if (livingEntity.hasEffect(AntarchyObjects.INVERTED_EFFECT.get())) {
|
||||
activeThisTick.add(player.getUUID());
|
||||
invertedPlayers.add(player.getUUID());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!invertedPlayers.remove(player.getUUID())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (AntarchyGravityApi.getGravityDirection(player) == AntarchyGravityDirection.UP
|
||||
|| AntarchyGravityApi.isGravityForced(player)) {
|
||||
AntarchyGravityApi.setGravityDirection(player, AntarchyGravityDirection.DOWN, INVERTED_CLEAR_TRANSITION);
|
||||
}
|
||||
notifyNearbyReveriesOfInversionChange(player);
|
||||
}
|
||||
}
|
||||
|
||||
private static void notifyNearbyReveriesOfInversionChange(Player player) {
|
||||
for (ReverieEntity reverie : player.level().getEntitiesOfClass(
|
||||
ReverieEntity.class,
|
||||
player.getBoundingBox().inflate(48.0D)
|
||||
)) {
|
||||
reverie.syncFocusInversionState();
|
||||
}
|
||||
}
|
||||
|
||||
private static void tickDuctTapePlayers(ServerLevel level) {
|
||||
for (Player player : level.players()) {
|
||||
DuctTapeBlock.tickStuckEntity(player);
|
||||
}
|
||||
}
|
||||
|
||||
private static void tickIchorPlayers(ServerLevel level) {
|
||||
if (!AntarchySettings.ichorWitherEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Player player : level.players()) {
|
||||
if (!antarchy$isInIchor(player)) {
|
||||
continue;
|
||||
}
|
||||
player.addEffect(new MobEffectInstance(MobEffects.WITHER, 40, 0, false, true, true));
|
||||
}
|
||||
}
|
||||
|
||||
private static void tickBloodglassRecharge(ServerLevel level) {
|
||||
for (Player player : level.players()) {
|
||||
if (player instanceof ServerPlayer sp) {
|
||||
BloodglassManager.tickRecharge(sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean antarchy$isInIchor(LivingEntity entity) {
|
||||
BlockPos min = BlockPos.containing(entity.getBoundingBox().minX, entity.getBoundingBox().minY, entity.getBoundingBox().minZ);
|
||||
BlockPos max = BlockPos.containing(entity.getBoundingBox().maxX, entity.getBoundingBox().maxY, entity.getBoundingBox().maxZ);
|
||||
BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos();
|
||||
for (int x = min.getX(); x <= max.getX(); x++) {
|
||||
for (int y = min.getY(); y <= max.getY(); y++) {
|
||||
for (int z = min.getZ(); z <= max.getZ(); z++) {
|
||||
cursor.set(x, y, z);
|
||||
if (PotentNyxiteBlock.isIchor(entity.level().getFluidState(cursor))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
package com.craisinlord.antarchy.fabric;
|
||||
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||
import com.craisinlord.antarchy.content.bloodglass.BloodglassAccess;
|
||||
import com.craisinlord.antarchy.content.item.BloodCrystalArmorItem;
|
||||
import com.craisinlord.antarchy.fabric.network.AntarchyFabricNetworking;
|
||||
import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||
import net.minecraft.core.particles.DustParticleOptions;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.damagesource.DamageType;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
public final class BloodglassManager {
|
||||
private static final TagKey<DamageType> BYPASSES_BLOODGLASS = TagKey.create(
|
||||
Registries.DAMAGE_TYPE,
|
||||
ResourceLocation.fromNamespaceAndPath("antarchy", "bypasses_bloodglass")
|
||||
);
|
||||
|
||||
private BloodglassManager() {}
|
||||
|
||||
public static void register() {
|
||||
ServerLivingEntityEvents.ALLOW_DAMAGE.register((entity, source, amount) -> {
|
||||
if (!(entity instanceof Player player)) return true;
|
||||
if (entity.level().isClientSide()) return true;
|
||||
if (amount <= 1.0f) return true;
|
||||
if (source.is(BYPASSES_BLOODGLASS)) return true;
|
||||
|
||||
BloodglassAccess access = (BloodglassAccess) player;
|
||||
if (access.antarchy$getTotalShieldsActive() <= 0) return true;
|
||||
|
||||
if (access.antarchy$getAppleShieldsActive() > 0) {
|
||||
access.antarchy$setAppleShieldsActive(access.antarchy$getAppleShieldsActive() - 1);
|
||||
access.antarchy$setAppleShieldLostCount(access.antarchy$getAppleShieldLostCount() + 1);
|
||||
if (access.antarchy$getAppleRechargeTimer() == 0) {
|
||||
access.antarchy$setAppleRechargeTimer(AntarchySettings.bloodCrystalAppleShieldRechargeTicks());
|
||||
}
|
||||
} else {
|
||||
access.antarchy$setArmorShieldsActive(access.antarchy$getArmorShieldsActive() - 1);
|
||||
access.antarchy$setArmorShieldLostCount(access.antarchy$getArmorShieldLostCount() + 1);
|
||||
if (access.antarchy$getArmorRechargeTimer() == 0) {
|
||||
access.antarchy$setArmorRechargeTimer(AntarchySettings.bloodCrystalArmorShieldRechargeTicks());
|
||||
}
|
||||
}
|
||||
|
||||
ServerLevel serverLevel = (ServerLevel) player.level();
|
||||
serverLevel.broadcastEntityEvent(player, (byte) 2);
|
||||
serverLevel.playSound(null, player.blockPosition(), SoundEvents.GLASS_BREAK, SoundSource.PLAYERS, 1.0f, 1.0f);
|
||||
serverLevel.sendParticles(
|
||||
new DustParticleOptions(new Vector3f(0.85f, 0.18f, 0.38f), 1.2f),
|
||||
player.getX(), player.getEyeY(), player.getZ(),
|
||||
35, 0.35, 0.55, 0.35, 0.12
|
||||
);
|
||||
|
||||
syncBloodglass((ServerPlayer) player);
|
||||
return false;
|
||||
});
|
||||
|
||||
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> handleLogin(handler.player));
|
||||
}
|
||||
|
||||
public static void syncBloodglass(ServerPlayer player) {
|
||||
BloodglassAccess access = (BloodglassAccess) player;
|
||||
AntarchyFabricNetworking.syncBloodglass(player,
|
||||
access.antarchy$getTotalShieldsActive(),
|
||||
access.antarchy$getTotalShieldsMax());
|
||||
}
|
||||
|
||||
public static void handleArmorEquipChange(Player player, EquipmentSlot slot, ItemStack from, ItemStack to) {
|
||||
if (player.level().isClientSide()) return;
|
||||
if (slot != EquipmentSlot.HEAD && slot != EquipmentSlot.CHEST
|
||||
&& slot != EquipmentSlot.LEGS && slot != EquipmentSlot.FEET) return;
|
||||
|
||||
boolean fromIsBC = from.getItem() instanceof BloodCrystalArmorItem;
|
||||
boolean toIsBC = to.getItem() instanceof BloodCrystalArmorItem;
|
||||
if (!fromIsBC && !toIsBC) return;
|
||||
|
||||
BloodglassAccess access = (BloodglassAccess) player;
|
||||
|
||||
if (fromIsBC && !toIsBC) {
|
||||
if (access.antarchy$getArmorShieldsActive() > 0) {
|
||||
access.antarchy$setArmorShieldsActive(access.antarchy$getArmorShieldsActive() - 1);
|
||||
} else if (access.antarchy$getArmorShieldLostCount() > 0) {
|
||||
access.antarchy$setArmorShieldLostCount(access.antarchy$getArmorShieldLostCount() - 1);
|
||||
if (access.antarchy$getArmorShieldLostCount() == 0) {
|
||||
access.antarchy$setArmorRechargeTimer(0);
|
||||
}
|
||||
}
|
||||
} else if (!fromIsBC) {
|
||||
// Count BC pieces: explicitly include the new piece (to) since getItemBySlot(slot)
|
||||
// may not reflect the new item yet when onEquipItem fires on Fabric.
|
||||
int bcPieces = 1; // the piece being equipped now
|
||||
for (EquipmentSlot s : new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET}) {
|
||||
if (s == slot) continue;
|
||||
if (player.getItemBySlot(s).getItem() instanceof BloodCrystalArmorItem) bcPieces++;
|
||||
}
|
||||
int currentTotal = access.antarchy$getArmorShieldsActive() + access.antarchy$getArmorShieldLostCount();
|
||||
if (currentTotal < bcPieces) {
|
||||
access.antarchy$setArmorShieldLostCount(access.antarchy$getArmorShieldLostCount() + 1);
|
||||
access.antarchy$setArmorRechargeTimer(AntarchySettings.bloodCrystalArmorShieldRechargeTicks());
|
||||
}
|
||||
} else {
|
||||
// BC → BC swap: remove old slot, queue new one
|
||||
if (access.antarchy$getArmorShieldsActive() > 0) {
|
||||
access.antarchy$setArmorShieldsActive(access.antarchy$getArmorShieldsActive() - 1);
|
||||
} else if (access.antarchy$getArmorShieldLostCount() > 0) {
|
||||
access.antarchy$setArmorShieldLostCount(access.antarchy$getArmorShieldLostCount() - 1);
|
||||
}
|
||||
access.antarchy$setArmorShieldLostCount(access.antarchy$getArmorShieldLostCount() + 1);
|
||||
access.antarchy$setArmorRechargeTimer(AntarchySettings.bloodCrystalArmorShieldRechargeTicks());
|
||||
}
|
||||
|
||||
if (player instanceof ServerPlayer sp) syncBloodglass(sp);
|
||||
}
|
||||
|
||||
public static void handleWardApplied(Player player, int amplifier) {
|
||||
if (player.level().isClientSide()) return;
|
||||
BloodglassAccess access = (BloodglassAccess) player;
|
||||
int cap = Math.max(0, AntarchySettings.bloodCrystalHardMaxShields()
|
||||
- access.antarchy$getArmorShieldsActive()
|
||||
- access.antarchy$getArmorShieldLostCount());
|
||||
access.antarchy$setAppleShieldsActive(Math.min(amplifier + 1, cap));
|
||||
access.antarchy$setAppleShieldLostCount(0);
|
||||
access.antarchy$setAppleRechargeTimer(0);
|
||||
if (player instanceof ServerPlayer sp) syncBloodglass(sp);
|
||||
}
|
||||
|
||||
public static void handleWardRemoved(Player player) {
|
||||
if (player.level().isClientSide()) return;
|
||||
BloodglassAccess access = (BloodglassAccess) player;
|
||||
access.antarchy$setAppleShieldsActive(0);
|
||||
access.antarchy$setAppleShieldLostCount(0);
|
||||
access.antarchy$setAppleRechargeTimer(0);
|
||||
if (player instanceof ServerPlayer sp) syncBloodglass(sp);
|
||||
}
|
||||
|
||||
public static void tickRecharge(ServerPlayer player) {
|
||||
BloodglassAccess access = (BloodglassAccess) player;
|
||||
boolean changed = false;
|
||||
int hardCap = AntarchySettings.bloodCrystalHardMaxShields();
|
||||
|
||||
if (access.antarchy$getArmorShieldLostCount() > 0) {
|
||||
int timer = access.antarchy$getArmorRechargeTimer();
|
||||
if (timer > 1) {
|
||||
access.antarchy$setArmorRechargeTimer(timer - 1);
|
||||
} else if (timer == 1) {
|
||||
if (access.antarchy$getTotalShieldsActive() < hardCap) {
|
||||
access.antarchy$setArmorShieldsActive(access.antarchy$getArmorShieldsActive() + 1);
|
||||
access.antarchy$setArmorShieldLostCount(access.antarchy$getArmorShieldLostCount() - 1);
|
||||
changed = true;
|
||||
}
|
||||
access.antarchy$setArmorRechargeTimer(access.antarchy$getArmorShieldLostCount() > 0
|
||||
? AntarchySettings.bloodCrystalArmorShieldRechargeTicks() : 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (access.antarchy$getAppleShieldLostCount() > 0 && player.hasEffect(AntarchyObjects.BLOODGLASS_WARD.get())) {
|
||||
int timer = access.antarchy$getAppleRechargeTimer();
|
||||
if (timer > 1) {
|
||||
access.antarchy$setAppleRechargeTimer(timer - 1);
|
||||
} else if (timer == 1) {
|
||||
if (access.antarchy$getTotalShieldsActive() < hardCap) {
|
||||
access.antarchy$setAppleShieldsActive(access.antarchy$getAppleShieldsActive() + 1);
|
||||
access.antarchy$setAppleShieldLostCount(access.antarchy$getAppleShieldLostCount() - 1);
|
||||
changed = true;
|
||||
}
|
||||
access.antarchy$setAppleRechargeTimer(access.antarchy$getAppleShieldLostCount() > 0
|
||||
? AntarchySettings.bloodCrystalAppleShieldRechargeTicks() : 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
syncBloodglass(player);
|
||||
player.playNotifySound(SoundEvents.AMETHYST_BLOCK_CHIME, SoundSource.PLAYERS, 0.6f, 1.6f);
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleDeath(ServerPlayer player) {
|
||||
BloodglassAccess access = (BloodglassAccess) player;
|
||||
access.antarchy$setArmorShieldsActive(0);
|
||||
access.antarchy$setArmorShieldLostCount(0);
|
||||
access.antarchy$setArmorRechargeTimer(0);
|
||||
access.antarchy$setAppleShieldsActive(0);
|
||||
access.antarchy$setAppleShieldLostCount(0);
|
||||
access.antarchy$setAppleRechargeTimer(0);
|
||||
syncBloodglass(player);
|
||||
}
|
||||
|
||||
public static void handleRespawn(ServerPlayer player) {
|
||||
BloodglassAccess access = (BloodglassAccess) player;
|
||||
int shields = Math.min(countBCArmorPieces(player), AntarchySettings.bloodCrystalHardMaxShields());
|
||||
access.antarchy$setArmorShieldsActive(shields);
|
||||
access.antarchy$setArmorShieldLostCount(0);
|
||||
access.antarchy$setArmorRechargeTimer(0);
|
||||
syncBloodglass(player);
|
||||
}
|
||||
|
||||
private static void handleLogin(ServerPlayer player) {
|
||||
BloodglassAccess access = (BloodglassAccess) player;
|
||||
if (player.hasEffect(AntarchyObjects.BLOODGLASS_WARD.get())) {
|
||||
var effect = player.getEffect(AntarchyObjects.BLOODGLASS_WARD.get());
|
||||
if (effect != null) {
|
||||
int cap = Math.max(0, AntarchySettings.bloodCrystalHardMaxShields()
|
||||
- access.antarchy$getArmorShieldsActive()
|
||||
- access.antarchy$getArmorShieldLostCount());
|
||||
access.antarchy$setAppleShieldsActive(Math.min(effect.getAmplifier() + 1, cap));
|
||||
access.antarchy$setAppleShieldLostCount(0);
|
||||
access.antarchy$setAppleRechargeTimer(0);
|
||||
}
|
||||
}
|
||||
syncBloodglass(player);
|
||||
}
|
||||
|
||||
private static int countBCArmorPieces(Player player) {
|
||||
int count = 0;
|
||||
for (EquipmentSlot slot : new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET}) {
|
||||
if (player.getItemBySlot(slot).getItem() instanceof BloodCrystalArmorItem) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.craisinlord.antarchy.fabric;
|
||||
|
||||
import com.craisinlord.antarchy.compat.infinity.InfinityCompatBridge;
|
||||
import net.lerariemann.infinity.util.InfinityMethods;
|
||||
import net.lerariemann.infinity.util.teleport.WarpLogic;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.RandomSource;
|
||||
|
||||
public final class FabricInfinityCompat implements InfinityCompatBridge {
|
||||
public static boolean isAvailableOnClasspath() {
|
||||
try {
|
||||
Class.forName("net.lerariemann.infinity.util.InfinityMethods");
|
||||
Class.forName("net.lerariemann.infinity.util.teleport.WarpLogic");
|
||||
return true;
|
||||
} catch (Throwable ignored) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getRandomDimensionId(RandomSource random) {
|
||||
try {
|
||||
return InfinityMethods.getRandomId(random);
|
||||
} catch (Throwable throwable) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requestWarp(ServerPlayer player, ResourceLocation dimensionId) {
|
||||
try {
|
||||
WarpLogic.requestWarp(player, dimensionId, false);
|
||||
return true;
|
||||
} catch (Throwable throwable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.fabric.network.AntarchyFabricClientNetworking;
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
|
||||
public final class AntarchyFabricClient implements ClientModInitializer {
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
AntarchyFabricClientNetworking.register();
|
||||
AntarchyFabricClientBootstrap.register();
|
||||
}
|
||||
}
|
||||
|
||||
+312
@@ -0,0 +1,312 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import com.craisinlord.antarchy.content.client.renderer.*;
|
||||
import com.craisinlord.antarchy.content.client.particle.*;
|
||||
import com.craisinlord.antarchy.content.client.renderer.AntiwaterFluidRenderer;
|
||||
import com.craisinlord.antarchy.fabric.AntarchyFabricContent;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.LivingEntityFeatureRendererRegistrationCallback;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry;
|
||||
import net.fabricmc.fabric.api.client.particle.v1.ParticleFactoryRegistry;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.BlockEntityRendererRegistry;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.EntityModelLayerRegistry;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
|
||||
import net.minecraft.client.model.BoatModel;
|
||||
import net.minecraft.client.model.ChestBoatModel;
|
||||
import net.minecraft.client.renderer.BiomeColors;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlas;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.client.renderer.blockentity.CampfireRenderer;
|
||||
import net.minecraft.client.renderer.entity.ThrownItemRenderer;
|
||||
import net.minecraft.client.renderer.item.ItemProperties;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.item.CrossbowItem;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.component.ChargedProjectiles;
|
||||
import net.minecraft.world.level.FoliageColor;
|
||||
import net.fabricmc.fabric.api.client.render.fluid.v1.SimpleFluidRenderHandler;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public final class AntarchyFabricClientBootstrap {
|
||||
private AntarchyFabricClientBootstrap() {
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
AntarchyKeyBindings.register();
|
||||
registerRenderers();
|
||||
registerEntityLayers();
|
||||
registerColors();
|
||||
registerParticles();
|
||||
registerFluids();
|
||||
registerRenderLayers();
|
||||
registerItemProperties();
|
||||
registerClientCallbacks();
|
||||
}
|
||||
|
||||
private static void registerRenderers() {
|
||||
BlockEntityRendererRegistry.register(
|
||||
(net.minecraft.world.level.block.entity.BlockEntityType) AntarchyFabricContent.DREAM_CAMPFIRE_BLOCK_ENTITY.get(),
|
||||
(BlockEntityRendererProvider) CampfireRenderer::new
|
||||
);
|
||||
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.EASTER_BUNNY.get(), EasterBunnyRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.FLYING_SQUIRREL.get(), FlyingSquirrelRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.CATERPILLAR.get(), CaterpillarRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.BUTTERFLY.get(), ButterflyRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.REVERIE.get(), ReverieRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.BRUTALFLY.get(), BrutalflyRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.RED_ANT.get(), AntRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.BROWN_ANT.get(), AntRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.RAINBOW_ANT.get(), AntRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.MOLEWORM.get(), MolewormRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.MANTIS.get(), MantisRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.MOLEVORE.get(), MolevoreRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.TRIFFID.get(), TriffidRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.OURANWOOD_BOAT_ENTITY.get(), context -> new OuranwoodBoatRenderer<>(context, ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/boat/ouranwood.png"), false));
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.OURANWOOD_CHEST_BOAT_ENTITY.get(), context -> new OuranwoodBoatRenderer<>(context, ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/chest_boat/ouranwood.png"), true));
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.APPLE_COW.get(), AppleCowRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.GOLDEN_APPLE_COW.get(), AppleCowRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.ENCHANTED_GOLDEN_APPLE_COW.get(), AppleCowRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.DIAMOND_MINECART.get(), DiamondMinecartRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.DR_TRAYAURUS.get(), context -> new DrTrayaurusRenderer(context, ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/dr_trayaurus.png")));
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.CLOUD_SHARK.get(), CloudSharkRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.KRAKEN.get(), KrakenRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.MISSILE_SQUID.get(), MissileSquidRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.NIGHTMARE.get(), NightmareRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.LUCID.get(), LucidRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.BED_BUG.get(), BedBugRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.WASP.get(), WaspRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.BOMBER.get(), BomberRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.BASILISK.get(), BasiliskRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.SHRINK_RAY_PROJECTILE.get(), SizeRayProjectileRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.GROWTH_RAY_PROJECTILE.get(), SizeRayProjectileRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.LUCID_BOLT.get(), LucidBoltRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.LUCID_PEARL_PROJECTILE.get(), ThrownItemRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.HUSH_PROJECTILE.get(), HushProjectileRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.BRUTALFLY_ORB.get(), BrutalflyOrbRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.UPWARD_FALLING_BLOCK.get(), UpwardFallingBlockRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.SCORPION.get(), ScorpionRenderer::new);
|
||||
EntityRendererRegistry.register(AntarchyFabricContent.EMPEROR_SCORPION.get(), EmperorScorpionRenderer::new);
|
||||
|
||||
EntityModelLayerRegistry.registerModelLayer(OuranwoodBoatRenderer.boatLayer(), BoatModel::createBodyModel);
|
||||
EntityModelLayerRegistry.registerModelLayer(OuranwoodBoatRenderer.chestBoatLayer(), ChestBoatModel::createBodyModel);
|
||||
}
|
||||
|
||||
private static void registerColors() {
|
||||
ColorProviderRegistry.BLOCK.register(
|
||||
(state, level, pos, tintIndex) -> level != null && pos != null
|
||||
? BiomeColors.getAverageFoliageColor(level, pos)
|
||||
: FoliageColor.getDefaultColor(),
|
||||
AntarchyFabricContent.OURANWOOD_LEAVES.get()
|
||||
);
|
||||
ColorProviderRegistry.BLOCK.register((state, level, pos, tintIndex) -> 0xFF4A0000, AntarchyFabricContent.ANTIWATER_BLOCK.get());
|
||||
ColorProviderRegistry.ITEM.register((stack, tintIndex) -> FoliageColor.getDefaultColor(), AntarchyFabricContent.OURANWOOD_LEAVES_ITEM.get());
|
||||
}
|
||||
|
||||
private static void registerFluids() {
|
||||
FluidRenderHandlerRegistry.INSTANCE.register(
|
||||
AntarchyFabricContent.ICHOR.get(),
|
||||
AntarchyFabricContent.FLOWING_ICHOR.get(),
|
||||
new SimpleFluidRenderHandler(
|
||||
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "block/antiwater_still"),
|
||||
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "block/antiwater_flow"),
|
||||
ResourceLocation.withDefaultNamespace("block/water_overlay"),
|
||||
0xFF2A0306
|
||||
)
|
||||
);
|
||||
|
||||
FluidRenderHandlerRegistry.INSTANCE.register(
|
||||
AntarchyFabricContent.ANTIWATER.get(),
|
||||
AntarchyFabricContent.FLOWING_ANTIWATER.get(),
|
||||
new SimpleFluidRenderHandler(
|
||||
ResourceLocation.withDefaultNamespace("block/water_still"),
|
||||
ResourceLocation.withDefaultNamespace("block/water_flow"),
|
||||
ResourceLocation.withDefaultNamespace("block/water_overlay"),
|
||||
0xFFFF1A1A
|
||||
) {
|
||||
@Override
|
||||
public void renderFluid(BlockPos pos, BlockAndTintGetter world, VertexConsumer vertexConsumer, BlockState blockState, FluidState fluidState) {
|
||||
TextureAtlasSprite[] sprites = this.getFluidSprites(world, pos, fluidState);
|
||||
AntiwaterFluidRenderer.render(
|
||||
world,
|
||||
pos,
|
||||
vertexConsumer,
|
||||
blockState,
|
||||
fluidState,
|
||||
sprites[0],
|
||||
sprites[1],
|
||||
sprites.length > 2 ? sprites[2] : null,
|
||||
this.getFluidColor(world, pos, fluidState)
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private static void registerParticles() {
|
||||
ParticleFactoryRegistry registry = ParticleFactoryRegistry.getInstance();
|
||||
registry.register(AntarchyFabricContent.DREAM_FIRE_FLAME.get(), DreamFlameParticle.Provider::new);
|
||||
registry.register(AntarchyFabricContent.HYPNOTIC_GAS.get(), HypnoticGasParticle.Provider::new);
|
||||
registry.register(AntarchyFabricContent.HYPNOTIC_GAS_DOWN.get(), sprites -> new HypnoticGasParticle.Provider(sprites, true));
|
||||
registry.register(AntarchyFabricContent.HYPNOTIC_GAS_CLOUD.get(), new HypnoticGasCloudParticle.Provider());
|
||||
registry.register(AntarchyFabricContent.HYPNOTIC_GAS_CLOUD_DOWN.get(), new HypnoticGasCloudParticle.Provider(true));
|
||||
registry.register(AntarchyFabricContent.INVERTED_GEYSER_BASE.get(), InvertedGeyserBaseParticle.Provider::new);
|
||||
registry.register(AntarchyFabricContent.INVERTED_GEYSER_PLUME.get(), InvertedGeyserPlumeParticle.Provider::new);
|
||||
registry.register(AntarchyFabricContent.INVERTED_GEYSER_POOF.get(), InvertedGeyserBaseParticle.Provider::new);
|
||||
registry.register(AntarchyFabricContent.INVERTED_GEYSER_ERUPTION.get(), new InvertedGeyserEruptionParticle.Provider());
|
||||
registry.register(AntarchyFabricContent.FIREFLY.get(), FireflyParticle.Provider::new);
|
||||
}
|
||||
|
||||
private static void registerRenderLayers() {
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.OURANWOOD_LEAVES.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.OURANWOOD_DOOR.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.OURANWOOD_TRAPDOOR.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.OURANWOOD_ACORN_BLOCK.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.DUPLICATOR_SAPLING.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.ORANGE_MILKWEED.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.PINK_MILKWEED.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.TORCHFLOWER_BUSH.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.HUSHWEED.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.CORNEA_STALK.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.ANTIMETAL_SCAFFOLDING.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.UMBRAL_MOSS_CARPET.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.NYXITE_SPIKE.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.SMALL_BLOOD_CRYSTAL_BUD.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.MEDIUM_BLOOD_CRYSTAL_BUD.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.LARGE_BLOOD_CRYSTAL_BUD.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.BLOOD_CRYSTAL_CRYSTAL.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.DREAM_TORCH.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.DREAM_WALL_TORCH.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.DREAM_LANTERN.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.DREAM_CAMPFIRE.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.DREAM_FIRE.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.DREAM_CEILING_FIRE.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.ANTIWATER_BLOCK.get(), RenderType.translucent());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.TRIFFID_GOO_BLOCK.get(), RenderType.translucent());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.URANIUM_DOOR.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.TITANIUM_DOOR.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.URANIUM_TRAPDOOR.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.TITANIUM_TRAPDOOR.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.URANIUM_BARS.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.TITANIUM_BARS.get(), RenderType.cutout());
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.CLOUD_BLOCK.get(), RenderType.translucent());
|
||||
BlockRenderLayerMap.INSTANCE.putFluids(
|
||||
RenderType.translucent(),
|
||||
AntarchyFabricContent.ICHOR.get(),
|
||||
AntarchyFabricContent.FLOWING_ICHOR.get(),
|
||||
AntarchyFabricContent.ANTIWATER.get(),
|
||||
AntarchyFabricContent.FLOWING_ANTIWATER.get()
|
||||
);
|
||||
}
|
||||
|
||||
private static void registerItemProperties() {
|
||||
ItemProperties.register(
|
||||
AntarchyFabricContent.ULTIMATE_BOW.get(),
|
||||
ResourceLocation.withDefaultNamespace("pull"),
|
||||
(stack, level, entity, seed) -> entity == null || entity.getUseItem() != stack
|
||||
? 0.0F
|
||||
: (stack.getItem().getUseDuration(stack, entity) - entity.getUseItemRemainingTicks()) / 20.0F
|
||||
);
|
||||
ItemProperties.register(
|
||||
AntarchyFabricContent.ULTIMATE_BOW.get(),
|
||||
ResourceLocation.withDefaultNamespace("pulling"),
|
||||
(stack, level, entity, seed) -> entity != null && entity.isUsingItem() && entity.getUseItem() == stack ? 1.0F : 0.0F
|
||||
);
|
||||
ItemProperties.register(
|
||||
AntarchyFabricContent.ULTIMATE_CROSSBOW.get(),
|
||||
ResourceLocation.withDefaultNamespace("pull"),
|
||||
(stack, level, entity, seed) -> {
|
||||
if (entity == null || CrossbowItem.isCharged(stack) || entity.getUseItem() != stack) {
|
||||
return 0.0F;
|
||||
}
|
||||
float adjustedChargeDuration = Math.max(1.0F, stack.getItem().getUseDuration(stack, entity) - 3.0F);
|
||||
return Mth.clamp((stack.getItem().getUseDuration(stack, entity) - entity.getUseItemRemainingTicks()) / adjustedChargeDuration, 0.0F, 1.0F);
|
||||
}
|
||||
);
|
||||
ItemProperties.register(
|
||||
AntarchyFabricContent.ULTIMATE_CROSSBOW.get(),
|
||||
ResourceLocation.withDefaultNamespace("pulling"),
|
||||
(stack, level, entity, seed) -> entity != null && entity.isUsingItem() && entity.getUseItem() == stack && !CrossbowItem.isCharged(stack) ? 1.0F : 0.0F
|
||||
);
|
||||
ItemProperties.register(
|
||||
AntarchyFabricContent.ULTIMATE_CROSSBOW.get(),
|
||||
ResourceLocation.withDefaultNamespace("charged"),
|
||||
(stack, level, entity, seed) -> CrossbowItem.isCharged(stack) ? 1.0F : 0.0F
|
||||
);
|
||||
ItemProperties.register(
|
||||
AntarchyFabricContent.ULTIMATE_CROSSBOW.get(),
|
||||
ResourceLocation.withDefaultNamespace("firework"),
|
||||
(stack, level, entity, seed) -> CrossbowItem.isCharged(stack) && ChargedProjectiles.of(stack).contains(Items.FIREWORK_ROCKET) ? 1.0F : 0.0F
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private static void registerEntityLayers() {
|
||||
LivingEntityFeatureRendererRegistrationCallback.EVENT.register((entityType, renderer, registrationHelper, context) -> {
|
||||
if (entityType == EntityType.PLAYER) {
|
||||
if (renderer instanceof net.minecraft.client.renderer.entity.player.PlayerRenderer playerRenderer) {
|
||||
registrationHelper.register(new ParalyzedStonePlayerLayer(playerRenderer));
|
||||
registrationHelper.register(new BrutalflyElytraLayer(playerRenderer));
|
||||
registrationHelper.register(new FallenKingCrownLayer(playerRenderer));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (software.bernie.geckolib.renderer.GeoEntityRenderer.class.isAssignableFrom(renderer.getClass())) {
|
||||
software.bernie.geckolib.renderer.GeoEntityRenderer geoRenderer =
|
||||
(software.bernie.geckolib.renderer.GeoEntityRenderer) (Object) renderer;
|
||||
geoRenderer.addRenderLayer(new ParalyzedStoneGeoLayer(geoRenderer));
|
||||
return;
|
||||
}
|
||||
registrationHelper.register(new ParalyzedStoneLivingLayer(renderer));
|
||||
});
|
||||
}
|
||||
|
||||
private static void registerClientCallbacks() {
|
||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||
if (client.player != null) {
|
||||
ParalyzedClientHandler.clampPlayerInput(client.player);
|
||||
}
|
||||
BrutalflyElytraClientHandler.tick();
|
||||
DiamondMinecartClientHandler.tick();
|
||||
ParalyzedClientHandler.tick();
|
||||
DreadClientHandler.tick();
|
||||
BloodCrystalKatanaTrailHandler.tick();
|
||||
ScorpionWhipTetherRenderHandler.tick();
|
||||
});
|
||||
|
||||
GravityGunClientHandler.register();
|
||||
|
||||
ElythiaFireflyManager.register();
|
||||
LucidSoundHandler.register();
|
||||
MogglesClientRenderer.register();
|
||||
ReverieTrailHandler.register();
|
||||
|
||||
HudRenderCallback.EVENT.register((guiGraphics, partialTick) -> {
|
||||
DreadHudRenderer.render(guiGraphics);
|
||||
ParalyzedHudRenderer.render(guiGraphics);
|
||||
BrutalflyElytraHudRenderer.render(guiGraphics);
|
||||
BloodglassHudRenderer.render(guiGraphics);
|
||||
TriffidGooHudRenderer.render(guiGraphics);
|
||||
});
|
||||
|
||||
WorldRenderEvents.AFTER_TRANSLUCENT.register(context -> {
|
||||
BloodCrystalKatanaTrailHandler.render(context);
|
||||
ScorpionWhipTetherRenderHandler.render(context);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import com.mojang.blaze3d.platform.InputConstants;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
||||
import net.minecraft.client.KeyMapping;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
public final class AntarchyKeyBindings {
|
||||
public static final String CATEGORY = "key.categories.antarchy";
|
||||
|
||||
public static final KeyMapping BRUTALFLY_FLAP = new KeyMapping(
|
||||
"key.antarchy.brutalfly_flap",
|
||||
InputConstants.Type.KEYSYM,
|
||||
GLFW.GLFW_KEY_G,
|
||||
CATEGORY
|
||||
);
|
||||
|
||||
private AntarchyKeyBindings() {}
|
||||
|
||||
public static void register() {
|
||||
KeyBindingHelper.registerKeyBinding(BRUTALFLY_FLAP);
|
||||
}
|
||||
|
||||
public static boolean isBrutalflyFlapPressed() {
|
||||
return Minecraft.getInstance().screen == null && BRUTALFLY_FLAP.isDown();
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
public final class BloodCrystalKatanaTrailClientState {
|
||||
private static final Map<Integer, Integer> ACTIVE = new HashMap<>();
|
||||
|
||||
private BloodCrystalKatanaTrailClientState() {}
|
||||
|
||||
public static void trigger(int entityId, int durationTicks) {
|
||||
if (durationTicks <= 0) {
|
||||
ACTIVE.remove(entityId);
|
||||
return;
|
||||
}
|
||||
ACTIVE.put(entityId, durationTicks);
|
||||
}
|
||||
|
||||
public static int getRemainingTicks(int entityId) {
|
||||
return ACTIVE.getOrDefault(entityId, 0);
|
||||
}
|
||||
|
||||
public static void tick() {
|
||||
Iterator<Map.Entry<Integer, Integer>> iterator = ACTIVE.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<Integer, Integer> entry = iterator.next();
|
||||
int remaining = entry.getValue() - 1;
|
||||
if (remaining <= 0) {
|
||||
iterator.remove();
|
||||
} else {
|
||||
entry.setValue(remaining);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
ACTIVE.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||
import com.mojang.blaze3d.vertex.BufferUploader;
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||
import com.mojang.blaze3d.vertex.MeshData;
|
||||
import com.mojang.blaze3d.vertex.Tesselator;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
public final class BloodCrystalKatanaTrailHandler {
|
||||
private static final int MAX_TRAIL_POINTS = 16;
|
||||
private static final int POINT_LIFETIME_TICKS = 10;
|
||||
private static final double MIN_DISTANCE_BETWEEN_POINTS = 0.05D;
|
||||
private static final float CORE_WIDTH = 0.06F;
|
||||
private static final float GLOW_WIDTH = 0.16F;
|
||||
private static final Map<Integer, ArrayDeque<TrailPoint>> TRAILS = new HashMap<>();
|
||||
|
||||
private BloodCrystalKatanaTrailHandler() {}
|
||||
|
||||
private static final class TrailPoint {
|
||||
private final Vec3 position;
|
||||
private int age;
|
||||
|
||||
private TrailPoint(Vec3 position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
private float alpha() {
|
||||
return 1.0F - ((float) age / POINT_LIFETIME_TICKS);
|
||||
}
|
||||
|
||||
private boolean expired() {
|
||||
return age >= POINT_LIFETIME_TICKS || alpha() <= 0.01F;
|
||||
}
|
||||
}
|
||||
|
||||
public static void tick() {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (mc.level == null) {
|
||||
TRAILS.clear();
|
||||
BloodCrystalKatanaTrailClientState.clear();
|
||||
return;
|
||||
}
|
||||
if (mc.isPaused()) {
|
||||
return;
|
||||
}
|
||||
|
||||
BloodCrystalKatanaTrailClientState.tick();
|
||||
Set<Integer> activeIds = new HashSet<>();
|
||||
|
||||
for (Entity entity : mc.level.entitiesForRendering()) {
|
||||
int remaining = BloodCrystalKatanaTrailClientState.getRemainingTicks(entity.getId());
|
||||
if (remaining <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
activeIds.add(entity.getId());
|
||||
Vec3 position = entity.position().add(0.0D, entity.getBbHeight() * 0.45D, 0.0D);
|
||||
ArrayDeque<TrailPoint> points = TRAILS.computeIfAbsent(entity.getId(), id -> new ArrayDeque<>());
|
||||
|
||||
if (points.isEmpty() || points.peekFirst().position.distanceToSqr(position) >= MIN_DISTANCE_BETWEEN_POINTS * MIN_DISTANCE_BETWEEN_POINTS) {
|
||||
points.addFirst(new TrailPoint(position));
|
||||
while (points.size() > MAX_TRAIL_POINTS) {
|
||||
points.pollLast();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TRAILS.keySet().removeIf(id -> !activeIds.contains(id));
|
||||
for (ArrayDeque<TrailPoint> points : TRAILS.values()) {
|
||||
Iterator<TrailPoint> iterator = points.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
TrailPoint point = iterator.next();
|
||||
point.age++;
|
||||
if (point.expired()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
TRAILS.values().removeIf(ArrayDeque::isEmpty);
|
||||
}
|
||||
|
||||
public static void render(WorldRenderContext context) {
|
||||
if (TRAILS.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.world() == null || context.matrixStack() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (mc.level == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Camera camera = context.camera();
|
||||
Vec3 cameraPos = camera.getPosition();
|
||||
Matrix4f matrix = context.matrixStack().last().pose();
|
||||
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.defaultBlendFunc();
|
||||
RenderSystem.depthMask(false);
|
||||
RenderSystem.disableCull();
|
||||
RenderSystem.setShader(GameRenderer::getPositionColorShader);
|
||||
|
||||
Tesselator tesselator = Tesselator.getInstance();
|
||||
List<List<TrailPoint>> snapshots = new ArrayList<>(TRAILS.size());
|
||||
for (ArrayDeque<TrailPoint> deque : TRAILS.values()) {
|
||||
if (deque.size() >= 2) {
|
||||
snapshots.add(new ArrayList<>(deque));
|
||||
}
|
||||
}
|
||||
|
||||
if (snapshots.isEmpty()) {
|
||||
RenderSystem.enableCull();
|
||||
RenderSystem.depthMask(true);
|
||||
RenderSystem.disableBlend();
|
||||
return;
|
||||
}
|
||||
|
||||
BufferBuilder glowBuffer = tesselator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
|
||||
for (List<TrailPoint> points : snapshots) {
|
||||
buildTrail(glowBuffer, matrix, points, cameraPos, GLOW_WIDTH, 0.95F, 0.14F, 0.18F, 0.38F);
|
||||
}
|
||||
MeshData glowMesh = glowBuffer.build();
|
||||
if (glowMesh != null) {
|
||||
BufferUploader.drawWithShader(glowMesh);
|
||||
}
|
||||
|
||||
BufferBuilder coreBuffer = tesselator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
|
||||
for (List<TrailPoint> points : snapshots) {
|
||||
buildTrail(coreBuffer, matrix, points, cameraPos, CORE_WIDTH, 1.0F, 0.32F, 0.36F, 0.92F);
|
||||
}
|
||||
MeshData coreMesh = coreBuffer.build();
|
||||
if (coreMesh != null) {
|
||||
BufferUploader.drawWithShader(coreMesh);
|
||||
}
|
||||
|
||||
RenderSystem.enableCull();
|
||||
RenderSystem.depthMask(true);
|
||||
RenderSystem.disableBlend();
|
||||
}
|
||||
|
||||
private static void buildTrail(BufferBuilder builder, Matrix4f matrix, List<TrailPoint> points, Vec3 cameraPos,
|
||||
float width, float red, float green, float blue, float alphaScale) {
|
||||
for (int i = 0; i < points.size() - 1; i++) {
|
||||
TrailPoint newer = points.get(i);
|
||||
TrailPoint older = points.get(i + 1);
|
||||
Vec3 side = cameraFacingRight(newer.position, older.position, cameraPos);
|
||||
if (side == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float nearAlpha = newer.alpha() * alphaScale;
|
||||
float farAlpha = older.alpha() * alphaScale * 0.85F;
|
||||
Vec3 nearOffset = side.scale(width);
|
||||
Vec3 farOffset = side.scale(width);
|
||||
Vec3 nearPos = newer.position.subtract(cameraPos);
|
||||
Vec3 farPos = older.position.subtract(cameraPos);
|
||||
|
||||
builder.addVertex(matrix, (float) (nearPos.x + nearOffset.x), (float) (nearPos.y + nearOffset.y), (float) (nearPos.z + nearOffset.z)).setColor(red, green, blue, nearAlpha);
|
||||
builder.addVertex(matrix, (float) (nearPos.x - nearOffset.x), (float) (nearPos.y - nearOffset.y), (float) (nearPos.z - nearOffset.z)).setColor(red, green, blue, nearAlpha);
|
||||
builder.addVertex(matrix, (float) (farPos.x - farOffset.x), (float) (farPos.y - farOffset.y), (float) (farPos.z - farOffset.z)).setColor(red, green, blue, farAlpha);
|
||||
builder.addVertex(matrix, (float) (farPos.x + farOffset.x), (float) (farPos.y + farOffset.y), (float) (farPos.z + farOffset.z)).setColor(red, green, blue, farAlpha);
|
||||
}
|
||||
}
|
||||
|
||||
private static Vec3 cameraFacingRight(Vec3 current, Vec3 next, Vec3 cameraPos) {
|
||||
Vec3 segmentDirection = next.subtract(current);
|
||||
if (segmentDirection.lengthSqr() < 1.0E-8D) {
|
||||
return null;
|
||||
}
|
||||
segmentDirection = segmentDirection.normalize();
|
||||
|
||||
Vec3 midpoint = current.add(next).scale(0.5D);
|
||||
Vec3 cameraDirection = cameraPos.subtract(midpoint);
|
||||
if (cameraDirection.lengthSqr() < 1.0E-8D) {
|
||||
return null;
|
||||
}
|
||||
cameraDirection = cameraDirection.normalize();
|
||||
|
||||
Vec3 side = segmentDirection.cross(cameraDirection);
|
||||
if (side.lengthSqr() < 1.0E-8D) {
|
||||
side = segmentDirection.cross(new Vec3(0.0D, 1.0D, 0.0D));
|
||||
if (side.lengthSqr() < 1.0E-8D) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return side.normalize();
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import com.craisinlord.antarchy.content.client.BloodglassClientState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
public final class BloodglassHudRenderer {
|
||||
private static final ResourceLocation HEART_CONTAINER =
|
||||
ResourceLocation.withDefaultNamespace("textures/gui/sprites/hud/heart/container.png");
|
||||
private static final ResourceLocation HEART_FULL =
|
||||
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/gui/sprites/hud/bloodglass_heart.png");
|
||||
private static final ResourceLocation HEART_CRACKED =
|
||||
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/gui/sprites/hud/bloodglass_heart_cracked.png");
|
||||
private static final int HEART_SIZE = 9;
|
||||
private static final int HEART_PITCH = 8;
|
||||
|
||||
private BloodglassHudRenderer() {}
|
||||
|
||||
public static void render(GuiGraphics gui) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (mc.options.hideGui) return;
|
||||
Player player = mc.player;
|
||||
if (player == null || player.isDeadOrDying()) return;
|
||||
// Don't show in creative or spectator — no health bar visible there
|
||||
if (player.isCreative() || player.isSpectator()) return;
|
||||
|
||||
int total = BloodglassClientState.getShieldsMax();
|
||||
if (total <= 0) return;
|
||||
|
||||
int active = BloodglassClientState.getShieldsActive();
|
||||
int w = mc.getWindow().getGuiScaledWidth();
|
||||
int h = mc.getWindow().getGuiScaledHeight();
|
||||
|
||||
// Vanilla health bar bottom row is at y = h - 39; each extra row (absorption, extra hearts) is 10px above.
|
||||
// The armor protection icons sit one row above the bottom health row (h - 49).
|
||||
// We place bloodglass hearts above both health+absorption stack AND the armor row.
|
||||
int maxHealth = Mth.ceil(player.getMaxHealth());
|
||||
int absorption = Mth.ceil(player.getAbsorptionAmount());
|
||||
int healthHearts = Mth.ceil(maxHealth / 2.0f);
|
||||
int absorptionHearts = Mth.ceil(absorption / 2.0f);
|
||||
int totalVanillaRows = Mth.ceil((healthHearts + absorptionHearts) / 10.0f);
|
||||
boolean hasArmor = player.getArmorValue() > 0;
|
||||
// +1 to clear the armor icon row only when armor is actually equipped
|
||||
int baseTop = h - 39 - (totalVanillaRows * 10) - (hasArmor ? 10 : 0);
|
||||
|
||||
int left = w / 2 - 91;
|
||||
|
||||
// Wrap across multiple rows if more than 10 bloodglass hearts
|
||||
for (int i = 0; i < total; i++) {
|
||||
int row = i / 10;
|
||||
int col = i % 10;
|
||||
int x = left + col * HEART_PITCH;
|
||||
int y = baseTop - row * 10;
|
||||
ResourceLocation tex = (i < active) ? HEART_FULL : HEART_CRACKED;
|
||||
gui.blit(HEART_CONTAINER, x, y, 0, 0, HEART_SIZE, HEART_SIZE, HEART_SIZE, HEART_SIZE);
|
||||
gui.blit(tex, x, y, 0, 0, HEART_SIZE, HEART_SIZE, HEART_SIZE, HEART_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.content.client.BrutalflyElytraClientState;
|
||||
import com.craisinlord.antarchy.content.item.BrutalflyElytraFlightHelper;
|
||||
import com.craisinlord.antarchy.content.item.BrutalflyElytraItem;
|
||||
import com.craisinlord.antarchy.content.network.BrutalflyElytraFlapPayload;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public final class BrutalflyElytraClientHandler {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Antarchy/BrutalflyElytra");
|
||||
private static boolean lastJumpDown;
|
||||
private static int chargeTicks;
|
||||
|
||||
static {
|
||||
BrutalflyElytraItem.FLAP_KEY_NAME = () -> AntarchyKeyBindings.BRUTALFLY_FLAP.getTranslatedKeyMessage();
|
||||
}
|
||||
|
||||
private BrutalflyElytraClientHandler() {
|
||||
}
|
||||
|
||||
public static void tick() {
|
||||
BrutalflyElytraClientState.tick();
|
||||
|
||||
Minecraft minecraft = Minecraft.getInstance();
|
||||
if (minecraft.player == null || minecraft.level == null || minecraft.screen != null) {
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!BrutalflyElytraItem.isWearingBrutalflyElytra(minecraft.player)) {
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!minecraft.player.isFallFlying()) {
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean sneakDown = AntarchyKeyBindings.isBrutalflyFlapPressed();
|
||||
boolean wasSneakDown = lastJumpDown;
|
||||
lastJumpDown = sneakDown;
|
||||
|
||||
if (sneakDown) {
|
||||
chargeTicks = Math.min(chargeTicks + 1, BrutalflyElytraFlightHelper.FLAP_CHARGE_TICKS_MAX);
|
||||
return;
|
||||
}
|
||||
|
||||
if (wasSneakDown && chargeTicks > 0) {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("[BrutalflyElytra] Sending flap payload chargeTicks={} fallFlying={} deltaMovement={}", chargeTicks, minecraft.player.isFallFlying(), minecraft.player.getDeltaMovement());
|
||||
}
|
||||
ClientPlayNetworking.send(new BrutalflyElytraFlapPayload(chargeTicks));
|
||||
}
|
||||
chargeTicks = 0;
|
||||
}
|
||||
|
||||
private static void reset() {
|
||||
lastJumpDown = false;
|
||||
chargeTicks = 0;
|
||||
}
|
||||
|
||||
public static boolean isCharging() {
|
||||
return chargeTicks > 0 && lastJumpDown;
|
||||
}
|
||||
|
||||
public static int getChargeTicks() {
|
||||
return chargeTicks;
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.content.item.BrutalflyElytraFlightHelper;
|
||||
import com.craisinlord.antarchy.content.item.BrutalflyElytraItem;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
public final class BrutalflyElytraHudRenderer {
|
||||
private static final ResourceLocation JUMP_BAR_BACKGROUND = ResourceLocation.withDefaultNamespace("textures/gui/sprites/hud/jump_bar_background.png");
|
||||
private static final ResourceLocation JUMP_BAR_PROGRESS = ResourceLocation.withDefaultNamespace("textures/gui/sprites/hud/jump_bar_progress.png");
|
||||
private static final int BAR_WIDTH = 182;
|
||||
private static final int BAR_HEIGHT = 5;
|
||||
|
||||
private BrutalflyElytraHudRenderer() {
|
||||
}
|
||||
|
||||
public static void render(GuiGraphics guiGraphics) {
|
||||
Minecraft minecraft = Minecraft.getInstance();
|
||||
Player player = minecraft.player;
|
||||
if (player == null || minecraft.screen != null || player.isDeadOrDying()) {
|
||||
return;
|
||||
}
|
||||
if (!BrutalflyElytraItem.isWearingBrutalflyElytra(player) || !player.isFallFlying()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int width = minecraft.getWindow().getGuiScaledWidth();
|
||||
int height = minecraft.getWindow().getGuiScaledHeight();
|
||||
int x0 = width / 2 - BAR_WIDTH / 2;
|
||||
int y0 = height - 29;
|
||||
|
||||
guiGraphics.blit(JUMP_BAR_BACKGROUND, x0, y0, 0, 0, BAR_WIDTH, BAR_HEIGHT, BAR_WIDTH, BAR_HEIGHT);
|
||||
|
||||
int chargeTicks = BrutalflyElytraClientHandler.getChargeTicks();
|
||||
float chargeRatio = Mth.clamp(chargeTicks / (float) BrutalflyElytraFlightHelper.FLAP_CHARGE_TICKS_MAX, 0.0F, 1.0F);
|
||||
int filledWidth = Mth.clamp((int) (chargeRatio * BAR_WIDTH), 0, BAR_WIDTH);
|
||||
if (filledWidth > 0) {
|
||||
guiGraphics.setColor(1.0F, 1.0F, 1.0F, 0.35F + chargeRatio * 0.65F);
|
||||
guiGraphics.blit(JUMP_BAR_PROGRESS, x0, y0, 0, 0, filledWidth, BAR_HEIGHT, BAR_WIDTH, BAR_HEIGHT);
|
||||
guiGraphics.setColor(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import net.minecraft.client.model.geom.ModelLayerLocation;
|
||||
import net.minecraft.client.model.geom.ModelPart;
|
||||
import net.minecraft.client.model.geom.PartPose;
|
||||
import net.minecraft.client.model.geom.builders.CubeListBuilder;
|
||||
import net.minecraft.client.model.geom.builders.LayerDefinition;
|
||||
import net.minecraft.client.model.geom.builders.MeshDefinition;
|
||||
import net.minecraft.client.model.geom.builders.PartDefinition;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
|
||||
public final class BrutalflyElytraModel {
|
||||
public static final ModelLayerLocation LAYER_LOCATION =
|
||||
new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "brutalfly_elytra"), "main");
|
||||
|
||||
private final ModelPart root;
|
||||
private final ModelPart leftWing;
|
||||
private final ModelPart rightWing;
|
||||
|
||||
public BrutalflyElytraModel(ModelPart root) {
|
||||
this.root = root;
|
||||
this.leftWing = root.getChild("left_wing");
|
||||
this.rightWing = root.getChild("right_wing");
|
||||
}
|
||||
|
||||
public static LayerDefinition createBodyLayer() {
|
||||
MeshDefinition meshDefinition = new MeshDefinition();
|
||||
PartDefinition root = meshDefinition.getRoot();
|
||||
root.addOrReplaceChild(
|
||||
"left_wing",
|
||||
CubeListBuilder.create().texOffs(22, 0).addBox(-10.0F, 0.0F, -1.0F, 10.0F, 20.0F, 2.0F),
|
||||
PartPose.offset(5.0F, 0.0F, -1.5F)
|
||||
);
|
||||
root.addOrReplaceChild(
|
||||
"right_wing",
|
||||
CubeListBuilder.create().mirror().texOffs(22, 0).addBox(0.0F, 0.0F, -1.0F, 10.0F, 20.0F, 2.0F),
|
||||
PartPose.offset(-5.0F, 0.0F, -1.5F)
|
||||
);
|
||||
return LayerDefinition.create(meshDefinition, 64, 32);
|
||||
}
|
||||
|
||||
public void setupAnimation(float progress, float strength, boolean crouching) {
|
||||
float wave = Mth.sin(progress * Mth.PI);
|
||||
float flap = wave * strength;
|
||||
float basePitch = crouching ? -0.18F : -0.05F;
|
||||
float wingSpread = 0.55F;
|
||||
this.leftWing.xRot = basePitch - flap * 1.2F;
|
||||
this.rightWing.xRot = basePitch - flap * 1.2F;
|
||||
this.leftWing.yRot = -wingSpread;
|
||||
this.rightWing.yRot = -wingSpread;
|
||||
this.leftWing.zRot = -0.35F - flap * 0.7F;
|
||||
this.rightWing.zRot = -0.35F - flap * 0.7F;
|
||||
}
|
||||
|
||||
public void renderToBuffer(PoseStack poseStack, VertexConsumer consumer, int packedLight, int overlay) {
|
||||
this.root.render(poseStack, consumer, packedLight, overlay);
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import com.craisinlord.antarchy.content.entity.DiamondMinecartEntity;
|
||||
import com.craisinlord.antarchy.content.network.DiamondMinecartInputPayload;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
public final class DiamondMinecartClientHandler {
|
||||
|
||||
private DiamondMinecartClientHandler() {
|
||||
}
|
||||
|
||||
|
||||
private static byte lastFlags = 0;
|
||||
|
||||
public static void tick() {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
|
||||
if (!AntarchySettings.diamondMinecartEnabled()) return;
|
||||
if (mc.player == null || mc.level == null) return;
|
||||
if (!(mc.player.getVehicle() instanceof DiamondMinecartEntity)) return;
|
||||
if (mc.screen != null) {
|
||||
if (lastFlags != 0) {
|
||||
ClientPlayNetworking.send(new DiamondMinecartInputPayload((byte) 0));
|
||||
lastFlags = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
byte flags = 0;
|
||||
if (mc.options.keyUp.isDown()) flags |= DiamondMinecartInputPayload.FLAG_FORWARD;
|
||||
if (mc.options.keyDown.isDown()) flags |= DiamondMinecartInputPayload.FLAG_BACK;
|
||||
if (mc.options.keyLeft.isDown()) flags |= DiamondMinecartInputPayload.FLAG_LEFT;
|
||||
if (mc.options.keyRight.isDown()) flags |= DiamondMinecartInputPayload.FLAG_RIGHT;
|
||||
|
||||
if (flags != lastFlags) {
|
||||
ClientPlayNetworking.send(new DiamondMinecartInputPayload(flags));
|
||||
lastFlags = flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import com.craisinlord.antarchy.content.AntarchyTags;
|
||||
import com.craisinlord.antarchy.fabric.AntarchyFabricContent;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.screens.DeathScreen;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.HolderSet;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
|
||||
public final class DreadClientHandler {
|
||||
private static final Holder<net.minecraft.world.effect.MobEffect> DREAD_EFFECT =
|
||||
BuiltInRegistries.MOB_EFFECT.wrapAsHolder(AntarchyFabricContent.DREAD.get());
|
||||
private static final int FOOTSTEP_MIN_INTERVAL_TICKS = 10;
|
||||
private static final int FOOTSTEP_MAX_INTERVAL_TICKS = 22;
|
||||
private static final int APPARITION_MIN_DURATION_TICKS = 16;
|
||||
private static final int APPARITION_MAX_DURATION_TICKS = 34;
|
||||
private static final int LUNGE_MIN_DURATION_TICKS = 10;
|
||||
private static final int LUNGE_MAX_DURATION_TICKS = 16;
|
||||
|
||||
private static int nextSoundTick = 0;
|
||||
private static int nextApparitionTick = 0;
|
||||
private static int nextFootstepTick = 0;
|
||||
private static final List<ApparitionEntry> ACTIVE_APPARITIONS = new ArrayList<>();
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
private DreadClientHandler() {
|
||||
}
|
||||
|
||||
private enum ApparitionType {
|
||||
PERIPHERAL_SILHOUETTE,
|
||||
CROSSING_SHADOW,
|
||||
LUNGE_FLASH
|
||||
}
|
||||
|
||||
private static final class ApparitionEntry {
|
||||
private final ApparitionType type;
|
||||
private final float scale;
|
||||
private final int lifetime;
|
||||
private final int baseColor;
|
||||
private float xNorm;
|
||||
private float yNorm;
|
||||
private float xVelocity;
|
||||
private float yVelocity;
|
||||
private int age;
|
||||
|
||||
private ApparitionEntry(ApparitionType type, float xNorm, float yNorm, float xVelocity, float yVelocity, float scale, int lifetime, int baseColor) {
|
||||
this.type = type;
|
||||
this.xNorm = xNorm;
|
||||
this.yNorm = yNorm;
|
||||
this.xVelocity = xVelocity;
|
||||
this.yVelocity = yVelocity;
|
||||
this.scale = scale;
|
||||
this.lifetime = lifetime;
|
||||
this.baseColor = baseColor;
|
||||
}
|
||||
|
||||
private void tick() {
|
||||
this.age++;
|
||||
this.xNorm += this.xVelocity;
|
||||
this.yNorm += this.yVelocity;
|
||||
}
|
||||
|
||||
private boolean expired() {
|
||||
return this.age >= this.lifetime;
|
||||
}
|
||||
|
||||
private float alpha() {
|
||||
float progress = this.lifetime <= 0 ? 1.0F : (float) this.age / (float) this.lifetime;
|
||||
return Mth.clamp(Mth.sin(progress * (float) Math.PI), 0.0F, 1.0F);
|
||||
}
|
||||
}
|
||||
|
||||
public static void tick() {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (mc.level == null || mc.player == null) {
|
||||
resetState();
|
||||
return;
|
||||
}
|
||||
if (mc.isPaused()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = mc.player;
|
||||
if (!player.isAlive() || player.isRemoved() || player.deathTime > 0 || player.isDeadOrDying() || mc.screen instanceof DeathScreen) {
|
||||
resetState();
|
||||
return;
|
||||
}
|
||||
|
||||
tickApparitions();
|
||||
|
||||
if (!player.hasEffect(DREAD_EFFECT)) {
|
||||
resetState();
|
||||
return;
|
||||
}
|
||||
|
||||
if (AntarchySettings.dreadHallucinationSoundsEnabled()) {
|
||||
nextSoundTick--;
|
||||
if (nextSoundTick <= 0) {
|
||||
playHallucinationSound(mc, player);
|
||||
nextSoundTick = randomIntervalTicks(
|
||||
AntarchySettings.dreadHallucinationSoundMinInterval(),
|
||||
AntarchySettings.dreadHallucinationSoundMaxInterval()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
nextSoundTick = 0;
|
||||
}
|
||||
|
||||
nextFootstepTick--;
|
||||
if (nextFootstepTick <= 0) {
|
||||
if (player.onGround() && player.getDeltaMovement().horizontalDistanceSqr() > 0.0025D) {
|
||||
playFootstepSound(mc, player);
|
||||
nextFootstepTick = randomTickInterval(FOOTSTEP_MIN_INTERVAL_TICKS, FOOTSTEP_MAX_INTERVAL_TICKS);
|
||||
} else {
|
||||
nextFootstepTick = 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (AntarchySettings.dreadHallucinationMobsEnabled()) {
|
||||
nextApparitionTick--;
|
||||
if (nextApparitionTick <= 0) {
|
||||
spawnApparition(mc, player);
|
||||
nextApparitionTick = randomIntervalTicks(
|
||||
AntarchySettings.dreadHallucinationMobMinInterval(),
|
||||
AntarchySettings.dreadHallucinationMobMaxInterval()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
nextApparitionTick = 0;
|
||||
ACTIVE_APPARITIONS.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static void render(GuiGraphics guiGraphics) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
Player player = mc.player;
|
||||
if (player == null || !player.hasEffect(DREAD_EFFECT) || ACTIVE_APPARITIONS.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int width = mc.getWindow().getGuiScaledWidth();
|
||||
int height = mc.getWindow().getGuiScaledHeight();
|
||||
for (ApparitionEntry entry : ACTIVE_APPARITIONS) {
|
||||
float alpha = entry.alpha();
|
||||
if (alpha <= 0.01F) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (entry.type) {
|
||||
case PERIPHERAL_SILHOUETTE -> renderPeripheralSilhouette(guiGraphics, width, height, entry, alpha);
|
||||
case CROSSING_SHADOW -> renderCrossingShadow(guiGraphics, width, height, entry, alpha);
|
||||
case LUNGE_FLASH -> renderLungeFlash(guiGraphics, width, height, entry, alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void tickApparitions() {
|
||||
Iterator<ApparitionEntry> iterator = ACTIVE_APPARITIONS.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
ApparitionEntry entry = iterator.next();
|
||||
entry.tick();
|
||||
if (entry.expired()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void playHallucinationSound(Minecraft mc, Player player) {
|
||||
Optional<HolderSet.Named<SoundEvent>> tagOpt =
|
||||
BuiltInRegistries.SOUND_EVENT.getTag(AntarchyTags.SoundEvents.DREAD_HALLUCINATION_SOUNDS);
|
||||
if (tagOpt.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Holder<SoundEvent>> sounds = tagOpt.get().stream().toList();
|
||||
if (sounds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SoundEvent soundEvent = sounds.get(RANDOM.nextInt(sounds.size())).value();
|
||||
|
||||
Vec3 look = player.getLookAngle();
|
||||
double baseAngle = Math.atan2(-look.x, -look.z);
|
||||
double spread = (RANDOM.nextDouble() - 0.5D) * Math.PI;
|
||||
double angle = baseAngle + spread;
|
||||
double distance = 10.0D + RANDOM.nextDouble() * 15.0D;
|
||||
|
||||
double soundX = player.getX() + Math.sin(angle) * distance;
|
||||
double soundY = player.getY() + RANDOM.nextDouble() * 4.0D - 1.0D;
|
||||
double soundZ = player.getZ() + Math.cos(angle) * distance;
|
||||
|
||||
mc.level.playLocalSound(
|
||||
soundX,
|
||||
soundY,
|
||||
soundZ,
|
||||
soundEvent,
|
||||
SoundSource.HOSTILE,
|
||||
1.0F,
|
||||
0.85F + RANDOM.nextFloat() * 0.3F,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
private static void spawnApparition(Minecraft mc, Player player) {
|
||||
double roll = RANDOM.nextDouble();
|
||||
if (roll < 0.5D) {
|
||||
spawnPeripheralSilhouette();
|
||||
return;
|
||||
}
|
||||
if (roll < 0.82D) {
|
||||
spawnCrossingShadow();
|
||||
return;
|
||||
}
|
||||
spawnLungeFlash(mc, player);
|
||||
}
|
||||
|
||||
private static void spawnPeripheralSilhouette() {
|
||||
boolean leftSide = RANDOM.nextBoolean();
|
||||
float xNorm = leftSide ? 0.08F + RANDOM.nextFloat() * 0.08F : 0.84F + RANDOM.nextFloat() * 0.08F;
|
||||
float yNorm = 0.48F + (RANDOM.nextFloat() - 0.5F) * 0.26F;
|
||||
float scale = 0.85F + RANDOM.nextFloat() * 0.4F;
|
||||
int lifetime = randomTickInterval(APPARITION_MIN_DURATION_TICKS, APPARITION_MAX_DURATION_TICKS);
|
||||
ACTIVE_APPARITIONS.add(new ApparitionEntry(
|
||||
ApparitionType.PERIPHERAL_SILHOUETTE,
|
||||
xNorm,
|
||||
yNorm,
|
||||
leftSide ? -0.0015F : 0.0015F,
|
||||
0.0F,
|
||||
scale,
|
||||
lifetime,
|
||||
0x160000
|
||||
));
|
||||
}
|
||||
|
||||
private static void spawnCrossingShadow() {
|
||||
boolean leftToRight = RANDOM.nextBoolean();
|
||||
float xNorm = leftToRight ? -0.18F : 1.18F;
|
||||
float yNorm = 0.38F + RANDOM.nextFloat() * 0.36F;
|
||||
float velocity = leftToRight ? 0.04F + RANDOM.nextFloat() * 0.015F : -(0.04F + RANDOM.nextFloat() * 0.015F);
|
||||
float scale = 0.9F + RANDOM.nextFloat() * 0.45F;
|
||||
int lifetime = randomTickInterval(APPARITION_MIN_DURATION_TICKS, APPARITION_MAX_DURATION_TICKS);
|
||||
ACTIVE_APPARITIONS.add(new ApparitionEntry(
|
||||
ApparitionType.CROSSING_SHADOW,
|
||||
xNorm,
|
||||
yNorm,
|
||||
velocity,
|
||||
0.0F,
|
||||
scale,
|
||||
lifetime,
|
||||
0x1A0000
|
||||
));
|
||||
}
|
||||
|
||||
private static void spawnLungeFlash(Minecraft mc, Player player) {
|
||||
float xNorm = 0.5F + (RANDOM.nextBoolean() ? -1.0F : 1.0F) * (0.12F + RANDOM.nextFloat() * 0.12F);
|
||||
float yNorm = 0.58F + (RANDOM.nextFloat() - 0.5F) * 0.12F;
|
||||
float scale = 0.95F + RANDOM.nextFloat() * 0.35F;
|
||||
int lifetime = randomTickInterval(LUNGE_MIN_DURATION_TICKS, LUNGE_MAX_DURATION_TICKS);
|
||||
ACTIVE_APPARITIONS.add(new ApparitionEntry(
|
||||
ApparitionType.LUNGE_FLASH,
|
||||
xNorm,
|
||||
yNorm,
|
||||
0.0F,
|
||||
-0.002F,
|
||||
scale,
|
||||
lifetime,
|
||||
0x2A0000
|
||||
));
|
||||
mc.level.playLocalSound(
|
||||
player.getX(),
|
||||
player.getY() + 1.0D,
|
||||
player.getZ(),
|
||||
AntarchyFabricContent.NIGHTMARE_BITE.get(),
|
||||
SoundSource.HOSTILE,
|
||||
0.4F,
|
||||
0.88F + RANDOM.nextFloat() * 0.12F,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
private static void playFootstepSound(Minecraft mc, Player player) {
|
||||
double soundX = player.getX() + (RANDOM.nextDouble() - 0.5D) * 1.2D;
|
||||
double soundY = player.getY() - 0.95D;
|
||||
double soundZ = player.getZ() + (RANDOM.nextDouble() - 0.5D) * 1.2D;
|
||||
|
||||
mc.level.playLocalSound(
|
||||
soundX,
|
||||
soundY,
|
||||
soundZ,
|
||||
SoundEvents.SILVERFISH_STEP,
|
||||
SoundSource.HOSTILE,
|
||||
0.45F,
|
||||
0.85F + RANDOM.nextFloat() * 0.25F,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
private static void renderPeripheralSilhouette(GuiGraphics guiGraphics, int width, int height, ApparitionEntry entry, float alpha) {
|
||||
int centerX = Math.round(entry.xNorm * width);
|
||||
int baseY = Math.round(entry.yNorm * height);
|
||||
int bodyWidth = Math.round(width * 0.045F * entry.scale);
|
||||
int bodyHeight = Math.round(height * 0.24F * entry.scale);
|
||||
int headSize = Math.round(bodyWidth * 0.78F);
|
||||
int x0 = centerX - bodyWidth / 2;
|
||||
int y0 = baseY - bodyHeight / 2;
|
||||
|
||||
int outerColor = alphaColor(entry.baseColor, alpha * 0.8F);
|
||||
int innerColor = alphaColor(0x5A0000, alpha * 0.22F);
|
||||
|
||||
guiGraphics.fill(x0, y0, x0 + bodyWidth, y0 + bodyHeight, outerColor);
|
||||
guiGraphics.fill(x0 - headSize / 2 + bodyWidth / 2, y0 - headSize / 2, x0 + bodyWidth / 2 + headSize / 2, y0 + headSize / 2, outerColor);
|
||||
guiGraphics.fill(x0 + bodyWidth / 6, y0 + bodyHeight / 6, x0 + bodyWidth - bodyWidth / 6, y0 + bodyHeight - bodyHeight / 7, innerColor);
|
||||
}
|
||||
|
||||
private static void renderCrossingShadow(GuiGraphics guiGraphics, int width, int height, ApparitionEntry entry, float alpha) {
|
||||
int centerX = Math.round(entry.xNorm * width);
|
||||
int centerY = Math.round(entry.yNorm * height);
|
||||
int shadowWidth = Math.round(width * 0.22F * entry.scale);
|
||||
int shadowHeight = Math.round(height * 0.035F * entry.scale);
|
||||
|
||||
int outerColor = alphaColor(entry.baseColor, alpha * 0.65F);
|
||||
int innerColor = alphaColor(0x340000, alpha * 0.28F);
|
||||
|
||||
guiGraphics.fill(centerX - shadowWidth / 2, centerY - shadowHeight / 2, centerX + shadowWidth / 2, centerY + shadowHeight / 2, outerColor);
|
||||
guiGraphics.fill(centerX - shadowWidth / 3, centerY - shadowHeight, centerX + shadowWidth / 3, centerY + shadowHeight, innerColor);
|
||||
}
|
||||
|
||||
private static void renderLungeFlash(GuiGraphics guiGraphics, int width, int height, ApparitionEntry entry, float alpha) {
|
||||
int centerX = Math.round(entry.xNorm * width);
|
||||
int centerY = Math.round(entry.yNorm * height);
|
||||
int faceWidth = Math.round(width * 0.11F * entry.scale);
|
||||
int faceHeight = Math.round(height * 0.12F * entry.scale);
|
||||
|
||||
int shadowColor = alphaColor(entry.baseColor, alpha * 0.82F);
|
||||
int glowColor = alphaColor(0x4A0000, alpha * 0.25F);
|
||||
int eyeColor = alphaColor(0xB02020, alpha * 0.8F);
|
||||
|
||||
guiGraphics.fill(centerX - faceWidth / 2, centerY - faceHeight / 2, centerX + faceWidth / 2, centerY + faceHeight / 2, shadowColor);
|
||||
guiGraphics.fill(centerX - faceWidth, centerY - faceHeight / 3, centerX + faceWidth, centerY + faceHeight, glowColor);
|
||||
|
||||
int eyeWidth = Math.max(2, faceWidth / 7);
|
||||
int eyeHeight = Math.max(2, faceHeight / 12);
|
||||
int eyeY = centerY - faceHeight / 8;
|
||||
int eyeOffset = faceWidth / 4;
|
||||
guiGraphics.fill(centerX - eyeOffset - eyeWidth, eyeY, centerX - eyeOffset + eyeWidth, eyeY + eyeHeight, eyeColor);
|
||||
guiGraphics.fill(centerX + eyeOffset - eyeWidth, eyeY, centerX + eyeOffset + eyeWidth, eyeY + eyeHeight, eyeColor);
|
||||
}
|
||||
|
||||
private static void resetState() {
|
||||
ACTIVE_APPARITIONS.clear();
|
||||
nextSoundTick = 0;
|
||||
nextApparitionTick = 0;
|
||||
nextFootstepTick = 0;
|
||||
}
|
||||
|
||||
private static int randomIntervalTicks(double minSeconds, double maxSeconds) {
|
||||
double seconds = minSeconds + RANDOM.nextDouble() * Math.max(0.0D, maxSeconds - minSeconds);
|
||||
return Math.max(1, (int) (seconds * 20.0D));
|
||||
}
|
||||
|
||||
private static int randomTickInterval(int minTicks, int maxTicks) {
|
||||
return minTicks + RANDOM.nextInt(Math.max(1, maxTicks - minTicks + 1));
|
||||
}
|
||||
|
||||
private static int alphaColor(int rgb, float alpha) {
|
||||
int alphaByte = Mth.clamp((int) (alpha * 255.0F), 0, 255);
|
||||
return (alphaByte << 24) | rgb;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.fabric.AntarchyFabricContent;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
public final class DreadHudRenderer {
|
||||
private static final Holder<MobEffect> DREAD_EFFECT = BuiltInRegistries.MOB_EFFECT.wrapAsHolder(AntarchyFabricContent.DREAD.get());
|
||||
|
||||
private DreadHudRenderer() {
|
||||
}
|
||||
|
||||
public static void render(GuiGraphics guiGraphics) {
|
||||
Minecraft minecraft = Minecraft.getInstance();
|
||||
Player player = minecraft.player;
|
||||
if (player == null || minecraft.screen != null || player.isDeadOrDying() || !player.hasEffect(DREAD_EFFECT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
float pulse = Math.max(0.0F, Mth.sin(player.tickCount * ((float) Math.PI * 2.0F / 80.0F)));
|
||||
int alpha = Mth.clamp(18 + Mth.floor(pulse * 64.0F), 0, 255);
|
||||
int color = (alpha << 24) | 0x120000;
|
||||
int width = minecraft.getWindow().getGuiScaledWidth();
|
||||
int height = minecraft.getWindow().getGuiScaledHeight();
|
||||
guiGraphics.fill(0, 0, width, height, color);
|
||||
DreadClientHandler.render(guiGraphics);
|
||||
}
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import com.craisinlord.antarchy.content.AntarchySoundEvents;
|
||||
import com.craisinlord.antarchy.content.client.renderer.ElythiaSkyRenderer;
|
||||
import com.craisinlord.antarchy.fabric.AntarchyFabricContent;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
public final class ElythiaFireflyManager {
|
||||
private static final long NIGHT_START = 13000L;
|
||||
private static final long NIGHT_END = 23000L;
|
||||
private static final int SPAWN_INTERVAL = 3;
|
||||
private static final int SPAWN_RADIUS_H = 20;
|
||||
private static final int SPAWN_Y_MIN = -2;
|
||||
private static final int SPAWN_Y_MAX = 10;
|
||||
private static final int SOUND_INTERVAL_MIN = 250;
|
||||
private static final int SOUND_INTERVAL_MAX = 450;
|
||||
|
||||
private static int nextSoundTick = SOUND_INTERVAL_MIN;
|
||||
|
||||
private ElythiaFireflyManager() {}
|
||||
|
||||
public static void register() {
|
||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||
ClientLevel level = client.level;
|
||||
if (level == null || client.player == null) return;
|
||||
if (client.isPaused()) return;
|
||||
if (!ElythiaSkyRenderer.shouldRender(level)) return;
|
||||
|
||||
long dayTime = level.getDayTime() % 24000L;
|
||||
if (dayTime < NIGHT_START || dayTime > NIGHT_END) return;
|
||||
|
||||
long gameTime = level.getGameTime();
|
||||
|
||||
if (AntarchySettings.elythiaFireflyParticlesEnabled()) {
|
||||
if (gameTime % SPAWN_INTERVAL == 0) {
|
||||
Player player = client.player;
|
||||
int px = (int) player.getX();
|
||||
int py = (int) player.getY();
|
||||
int pz = (int) player.getZ();
|
||||
|
||||
int attempts = 1 + level.random.nextInt(3);
|
||||
for (int i = 0; i < attempts; i++) {
|
||||
int ox = level.random.nextInt(SPAWN_RADIUS_H * 2 + 1) - SPAWN_RADIUS_H;
|
||||
int oy = SPAWN_Y_MIN + level.random.nextInt(SPAWN_Y_MAX - SPAWN_Y_MIN + 1);
|
||||
int oz = level.random.nextInt(SPAWN_RADIUS_H * 2 + 1) - SPAWN_RADIUS_H;
|
||||
|
||||
BlockPos candidate = new BlockPos(px + ox, py + oy, pz + oz);
|
||||
if (!level.getBlockState(candidate).isAir()) continue;
|
||||
|
||||
level.addParticle(
|
||||
AntarchyFabricContent.FIREFLY.get(),
|
||||
candidate.getX() + level.random.nextDouble(),
|
||||
candidate.getY() + level.random.nextDouble(),
|
||||
candidate.getZ() + level.random.nextDouble(),
|
||||
0.0, 0.0, 0.0
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nextSoundTick--;
|
||||
if (nextSoundTick <= 0) {
|
||||
nextSoundTick = SOUND_INTERVAL_MIN + level.random.nextInt(SOUND_INTERVAL_MAX - SOUND_INTERVAL_MIN + 1);
|
||||
Player player = client.player;
|
||||
level.playLocalSound(
|
||||
player.getX(), player.getY(), player.getZ(),
|
||||
AntarchySoundEvents.ELYTHIA_FIREFLY_AMBIENT.get(),
|
||||
SoundSource.AMBIENT,
|
||||
0.6f + level.random.nextFloat() * 0.3f,
|
||||
0.9f + level.random.nextFloat() * 0.2f,
|
||||
false
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.fabric.AntarchyFabricContent;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.entity.ItemRenderer;
|
||||
import net.minecraft.client.model.PlayerModel;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.RenderLayerParent;
|
||||
import net.minecraft.client.renderer.entity.layers.RenderLayer;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
public final class FallenKingCrownLayer extends RenderLayer<AbstractClientPlayer, PlayerModel<AbstractClientPlayer>> {
|
||||
private static final ModelResourceLocation WORN_MODEL = ModelResourceLocation.inventory(
|
||||
net.minecraft.resources.ResourceLocation.fromNamespaceAndPath("antarchy", "fallen_king_crown_worn")
|
||||
);
|
||||
private final ItemRenderer itemRenderer;
|
||||
|
||||
public FallenKingCrownLayer(RenderLayerParent<AbstractClientPlayer, PlayerModel<AbstractClientPlayer>> renderer) {
|
||||
super(renderer);
|
||||
this.itemRenderer = Minecraft.getInstance().getItemRenderer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
PoseStack poseStack,
|
||||
MultiBufferSource buffer,
|
||||
int packedLight,
|
||||
AbstractClientPlayer player,
|
||||
float limbSwing,
|
||||
float limbSwingAmount,
|
||||
float partialTick,
|
||||
float ageInTicks,
|
||||
float netHeadYaw,
|
||||
float headPitch
|
||||
) {
|
||||
ItemStack headStack = player.getItemBySlot(EquipmentSlot.HEAD);
|
||||
if (!headStack.is(AntarchyFabricContent.FALLEN_KING_CROWN.get()) || player.isInvisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
poseStack.pushPose();
|
||||
this.getParentModel().head.translateAndRotate(poseStack);
|
||||
this.itemRenderer.render(
|
||||
headStack,
|
||||
ItemDisplayContext.HEAD,
|
||||
false,
|
||||
poseStack,
|
||||
buffer,
|
||||
packedLight,
|
||||
LivingEntityRenderer.getOverlayCoords(player, 0.0F),
|
||||
Minecraft.getInstance().getModelManager().getModel(WORN_MODEL)
|
||||
);
|
||||
poseStack.popPose();
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import com.craisinlord.antarchy.content.item.GravityGunItem;
|
||||
import com.craisinlord.antarchy.content.network.GravityGunPrimaryPayload;
|
||||
import com.craisinlord.antarchy.content.network.GravityGunScrollPayload;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.util.Mth;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
public final class GravityGunClientHandler {
|
||||
private static final double SCROLL_STEP_DISTANCE = 0.75D;
|
||||
private static boolean lastAttackDown;
|
||||
private static double scrollAccumulator;
|
||||
|
||||
private GravityGunClientHandler() {
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
ClientTickEvents.END_CLIENT_TICK.register(client -> tickMouse(client));
|
||||
}
|
||||
|
||||
private static void tickMouse(Minecraft mc) {
|
||||
if (mc.player == null || mc.level == null || mc.screen != null || !AntarchySettings.gravityGunEnabled()) {
|
||||
lastAttackDown = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(mc.player.getMainHandItem().getItem() instanceof GravityGunItem)) {
|
||||
lastAttackDown = false;
|
||||
return;
|
||||
}
|
||||
|
||||
long window = mc.getWindow().getWindow();
|
||||
boolean attackDown = org.lwjgl.glfw.GLFW.glfwGetMouseButton(window, GLFW.GLFW_MOUSE_BUTTON_LEFT) == GLFW.GLFW_PRESS;
|
||||
if (attackDown && !lastAttackDown) {
|
||||
ClientPlayNetworking.send(new GravityGunPrimaryPayload());
|
||||
}
|
||||
lastAttackDown = attackDown;
|
||||
}
|
||||
|
||||
public static boolean onScroll(double verticalAmount) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (mc.player == null || mc.level == null || mc.screen != null || !Screen.hasControlDown() || !AntarchySettings.gravityGunEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(mc.player.getMainHandItem().getItem() instanceof GravityGunItem) || !GravityGunItem.hasHeldTarget(mc.player.getMainHandItem())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
double scrollAmount = Mth.clamp(verticalAmount, -1.0D, 1.0D);
|
||||
if (Math.abs(scrollAmount) < 1.0E-4D) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ClientPlayNetworking.send(new GravityGunScrollPayload(scrollAmount * SCROLL_STEP_DISTANCE));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.content.client.particle.InvertedGeyserBaseParticleOptions;
|
||||
import com.craisinlord.antarchy.content.client.particle.InvertedGeyserParticleOptions;
|
||||
import com.craisinlord.antarchy.fabric.AntarchyFabricContent;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.particle.NoRenderParticle;
|
||||
import net.minecraft.client.particle.Particle;
|
||||
import net.minecraft.client.particle.ParticleProvider;
|
||||
|
||||
public final class InvertedGeyserEruptionParticle extends NoRenderParticle {
|
||||
private final int fluidBlocks;
|
||||
private final double motionX;
|
||||
private final double motionY;
|
||||
private final double motionZ;
|
||||
private final InvertedGeyserParticleOptions plumeParticle;
|
||||
private final InvertedGeyserBaseParticleOptions baseParticle;
|
||||
private final InvertedGeyserBaseParticleOptions poofParticle;
|
||||
|
||||
protected InvertedGeyserEruptionParticle(
|
||||
ClientLevel level,
|
||||
double x,
|
||||
double y,
|
||||
double z,
|
||||
double xd,
|
||||
double yd,
|
||||
double zd,
|
||||
InvertedGeyserParticleOptions options
|
||||
) {
|
||||
super(level, x, y, z);
|
||||
this.motionX = xd;
|
||||
this.motionY = yd;
|
||||
this.motionZ = zd;
|
||||
this.fluidBlocks = options.fluidBlocks();
|
||||
this.lifetime = 20;
|
||||
this.plumeParticle = new InvertedGeyserParticleOptions(AntarchyFabricContent.INVERTED_GEYSER_PLUME.get(), this.fluidBlocks, options.direction());
|
||||
this.baseParticle = new InvertedGeyserBaseParticleOptions(AntarchyFabricContent.INVERTED_GEYSER_BASE.get(), this.fluidBlocks, 1.5F, options.direction());
|
||||
this.poofParticle = new InvertedGeyserBaseParticleOptions(AntarchyFabricContent.INVERTED_GEYSER_POOF.get(), this.fluidBlocks, 2.0F, options.direction());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (this.age % 2 == 0) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
this.level.addParticle(this.baseParticle, this.x, this.y, this.z, this.motionX, this.motionY, this.motionZ);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < this.fluidBlocks + 2; i++) {
|
||||
this.level.addParticle(this.plumeParticle, this.x, this.y, this.z, this.motionX, this.motionY, this.motionZ);
|
||||
}
|
||||
|
||||
if (this.age % 10 == 0) {
|
||||
for (int i = 0; i < 20; i++) {
|
||||
this.level.addParticle(this.poofParticle, this.x, this.y, this.z, this.motionX, this.motionY, this.motionZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Provider implements ParticleProvider<InvertedGeyserParticleOptions> {
|
||||
@Override
|
||||
public Particle createParticle(
|
||||
InvertedGeyserParticleOptions options,
|
||||
ClientLevel level,
|
||||
double x,
|
||||
double y,
|
||||
double z,
|
||||
double xd,
|
||||
double yd,
|
||||
double zd
|
||||
) {
|
||||
return new InvertedGeyserEruptionParticle(level, x, y, z, xd, yd, zd, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.content.entity.lucid.LucidEntity;
|
||||
import com.craisinlord.antarchy.fabric.AntarchyFabricContent;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.screens.DeathScreen;
|
||||
import net.minecraft.client.resources.sounds.AbstractTickableSoundInstance;
|
||||
import net.minecraft.client.resources.sounds.SoundInstance;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class LucidSoundHandler {
|
||||
private static final double START_SCAN_RADIUS = 96.0D;
|
||||
private static final int ANIM_ATTACK = 2;
|
||||
private static final int ANIM_DEATH = 3;
|
||||
private static final Map<UUID, LucidLoopSet> ACTIVE_LOOPS = new HashMap<>();
|
||||
|
||||
private LucidSoundHandler() {
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||
if (client.level == null || client.player == null || client.isPaused()) {
|
||||
resetAll(client);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!client.player.isAlive() || client.player.isRemoved() || client.player.isDeadOrDying()
|
||||
|| client.screen instanceof DeathScreen) {
|
||||
resetAll(client);
|
||||
return;
|
||||
}
|
||||
|
||||
pruneStaleLoops(client);
|
||||
refreshNearbyLucids(client);
|
||||
});
|
||||
}
|
||||
|
||||
private static void refreshNearbyLucids(Minecraft mc) {
|
||||
List<LucidEntity> lucids = mc.level.getEntitiesOfClass(
|
||||
LucidEntity.class,
|
||||
mc.player.getBoundingBox().inflate(START_SCAN_RADIUS)
|
||||
);
|
||||
|
||||
for (LucidEntity lucid : lucids) {
|
||||
if (!lucid.shouldPlayAmbientLoop()) continue;
|
||||
|
||||
LucidLoopSet set = ACTIVE_LOOPS.get(lucid.getUUID());
|
||||
if (set == null) {
|
||||
set = new LucidLoopSet(lucid);
|
||||
ACTIVE_LOOPS.put(lucid.getUUID(), set);
|
||||
set.start(mc);
|
||||
} else {
|
||||
set.refresh(mc, lucid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void pruneStaleLoops(Minecraft mc) {
|
||||
Iterator<Map.Entry<UUID, LucidLoopSet>> iterator = ACTIVE_LOOPS.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
LucidLoopSet set = iterator.next().getValue();
|
||||
if (!set.isValid()) {
|
||||
set.stop(mc);
|
||||
iterator.remove();
|
||||
} else if (!set.entity.shouldPlayAmbientLoop()) {
|
||||
set.stop(mc);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void resetAll(Minecraft mc) {
|
||||
for (LucidLoopSet set : ACTIVE_LOOPS.values()) {
|
||||
set.stop(mc);
|
||||
}
|
||||
ACTIVE_LOOPS.clear();
|
||||
}
|
||||
|
||||
private static final class LucidLoopSet {
|
||||
private LucidEntity entity;
|
||||
@Nullable private LucidLoopSound ambient;
|
||||
@Nullable private LucidLoopSound flying;
|
||||
private int lastAnimationState = -1;
|
||||
|
||||
private LucidLoopSet(LucidEntity entity) {
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
private boolean isValid() {
|
||||
return entity != null && entity.isAlive() && !entity.isRemoved();
|
||||
}
|
||||
|
||||
private void start(Minecraft mc) {
|
||||
playAttackSoundIfNeeded(mc, entity);
|
||||
|
||||
if (ambient == null || !mc.getSoundManager().isActive(ambient)) {
|
||||
ambient = new LucidLoopSound(entity, AntarchyFabricContent.LUCID_AMBIENT.get(),
|
||||
SoundSource.HOSTILE, 0.14F, 0.97F, true);
|
||||
mc.getSoundManager().play(ambient);
|
||||
}
|
||||
|
||||
if (entity.shouldPlayFlyingLoop() && (flying == null || !mc.getSoundManager().isActive(flying))) {
|
||||
flying = new LucidLoopSound(entity, AntarchyFabricContent.LUCID_FLYING.get(),
|
||||
SoundSource.HOSTILE, 0.18F, 1.0F, false);
|
||||
mc.getSoundManager().play(flying);
|
||||
}
|
||||
}
|
||||
|
||||
private void refresh(Minecraft mc, LucidEntity entity) {
|
||||
this.entity = entity;
|
||||
playAttackSoundIfNeeded(mc, entity);
|
||||
|
||||
if (ambient == null || !mc.getSoundManager().isActive(ambient)) {
|
||||
ambient = new LucidLoopSound(entity, AntarchyFabricContent.LUCID_AMBIENT.get(),
|
||||
SoundSource.HOSTILE, 0.14F, 0.97F, true);
|
||||
mc.getSoundManager().play(ambient);
|
||||
} else {
|
||||
ambient.setEntity(entity);
|
||||
}
|
||||
|
||||
if (entity.shouldPlayFlyingLoop()) {
|
||||
if (flying == null || !mc.getSoundManager().isActive(flying)) {
|
||||
flying = new LucidLoopSound(entity, AntarchyFabricContent.LUCID_FLYING.get(),
|
||||
SoundSource.HOSTILE, 0.18F, 1.0F, false);
|
||||
mc.getSoundManager().play(flying);
|
||||
} else {
|
||||
flying.setEntity(entity);
|
||||
}
|
||||
} else if (flying != null) {
|
||||
mc.getSoundManager().stop(flying);
|
||||
flying = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void stop(Minecraft mc) {
|
||||
if (ambient != null) { mc.getSoundManager().stop(ambient); ambient = null; }
|
||||
if (flying != null) { mc.getSoundManager().stop(flying); flying = null; }
|
||||
lastAnimationState = -1;
|
||||
}
|
||||
|
||||
private void playAttackSoundIfNeeded(Minecraft mc, LucidEntity entity) {
|
||||
int currentState = entity.getAnimationState();
|
||||
if (currentState == ANIM_ATTACK && lastAnimationState != ANIM_ATTACK) {
|
||||
mc.getSoundManager().play(new LucidOneShotSound(entity, AntarchyFabricContent.LUCID_ATTACK.get(),
|
||||
SoundSource.HOSTILE, 1.0F, 1.02F + entity.getRandom().nextFloat() * 0.08F));
|
||||
}
|
||||
lastAnimationState = currentState;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class LucidLoopSound extends AbstractTickableSoundInstance {
|
||||
private LucidEntity entity;
|
||||
private final boolean ambient;
|
||||
|
||||
private LucidLoopSound(LucidEntity entity, SoundEvent soundEvent, SoundSource source,
|
||||
float volume, float pitch, boolean ambient) {
|
||||
super(soundEvent, source, RandomSource.create());
|
||||
this.entity = entity;
|
||||
this.ambient = ambient;
|
||||
this.looping = true;
|
||||
this.delay = 0;
|
||||
this.relative = false;
|
||||
this.attenuation = SoundInstance.Attenuation.LINEAR;
|
||||
this.volume = volume;
|
||||
this.pitch = pitch;
|
||||
this.x = entity.getX();
|
||||
this.y = entity.getY();
|
||||
this.z = entity.getZ();
|
||||
}
|
||||
|
||||
private void setEntity(LucidEntity entity) { this.entity = entity; }
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (entity == null || entity.isRemoved() || entity.isDeadOrDying()
|
||||
|| entity.getAnimationState() == ANIM_DEATH || !entity.shouldPlayAmbientLoop()) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
if (!ambient && !entity.shouldPlayFlyingLoop()) { stop(); return; }
|
||||
x = entity.getX(); y = entity.getY(); z = entity.getZ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canStartSilent() { return true; }
|
||||
}
|
||||
|
||||
private static final class LucidOneShotSound extends AbstractTickableSoundInstance {
|
||||
private final LucidEntity entity;
|
||||
|
||||
private LucidOneShotSound(LucidEntity entity, SoundEvent soundEvent, SoundSource source,
|
||||
float volume, float pitch) {
|
||||
super(soundEvent, source, RandomSource.create());
|
||||
this.entity = entity;
|
||||
this.looping = false;
|
||||
this.delay = 0;
|
||||
this.relative = false;
|
||||
this.attenuation = SoundInstance.Attenuation.LINEAR;
|
||||
this.volume = volume;
|
||||
this.pitch = pitch;
|
||||
this.x = entity.getX();
|
||||
this.y = entity.getY();
|
||||
this.z = entity.getZ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (entity == null || entity.isRemoved() || entity.isDeadOrDying()
|
||||
|| entity.getAnimationState() == ANIM_DEATH) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
x = entity.getX(); y = entity.getY(); z = entity.getZ();
|
||||
}
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.content.item.MogglesCaveDetector;
|
||||
import com.craisinlord.antarchy.content.item.MogglesLogic;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public final class MogglesClientRenderer {
|
||||
private MogglesClientRenderer() {}
|
||||
|
||||
public static void register() {
|
||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||
Player player = client.player;
|
||||
Level level = client.level;
|
||||
if (player == null || level == null) return;
|
||||
|
||||
if (!MogglesLogic.isWearingMoggles(player) || level.canSeeSky(player.blockPosition())) {
|
||||
MogglesCaveDetector.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
MogglesCaveDetector.tick(player, level);
|
||||
|
||||
BlockPos target = MogglesCaveDetector.getCaveTarget();
|
||||
if (target == null) return;
|
||||
|
||||
if (level.getGameTime() % 2 != 0) return;
|
||||
|
||||
Vec3 eye = player.getEyePosition();
|
||||
Vec3 end = Vec3.atCenterOf(target);
|
||||
double totalDist = eye.distanceTo(end);
|
||||
if (totalDist < 1.5) return;
|
||||
|
||||
Vec3 dir = end.subtract(eye).normalize();
|
||||
|
||||
int steps = Math.min(5, (int) (totalDist / 1.5));
|
||||
double spacing = (totalDist - 1.5) / Math.max(steps, 1);
|
||||
|
||||
for (int i = 0; i < steps; i++) {
|
||||
double t = 1.5 + i * spacing;
|
||||
Vec3 p = eye.add(dir.scale(t));
|
||||
Vec3 vel = dir.scale(0.04);
|
||||
level.addParticle(ParticleTypes.END_ROD,
|
||||
p.x, p.y, p.z,
|
||||
vel.x, vel.y, vel.z);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.fabric.AntarchyFabricContent;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.core.particles.BlockParticleOption;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
public final class ParalyzedClientHandler {
|
||||
private static final Holder<net.minecraft.world.effect.MobEffect> PARALYZED_EFFECT =
|
||||
BuiltInRegistries.MOB_EFFECT.wrapAsHolder(AntarchyFabricContent.PARALYZED.get());
|
||||
|
||||
|
||||
private static final int PARTICLE_INTERVAL = 3;
|
||||
|
||||
private static final int PARTICLES_PER_ENTITY = 4;
|
||||
|
||||
private static final double PARTICLE_RADIUS = 24.0;
|
||||
|
||||
private ParalyzedClientHandler() {
|
||||
}
|
||||
|
||||
|
||||
public static void clampPlayerInput(LocalPlayer player) {
|
||||
if (!player.hasEffect(PARALYZED_EFFECT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var input = player.input;
|
||||
input.left = false;
|
||||
input.right = false;
|
||||
input.up = false;
|
||||
input.down = false;
|
||||
input.leftImpulse = 0.0F;
|
||||
input.forwardImpulse = 0.0F;
|
||||
input.jumping = false;
|
||||
}
|
||||
|
||||
public static void tick() {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (mc.player == null || mc.level == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
LocalPlayer player = mc.player;
|
||||
if (player.hasEffect(PARALYZED_EFFECT)) {
|
||||
while (mc.options.keyAttack.consumeClick()) { }
|
||||
while (mc.options.keyUse.consumeClick()) { }
|
||||
}
|
||||
if (player.tickCount % PARTICLE_INTERVAL != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ClientLevel level = mc.level;
|
||||
level.getEntitiesOfClass(
|
||||
LivingEntity.class,
|
||||
player.getBoundingBox().inflate(PARTICLE_RADIUS),
|
||||
entity -> entity != player
|
||||
&& entity.isAlive()
|
||||
&& entity.hasEffect(PARALYZED_EFFECT)
|
||||
).forEach(entity -> spawnStoneParticles(level, entity));
|
||||
}
|
||||
|
||||
private static void spawnStoneParticles(ClientLevel level, LivingEntity entity) {
|
||||
BlockState stone = Blocks.STONE.defaultBlockState();
|
||||
BlockParticleOption particle = new BlockParticleOption(ParticleTypes.BLOCK, stone);
|
||||
|
||||
float w = entity.getBbWidth();
|
||||
float h = entity.getBbHeight();
|
||||
|
||||
for (int i = 0; i < PARTICLES_PER_ENTITY; i++) {
|
||||
double px = entity.getX() + (Math.random() - 0.5) * w;
|
||||
double py = entity.getY() + Math.random() * h;
|
||||
double pz = entity.getZ() + (Math.random() - 0.5) * w;
|
||||
|
||||
double vx = (Math.random() - 0.5) * 0.08;
|
||||
double vy = Math.random() * 0.06;
|
||||
double vz = (Math.random() - 0.5) * 0.08;
|
||||
|
||||
level.addParticle(particle, px, py, pz, vx, vy, vz);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.fabric.AntarchyFabricContent;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
public final class ParalyzedHudRenderer {
|
||||
private static final Holder<MobEffect> PARALYZED_EFFECT = BuiltInRegistries.MOB_EFFECT.wrapAsHolder(AntarchyFabricContent.PARALYZED.get());
|
||||
|
||||
private ParalyzedHudRenderer() {
|
||||
}
|
||||
|
||||
public static void render(GuiGraphics guiGraphics) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
Player player = mc.player;
|
||||
if (player == null || player.isDeadOrDying()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MobEffectInstance effect = player.getEffect(PARALYZED_EFFECT);
|
||||
if (effect == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int duration = effect.getDuration();
|
||||
float fade = effect.isInfiniteDuration()
|
||||
? 1.0F
|
||||
: Math.min(1.0F, Math.max(duration, 20) / 20.0F);
|
||||
float pulse = 0.85F + 0.15F * Mth.sin(player.tickCount * ((float) Math.PI * 2.0F / 120.0F));
|
||||
|
||||
int alpha = Mth.clamp((int) (fade * pulse * 0xC0), 0, 0xFF);
|
||||
|
||||
int width = mc.getWindow().getGuiScaledWidth();
|
||||
int height = mc.getWindow().getGuiScaledHeight();
|
||||
int color = (alpha << 24) | 0x303030;
|
||||
guiGraphics.fill(0, 0, width, height, color);
|
||||
int innerAlpha = Mth.clamp(alpha / 3, 0, 0xFF);
|
||||
int innerColor = (innerAlpha << 24) | 0x606060;
|
||||
int margin = Math.min(width, height) / 6;
|
||||
guiGraphics.fill(margin, margin, width - margin, height - margin, innerColor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.content.entity.ReverieEntity;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||
import com.mojang.blaze3d.vertex.BufferUploader;
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||
import com.mojang.blaze3d.vertex.MeshData;
|
||||
import com.mojang.blaze3d.vertex.Tesselator;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public final class ReverieTrailHandler {
|
||||
|
||||
private static final int MAX_TRAIL_POINTS = 20;
|
||||
private static final int IDLE_LIFETIME_TICKS = 8;
|
||||
private static final int NORMAL_LIFETIME_TICKS = 14;
|
||||
private static final int DASH_LIFETIME_TICKS = 22;
|
||||
private static final float CORE_LINE_WIDTH = 0.035f;
|
||||
private static final float GLOW_LINE_WIDTH = 0.10f;
|
||||
private static final double MIN_DISTANCE_BETWEEN_POINTS = 0.05;
|
||||
private static final double DASH_DISTANCE_THRESHOLD = 0.35;
|
||||
|
||||
private static final Map<Integer, ArrayDeque<TrailPoint>> TRAILS = new HashMap<>();
|
||||
|
||||
private ReverieTrailHandler() {}
|
||||
|
||||
private static final class TrailPoint {
|
||||
final Vec3 pos;
|
||||
final ReverieEntity.Mood mood;
|
||||
int age;
|
||||
final int lifetime;
|
||||
|
||||
TrailPoint(Vec3 pos, ReverieEntity.Mood mood, int lifetime) {
|
||||
this.pos = pos;
|
||||
this.mood = mood;
|
||||
this.age = 0;
|
||||
this.lifetime = lifetime;
|
||||
}
|
||||
|
||||
float progress() { return lifetime <= 0 ? 1f : (float) age / (float) lifetime; }
|
||||
boolean expired() { return age >= lifetime; }
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||
if (client.level == null) { TRAILS.clear(); return; }
|
||||
if (client.isPaused()) return;
|
||||
|
||||
Set<Integer> activeIds = new HashSet<>();
|
||||
|
||||
for (Entity entity : client.level.entitiesForRendering()) {
|
||||
if (!(entity instanceof ReverieEntity reverie)) continue;
|
||||
|
||||
int id = reverie.getId();
|
||||
activeIds.add(id);
|
||||
ReverieEntity.Mood mood = reverie.getMood();
|
||||
Vec3 pos = reverie.position().add(0.0, reverie.getBbHeight() * 0.5, 0.0);
|
||||
|
||||
ArrayDeque<TrailPoint> points = TRAILS.computeIfAbsent(id, k -> new ArrayDeque<>());
|
||||
|
||||
if (points.isEmpty()) {
|
||||
points.addFirst(new TrailPoint(pos, mood, lifetimeFor(mood, false)));
|
||||
} else {
|
||||
Vec3 lastPos = points.peekFirst().pos;
|
||||
double distSq = pos.distanceToSqr(lastPos);
|
||||
if (distSq >= MIN_DISTANCE_BETWEEN_POINTS * MIN_DISTANCE_BETWEEN_POINTS) {
|
||||
boolean isDash = distSq >= DASH_DISTANCE_THRESHOLD * DASH_DISTANCE_THRESHOLD;
|
||||
points.addFirst(new TrailPoint(pos, mood, lifetimeFor(mood, isDash)));
|
||||
while (points.size() > MAX_TRAIL_POINTS) points.pollLast();
|
||||
}
|
||||
}
|
||||
|
||||
Iterator<TrailPoint> it = points.iterator();
|
||||
while (it.hasNext()) {
|
||||
TrailPoint p = it.next();
|
||||
p.age++;
|
||||
if (p.expired()) it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
TRAILS.keySet().removeIf(id -> !activeIds.contains(id));
|
||||
});
|
||||
|
||||
WorldRenderEvents.AFTER_TRANSLUCENT.register(context -> {
|
||||
if (TRAILS.isEmpty()) return;
|
||||
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (mc.level == null) return;
|
||||
|
||||
Camera camera = context.camera();
|
||||
Vec3 camPos = camera.getPosition();
|
||||
Matrix4f mat = context.matrixStack().last().pose();
|
||||
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.defaultBlendFunc();
|
||||
RenderSystem.depthMask(false);
|
||||
RenderSystem.disableCull();
|
||||
RenderSystem.setShader(GameRenderer::getPositionColorShader);
|
||||
|
||||
Tesselator tesselator = Tesselator.getInstance();
|
||||
|
||||
List<List<TrailPoint>> snapshots = new ArrayList<>(TRAILS.size());
|
||||
for (ArrayDeque<TrailPoint> deque : TRAILS.values()) {
|
||||
if (deque.size() >= 2) snapshots.add(new ArrayList<>(deque));
|
||||
}
|
||||
|
||||
if (!snapshots.isEmpty()) {
|
||||
BufferBuilder glowBuf = tesselator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
|
||||
for (List<TrailPoint> points : snapshots) buildPass(glowBuf, mat, points, camPos, true);
|
||||
MeshData glowMesh = glowBuf.build();
|
||||
if (glowMesh != null) BufferUploader.drawWithShader(glowMesh);
|
||||
|
||||
BufferBuilder coreBuf = tesselator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
|
||||
for (List<TrailPoint> points : snapshots) buildPass(coreBuf, mat, points, camPos, false);
|
||||
MeshData coreMesh = coreBuf.build();
|
||||
if (coreMesh != null) BufferUploader.drawWithShader(coreMesh);
|
||||
}
|
||||
|
||||
RenderSystem.enableCull();
|
||||
RenderSystem.depthMask(true);
|
||||
RenderSystem.disableBlend();
|
||||
});
|
||||
}
|
||||
|
||||
private static int lifetimeFor(ReverieEntity.Mood mood, boolean isDash) {
|
||||
if (isDash || mood == ReverieEntity.Mood.PURPLE) return DASH_LIFETIME_TICKS;
|
||||
if (mood == ReverieEntity.Mood.WHITE) return IDLE_LIFETIME_TICKS;
|
||||
return NORMAL_LIFETIME_TICKS;
|
||||
}
|
||||
|
||||
private static void buildPass(BufferBuilder buf, Matrix4f mat, List<TrailPoint> points, Vec3 camPos, boolean glow) {
|
||||
int n = points.size();
|
||||
for (int i = 0; i < n - 1; i++) {
|
||||
TrailPoint newer = points.get(i);
|
||||
TrailPoint older = points.get(i + 1);
|
||||
|
||||
float alphaNearer = (glow ? glowAlpha(newer.mood) : coreAlpha(newer.mood)) * indexAlpha(i, n) * (1f - newer.progress());
|
||||
float alphaFarther = (glow ? glowAlpha(older.mood) : coreAlpha(older.mood)) * indexAlpha(i + 1, n) * (1f - older.progress());
|
||||
if (alphaNearer < 0.005f && alphaFarther < 0.005f) continue;
|
||||
|
||||
Vec3 right = cameraFacingRight(newer.pos, older.pos, camPos);
|
||||
if (right == null) continue;
|
||||
|
||||
float halfWidth = glow ? glowHalfWidth(newer.mood) : coreHalfWidth(newer.mood);
|
||||
right = right.scale(halfWidth);
|
||||
|
||||
float[] cn = color(newer.mood);
|
||||
float[] co = color(older.mood);
|
||||
Vec3 na = newer.pos.subtract(camPos);
|
||||
Vec3 nb = older.pos.subtract(camPos);
|
||||
|
||||
buf.addVertex(mat, (float)(na.x + right.x), (float)(na.y + right.y), (float)(na.z + right.z)).setColor(cn[0], cn[1], cn[2], alphaNearer);
|
||||
buf.addVertex(mat, (float)(na.x - right.x), (float)(na.y - right.y), (float)(na.z - right.z)).setColor(cn[0], cn[1], cn[2], alphaNearer);
|
||||
buf.addVertex(mat, (float)(nb.x - right.x), (float)(nb.y - right.y), (float)(nb.z - right.z)).setColor(co[0], co[1], co[2], alphaFarther);
|
||||
buf.addVertex(mat, (float)(nb.x + right.x), (float)(nb.y + right.y), (float)(nb.z + right.z)).setColor(co[0], co[1], co[2], alphaFarther);
|
||||
}
|
||||
}
|
||||
|
||||
private static Vec3 cameraFacingRight(Vec3 a, Vec3 b, Vec3 camPos) {
|
||||
Vec3 segDir = b.subtract(a);
|
||||
if (segDir.lengthSqr() < 1e-12) return null;
|
||||
segDir = segDir.normalize();
|
||||
Vec3 mid = a.add(b).scale(0.5);
|
||||
Vec3 toCamera = camPos.subtract(mid);
|
||||
if (toCamera.lengthSqr() < 1e-12) return null;
|
||||
toCamera = toCamera.normalize();
|
||||
Vec3 right = segDir.cross(toCamera);
|
||||
if (right.lengthSqr() < 1e-10) {
|
||||
right = segDir.cross(new Vec3(0.0, 1.0, 0.0));
|
||||
if (right.lengthSqr() < 1e-10) return null;
|
||||
}
|
||||
return right.normalize();
|
||||
}
|
||||
|
||||
private static float indexAlpha(int i, int n) {
|
||||
if (n <= 1) return 1f;
|
||||
return 1f - (float) i / (float) (n - 1);
|
||||
}
|
||||
|
||||
private static final float[] COLOR_WHITE = { 1.0f, 1.0f, 1.0f };
|
||||
private static final float[] COLOR_YELLOW = { 1.0f, 0.85f, 0.1f };
|
||||
private static final float[] COLOR_RED = { 1.0f, 0.1f, 0.05f };
|
||||
private static final float[] COLOR_PURPLE = { 0.7f, 0.1f, 1.0f };
|
||||
private static final float[] COLOR_BLUE = { 0.1f, 0.5f, 1.0f };
|
||||
|
||||
private static float[] color(ReverieEntity.Mood mood) {
|
||||
return switch (mood) {
|
||||
case WHITE -> COLOR_WHITE;
|
||||
case YELLOW -> COLOR_YELLOW;
|
||||
case RED -> COLOR_RED;
|
||||
case PURPLE -> COLOR_PURPLE;
|
||||
case BLUE -> COLOR_BLUE;
|
||||
};
|
||||
}
|
||||
|
||||
private static float glowAlpha(ReverieEntity.Mood mood) {
|
||||
return switch (mood) {
|
||||
case WHITE -> 0.15f;
|
||||
case YELLOW -> 0.30f;
|
||||
case RED -> 0.55f;
|
||||
case PURPLE -> 0.65f;
|
||||
case BLUE -> 0.35f;
|
||||
};
|
||||
}
|
||||
|
||||
private static float coreAlpha(ReverieEntity.Mood mood) {
|
||||
return switch (mood) {
|
||||
case WHITE -> 0.35f;
|
||||
case YELLOW -> 0.55f;
|
||||
case RED -> 0.85f;
|
||||
case PURPLE -> 0.95f;
|
||||
case BLUE -> 0.60f;
|
||||
};
|
||||
}
|
||||
|
||||
private static float glowHalfWidth(ReverieEntity.Mood mood) {
|
||||
float base = GLOW_LINE_WIDTH * 0.5f;
|
||||
return switch (mood) {
|
||||
case WHITE -> base * 0.60f;
|
||||
case YELLOW -> base * 0.80f;
|
||||
case RED -> base * 1.00f;
|
||||
case PURPLE -> base * 1.25f;
|
||||
case BLUE -> base * 0.90f;
|
||||
};
|
||||
}
|
||||
|
||||
private static float coreHalfWidth(ReverieEntity.Mood mood) {
|
||||
float base = CORE_LINE_WIDTH * 0.5f;
|
||||
return switch (mood) {
|
||||
case WHITE -> base * 0.60f;
|
||||
case YELLOW -> base * 0.80f;
|
||||
case RED -> base * 1.20f;
|
||||
case PURPLE -> base * 1.50f;
|
||||
case BLUE -> base * 1.00f;
|
||||
};
|
||||
}
|
||||
}
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.content.client.ScorpionWhipTetherClientState;
|
||||
import com.craisinlord.antarchy.content.item.ScorpionWhipItem;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||
import com.mojang.blaze3d.vertex.BufferUploader;
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||
import com.mojang.blaze3d.vertex.MeshData;
|
||||
import com.mojang.blaze3d.vertex.Tesselator;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
import java.util.Map;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.HumanoidArm;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
public final class ScorpionWhipTetherRenderHandler {
|
||||
private ScorpionWhipTetherRenderHandler() {
|
||||
}
|
||||
|
||||
public static void tick() {
|
||||
Minecraft minecraft = Minecraft.getInstance();
|
||||
if (minecraft.level == null) {
|
||||
ScorpionWhipTetherClientState.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static void render(WorldRenderContext context) {
|
||||
if (context.world() == null || context.matrixStack() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Minecraft minecraft = Minecraft.getInstance();
|
||||
if (minecraft.level == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<Integer, Integer> tethers = ScorpionWhipTetherClientState.snapshot();
|
||||
if (tethers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Camera camera = context.camera();
|
||||
Vec3 cameraPos = camera.getPosition();
|
||||
Matrix4f pose = context.matrixStack().last().pose();
|
||||
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.defaultBlendFunc();
|
||||
RenderSystem.depthMask(false);
|
||||
RenderSystem.disableCull();
|
||||
RenderSystem.setShader(GameRenderer::getPositionColorShader);
|
||||
|
||||
BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
|
||||
for (Map.Entry<Integer, Integer> entry : tethers.entrySet()) {
|
||||
Entity source = minecraft.level.getEntity(entry.getKey());
|
||||
Entity target = minecraft.level.getEntity(entry.getValue());
|
||||
if (!(source instanceof Player player) || target == null || target.isRemoved()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
buildTether(
|
||||
buffer,
|
||||
pose,
|
||||
tetherStart(player, context.tickCounter().getGameTimeDeltaPartialTick(false)),
|
||||
target.position().add(0.0D, target.getBbHeight() * 0.5D, 0.0D),
|
||||
cameraPos
|
||||
);
|
||||
}
|
||||
|
||||
MeshData mesh = buffer.build();
|
||||
if (mesh != null) {
|
||||
BufferUploader.drawWithShader(mesh);
|
||||
}
|
||||
|
||||
RenderSystem.enableCull();
|
||||
RenderSystem.depthMask(true);
|
||||
RenderSystem.disableBlend();
|
||||
}
|
||||
|
||||
private static Vec3 tetherStart(Player player, float partialTick) {
|
||||
Vec3 start = player.getEyePosition(partialTick).add(0.0D, -0.45D, 0.0D);
|
||||
boolean mainHandWhip = player.getMainHandItem().getItem() instanceof ScorpionWhipItem;
|
||||
boolean offHandWhip = player.getOffhandItem().getItem() instanceof ScorpionWhipItem;
|
||||
if (!mainHandWhip && !offHandWhip) {
|
||||
return start;
|
||||
}
|
||||
|
||||
boolean useMainHand = mainHandWhip || !offHandWhip;
|
||||
HumanoidArm arm = useMainHand ? player.getMainArm() : player.getMainArm().getOpposite();
|
||||
float bodyYaw = Mth.rotLerp(partialTick, player.yBodyRotO, player.yBodyRot);
|
||||
double radians = Math.toRadians(bodyYaw + 90.0F);
|
||||
double side = arm == HumanoidArm.RIGHT ? -0.28D : 0.28D;
|
||||
return start.add(Math.cos(radians) * side, -0.12D, Math.sin(radians) * side);
|
||||
}
|
||||
|
||||
private static void buildTether(BufferBuilder buffer, Matrix4f pose, Vec3 start, Vec3 end, Vec3 cameraPos) {
|
||||
Vec3 delta = end.subtract(start);
|
||||
double length = delta.length();
|
||||
if (length < 0.001D) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3 forward = delta.scale(1.0D / length);
|
||||
Vec3 right = forward.cross(new Vec3(0.0D, 1.0D, 0.0D));
|
||||
if (right.lengthSqr() < 1.0E-6D) {
|
||||
right = forward.cross(new Vec3(1.0D, 0.0D, 0.0D));
|
||||
}
|
||||
right = right.normalize();
|
||||
|
||||
int segments = Math.max(16, Mth.ceil(length * 8.0D));
|
||||
for (int i = 0; i < segments; i++) {
|
||||
double t0 = (double) i / (double) segments;
|
||||
double t1 = (double) (i + 1) / (double) segments;
|
||||
Vec3 p0 = ropePoint(start, delta, t0, length);
|
||||
Vec3 p1 = ropePoint(start, delta, t1, length);
|
||||
float width = 0.045F;
|
||||
Vec3 offset = right.scale(width);
|
||||
|
||||
Vec3 a = p0.subtract(cameraPos);
|
||||
Vec3 b = p1.subtract(cameraPos);
|
||||
float shade = i % 2 == 0 ? 0.82F : 0.62F;
|
||||
float red = 0.36F * shade;
|
||||
float green = 0.20F * shade;
|
||||
float blue = 0.11F * shade;
|
||||
|
||||
buffer.addVertex(pose, (float) (a.x + offset.x), (float) (a.y + offset.y), (float) (a.z + offset.z)).setColor(red, green, blue, 1.0F);
|
||||
buffer.addVertex(pose, (float) (a.x - offset.x), (float) (a.y - offset.y), (float) (a.z - offset.z)).setColor(red, green, blue, 1.0F);
|
||||
buffer.addVertex(pose, (float) (b.x - offset.x), (float) (b.y - offset.y), (float) (b.z - offset.z)).setColor(red, green, blue, 1.0F);
|
||||
buffer.addVertex(pose, (float) (b.x + offset.x), (float) (b.y + offset.y), (float) (b.z + offset.z)).setColor(red, green, blue, 1.0F);
|
||||
}
|
||||
}
|
||||
|
||||
private static Vec3 ropePoint(Vec3 start, Vec3 delta, double t, double length) {
|
||||
double sag = Math.sin(t * Math.PI) * Math.min(0.45D, length * 0.07D);
|
||||
return start.add(delta.scale(t)).add(0.0D, -sag, 0.0D);
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package com.craisinlord.antarchy.fabric.client;
|
||||
|
||||
import com.craisinlord.antarchy.fabric.AntarchyFabricContent;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
||||
public final class TriffidGooHudRenderer {
|
||||
private TriffidGooHudRenderer() {
|
||||
}
|
||||
|
||||
private static float fadeProgress = 0f;
|
||||
private static final float FADE_SPEED = 0.05f;
|
||||
private static final int MAX_ALPHA = 0x55;
|
||||
|
||||
public static void render(GuiGraphics guiGraphics) {
|
||||
Minecraft minecraft = Minecraft.getInstance();
|
||||
Player player = minecraft.player;
|
||||
if (player == null || player.isDeadOrDying()) {
|
||||
fadeProgress = Math.max(0f, fadeProgress - FADE_SPEED);
|
||||
if (fadeProgress <= 0f) return;
|
||||
} else {
|
||||
Block goo = AntarchyFabricContent.TRIFFID_GOO_BLOCK.get();
|
||||
BlockPos feet = player.blockPosition();
|
||||
boolean inGoo = player.level().getBlockState(feet).is(goo)
|
||||
|| player.level().getBlockState(feet.above()).is(goo);
|
||||
|
||||
if (inGoo) {
|
||||
fadeProgress = Math.min(1f, fadeProgress + FADE_SPEED);
|
||||
} else {
|
||||
fadeProgress = Math.max(0f, fadeProgress - FADE_SPEED);
|
||||
}
|
||||
|
||||
if (fadeProgress <= 0f || minecraft.screen != null) return;
|
||||
}
|
||||
|
||||
int alpha = Mth.floor(MAX_ALPHA * fadeProgress);
|
||||
int color = (alpha << 24) | 0x003300;
|
||||
int width = minecraft.getWindow().getGuiScaledWidth();
|
||||
int height = minecraft.getWindow().getGuiScaledHeight();
|
||||
guiGraphics.fill(0, 0, width, height, color);
|
||||
}
|
||||
}
|
||||
+442
@@ -0,0 +1,442 @@
|
||||
package com.craisinlord.antarchy.fabric.content.fluid;
|
||||
|
||||
import com.craisinlord.antarchy.fabric.AntarchyFabricContent;
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.LiquidBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.material.FlowingFluid;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
import net.minecraft.tags.FluidTags;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public abstract class AntiwaterFluid extends FlowingFluid {
|
||||
private static final int MAX_HORIZONTAL_SPREAD_AMOUNT = 5;
|
||||
private static final int MAX_VERTICAL_FLOW_AMOUNT = 7;
|
||||
|
||||
@Override
|
||||
public Fluid getFlowing() {
|
||||
return AntarchyFabricContent.FLOWING_ANTIWATER.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fluid getSource() {
|
||||
return AntarchyFabricContent.ANTIWATER.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item getBucket() {
|
||||
return AntarchyFabricContent.ANTIWATER_BUCKET.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSame(Fluid fluid) {
|
||||
return fluid == AntarchyFabricContent.ANTIWATER.get() || fluid == AntarchyFabricContent.FLOWING_ANTIWATER.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canConvertToSource(Level level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeDestroyingBlock(LevelAccessor level, BlockPos pos, BlockState state) {
|
||||
net.minecraft.world.level.block.Block.dropResources(state, level, pos, state.hasBlockEntity() ? level.getBlockEntity(pos) : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getSlopeFindDistance(LevelReader level) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDropOff(LevelReader level) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTickDelay(LevelReader level) {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getExplosionResistance() {
|
||||
return 100.0F;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlockState createLegacyBlock(FluidState state) {
|
||||
return AntarchyFabricContent.ANTIWATER_BLOCK.get()
|
||||
.defaultBlockState()
|
||||
.setValue(LiquidBlock.LEVEL, getLegacyLevel(state));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canBeReplacedWith(FluidState state, BlockGetter level, BlockPos pos, Fluid fluid, Direction direction) {
|
||||
return direction != Direction.DOWN && !this.isSame(fluid);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canSpreadTo(
|
||||
BlockGetter level,
|
||||
BlockPos fromPos,
|
||||
BlockState fromState,
|
||||
Direction direction,
|
||||
BlockPos toPos,
|
||||
BlockState toState,
|
||||
FluidState toFluidState,
|
||||
Fluid fluid
|
||||
) {
|
||||
if (direction == Direction.DOWN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return super.canSpreadTo(level, fromPos, fromState, direction, toPos, toState, toFluidState, fluid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<SoundEvent> getPickupSound() {
|
||||
return Optional.of(SoundEvents.BUCKET_FILL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getSpreadDelay(Level level, BlockPos pos, FluidState currentState, FluidState newState) {
|
||||
return this.getTickDelay(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 getFlow(BlockGetter level, BlockPos pos, FluidState state) {
|
||||
double flowX = 0.0D;
|
||||
double flowZ = 0.0D;
|
||||
|
||||
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
||||
BlockPos neighborPos = pos.relative(direction);
|
||||
FluidState neighborFluid = level.getFluidState(neighborPos);
|
||||
int neighborAmount = this.isSame(neighborFluid.getType()) ? neighborFluid.getAmount() : 0;
|
||||
int currentAmount = state.getAmount();
|
||||
int delta = neighborAmount - currentAmount;
|
||||
if (delta != 0) {
|
||||
flowX += direction.getStepX() * delta;
|
||||
flowZ += direction.getStepZ() * delta;
|
||||
}
|
||||
}
|
||||
|
||||
Vec3 flow = new Vec3(flowX, 1.0D, flowZ);
|
||||
return flow.lengthSqr() < 1.0E-6D ? new Vec3(0.0D, 1.0D, 0.0D) : flow.normalize();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FluidState getNewLiquid(Level level, BlockPos pos, BlockState blockState) {
|
||||
FluidState currentState = blockState.getFluidState();
|
||||
if (!currentState.isSource() && !this.isFlowingStateValid(level, pos, currentState)) {
|
||||
return Fluids.EMPTY.defaultFluidState();
|
||||
}
|
||||
|
||||
if (this.canCreateSourceAt(level, pos)) {
|
||||
return this.getSource(false);
|
||||
}
|
||||
|
||||
if (this.isValidVerticalSupport(level, pos)) {
|
||||
return this.getFlowing(MAX_VERTICAL_FLOW_AMOUNT, false);
|
||||
}
|
||||
|
||||
int bestNeighborAmount = this.getBestHorizontalNeighborAmount(level, pos);
|
||||
if (bestNeighborAmount > 1) {
|
||||
return this.getFlowing(bestNeighborAmount - 1, false);
|
||||
}
|
||||
|
||||
return Fluids.EMPTY.defaultFluidState();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void spread(Level level, BlockPos pos, FluidState state) {
|
||||
if (state.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!state.isSource() && !this.isFlowingStateValid(level, pos, state)) {
|
||||
level.setBlockAndUpdate(pos, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState());
|
||||
this.scheduleCleanup(level, pos);
|
||||
return;
|
||||
}
|
||||
|
||||
BlockState blockState = level.getBlockState(pos);
|
||||
this.spreadUpward(level, pos, state, blockState);
|
||||
|
||||
if (!this.canHangAt(level, pos)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int nextAmount = state.getAmount() - 1;
|
||||
if (nextAmount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.spreadHorizontally(level, pos, blockState, nextAmount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(Level level, BlockPos pos, FluidState state) {
|
||||
if (!state.isSource() && !this.isFlowingStateValid(level, pos, state)) {
|
||||
level.setBlockAndUpdate(pos, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState());
|
||||
this.scheduleDependentCleanup(level, pos);
|
||||
return;
|
||||
}
|
||||
|
||||
super.tick(level, pos, state);
|
||||
}
|
||||
|
||||
public static final class Source extends AntiwaterFluid {
|
||||
@Override
|
||||
public int getAmount(FluidState state) {
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSource(FluidState state) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Flowing extends AntiwaterFluid {
|
||||
public Flowing() {
|
||||
this.registerDefaultState(this.getStateDefinition().any().setValue(LEVEL, 7));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createFluidStateDefinition(net.minecraft.world.level.block.state.StateDefinition.Builder<Fluid, FluidState> builder) {
|
||||
super.createFluidStateDefinition(builder);
|
||||
builder.add(LEVEL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAmount(FluidState state) {
|
||||
return state.getValue(LEVEL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSource(FluidState state) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasCeiling(Level level, BlockPos pos) {
|
||||
return level.getBlockState(pos.above()).isSolid();
|
||||
}
|
||||
|
||||
private boolean canHangAt(Level level, BlockPos pos) {
|
||||
return this.hasCeiling(level, pos);
|
||||
}
|
||||
|
||||
private boolean hasHorizontalSupport(Level level, BlockPos pos) {
|
||||
FluidState state = level.getFluidState(pos);
|
||||
if (!this.isAntiwater(state)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int currentAmount = state.getAmount();
|
||||
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
||||
FluidState neighbor = level.getFluidState(pos.relative(direction));
|
||||
if (!this.isAntiwater(neighbor)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.getHorizontalSpreadAmount(neighbor) > currentAmount) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean canSpreadHorizontallyInto(Level level, BlockPos pos) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private int getBestHorizontalNeighborAmount(Level level, BlockPos pos) {
|
||||
int bestAmount = 0;
|
||||
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
||||
BlockPos neighborPos = pos.relative(direction);
|
||||
FluidState neighborFluid = level.getFluidState(neighborPos);
|
||||
if (neighborFluid.isEmpty() || !neighborFluid.getType().isSame(this)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!this.hasSourceConnection(level, neighborPos, neighborFluid, new HashSet<>())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bestAmount = Math.max(bestAmount, this.getHorizontalSpreadAmount(neighborFluid));
|
||||
}
|
||||
|
||||
return bestAmount;
|
||||
}
|
||||
|
||||
private int getHorizontalSpreadAmount(FluidState state) {
|
||||
if (state.isSource() || this.isValidVerticalSupportState(state)) {
|
||||
return MAX_HORIZONTAL_SPREAD_AMOUNT + 1;
|
||||
}
|
||||
|
||||
return state.getAmount();
|
||||
}
|
||||
|
||||
private boolean isValidVerticalSupportState(FluidState state) {
|
||||
return this.isAntiwater(state) && !state.isSource() && state.getAmount() >= MAX_VERTICAL_FLOW_AMOUNT;
|
||||
}
|
||||
|
||||
private boolean isFlowingStateValid(Level level, BlockPos pos, FluidState state) {
|
||||
return state.isSource()
|
||||
|| this.hasImmediateVerticalSupport(level, pos)
|
||||
|| this.hasHorizontalSupport(level, pos);
|
||||
}
|
||||
|
||||
private boolean canCreateSourceAt(Level level, BlockPos pos) {
|
||||
if (!this.canHangAt(level, pos)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int sourceNeighbors = 0;
|
||||
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
||||
FluidState neighbor = level.getFluidState(pos.relative(direction));
|
||||
if (this.isAntiwater(neighbor) && neighbor.isSource()) {
|
||||
sourceNeighbors++;
|
||||
if (sourceNeighbors >= 2) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isValidVerticalSupport(Level level, BlockPos pos) {
|
||||
return this.hasImmediateVerticalSupport(level, pos);
|
||||
}
|
||||
|
||||
private boolean isAntiwater(FluidState state) {
|
||||
return !state.isEmpty() && state.getType().isSame(this);
|
||||
}
|
||||
|
||||
private boolean hasImmediateVerticalSupport(Level level, BlockPos pos) {
|
||||
FluidState below = level.getFluidState(pos.below());
|
||||
return this.isAntiwater(below);
|
||||
}
|
||||
|
||||
private void spreadUpward(Level level, BlockPos pos, FluidState state, BlockState blockState) {
|
||||
BlockPos abovePos = pos.above();
|
||||
BlockState aboveState = level.getBlockState(abovePos);
|
||||
FluidState aboveFluid = level.getFluidState(abovePos);
|
||||
|
||||
if (aboveFluid.is(FluidTags.WATER)) {
|
||||
BlockState result = state.isSource()
|
||||
? AntarchyFabricContent.ANTIMETAL.get().defaultBlockState()
|
||||
: AntarchyFabricContent.NYXITE.get().defaultBlockState();
|
||||
level.setBlockAndUpdate(pos, result);
|
||||
level.levelEvent(1501, pos, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
FluidState upwardState = this.getFlowing(MAX_VERTICAL_FLOW_AMOUNT, false);
|
||||
if (!this.canSpreadTo(level, pos, blockState, Direction.UP, abovePos, aboveState, aboveFluid, upwardState.getType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aboveFluid.getType().isSame(this) && aboveFluid.getAmount() >= upwardState.getAmount()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.spreadTo(level, abovePos, aboveState, Direction.UP, upwardState);
|
||||
}
|
||||
|
||||
private void spreadHorizontally(Level level, BlockPos pos, BlockState blockState, int nextAmount) {
|
||||
FluidState horizontalState = this.getFlowing(Math.min(nextAmount, MAX_HORIZONTAL_SPREAD_AMOUNT), false);
|
||||
|
||||
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
||||
BlockPos targetPos = pos.relative(direction);
|
||||
BlockState targetState = level.getBlockState(targetPos);
|
||||
FluidState targetFluid = targetState.getFluidState();
|
||||
|
||||
if (!this.canSpreadHorizontallyInto(level, targetPos)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (targetFluid.getType().isSame(this) && targetFluid.getAmount() >= horizontalState.getAmount()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!this.canSpreadTo(level, pos, blockState, direction, targetPos, targetState, targetFluid, horizontalState.getType())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.spreadTo(level, targetPos, targetState, direction, horizontalState);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasSourceConnection(Level level, BlockPos pos, FluidState state, Set<BlockPos> visited) {
|
||||
if (!this.isAntiwater(state)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state.isSource()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!visited.add(pos)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FluidState below = level.getFluidState(pos.below());
|
||||
if (this.hasSourceConnection(level, pos.below(), below, visited)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int currentAmount = state.getAmount();
|
||||
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
||||
BlockPos neighborPos = pos.relative(direction);
|
||||
FluidState neighbor = level.getFluidState(neighborPos);
|
||||
if (!this.isAntiwater(neighbor)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.getHorizontalSpreadAmount(neighbor) <= currentAmount) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.hasSourceConnection(level, neighborPos, neighbor, visited)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void scheduleCleanup(Level level, BlockPos pos) {
|
||||
int tickDelay = this.getTickDelay(level);
|
||||
level.scheduleTick(pos, this, tickDelay);
|
||||
level.scheduleTick(pos.above(), this, tickDelay);
|
||||
level.scheduleTick(pos.below(), this, tickDelay);
|
||||
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
||||
level.scheduleTick(pos.relative(direction), this, tickDelay);
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleDependentCleanup(Level level, BlockPos pos) {
|
||||
int tickDelay = this.getTickDelay(level);
|
||||
level.scheduleTick(pos.above(), this, tickDelay);
|
||||
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
||||
level.scheduleTick(pos.relative(direction), this, tickDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.craisinlord.antarchy.fabric.content.fluid;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.LiquidBlock;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.material.FlowingFluid;
|
||||
|
||||
public class AntiwaterLiquidBlock extends LiquidBlock {
|
||||
public AntiwaterLiquidBlock(FlowingFluid fluid, BlockBehaviour.Properties properties) {
|
||||
super(fluid, properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
|
||||
super.onPlace(state, level, pos, oldState, movedByPiston);
|
||||
scheduleCurrentAntiwaterTick(level, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, BlockPos neighborPos, boolean movedByPiston) {
|
||||
super.neighborChanged(state, level, pos, neighborBlock, neighborPos, movedByPiston);
|
||||
scheduleCurrentAntiwaterTick(level, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlockState updateShape(
|
||||
BlockState state,
|
||||
Direction direction,
|
||||
BlockState neighborState,
|
||||
LevelAccessor level,
|
||||
BlockPos pos,
|
||||
BlockPos neighborPos
|
||||
) {
|
||||
scheduleCurrentAntiwaterTick(level, pos);
|
||||
return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
|
||||
if (!state.is(newState.getBlock())) {
|
||||
scheduleDependentAntiwaterTicks(level, pos);
|
||||
}
|
||||
super.onRemove(state, level, pos, newState, movedByPiston);
|
||||
}
|
||||
|
||||
private void scheduleCurrentAntiwaterTick(LevelAccessor level, BlockPos pos) {
|
||||
level.scheduleTick(pos, this.fluid, this.fluid.getTickDelay(level));
|
||||
}
|
||||
|
||||
private void scheduleDependentAntiwaterTicks(LevelAccessor level, BlockPos pos) {
|
||||
level.scheduleTick(pos.above(), this.fluid, this.fluid.getTickDelay(level));
|
||||
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
||||
level.scheduleTick(pos.relative(direction), this.fluid, this.fluid.getTickDelay(level));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package com.craisinlord.antarchy.fabric.content.fluid;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.LiquidBlock;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.material.FlowingFluid;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
|
||||
public abstract class SimpleFluid extends FlowingFluid {
|
||||
private final Supplier<? extends FlowingFluid> source;
|
||||
private final Supplier<? extends FlowingFluid> flowing;
|
||||
private final Supplier<? extends Item> bucket;
|
||||
private final String blockId;
|
||||
private final int slopeFindDistance;
|
||||
private final int dropOff;
|
||||
private final int tickDelay;
|
||||
|
||||
protected SimpleFluid(
|
||||
Supplier<? extends FlowingFluid> source,
|
||||
Supplier<? extends FlowingFluid> flowing,
|
||||
Supplier<? extends Item> bucket,
|
||||
String blockId,
|
||||
int slopeFindDistance,
|
||||
int dropOff,
|
||||
int tickDelay
|
||||
) {
|
||||
this.source = source;
|
||||
this.flowing = flowing;
|
||||
this.bucket = bucket;
|
||||
this.blockId = blockId;
|
||||
this.slopeFindDistance = slopeFindDistance;
|
||||
this.dropOff = dropOff;
|
||||
this.tickDelay = tickDelay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fluid getFlowing() {
|
||||
return this.flowing.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fluid getSource() {
|
||||
return this.source.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item getBucket() {
|
||||
return this.bucket.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canConvertToSource(Level level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeDestroyingBlock(LevelAccessor level, BlockPos pos, BlockState state) {
|
||||
BlockEntity blockEntity = state.hasBlockEntity() ? level.getBlockEntity(pos) : null;
|
||||
net.minecraft.world.level.block.Block.dropResources(state, level, pos, blockEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getSlopeFindDistance(LevelReader level) {
|
||||
return this.slopeFindDistance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDropOff(LevelReader level) {
|
||||
return this.dropOff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTickDelay(LevelReader level) {
|
||||
return this.tickDelay;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getExplosionResistance() {
|
||||
return 100.0F;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSame(Fluid fluid) {
|
||||
return fluid == this.source.get() || fluid == this.flowing.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlockState createLegacyBlock(FluidState state) {
|
||||
LiquidBlock block = (LiquidBlock) BuiltInRegistries.BLOCK.get(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, this.blockId));
|
||||
return block.defaultBlockState().setValue(LiquidBlock.LEVEL, getLegacyLevel(state));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<SoundEvent> getPickupSound() {
|
||||
return Optional.of(SoundEvents.BUCKET_FILL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canBeReplacedWith(FluidState state, BlockGetter level, BlockPos pos, Fluid fluid, Direction direction) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static final class Flowing extends SimpleFluid {
|
||||
public Flowing(
|
||||
Supplier<? extends FlowingFluid> source,
|
||||
Supplier<? extends FlowingFluid> flowing,
|
||||
Supplier<? extends Item> bucket,
|
||||
String blockId,
|
||||
int slopeFindDistance,
|
||||
int dropOff,
|
||||
int tickDelay
|
||||
) {
|
||||
super(source, flowing, bucket, blockId, slopeFindDistance, dropOff, tickDelay);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createFluidStateDefinition(net.minecraft.world.level.block.state.StateDefinition.Builder<Fluid, FluidState> builder) {
|
||||
super.createFluidStateDefinition(builder);
|
||||
builder.add(LEVEL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAmount(FluidState state) {
|
||||
return state.getValue(LEVEL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSource(FluidState state) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Source extends SimpleFluid {
|
||||
public Source(
|
||||
Supplier<? extends FlowingFluid> source,
|
||||
Supplier<? extends FlowingFluid> flowing,
|
||||
Supplier<? extends Item> bucket,
|
||||
String blockId,
|
||||
int slopeFindDistance,
|
||||
int dropOff,
|
||||
int tickDelay
|
||||
) {
|
||||
super(source, flowing, bucket, blockId, slopeFindDistance, dropOff, tickDelay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAmount(FluidState state) {
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSource(FluidState state) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.craisinlord.antarchy.fabric.item;
|
||||
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ScaffoldingBlockItem;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
||||
public final class AntimetalScaffoldingItem extends ScaffoldingBlockItem {
|
||||
public AntimetalScaffoldingItem(Block block, Item.Properties properties) {
|
||||
super(block, properties);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.craisinlord.antarchy.fabric.item;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.SpawnEggItem;
|
||||
|
||||
public final class DeferredSpawnEggItem extends SpawnEggItem {
|
||||
public DeferredSpawnEggItem(Supplier<? extends EntityType<? extends Mob>> typeSupplier, int backgroundColor, int highlightColor, Item.Properties properties) {
|
||||
super(typeSupplier.get(), backgroundColor, highlightColor, properties);
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package com.craisinlord.antarchy.fabric.mixin;
|
||||
|
||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityTransition;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.particles.DustParticleOptions;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import org.joml.Vector3f;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(LivingEntity.class)
|
||||
public abstract class AntimetalInversionMixin {
|
||||
|
||||
private static final int ANTIMETAL_INVERTED_REFRESH_TICKS = 20;
|
||||
|
||||
@Inject(method = "tick", at = @At("TAIL"))
|
||||
private void antarchy$tickOverheadInversion(CallbackInfo ci) {
|
||||
LivingEntity entity = (LivingEntity) (Object) this;
|
||||
if (entity.level().isClientSide()) return;
|
||||
if (entity instanceof Player player && player.isSpectator()) return;
|
||||
if (!antarchy$isDirectlyBelowAntimetal(entity)) return;
|
||||
|
||||
MobEffectInstance existing = entity.getEffect(AntarchyObjects.INVERTED_EFFECT.get());
|
||||
if (existing == null || existing.getDuration() <= 5) {
|
||||
entity.addEffect(new MobEffectInstance(AntarchyObjects.INVERTED_EFFECT.get(), ANTIMETAL_INVERTED_REFRESH_TICKS, 0, false, false, false));
|
||||
antarchy$spawnInversionParticles(entity);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean antarchy$isDirectlyBelowAntimetal(LivingEntity entity) {
|
||||
AABB bounds = entity.getBoundingBox().deflate(1.0E-3D);
|
||||
int minX = Mth.floor(bounds.minX);
|
||||
int maxX = Mth.floor(bounds.maxX);
|
||||
int minY = Mth.floor(bounds.minY);
|
||||
int maxY = Mth.floor(bounds.maxY);
|
||||
int minZ = Mth.floor(bounds.minZ);
|
||||
int maxZ = Mth.floor(bounds.maxZ);
|
||||
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
for (int z = minZ; z <= maxZ; z++) {
|
||||
BlockPos above = new BlockPos(x, y + 1, z);
|
||||
if (entity.level().getBlockState(above).is(AntarchyObjects.ANTIMETAL.get())
|
||||
|| entity.level().getBlockState(above).is(AntarchyObjects.POLISHED_ANTIMETAL.get())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Inject(method = "onEffectRemoved", at = @At("HEAD"))
|
||||
private void antarchy$onInvertedRemoved(MobEffectInstance effectInstance, CallbackInfo ci) {
|
||||
LivingEntity entity = (LivingEntity) (Object) this;
|
||||
if (entity.level().isClientSide()) return;
|
||||
if (!effectInstance.is(AntarchyObjects.INVERTED_EFFECT.get())) return;
|
||||
AntarchyGravityApi.setGravityDirection(entity, AntarchyGravityDirection.DOWN, new AntarchyGravityTransition(12));
|
||||
}
|
||||
|
||||
private static void antarchy$spawnInversionParticles(LivingEntity entity) {
|
||||
if (!(entity.level() instanceof ServerLevel serverLevel)) return;
|
||||
double x = entity.getX();
|
||||
double y = entity.getBoundingBox().maxY + 0.1D;
|
||||
double z = entity.getZ();
|
||||
serverLevel.sendParticles(
|
||||
new DustParticleOptions(new Vector3f(1.0F, 0.1F, 0.1F), 1.0F),
|
||||
x, y, z, 6, 0.2D, 0.05D, 0.2D, 0.0D
|
||||
);
|
||||
}
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
package com.craisinlord.antarchy.fabric.mixin;
|
||||
|
||||
import com.craisinlord.antarchy.fabric.AntarchyFabricContent;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.item.FallingBlockEntity;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.ScaffoldingBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(ScaffoldingBlock.class)
|
||||
public abstract class AntimetalScaffoldingMixin {
|
||||
@Inject(method = "getStateForPlacement", at = @At("HEAD"), cancellable = true)
|
||||
private void antarchy$antimetalPlacement(BlockPlaceContext context, CallbackInfoReturnable<BlockState> cir) {
|
||||
if (!antarchy$isAntimetalScaffolding()) {
|
||||
return;
|
||||
}
|
||||
|
||||
BlockPos pos = context.getClickedPos();
|
||||
Level level = context.getLevel();
|
||||
int distance = antarchy$getDistance(level, pos);
|
||||
BlockState state = ((ScaffoldingBlock) (Object) this).defaultBlockState()
|
||||
.setValue(ScaffoldingBlock.WATERLOGGED, level.getFluidState(pos).getType().isSame(net.minecraft.world.level.material.Fluids.WATER))
|
||||
.setValue(ScaffoldingBlock.DISTANCE, distance)
|
||||
.setValue(ScaffoldingBlock.BOTTOM, antarchy$isBottom(level, pos, distance));
|
||||
cir.setReturnValue(state);
|
||||
}
|
||||
|
||||
@Inject(method = "canSurvive", at = @At("HEAD"), cancellable = true)
|
||||
private void antarchy$antimetalCanSurvive(BlockState state, LevelReader level, BlockPos pos, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (!antarchy$isAntimetalScaffolding()) {
|
||||
return;
|
||||
}
|
||||
|
||||
cir.setReturnValue(antarchy$getDistance(level, pos) < 7);
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"), cancellable = true)
|
||||
private void antarchy$antimetalTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random, CallbackInfo ci) {
|
||||
if (!antarchy$isAntimetalScaffolding()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int distance = antarchy$getDistance(level, pos);
|
||||
BlockState updated = state.setValue(ScaffoldingBlock.DISTANCE, distance)
|
||||
.setValue(ScaffoldingBlock.BOTTOM, antarchy$isBottom(level, pos, distance));
|
||||
|
||||
if (updated.getValue(ScaffoldingBlock.DISTANCE) == 7) {
|
||||
if (state.getValue(ScaffoldingBlock.DISTANCE) == 7) {
|
||||
FallingBlockEntity.fall(level, pos, updated);
|
||||
} else {
|
||||
level.destroyBlock(pos, true);
|
||||
}
|
||||
} else if (state != updated) {
|
||||
level.setBlock(pos, updated, 3);
|
||||
}
|
||||
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
private boolean antarchy$isAntimetalScaffolding() {
|
||||
return ((ScaffoldingBlock) (Object) this).asItem() == AntarchyFabricContent.ANTIMETAL_SCAFFOLDING.get().asItem();
|
||||
}
|
||||
|
||||
private int antarchy$getDistance(BlockGetter level, BlockPos pos) {
|
||||
BlockPos.MutableBlockPos cursor = pos.mutable().move(Direction.DOWN);
|
||||
BlockState below = level.getBlockState(cursor);
|
||||
int distance = 7;
|
||||
if (below.is((ScaffoldingBlock) (Object) this)) {
|
||||
distance = below.getValue(ScaffoldingBlock.DISTANCE);
|
||||
} else if (below.isFaceSturdy(level, cursor, Direction.UP)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
||||
BlockPos.MutableBlockPos neighborPos = pos.mutable().move(direction);
|
||||
BlockState neighbor = level.getBlockState(neighborPos);
|
||||
if (!neighbor.is((ScaffoldingBlock) (Object) this)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
distance = Math.min(distance, neighbor.getValue(ScaffoldingBlock.DISTANCE) + 1);
|
||||
if (distance == 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
private boolean antarchy$isBottom(BlockGetter level, BlockPos pos, int distance) {
|
||||
if (distance <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !level.getBlockState(pos.below()).is((ScaffoldingBlock) (Object) this);
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.craisinlord.antarchy.fabric.mixin;
|
||||
|
||||
import com.craisinlord.antarchy.content.block.PotentNyxiteBlock;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ItemEntity.class)
|
||||
public abstract class AntiwaterItemEntityMixin {
|
||||
@Inject(method = "tick", at = @At("TAIL"))
|
||||
private void antarchy$applyAntiwaterItemMovement(CallbackInfo ci) {
|
||||
ItemEntity entity = (ItemEntity) (Object) this;
|
||||
if (!antarchy$isTouchingAntiwater(entity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3 motion = entity.getDeltaMovement();
|
||||
entity.setDeltaMovement(
|
||||
motion.x * 0.99D,
|
||||
motion.y + (motion.y < 0.06D ? 5.0E-4D : 0.0D),
|
||||
motion.z * 0.99D
|
||||
);
|
||||
}
|
||||
|
||||
private boolean antarchy$isTouchingAntiwater(ItemEntity entity) {
|
||||
BlockPos min = BlockPos.containing(entity.getBoundingBox().minX, entity.getBoundingBox().minY, entity.getBoundingBox().minZ);
|
||||
BlockPos max = BlockPos.containing(entity.getBoundingBox().maxX, entity.getBoundingBox().maxY, entity.getBoundingBox().maxZ);
|
||||
BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos();
|
||||
for (int x = min.getX(); x <= max.getX(); x++) {
|
||||
for (int y = min.getY(); y <= max.getY(); y++) {
|
||||
for (int z = min.getZ(); z <= max.getZ(); z++) {
|
||||
cursor.set(x, y, z);
|
||||
FluidState fluidState = entity.level().getFluidState(cursor);
|
||||
if (PotentNyxiteBlock.isAntiwater(fluidState)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
package com.craisinlord.antarchy.fabric.mixin;
|
||||
|
||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||
import com.craisinlord.antarchy.content.block.PotentNyxiteBlock;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.MoverType;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(LivingEntity.class)
|
||||
public abstract class AntiwaterLivingEntityMixin {
|
||||
@Inject(method = "travel", at = @At("HEAD"), cancellable = true)
|
||||
private void antarchy$moveInAntiwater(Vec3 travelVector, CallbackInfo ci) {
|
||||
LivingEntity entity = (LivingEntity) (Object) this;
|
||||
if (!antarchy$isTouchingAntiwaterLocal(entity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
double prevY = entity.getY();
|
||||
float swimSpeed = entity.isSprinting() ? 0.026F : 0.02F;
|
||||
entity.moveRelative(swimSpeed, travelVector);
|
||||
entity.move(MoverType.SELF, entity.getDeltaMovement());
|
||||
|
||||
Vec3 motion = entity.getDeltaMovement();
|
||||
if (entity.horizontalCollision && entity.onClimbable()) {
|
||||
motion = new Vec3(motion.x, 0.2D, motion.z);
|
||||
}
|
||||
|
||||
AntarchyGravityDirection gravityDirection = antarchy$getEffectiveGravityDirection(entity);
|
||||
Vec3 worldMotion = gravityDirection.isInverted()
|
||||
? AntarchyGravityRotationUtil.vecPlayerToWorld(motion, gravityDirection)
|
||||
: motion;
|
||||
|
||||
double drag = entity.isSwimming() ? 0.9D : 0.8D;
|
||||
worldMotion = worldMotion.scale(drag);
|
||||
boolean flying = entity instanceof Player player && player.getAbilities().flying;
|
||||
if (!flying) {
|
||||
worldMotion = worldMotion.add(0.0D, 0.005D, 0.0D);
|
||||
}
|
||||
|
||||
entity.setDeltaMovement(
|
||||
gravityDirection.isInverted()
|
||||
? AntarchyGravityRotationUtil.vecWorldToPlayer(worldMotion, gravityDirection)
|
||||
: worldMotion
|
||||
);
|
||||
|
||||
if (entity.horizontalCollision && entity.isFree(
|
||||
worldMotion.x,
|
||||
worldMotion.y + 0.6D - entity.getY() + prevY,
|
||||
worldMotion.z
|
||||
)) {
|
||||
Vec3 boostedWorldMotion = new Vec3(worldMotion.x, 0.3D, worldMotion.z);
|
||||
entity.setDeltaMovement(
|
||||
gravityDirection.isInverted()
|
||||
? AntarchyGravityRotationUtil.vecWorldToPlayer(boostedWorldMotion, gravityDirection)
|
||||
: boostedWorldMotion
|
||||
);
|
||||
}
|
||||
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
private AntarchyGravityDirection antarchy$getEffectiveGravityDirection(LivingEntity entity) {
|
||||
AntarchyGravityDirection gravityDirection = AntarchyGravityApi.getGravityDirection(entity);
|
||||
if (gravityDirection.isInverted() || !entity.hasEffect(AntarchyObjects.INVERTED_EFFECT.get())) {
|
||||
return gravityDirection;
|
||||
}
|
||||
|
||||
return AntarchyGravityDirection.UP;
|
||||
}
|
||||
|
||||
private boolean antarchy$isTouchingAntiwaterLocal(LivingEntity entity) {
|
||||
AABB box = entity.getBoundingBox().inflate(0.05D);
|
||||
BlockPos min = BlockPos.containing(box.minX, box.minY, box.minZ);
|
||||
BlockPos max = BlockPos.containing(box.maxX, box.maxY, box.maxZ);
|
||||
BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos();
|
||||
for (int x = min.getX(); x <= max.getX(); x++) {
|
||||
for (int y = min.getY(); y <= max.getY(); y++) {
|
||||
for (int z = min.getZ(); z <= max.getZ(); z++) {
|
||||
cursor.set(x, y, z);
|
||||
FluidState fluidState = entity.level().getFluidState(cursor);
|
||||
if (PotentNyxiteBlock.isAntiwater(fluidState)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.craisinlord.antarchy.fabric.mixin;
|
||||
|
||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||
import com.craisinlord.antarchy.fabric.BloodglassManager;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(LivingEntity.class)
|
||||
public abstract class BloodglassEffectMixin {
|
||||
|
||||
@Inject(method = "onEffectAdded", at = @At("TAIL"))
|
||||
private void antarchy$onBloodglassWardAdded(MobEffectInstance effectInstance, @Nullable Entity source, CallbackInfo ci) {
|
||||
LivingEntity entity = (LivingEntity) (Object) this;
|
||||
if (!effectInstance.is(AntarchyObjects.BLOODGLASS_WARD.get())) return;
|
||||
if (!(entity instanceof Player player)) return;
|
||||
BloodglassManager.handleWardApplied(player, effectInstance.getAmplifier());
|
||||
}
|
||||
|
||||
@Inject(method = "onEffectRemoved", at = @At("HEAD"))
|
||||
private void antarchy$onBloodglassWardRemoved(MobEffectInstance effectInstance, CallbackInfo ci) {
|
||||
LivingEntity entity = (LivingEntity) (Object) this;
|
||||
if (!effectInstance.is(AntarchyObjects.BLOODGLASS_WARD.get())) return;
|
||||
if (!(entity instanceof Player player)) return;
|
||||
BloodglassManager.handleWardRemoved(player);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.craisinlord.antarchy.fabric.mixin;
|
||||
|
||||
import com.craisinlord.antarchy.fabric.BloodglassManager;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(LivingEntity.class)
|
||||
public abstract class BloodglassEquipMixin {
|
||||
|
||||
@Inject(method = "onEquipItem", at = @At("TAIL"))
|
||||
private void antarchy$onBloodglassEquip(EquipmentSlot slot, ItemStack from, ItemStack to, CallbackInfo ci) {
|
||||
LivingEntity entity = (LivingEntity) (Object) this;
|
||||
if (entity instanceof Player player) {
|
||||
BloodglassManager.handleArmorEquipChange(player, slot, from, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.craisinlord.antarchy.fabric.mixin;
|
||||
|
||||
import com.craisinlord.antarchy.fabric.BloodglassManager;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ServerPlayer.class)
|
||||
public abstract class BloodglassRespawnMixin {
|
||||
|
||||
@Inject(method = "restoreFrom", at = @At("TAIL"))
|
||||
private void antarchy$onRespawn(ServerPlayer oldPlayer, boolean keepEverything, CallbackInfo ci) {
|
||||
BloodglassManager.handleRespawn((ServerPlayer) (Object) this);
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.craisinlord.antarchy.fabric.mixin;
|
||||
|
||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||
import com.craisinlord.antarchy.content.block.entity.DreamCampfireBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.entity.CampfireBlockEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||
|
||||
@Mixin(CampfireBlockEntity.class)
|
||||
public abstract class DreamCampfireBlockEntityMixin {
|
||||
@ModifyArg(
|
||||
method = "<init>",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/level/block/entity/BlockEntity;<init>(Lnet/minecraft/world/level/block/entity/BlockEntityType;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)V"
|
||||
),
|
||||
index = 0
|
||||
)
|
||||
private static BlockEntityType<? extends BlockEntity> antarchy$useDreamCampfireType(
|
||||
BlockEntityType<? extends BlockEntity> original
|
||||
) {
|
||||
return DreamCampfireBlockEntity.isConstructingDreamCampfire()
|
||||
? AntarchyObjects.DREAM_CAMPFIRE_BLOCK_ENTITY.get()
|
||||
: original;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.craisinlord.antarchy.fabric.mixin;
|
||||
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.ElytraItem;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@Mixin(LivingEntity.class)
|
||||
public abstract class ElytraFallFlyingMixin {
|
||||
|
||||
/**
|
||||
* Redirect to allow any ElytraItem subclass to sustain fall flying.
|
||||
*/
|
||||
@Redirect(
|
||||
method = "updateFallFlying",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/item/ItemStack;is(Lnet/minecraft/world/item/Item;)Z"
|
||||
)
|
||||
)
|
||||
private boolean antarchy$allowCustomElytraFallFlying(ItemStack itemStack, Item item) {
|
||||
return itemStack.getItem() instanceof ElytraItem;
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.craisinlord.antarchy.fabric.mixin;
|
||||
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ElytraItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(Player.class)
|
||||
public abstract class ElytraStartFlyingMixin {
|
||||
|
||||
@Shadow
|
||||
public abstract void startFallFlying();
|
||||
|
||||
@Inject(method = "tryToStartFallFlying", at = @At("RETURN"), cancellable = true)
|
||||
private void antarchy$allowCustomElytra(CallbackInfoReturnable<Boolean> cir) {
|
||||
if (cir.getReturnValue()) return;
|
||||
Player player = (Player) (Object) this;
|
||||
if (!player.onGround() && !player.isFallFlying() && !player.isInWater()
|
||||
&& !player.hasEffect(net.minecraft.world.effect.MobEffects.LEVITATION)) {
|
||||
ItemStack chest = player.getItemBySlot(EquipmentSlot.CHEST);
|
||||
if (chest.getItem() instanceof ElytraItem && ElytraItem.isFlyEnabled(chest)) {
|
||||
this.startFallFlying();
|
||||
cir.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package com.craisinlord.antarchy.fabric.mixin.client;
|
||||
|
||||
import com.craisinlord.antarchy.content.block.PotentNyxiteBlock;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.shaders.FogShape;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.FogRenderer;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(FogRenderer.class)
|
||||
public abstract class AntiwaterFogMixin {
|
||||
// @Inject(method = "setupColor", at = @At("TAIL"))
|
||||
// private static void antarchy$overrideAntiwaterColor(Camera camera, float partialTick, ClientLevel level, int renderDistance, float darkenWorldAmount, CallbackInfo ci) {
|
||||
// if (!antarchy$isInAntiwater(camera)) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// RenderSystem.clearColor(0.52F, 0.06F, 0.06F, 0.0F);
|
||||
// }
|
||||
//
|
||||
// @Inject(method = "setupFog", at = @At("TAIL"))
|
||||
// private static void antarchy$overrideAntiwaterFog(Camera camera, FogRenderer.FogMode mode, float renderDistance, boolean thickFog, float partialTick, CallbackInfo ci) {
|
||||
// if (!antarchy$isInAntiwater(camera)) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// RenderSystem.setShaderFogStart(0.5F);
|
||||
// RenderSystem.setShaderFogEnd(Math.min(renderDistance, 12.0F));
|
||||
// RenderSystem.setShaderFogShape(FogShape.CYLINDER);
|
||||
// }
|
||||
//
|
||||
// private static boolean antarchy$isInAntiwater(Camera camera) {
|
||||
// Entity entity = camera.getEntity();
|
||||
// if (entity == null || entity.level() == null) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// BlockPos pos = BlockPos.containing(camera.getPosition());
|
||||
// FluidState fluidState = entity.level().getFluidState(pos);
|
||||
// return PotentNyxiteBlock.isAntiwater(fluidState);
|
||||
// }
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.craisinlord.antarchy.fabric.mixin.client;
|
||||
|
||||
import com.craisinlord.antarchy.content.item.GravityGunItem;
|
||||
import com.craisinlord.antarchy.content.item.SizeRayItem;
|
||||
import com.craisinlord.antarchy.content.item.SquidzookaItem;
|
||||
import net.minecraft.client.model.HumanoidModel;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(PlayerRenderer.class)
|
||||
public class CrossbowArmPoseMixin {
|
||||
|
||||
@Inject(method = "getArmPose", at = @At("RETURN"), cancellable = true)
|
||||
private static void antarchy$customArmPose(
|
||||
AbstractClientPlayer player, InteractionHand hand,
|
||||
CallbackInfoReturnable<HumanoidModel.ArmPose> cir) {
|
||||
ItemStack stack = player.getItemInHand(hand);
|
||||
Item item = stack.getItem();
|
||||
|
||||
if (item instanceof GravityGunItem || item instanceof SquidzookaItem) {
|
||||
cir.setReturnValue(HumanoidModel.ArmPose.CROSSBOW_HOLD);
|
||||
} else if (item instanceof SizeRayItem) {
|
||||
if (player.isUsingItem() && player.getUsedItemHand() == hand) {
|
||||
cir.setReturnValue(HumanoidModel.ArmPose.CROSSBOW_HOLD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.craisinlord.antarchy.fabric.mixin.client;
|
||||
|
||||
import com.craisinlord.antarchy.content.block.DuctTapeBlock;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.Input;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(Input.class)
|
||||
public abstract class DuctTapeInputMixin {
|
||||
|
||||
@Inject(method = "tick", at = @At("RETURN"))
|
||||
private void blockInputInDuctTape(boolean isSneaking, float slowFactor, CallbackInfo ci) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (mc.player == null || mc.level == null) return;
|
||||
if (!mc.player.isNoGravity() && !DuctTapeBlock.isTouchingTape(mc.level, mc.player)) return;
|
||||
|
||||
Input self = (Input) (Object) this;
|
||||
self.left = false;
|
||||
self.right = false;
|
||||
self.up = false;
|
||||
self.down = false;
|
||||
self.leftImpulse = 0.0F;
|
||||
self.forwardImpulse = 0.0F;
|
||||
self.jumping = false;
|
||||
self.shiftKeyDown = false;
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.craisinlord.antarchy.fabric.mixin.client;
|
||||
|
||||
import com.craisinlord.antarchy.fabric.client.GravityGunClientHandler;
|
||||
import net.minecraft.client.MouseHandler;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(MouseHandler.class)
|
||||
public abstract class GravityGunMouseScrollMixin {
|
||||
@Inject(method = "onScroll", at = @At("HEAD"), cancellable = true)
|
||||
private void antarchy$handleGravityGunScroll(long window, double horizontalAmount, double verticalAmount, CallbackInfo ci) {
|
||||
if (GravityGunClientHandler.onScroll(verticalAmount)) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.craisinlord.antarchy.fabric.mixin.client;
|
||||
|
||||
import com.craisinlord.antarchy.content.entity.nightmare.NightmareEntity;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Axis;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
//TODO FIX ON FABRIC SIDE
|
||||
@Mixin(GameRenderer.class)
|
||||
public abstract class NightmareCameraShakeMixin {
|
||||
// private static final double MAX_SHAKE_RANGE = 32.0D;
|
||||
//
|
||||
// @Shadow @Final private Minecraft minecraft;
|
||||
//
|
||||
// @Redirect(
|
||||
// method = "renderLevel",
|
||||
// at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;bobView(Lcom/mojang/blaze3d/vertex/PoseStack;F)V")
|
||||
// )
|
||||
// private void applyNightmareCameraShake(GameRenderer instance, PoseStack poseStack, float partialTick) {
|
||||
// instance.bobView(poseStack, partialTick);
|
||||
// if (minecraft.level == null || minecraft.player == null) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// Vec3 cameraPos = minecraft.gameRenderer.getMainCamera().getPosition();
|
||||
// float shakeStrength = 0.0F;
|
||||
//
|
||||
// for (NightmareEntity nightmare : minecraft.level.getEntitiesOfClass(
|
||||
// NightmareEntity.class,
|
||||
// minecraft.player.getBoundingBox().inflate(MAX_SHAKE_RANGE),
|
||||
// e -> e.isAlive() && e.isRoaring()
|
||||
// )) {
|
||||
// double distance = Math.sqrt(cameraPos.distanceToSqr(nightmare.position().add(0.0D, nightmare.getBbHeight() * 0.5D, 0.0D)));
|
||||
// if (distance > MAX_SHAKE_RANGE) {
|
||||
// continue;
|
||||
// }
|
||||
// shakeStrength += (float) ((1.0D - distance / MAX_SHAKE_RANGE) * 1.35D);
|
||||
// }
|
||||
//
|
||||
// if (shakeStrength <= 0.0F) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// float time = (float) (minecraft.player.tickCount + partialTick);
|
||||
// float yawOffset = Mth.sin(time * 1.85F) * shakeStrength * 1.8F;
|
||||
// float pitchOffset = Mth.cos(time * 2.15F) * shakeStrength * 1.45F;
|
||||
// float rollOffset = Mth.sin(time * 2.65F) * shakeStrength * 1.05F;
|
||||
//
|
||||
// poseStack.mulPose(Axis.YP.rotationDegrees(yawOffset));
|
||||
// poseStack.mulPose(Axis.XP.rotationDegrees(pitchOffset));
|
||||
// poseStack.mulPose(Axis.ZP.rotationDegrees(rollOffset));
|
||||
// }
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package com.craisinlord.antarchy.fabric.mixin.infinity;
|
||||
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.NetherPortalBlock;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(value = NetherPortalBlock.class, priority = 2000)
|
||||
public abstract class PortalCreatorMixin {
|
||||
@Inject(
|
||||
method = "entityInside",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void antarchy$blockInfinityBookActivation(BlockState state, Level level, BlockPos pos, Entity entity, CallbackInfo ci) {
|
||||
if (!AntarchySettings.disableInfinityBookPortalCreation()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(entity instanceof ItemEntity itemEntity) || itemEntity.isRemoved()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack stack = itemEntity.getItem();
|
||||
if (!stack.has(DataComponents.WRITABLE_BOOK_CONTENT) && !stack.has(DataComponents.WRITTEN_BOOK_CONTENT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.craisinlord.antarchy.fabric.mixin.infinity;
|
||||
|
||||
import net.lerariemann.infinity.dimensions.features.fluid_springs.RandomSpring;
|
||||
import net.lerariemann.infinity.util.core.ConfigType;
|
||||
import net.lerariemann.infinity.util.core.RandomProvider;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
@Mixin(value = RandomSpring.class, remap = false)
|
||||
/*
|
||||
* Skips bad fluid picks for Infinity random springs on Fabric.
|
||||
*/
|
||||
public abstract class RandomSpringMixin {
|
||||
@Redirect(
|
||||
method = "feature",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/lerariemann/infinity/util/core/RandomProvider;randomName(Ljava/util/Random;Lnet/lerariemann/infinity/util/core/ConfigType;)Ljava/lang/String;"
|
||||
)
|
||||
)
|
||||
private String antarchy$useFluidIdForSpring(RandomProvider provider, Random random, ConfigType configType) {
|
||||
if (configType != ConfigType.FLUIDS) {
|
||||
return provider.randomName(random, configType);
|
||||
}
|
||||
|
||||
CompoundTag fluidTag = provider.randomElement(random, configType);
|
||||
String fluidId = fluidTag.getString("fluidName");
|
||||
if (!fluidId.isEmpty()) {
|
||||
return fluidId;
|
||||
}
|
||||
return fluidTag.getString("Name");
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.craisinlord.antarchy.fabric.network;
|
||||
|
||||
import com.craisinlord.antarchy.content.client.BloodglassClientState;
|
||||
import com.craisinlord.antarchy.content.client.BrutalflyElytraClientState;
|
||||
import com.craisinlord.antarchy.content.client.ScorpionWhipTetherClientState;
|
||||
import com.craisinlord.antarchy.content.client.ThoraxisWeatherClientState;
|
||||
import com.craisinlord.antarchy.content.network.*;
|
||||
import com.craisinlord.antarchy.content.weather.ThoraxisWeatherKind;
|
||||
import com.craisinlord.antarchy.fabric.client.BloodCrystalKatanaTrailClientState;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public final class AntarchyFabricClientNetworking {
|
||||
private AntarchyFabricClientNetworking() {
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
ClientPlayNetworking.registerGlobalReceiver(GravityStatePayload.TYPE, (payload, context) ->
|
||||
context.client().execute(() -> AntarchyFabricNetworking.handleGravityState(context.player(), payload)));
|
||||
ClientPlayNetworking.registerGlobalReceiver(BloodglassStatePayload.TYPE, (payload, context) ->
|
||||
context.client().execute(() -> BloodglassClientState.update(payload.shieldsActive(), payload.shieldsMax())));
|
||||
ClientPlayNetworking.registerGlobalReceiver(BloodCrystalKatanaTrailPayload.TYPE, (payload, context) ->
|
||||
context.client().execute(() -> BloodCrystalKatanaTrailClientState.trigger(payload.entityId(), payload.durationTicks())));
|
||||
ClientPlayNetworking.registerGlobalReceiver(ScorpionWhipTetherPayload.TYPE, (payload, context) ->
|
||||
context.client().execute(() -> ScorpionWhipTetherClientState.update(payload.playerId(), payload.targetId())));
|
||||
ClientPlayNetworking.registerGlobalReceiver(BrutalflyElytraAnimationPayload.TYPE, (payload, context) ->
|
||||
context.client().execute(() -> BrutalflyElytraClientState.trigger(payload.entityId(), payload.durationTicks(), payload.strength())));
|
||||
ClientPlayNetworking.registerGlobalReceiver(ThoraxisWeatherPayload.TYPE, (payload, context) ->
|
||||
context.client().execute(() -> ThoraxisWeatherClientState.apply(
|
||||
ResourceLocation.parse(payload.dimensionId()),
|
||||
ThoraxisWeatherKind.byId(payload.weatherId()),
|
||||
payload.expiresAt(),
|
||||
payload.anchorX(),
|
||||
payload.anchorY(),
|
||||
payload.anchorZ()
|
||||
)));
|
||||
}
|
||||
}
|
||||
+265
@@ -0,0 +1,265 @@
|
||||
package com.craisinlord.antarchy.fabric.network;
|
||||
|
||||
import com.craisinlord.antarchy.content.entity.DiamondMinecartEntity;
|
||||
import com.craisinlord.antarchy.content.entity.multipart.MultipartEntityOwner;
|
||||
import com.craisinlord.antarchy.content.entity.multipart.network.MultipartAttackPayload;
|
||||
import com.craisinlord.antarchy.content.entity.multipart.network.MultipartInteractPayload;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||
import com.craisinlord.antarchy.content.item.BrutalflyElytraFlightHelper;
|
||||
import com.craisinlord.antarchy.content.item.BrutalflyElytraItem;
|
||||
import com.craisinlord.antarchy.content.item.GravityGunItem;
|
||||
import com.craisinlord.antarchy.content.network.*;
|
||||
import com.craisinlord.antarchy.content.weather.ThoraxisWeatherSnapshot;
|
||||
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
|
||||
import net.fabricmc.fabric.api.networking.v1.PlayerLookup;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
import net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public final class AntarchyFabricNetworking {
|
||||
private AntarchyFabricNetworking() {
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
registerPayloadTypes();
|
||||
registerServerReceivers();
|
||||
}
|
||||
|
||||
private static void registerPayloadTypes() {
|
||||
PayloadTypeRegistry.playS2C().register(GravityStatePayload.TYPE, GravityStatePayload.STREAM_CODEC);
|
||||
PayloadTypeRegistry.playS2C().register(BloodglassStatePayload.TYPE, BloodglassStatePayload.STREAM_CODEC);
|
||||
PayloadTypeRegistry.playS2C().register(BloodCrystalKatanaTrailPayload.TYPE, BloodCrystalKatanaTrailPayload.STREAM_CODEC);
|
||||
PayloadTypeRegistry.playS2C().register(ScorpionWhipTetherPayload.TYPE, ScorpionWhipTetherPayload.STREAM_CODEC);
|
||||
PayloadTypeRegistry.playS2C().register(BrutalflyElytraAnimationPayload.TYPE, BrutalflyElytraAnimationPayload.STREAM_CODEC);
|
||||
PayloadTypeRegistry.playS2C().register(ThoraxisWeatherPayload.TYPE, ThoraxisWeatherPayload.STREAM_CODEC);
|
||||
|
||||
PayloadTypeRegistry.playC2S().register(GravityGunPrimaryPayload.TYPE, GravityGunPrimaryPayload.STREAM_CODEC);
|
||||
PayloadTypeRegistry.playC2S().register(GravityGunScrollPayload.TYPE, GravityGunScrollPayload.STREAM_CODEC);
|
||||
PayloadTypeRegistry.playC2S().register(DiamondMinecartInputPayload.TYPE, DiamondMinecartInputPayload.STREAM_CODEC);
|
||||
PayloadTypeRegistry.playC2S().register(BrutalflyElytraFlapPayload.TYPE, BrutalflyElytraFlapPayload.STREAM_CODEC);
|
||||
PayloadTypeRegistry.playC2S().register(MultipartAttackPayload.TYPE, MultipartAttackPayload.STREAM_CODEC);
|
||||
PayloadTypeRegistry.playC2S().register(MultipartInteractPayload.TYPE, MultipartInteractPayload.STREAM_CODEC);
|
||||
}
|
||||
|
||||
private static void registerServerReceivers() {
|
||||
ServerPlayNetworking.registerGlobalReceiver(GravityGunPrimaryPayload.TYPE, (payload, context) ->
|
||||
context.server().execute(() -> handleGravityGunPrimary(context.player(), payload)));
|
||||
ServerPlayNetworking.registerGlobalReceiver(GravityGunScrollPayload.TYPE, (payload, context) ->
|
||||
context.server().execute(() -> handleGravityGunScroll(context.player(), payload)));
|
||||
ServerPlayNetworking.registerGlobalReceiver(DiamondMinecartInputPayload.TYPE, (payload, context) ->
|
||||
context.server().execute(() -> handleDiamondMinecartInput(context.player(), payload)));
|
||||
ServerPlayNetworking.registerGlobalReceiver(BrutalflyElytraFlapPayload.TYPE, (payload, context) ->
|
||||
context.server().execute(() -> handleBrutalflyFlap(context.player(), payload)));
|
||||
ServerPlayNetworking.registerGlobalReceiver(MultipartAttackPayload.TYPE, (payload, context) ->
|
||||
context.server().execute(() -> handleMultipartAttack(context.player(), payload)));
|
||||
ServerPlayNetworking.registerGlobalReceiver(MultipartInteractPayload.TYPE, (payload, context) ->
|
||||
context.server().execute(() -> handleMultipartInteract(context.player(), payload)));
|
||||
}
|
||||
|
||||
public static void syncGravityToPlayer(ServerPlayer target, Entity entity) {
|
||||
ServerPlayNetworking.send(target, new GravityStatePayload(
|
||||
entity.getId(),
|
||||
AntarchyGravityApi.getGravityDirection(entity),
|
||||
AntarchyGravityApi.getPrevGravityDirection(entity),
|
||||
AntarchyGravityApi.isGravityForced(entity),
|
||||
AntarchyGravityApi.getTransitionDuration(entity),
|
||||
AntarchyGravityApi.getTransitionRemaining(entity)
|
||||
));
|
||||
}
|
||||
|
||||
public static void syncGravityEntity(Entity entity) {
|
||||
GravityStatePayload payload = new GravityStatePayload(
|
||||
entity.getId(),
|
||||
AntarchyGravityApi.getGravityDirection(entity),
|
||||
AntarchyGravityApi.getPrevGravityDirection(entity),
|
||||
AntarchyGravityApi.isGravityForced(entity),
|
||||
AntarchyGravityApi.getTransitionDuration(entity),
|
||||
AntarchyGravityApi.getTransitionRemaining(entity)
|
||||
);
|
||||
|
||||
for (ServerPlayer player : PlayerLookup.tracking(entity)) {
|
||||
ServerPlayNetworking.send(player, payload);
|
||||
}
|
||||
if (entity instanceof ServerPlayer player) {
|
||||
ServerPlayNetworking.send(player, payload);
|
||||
}
|
||||
}
|
||||
|
||||
public static void syncBloodglass(ServerPlayer player, int shieldsActive, int shieldsMax) {
|
||||
ServerPlayNetworking.send(player, new BloodglassStatePayload(shieldsActive, shieldsMax));
|
||||
}
|
||||
|
||||
public static void syncKatanaTrail(Entity entity, int durationTicks) {
|
||||
BloodCrystalKatanaTrailPayload payload = new BloodCrystalKatanaTrailPayload(entity.getId(), durationTicks);
|
||||
for (ServerPlayer player : PlayerLookup.tracking(entity)) {
|
||||
ServerPlayNetworking.send(player, payload);
|
||||
}
|
||||
if (entity instanceof ServerPlayer serverPlayer) {
|
||||
ServerPlayNetworking.send(serverPlayer, payload);
|
||||
}
|
||||
}
|
||||
|
||||
public static void syncScorpionWhipTether(ServerPlayer player, int targetId) {
|
||||
ScorpionWhipTetherPayload payload = new ScorpionWhipTetherPayload(player.getId(), targetId);
|
||||
for (ServerPlayer tracking : PlayerLookup.tracking(player)) {
|
||||
ServerPlayNetworking.send(tracking, payload);
|
||||
}
|
||||
ServerPlayNetworking.send(player, payload);
|
||||
}
|
||||
|
||||
public static void syncThoraxisWeather(ServerLevel level, ThoraxisWeatherSnapshot snapshot) {
|
||||
ThoraxisWeatherPayload payload = new ThoraxisWeatherPayload(
|
||||
snapshot.dimension(),
|
||||
snapshot.kind(),
|
||||
snapshot.expiresAt(),
|
||||
snapshot.anchor().getX(),
|
||||
snapshot.anchor().getY(),
|
||||
snapshot.anchor().getZ()
|
||||
);
|
||||
for (ServerPlayer player : level.players()) {
|
||||
ServerPlayNetworking.send(player, payload);
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleGravityState(Entity contextPlayer, GravityStatePayload payload) {
|
||||
Entity entity = contextPlayer.level().getEntity(payload.entityId());
|
||||
if (entity == null && contextPlayer.getId() == payload.entityId()) {
|
||||
entity = contextPlayer;
|
||||
}
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
AntarchyGravityApi.applySyncedState(
|
||||
entity,
|
||||
payload.direction(),
|
||||
payload.previousDirection(),
|
||||
payload.forced(),
|
||||
payload.transitionDuration(),
|
||||
payload.transitionRemaining()
|
||||
);
|
||||
}
|
||||
|
||||
private static void handleGravityGunPrimary(ServerPlayer player, GravityGunPrimaryPayload payload) {
|
||||
if (!(player.getMainHandItem().getItem() instanceof GravityGunItem gravityGunItem)) {
|
||||
return;
|
||||
}
|
||||
gravityGunItem.firePrimary(player.serverLevel(), player, player.getMainHandItem());
|
||||
}
|
||||
|
||||
private static void handleGravityGunScroll(ServerPlayer player, GravityGunScrollPayload payload) {
|
||||
if (!(player.getMainHandItem().getItem() instanceof GravityGunItem)) {
|
||||
return;
|
||||
}
|
||||
GravityGunItem.adjustHeldDistance(player.getMainHandItem(), payload.distanceDelta());
|
||||
}
|
||||
|
||||
private static void handleDiamondMinecartInput(ServerPlayer player, DiamondMinecartInputPayload payload) {
|
||||
if (player.getVehicle() instanceof DiamondMinecartEntity cart) {
|
||||
cart.onInputReceived(payload.inputFlags());
|
||||
}
|
||||
}
|
||||
|
||||
private static void handleBrutalflyFlap(ServerPlayer player, BrutalflyElytraFlapPayload payload) {
|
||||
ItemStack chestStack = player.getItemBySlot(EquipmentSlot.CHEST);
|
||||
if (!(chestStack.getItem() instanceof BrutalflyElytraItem)) {
|
||||
return;
|
||||
}
|
||||
if (player.isSpectator() || !player.isFallFlying() || player.isPassenger()) {
|
||||
return;
|
||||
}
|
||||
if (player.getCooldowns().isOnCooldown(chestStack.getItem())) {
|
||||
return;
|
||||
}
|
||||
|
||||
BrutalflyElytraFlightHelper.FlapTier tier = BrutalflyElytraFlightHelper.resolveFlapTier(payload.chargeTicks());
|
||||
if (tier == BrutalflyElytraFlightHelper.FlapTier.FAIL) {
|
||||
return;
|
||||
}
|
||||
|
||||
float lift = BrutalflyElytraFlightHelper.liftFor(tier);
|
||||
float forwardBoost = BrutalflyElytraFlightHelper.forwardBoostFor(tier);
|
||||
Vec3 look = player.getLookAngle();
|
||||
Vec3 boost = new Vec3(look.x * forwardBoost, lift, look.z * forwardBoost);
|
||||
player.setDeltaMovement(player.getDeltaMovement().add(boost));
|
||||
player.hasImpulse = true;
|
||||
player.hurtMarked = true;
|
||||
player.resetFallDistance();
|
||||
player.connection.send(new ClientboundSetEntityMotionPacket(player));
|
||||
chestStack.hurtAndBreak(1, player, EquipmentSlot.CHEST);
|
||||
player.getCooldowns().addCooldown(chestStack.getItem(), BrutalflyElytraFlightHelper.FLAP_COOLDOWN_TICKS);
|
||||
player.level().playSound(null, player.blockPosition(), SoundEvents.PHANTOM_FLAP, SoundSource.PLAYERS, 0.9F,
|
||||
tier == BrutalflyElytraFlightHelper.FlapTier.PERFECT ? 0.8F : tier == BrutalflyElytraFlightHelper.FlapTier.GOOD ? 0.95F : 1.1F);
|
||||
|
||||
BrutalflyElytraAnimationPayload animationPayload = new BrutalflyElytraAnimationPayload(
|
||||
player.getId(),
|
||||
BrutalflyElytraFlightHelper.animationTicksFor(tier),
|
||||
lift
|
||||
);
|
||||
for (ServerPlayer tracking : PlayerLookup.tracking(player)) {
|
||||
ServerPlayNetworking.send(tracking, animationPayload);
|
||||
}
|
||||
ServerPlayNetworking.send(player, animationPayload);
|
||||
}
|
||||
|
||||
private static void handleMultipartAttack(ServerPlayer serverPlayer, MultipartAttackPayload payload) {
|
||||
Entity entity = serverPlayer.serverLevel().getEntity(payload.parentId());
|
||||
if (!(entity instanceof MultipartEntityOwner owner)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Entity[] parts = owner.antarchy$getMultipartParts();
|
||||
if (parts == null) {
|
||||
parts = owner.antarchy$createMultipartParts();
|
||||
owner.antarchy$setMultipartParts(parts);
|
||||
owner.antarchy$syncMultipartParts();
|
||||
}
|
||||
if (payload.partIndex() < 0 || payload.partIndex() >= parts.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
Entity part = parts[payload.partIndex()];
|
||||
if (part == null || part.isRemoved()) {
|
||||
return;
|
||||
}
|
||||
if (serverPlayer.distanceToSqr(part) > 10000.0D) {
|
||||
return;
|
||||
}
|
||||
|
||||
DamageSource source = serverPlayer.level().damageSources().playerAttack(serverPlayer);
|
||||
owner.antarchy$hurtMultipartPart(part, source, payload.damage());
|
||||
}
|
||||
|
||||
private static void handleMultipartInteract(ServerPlayer serverPlayer, MultipartInteractPayload payload) {
|
||||
Entity entity = serverPlayer.serverLevel().getEntity(payload.parentId());
|
||||
if (!(entity instanceof MultipartEntityOwner owner)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Entity[] parts = owner.antarchy$getMultipartParts();
|
||||
if (parts == null) {
|
||||
parts = owner.antarchy$createMultipartParts();
|
||||
owner.antarchy$setMultipartParts(parts);
|
||||
owner.antarchy$syncMultipartParts();
|
||||
}
|
||||
if (payload.partIndex() < 0 || payload.partIndex() >= parts.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
Entity part = parts[payload.partIndex()];
|
||||
if (part == null || part.isRemoved()) {
|
||||
return;
|
||||
}
|
||||
|
||||
InteractionHand hand = payload.handId() == 0 ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND;
|
||||
owner.antarchy$interactMultipartPart(part, serverPlayer, part.position(), hand);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.craisinlord.antarchy.fabric.registry;
|
||||
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
||||
public final class DeferredBlock<T extends Block> extends DeferredHolder<Block, T> {
|
||||
DeferredBlock(ResourceKey<?> registryKey, ResourceLocation id) {
|
||||
super(registryKey, id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.craisinlord.antarchy.fabric.registry;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class DeferredHolder<R, T extends R> implements Supplier<T> {
|
||||
private final ResourceKey<?> registryKey;
|
||||
private final ResourceLocation id;
|
||||
private T value;
|
||||
|
||||
DeferredHolder(ResourceKey<?> registryKey, ResourceLocation id) {
|
||||
this.registryKey = registryKey;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
void bind(T value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public ResourceLocation getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ResourceKey<T> getKey() {
|
||||
return (ResourceKey<T>) ResourceKey.create((ResourceKey) this.registryKey, this.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
if (this.value == null) {
|
||||
throw new IllegalStateException("Registry object not yet bound: " + this.id);
|
||||
}
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.craisinlord.antarchy.fabric.registry;
|
||||
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
|
||||
public final class DeferredItem<T extends Item> extends DeferredHolder<Item, T> {
|
||||
DeferredItem(ResourceKey<?> registryKey, ResourceLocation id) {
|
||||
super(registryKey, id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package com.craisinlord.antarchy.fabric.registry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
||||
public class DeferredRegister<T> {
|
||||
public static final class Blocks extends DeferredRegister<Block> {
|
||||
private Blocks(String modId) {
|
||||
super(net.minecraft.core.registries.Registries.BLOCK, modId);
|
||||
}
|
||||
|
||||
public <I extends Block> DeferredBlock<I> register(String name, Supplier<? extends I> supplier) {
|
||||
return this.registerTyped(name, supplier, DeferredBlock::new);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Items extends DeferredRegister<Item> {
|
||||
private Items(String modId) {
|
||||
super(net.minecraft.core.registries.Registries.ITEM, modId);
|
||||
}
|
||||
|
||||
public <I extends Item> DeferredItem<I> register(String name, Supplier<? extends I> supplier) {
|
||||
return this.registerTyped(name, supplier, DeferredItem::new);
|
||||
}
|
||||
|
||||
public DeferredItem<Item> registerSimpleItem(String name) {
|
||||
return this.registerSimpleItem(name, new Item.Properties());
|
||||
}
|
||||
|
||||
public DeferredItem<Item> registerSimpleItem(String name, Item.Properties properties) {
|
||||
return this.register(name, () -> new Item(properties));
|
||||
}
|
||||
|
||||
public DeferredItem<BlockItem> registerSimpleBlockItem(DeferredBlock<? extends Block> block) {
|
||||
return this.register(block.getId().getPath(), () -> new BlockItem(block.get(), new Item.Properties()));
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
protected interface HolderFactory<R, T extends R, H extends DeferredHolder<R, T>> {
|
||||
H create(ResourceKey<?> registryKey, ResourceLocation id);
|
||||
}
|
||||
|
||||
private record PendingEntry<T>(ResourceLocation id, Supplier<? extends T> supplier, DeferredHolder<T, ? extends T> holder) {
|
||||
}
|
||||
|
||||
private final ResourceKey<? extends Registry<T>> registryKey;
|
||||
private final String modId;
|
||||
private final List<PendingEntry<T>> entries = new ArrayList<>();
|
||||
|
||||
protected DeferredRegister(ResourceKey<? extends Registry<T>> registryKey, String modId) {
|
||||
this.registryKey = registryKey;
|
||||
this.modId = modId;
|
||||
}
|
||||
|
||||
public static Blocks createBlocks(String modId) {
|
||||
return new Blocks(modId);
|
||||
}
|
||||
|
||||
public static Items createItems(String modId) {
|
||||
return new Items(modId);
|
||||
}
|
||||
|
||||
public static <T> DeferredRegister<T> create(ResourceKey<? extends Registry<T>> registryKey, String modId) {
|
||||
return new DeferredRegister<>(registryKey, modId);
|
||||
}
|
||||
|
||||
public <I extends T> DeferredHolder<T, I> register(String name, Supplier<? extends I> supplier) {
|
||||
return this.registerTyped(name, supplier, DeferredHolder::new);
|
||||
}
|
||||
|
||||
protected <I extends T, H extends DeferredHolder<T, I>> H registerTyped(String name, Supplier<? extends I> supplier, HolderFactory<T, I, H> factory) {
|
||||
ResourceLocation id = ResourceLocation.fromNamespaceAndPath(this.modId, name);
|
||||
H holder = factory.create(this.registryKey, id);
|
||||
this.entries.add(new PendingEntry<>(id, supplier, holder));
|
||||
return holder;
|
||||
}
|
||||
|
||||
public List<DeferredHolder<T, ? extends T>> getEntries() {
|
||||
List<DeferredHolder<T, ? extends T>> holders = new ArrayList<>(this.entries.size());
|
||||
for (PendingEntry<T> entry : this.entries) {
|
||||
holders.add(entry.holder());
|
||||
}
|
||||
return Collections.unmodifiableList(holders);
|
||||
}
|
||||
|
||||
public void register() {
|
||||
Registry<T> registry = resolveRegistry(this.registryKey);
|
||||
for (PendingEntry<T> entry : this.entries) {
|
||||
T value = Registry.register(registry, entry.id(), entry.supplier().get());
|
||||
bind(entry.holder(), value);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private static <T> void bind(DeferredHolder<T, ? extends T> holder, T value) {
|
||||
((DeferredHolder) holder).bind(value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> Registry<T> resolveRegistry(ResourceKey<? extends Registry<T>> registryKey) {
|
||||
Registry<?> registry = BuiltInRegistries.REGISTRY.get(registryKey.location());
|
||||
if (registry == null) {
|
||||
throw new IllegalStateException("Could not resolve registry: " + registryKey.location());
|
||||
}
|
||||
return (Registry<T>) registry;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"required": true,
|
||||
"package": "com.craisinlord.antarchy.fabric.mixin",
|
||||
"refmap": "antarchy.refmap.json",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"mixins": [
|
||||
"AntiwaterLivingEntityMixin",
|
||||
"AntiwaterItemEntityMixin",
|
||||
"AntimetalInversionMixin",
|
||||
"AntimetalScaffoldingMixin",
|
||||
"ElytraStartFlyingMixin",
|
||||
"ElytraFallFlyingMixin",
|
||||
"BloodglassEquipMixin",
|
||||
"BloodglassEffectMixin",
|
||||
"BloodglassRespawnMixin",
|
||||
"DreamCampfireBlockEntityMixin",
|
||||
"infinity.RandomSpringMixin",
|
||||
"infinity.PortalCreatorMixin"
|
||||
],
|
||||
"client": [
|
||||
"client.NightmareCameraShakeMixin",
|
||||
"client.DuctTapeInputMixin",
|
||||
"client.AntiwaterFogMixin",
|
||||
"client.GravityGunMouseScrollMixin",
|
||||
"client.CrossbowArmPoseMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
},
|
||||
"minVersion": "0.8"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "antarchy:item/antiwater_bucket"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"parent": "antarchy:item/battle_axe_held"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"parent": "antarchy:item/big_bertha_held"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"parent": "antarchy:item/gravity_gun_held_geo"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"parent": "antarchy:item/grow_ray_held_geo"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "antarchy:item/ichor_bucket"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"parent": "antarchy:item/shrink_ray_held_geo"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"parent": "antarchy:item/squidzooka_held_geo"
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "${mod_id}",
|
||||
"version": "${version}",
|
||||
"name": "${mod_name}",
|
||||
"description": "${mod_description}",
|
||||
"authors": [
|
||||
"${mod_author}"
|
||||
],
|
||||
"contact": {
|
||||
"homepage": "${homepage_url}",
|
||||
"sources": "${sources_url}",
|
||||
"issues": "${issues_url}"
|
||||
},
|
||||
"license": "${license}",
|
||||
"environment": "*",
|
||||
"icon": "${logo_fabric}",
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"com.craisinlord.antarchy.fabric.AntarchyFabric"
|
||||
],
|
||||
"client": [
|
||||
"com.craisinlord.antarchy.fabric.client.AntarchyFabricClient"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
"antarchy-common.mixins.json",
|
||||
"antarchy-fabric.mixins.json"
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=${fabric_loader_version}",
|
||||
"minecraft": "~${minecraft_version}",
|
||||
"java": ">=21",
|
||||
"fabric-api": "*",
|
||||
"integrated_api": "*",
|
||||
"geckolib": "*"
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user