Compare commits
No commits in common. "ac3d92fc97a2020e95c07fa365f1213a85e38f63" and "34ea071e5fc67cfa6030916a9927a1590661066b" have entirely different histories.
ac3d92fc97
...
34ea071e5f
54 changed files with 1188 additions and 852 deletions
40
.github/workflows/build.yml
vendored
40
.github/workflows/build.yml
vendored
|
@ -1,40 +0,0 @@
|
|||
# Automatically build the project and run any configured tests for every push
|
||||
# and submitted pull request. This can help catch issues that only occur on
|
||||
# certain platforms or Java versions, and provides a first line of defence
|
||||
# against bad commits.
|
||||
|
||||
name: build
|
||||
on: [pull_request, push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
# Use these Java versions
|
||||
java: [
|
||||
17, # Current Java LTS & minimum supported by Minecraft
|
||||
]
|
||||
# and run on both Linux and Windows
|
||||
os: [ubuntu-22.04, windows-2022]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: validate gradle wrapper
|
||||
uses: gradle/wrapper-validation-action@v1
|
||||
- name: setup jdk ${{ matrix.java }}
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: ${{ matrix.java }}
|
||||
distribution: 'microsoft'
|
||||
- name: make gradle wrapper executable
|
||||
if: ${{ runner.os != 'Windows' }}
|
||||
run: chmod +x ./gradlew
|
||||
- name: build
|
||||
run: ./gradlew build
|
||||
- name: capture build artifacts
|
||||
if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Artifacts
|
||||
path: build/libs/
|
47
.gitignore
vendored
47
.gitignore
vendored
|
@ -1,40 +1,19 @@
|
|||
# gradle
|
||||
|
||||
.gradle/
|
||||
build/
|
||||
out/
|
||||
classes/
|
||||
|
||||
# eclipse
|
||||
|
||||
*.launch
|
||||
|
||||
# idea
|
||||
|
||||
.idea/
|
||||
*.iml
|
||||
*.ipr
|
||||
run/
|
||||
*.iws
|
||||
|
||||
# vscode
|
||||
|
||||
.settings/
|
||||
.vscode/
|
||||
out/
|
||||
*.iml
|
||||
.gradle/
|
||||
output/
|
||||
bin/
|
||||
libs/
|
||||
|
||||
.classpath
|
||||
.project
|
||||
|
||||
# macos
|
||||
|
||||
*.DS_Store
|
||||
|
||||
# fabric
|
||||
|
||||
run/
|
||||
|
||||
# java
|
||||
|
||||
hs_err_*.log
|
||||
replay_*.log
|
||||
*.hprof
|
||||
*.jfr
|
||||
.idea/
|
||||
classes/
|
||||
.metadata
|
||||
.vscode
|
||||
.settings
|
||||
*.launch
|
121
LICENSE
121
LICENSE
|
@ -1,121 +0,0 @@
|
|||
Creative Commons Legal Code
|
||||
|
||||
CC0 1.0 Universal
|
||||
|
||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||
HEREUNDER.
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for
|
||||
the purpose of contributing to a commons of creative, cultural and
|
||||
scientific works ("Commons") that the public can reliably and without fear
|
||||
of later claims of infringement build upon, modify, incorporate in other
|
||||
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||
and for any purposes, including without limitation commercial purposes.
|
||||
These owners may contribute to the Commons to promote the ideal of a free
|
||||
culture and the further production of creative, cultural and scientific
|
||||
works, or to gain reputation or greater distribution for their Work in
|
||||
part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any
|
||||
expectation of additional consideration or compensation, the person
|
||||
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not
|
||||
limited to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display,
|
||||
communicate, and translate a Work;
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
iii. publicity and privacy rights pertaining to a person's image or
|
||||
likeness depicted in a Work;
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||
in a Work;
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation
|
||||
thereof, including any amended or successor version of such
|
||||
directive); and
|
||||
vii. other similar, equivalent or corresponding rights throughout the
|
||||
world based on applicable law or treaty, and any national
|
||||
implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||
of action, whether now known or unknown (including existing as well as
|
||||
future claims and causes of action), in the Work (i) in all territories
|
||||
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||
treaty (including future time extensions), (iii) in any current or future
|
||||
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||
including without limitation commercial, advertising or promotional
|
||||
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||
member of the public at large and to the detriment of Affirmer's heirs and
|
||||
successors, fully intending that such Waiver shall not be subject to
|
||||
revocation, rescission, cancellation, termination, or any other legal or
|
||||
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||
as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||
be judged legally invalid or ineffective under applicable law, then the
|
||||
Waiver shall be preserved to the maximum extent permitted taking into
|
||||
account Affirmer's express Statement of Purpose. In addition, to the
|
||||
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||
maximum duration provided by applicable law or treaty (including future
|
||||
time extensions), (iii) in any current or future medium and for any number
|
||||
of copies, and (iv) for any purpose whatsoever, including without
|
||||
limitation commercial, advertising or promotional purposes (the
|
||||
"License"). The License shall be deemed effective as of the date CC0 was
|
||||
applied by Affirmer to the Work. Should any part of the License for any
|
||||
reason be judged legally invalid or ineffective under applicable law, such
|
||||
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||
of the License, and in such case Affirmer hereby affirms that he or she
|
||||
will not (i) exercise any of his or her remaining Copyright and Related
|
||||
Rights in the Work or (ii) assert any associated claims and causes of
|
||||
action with respect to the Work, in either case contrary to Affirmer's
|
||||
express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
b. Affirmer offers the Work as-is and makes no representations or
|
||||
warranties of any kind concerning the Work, express, implied,
|
||||
statutory or otherwise, including without limitation warranties of
|
||||
title, merchantability, fitness for a particular purpose, non
|
||||
infringement, or the absence of latent or other defects, accuracy, or
|
||||
the present or absence of errors, whether or not discoverable, all to
|
||||
the greatest extent permissible under applicable law.
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without
|
||||
limitation any person's Copyright and Related Rights in the Work.
|
||||
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||
consents, permissions or other rights required for any use of the
|
||||
Work.
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to
|
||||
this CC0 or use of the Work.
|
120
build.gradle
120
build.gradle
|
@ -1,88 +1,52 @@
|
|||
plugins {
|
||||
id 'fabric-loom' version '1.4-SNAPSHOT'
|
||||
id 'maven-publish'
|
||||
id "architectury-plugin" version "3.4-SNAPSHOT"
|
||||
id "dev.architectury.loom" version "1.4-SNAPSHOT" apply false
|
||||
}
|
||||
|
||||
version = project.mod_version
|
||||
group = project.maven_group
|
||||
|
||||
base {
|
||||
archivesName = project.archives_base_name
|
||||
architectury {
|
||||
minecraft = rootProject.minecraft_version
|
||||
}
|
||||
|
||||
repositories {
|
||||
// Add repositories to retrieve artifacts from in here.
|
||||
// You should only use this when depending on other mods because
|
||||
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
|
||||
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
|
||||
// for more information about repositories.
|
||||
subprojects {
|
||||
apply plugin: "dev.architectury.loom"
|
||||
|
||||
loom {
|
||||
silentMojangMappingsLicense()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
|
||||
// The following line declares the yarn mappings you may select this one as well.
|
||||
mappings "net.fabricmc:yarn:1.20.1+build.10:v2"
|
||||
}
|
||||
}
|
||||
|
||||
loom {
|
||||
splitEnvironmentSourceSets()
|
||||
allprojects {
|
||||
apply plugin: "java"
|
||||
apply plugin: "architectury-plugin"
|
||||
apply plugin: "maven-publish"
|
||||
|
||||
mods {
|
||||
"knockdowns" {
|
||||
sourceSet sourceSets.main
|
||||
sourceSet sourceSets.client
|
||||
}
|
||||
}
|
||||
base {
|
||||
archivesName = rootProject.archives_base_name
|
||||
}
|
||||
|
||||
version = rootProject.mod_version
|
||||
group = rootProject.maven_group
|
||||
|
||||
repositories {
|
||||
// Add repositories to retrieve artifacts from in here.
|
||||
// You should only use this when depending on other mods because
|
||||
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
|
||||
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
|
||||
// for more information about repositories.
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.encoding = "UTF-8"
|
||||
options.release = 17
|
||||
}
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// To change the versions see the gradle.properties file
|
||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
||||
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||
|
||||
// Fabric API. This is technically optional, but you probably want it anyway.
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||
|
||||
include(implementation(annotationProcessor("io.github.llamalad7:mixinextras-fabric:0.2.0")))
|
||||
}
|
||||
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
|
||||
filesMatching("fabric.mod.json") {
|
||||
expand "version": project.version
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
it.options.release = 17
|
||||
}
|
||||
|
||||
java {
|
||||
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
|
||||
// if it is present.
|
||||
// If you remove this line, sources will not be generated.
|
||||
withSourcesJar()
|
||||
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
jar {
|
||||
from("LICENSE") {
|
||||
rename { "${it}_${project.base.archivesName.get()}"}
|
||||
}
|
||||
}
|
||||
|
||||
// configure the maven publication
|
||||
publishing {
|
||||
publications {
|
||||
mavenJava(MavenPublication) {
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
|
||||
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
|
||||
repositories {
|
||||
// Add repositories to publish to here.
|
||||
// Notice: This block does NOT have the same function as the block in the top level.
|
||||
// The repositories here will be used for publishing your artifact, not for
|
||||
// retrieving dependencies.
|
||||
}
|
||||
}
|
31
common/build.gradle
Normal file
31
common/build.gradle
Normal file
|
@ -0,0 +1,31 @@
|
|||
architectury {
|
||||
common(rootProject.enabled_platforms.split(","))
|
||||
}
|
||||
|
||||
loom {
|
||||
accessWidenerPath = file("src/main/resources/knockdowns.accesswidener")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies
|
||||
// Do NOT use other classes from fabric loader
|
||||
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
||||
// Remove the next line if you don't want to depend on the API
|
||||
modApi "dev.architectury:architectury:${rootProject.architectury_version}"
|
||||
|
||||
compileOnly(annotationProcessor("io.github.llamalad7:mixinextras-common:0.3.3"))
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
mavenCommon(MavenPublication) {
|
||||
artifactId = rootProject.archives_base_name
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
|
||||
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
|
||||
repositories {
|
||||
// Add repositories to publish to here.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package ru.octol1ttle.knockdowns.common;
|
||||
|
||||
import dev.architectury.event.EventResult;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.hit.EntityHitResult;
|
||||
import net.minecraft.util.hit.HitResult;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import ru.octol1ttle.knockdowns.common.api.IKnockableDown;
|
||||
import ru.octol1ttle.knockdowns.common.events.KnockdownsClientEvents;
|
||||
import ru.octol1ttle.knockdowns.common.network.KnockdownsNetwork;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.RequestStartRevivingC2SPacket;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.StopRevivingC2SPacket;
|
||||
import ru.octol1ttle.knockdowns.common.registries.KnockdownsSoundEvents;
|
||||
import ru.octol1ttle.knockdowns.common.registries.KnockedDownSoundInstance;
|
||||
|
||||
public class KnockdownsClient {
|
||||
@Nullable
|
||||
public static Entity reviving;
|
||||
|
||||
public static void init() {
|
||||
KnockdownsClientEvents.registerCallbacks();
|
||||
}
|
||||
|
||||
public static void playKnockedDownSound(Vec3d pos) {
|
||||
MinecraftClient.getInstance().getSoundManager().play(
|
||||
new KnockedDownSoundInstance(KnockdownsSoundEvents.KNOCKED_DOWN.get(), pos)
|
||||
);
|
||||
}
|
||||
|
||||
public static EventResult onEntityUse(PlayerEntity player, Entity entity) {
|
||||
if (KnockdownsUtils.isKnockedOrReviving(player) || !(entity instanceof IKnockableDown knockable) || !knockable.is_KnockedDown()) {
|
||||
return EventResult.pass();
|
||||
}
|
||||
|
||||
KnockdownsNetwork.sendToServer(new RequestStartRevivingC2SPacket(entity.getUuid()));
|
||||
reviving = entity;
|
||||
|
||||
return EventResult.interruptTrue();
|
||||
}
|
||||
|
||||
public static void onPlayerTick(PlayerEntity player) {
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
if (!player.equals(client.player) || reviving == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean playerKnocked = ((IKnockableDown) player).is_KnockedDown();
|
||||
boolean revivingTargeted = client.crosshairTarget != null && client.crosshairTarget.getType() == HitResult.Type.ENTITY
|
||||
&& ((EntityHitResult) client.crosshairTarget).getEntity().equals(reviving);
|
||||
|
||||
if (!(reviving instanceof IKnockableDown knockable)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!knockable.is_KnockedDown() || playerKnocked || !revivingTargeted) {
|
||||
KnockdownsNetwork.sendToServer(new StopRevivingC2SPacket(reviving.getUuid()));
|
||||
reviving = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package ru.octol1ttle.knockdowns.common;
|
||||
|
||||
import net.minecraft.SharedConstants;
|
||||
import ru.octol1ttle.knockdowns.common.events.KnockdownsEvents;
|
||||
import ru.octol1ttle.knockdowns.common.network.KnockdownsNetwork;
|
||||
import ru.octol1ttle.knockdowns.common.registries.KnockdownsSoundEvents;
|
||||
|
||||
public class KnockdownsCommon {
|
||||
public static final String MOD_ID = "knockdowns";
|
||||
public static final int REVIVE_WAIT_TIME = 10 * SharedConstants.TICKS_PER_SECOND;
|
||||
|
||||
public static void init() {
|
||||
KnockdownsSoundEvents.register();
|
||||
KnockdownsNetwork.registerPackets();
|
||||
KnockdownsEvents.registerCallbacks();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package ru.octol1ttle.knockdowns.common;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import ru.octol1ttle.knockdowns.common.api.IKnockableDown;
|
||||
|
||||
public class KnockdownsUtils {
|
||||
public static boolean isKnockedOrReviving(PlayerEntity player) {
|
||||
return player instanceof IKnockableDown knockable && (knockable.is_KnockedDown() || knockable.is_Reviving());
|
||||
}
|
||||
|
||||
public static boolean allTeammatesKnocked(MinecraftServer server, PlayerEntity player) {
|
||||
for (PlayerEntity teammate : server.getPlayerManager().getPlayerList()) {
|
||||
if (teammate.equals(player)) {
|
||||
continue;
|
||||
}
|
||||
IKnockableDown knockable = (IKnockableDown) teammate;
|
||||
if (!knockable.is_KnockedDown() && !player.isDead()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void hurtTenacity(PlayerEntity player, float damage) {
|
||||
player.setInvulnerable(false);
|
||||
//DamageSource recent = player.getRecentDamageSource();
|
||||
player.damage(/*Objects.requireNonNullElse(recent, */player.getDamageSources().generic()/*)*/, damage);
|
||||
player.velocityModified = false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package ru.octol1ttle.knockdowns.common.api;
|
||||
|
||||
public interface IKnockableDown {
|
||||
boolean is_KnockedDown();
|
||||
|
||||
void set_KnockedDown(boolean knockedDown);
|
||||
|
||||
int get_ReviverCount();
|
||||
|
||||
void set_ReviverCount(int reviverCount);
|
||||
|
||||
boolean is_Reviving();
|
||||
|
||||
void set_Reviving(boolean reviving);
|
||||
|
||||
int get_ReviveTimer();
|
||||
|
||||
void set_ReviveTimer(int reviveTimer);
|
||||
|
||||
int get_KnockedAge();
|
||||
|
||||
void set_KnockedAge(int knockedAge);
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package ru.octol1ttle.knockdowns.common.events;
|
||||
|
||||
import dev.architectury.event.events.client.ClientGuiEvent;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.font.TextRenderer;
|
||||
import net.minecraft.util.Formatting;
|
||||
import ru.octol1ttle.knockdowns.common.KnockdownsClient;
|
||||
import ru.octol1ttle.knockdowns.common.api.IKnockableDown;
|
||||
|
||||
public class KnockdownsClientEvents {
|
||||
public static void registerCallbacks() {
|
||||
registerOnHudRender();
|
||||
}
|
||||
|
||||
private static void registerOnHudRender() {
|
||||
ClientGuiEvent.RENDER_HUD.register((drawContext, tickDelta) -> {
|
||||
IKnockableDown reviving = (IKnockableDown) KnockdownsClient.reviving;
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
if (reviving == null) {
|
||||
reviving = (IKnockableDown) client.player;
|
||||
if (reviving == null || reviving.get_ReviverCount() == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TextRenderer renderer = client.textRenderer;
|
||||
|
||||
String timerText = String.format("%.1f", reviving.get_ReviveTimer() / (float) SharedConstants.TICKS_PER_SECOND);
|
||||
int timerX = (drawContext.getScaledWindowWidth() - renderer.getWidth(timerText)) / 2;
|
||||
|
||||
int reviverCount = reviving.get_ReviverCount();
|
||||
Integer color = reviverCount > 1 ? Formatting.GREEN.getColorValue() : Formatting.WHITE.getColorValue();
|
||||
|
||||
String reviverCountText = "x" + reviverCount;
|
||||
int reviveCountX = (drawContext.getScaledWindowWidth() - renderer.getWidth(reviverCountText)) / 2;
|
||||
|
||||
if (color != null) {
|
||||
drawContext.drawTextWithShadow(renderer, timerText, timerX, drawContext.getScaledWindowHeight() / 2 + 5, color);
|
||||
drawContext.drawTextWithShadow(renderer, reviverCountText, reviveCountX, drawContext.getScaledWindowHeight() / 2 + 14, color);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
package ru.octol1ttle.knockdowns.common.events;
|
||||
|
||||
import dev.architectury.event.CompoundEventResult;
|
||||
import dev.architectury.event.EventResult;
|
||||
import dev.architectury.event.events.common.EntityEvent;
|
||||
import dev.architectury.event.events.common.InteractionEvent;
|
||||
import dev.architectury.event.events.common.PlayerEvent;
|
||||
import dev.architectury.event.events.common.TickEvent;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.TranslatableTextContent;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import ru.octol1ttle.knockdowns.common.KnockdownsClient;
|
||||
import ru.octol1ttle.knockdowns.common.KnockdownsCommon;
|
||||
import ru.octol1ttle.knockdowns.common.KnockdownsUtils;
|
||||
import ru.octol1ttle.knockdowns.common.api.IKnockableDown;
|
||||
import ru.octol1ttle.knockdowns.common.network.KnockdownsNetwork;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.PlayKnockedDownSoundS2CPacket;
|
||||
|
||||
public class KnockdownsEvents {
|
||||
private static final float KNOCKED_INVULNERABILITY_TICKS = 3.0f * SharedConstants.TICKS_PER_SECOND;
|
||||
private static final float KNOCKED_HURT_PERIOD = 1.2f;
|
||||
private static final float KNOCKED_TENACITY = 60.0f;
|
||||
|
||||
public static void registerCallbacks() {
|
||||
registerOnLivingDeath();
|
||||
registerOnPlayerTick();
|
||||
registerOnPlayerInteractions();
|
||||
registerOnEntityUse();
|
||||
}
|
||||
|
||||
private static void registerOnLivingDeath() {
|
||||
EntityEvent.LIVING_DEATH.register((entity, source) -> {
|
||||
MinecraftServer server = entity.getServer();
|
||||
if (server == null || !(entity instanceof IKnockableDown knockable)) {
|
||||
return EventResult.pass();
|
||||
}
|
||||
|
||||
ServerPlayerEntity player = (ServerPlayerEntity) entity;
|
||||
|
||||
if (KnockdownsUtils.allTeammatesKnocked(server, player)) {
|
||||
return EventResult.pass();
|
||||
}
|
||||
|
||||
if (knockable.is_KnockedDown()) {
|
||||
knockable.set_KnockedDown(false);
|
||||
knockable.set_ReviverCount(0);
|
||||
knockable.set_ReviveTimer(KnockdownsCommon.REVIVE_WAIT_TIME);
|
||||
knockable.set_KnockedAge(0);
|
||||
|
||||
return EventResult.pass();
|
||||
}
|
||||
|
||||
entity.clearStatusEffects();
|
||||
entity.setInvulnerable(true);
|
||||
entity.setGlowing(true);
|
||||
entity.setHealth(entity.getMaxHealth());
|
||||
entity.extinguish();
|
||||
entity.setAir(entity.getMaxAir());
|
||||
entity.setFrozenTicks(0);
|
||||
player.stopFallFlying();
|
||||
|
||||
knockable.set_KnockedDown(true);
|
||||
knockable.set_ReviveTimer(KnockdownsCommon.REVIVE_WAIT_TIME);
|
||||
knockable.set_KnockedAge(0);
|
||||
|
||||
KnockdownsNetwork.sendToWorld(player.getServerWorld(), new PlayKnockedDownSoundS2CPacket(player.getX(), player.getY(), player.getZ()));
|
||||
|
||||
Text deathMessage = entity.getDamageTracker().getDeathMessage();
|
||||
TranslatableTextContent content = (TranslatableTextContent) deathMessage.getContent();
|
||||
Text replaced = Text.translatableWithFallback(content.getKey().replace("death.", "knockdown."), deathMessage.getString(), content.getArgs());
|
||||
|
||||
server.getPlayerManager().broadcast(replaced, false);
|
||||
|
||||
return EventResult.interruptFalse();
|
||||
});
|
||||
}
|
||||
|
||||
private static void registerOnPlayerTick() {
|
||||
TickEvent.PLAYER_POST.register(player -> {
|
||||
MinecraftServer server = player.getServer();
|
||||
if (server == null) {
|
||||
KnockdownsClient.onPlayerTick(player);
|
||||
return;
|
||||
}
|
||||
if (!(player instanceof IKnockableDown knockable) || !knockable.is_KnockedDown()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (KnockdownsUtils.allTeammatesKnocked(server, player)) {
|
||||
KnockdownsUtils.hurtTenacity(player, player.getMaxHealth());
|
||||
return;
|
||||
}
|
||||
|
||||
if (knockable.get_ReviverCount() > 0) {
|
||||
knockable.set_ReviveTimer(knockable.get_ReviveTimer() - knockable.get_ReviverCount());
|
||||
|
||||
if (knockable.get_ReviveTimer() <= 0) {
|
||||
knockable.set_KnockedDown(false);
|
||||
knockable.set_ReviverCount(0);
|
||||
knockable.set_ReviveTimer(KnockdownsCommon.REVIVE_WAIT_TIME);
|
||||
knockable.set_KnockedAge(0);
|
||||
|
||||
player.setInvulnerable(false);
|
||||
player.setGlowing(false);
|
||||
player.setHealth(6.0f);
|
||||
}
|
||||
return;
|
||||
}
|
||||
knockable.set_ReviveTimer(Math.min(KnockdownsCommon.REVIVE_WAIT_TIME, knockable.get_ReviveTimer() + 1));
|
||||
|
||||
knockable.set_KnockedAge(knockable.get_KnockedAge() + 1);
|
||||
|
||||
int period = MathHelper.floor(KNOCKED_HURT_PERIOD * SharedConstants.TICKS_PER_SECOND);
|
||||
if (knockable.get_KnockedAge() >= KNOCKED_INVULNERABILITY_TICKS && knockable.get_KnockedAge() % period == 0) {
|
||||
KnockdownsUtils.hurtTenacity(player, player.getMaxHealth() / (KNOCKED_TENACITY / KNOCKED_HURT_PERIOD));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void registerOnPlayerInteractions() {
|
||||
InteractionEvent.LEFT_CLICK_BLOCK.register((player, hand, pos, direction) -> {
|
||||
if (KnockdownsUtils.isKnockedOrReviving(player)) {
|
||||
return EventResult.interruptFalse();
|
||||
}
|
||||
return EventResult.pass();
|
||||
});
|
||||
PlayerEvent.ATTACK_ENTITY.register((player, world, hand, entity, hitResult) -> {
|
||||
if (KnockdownsUtils.isKnockedOrReviving(player)) {
|
||||
return EventResult.interruptFalse();
|
||||
}
|
||||
return EventResult.pass();
|
||||
});
|
||||
InteractionEvent.RIGHT_CLICK_ITEM.register((player, hand) -> {
|
||||
if (KnockdownsUtils.isKnockedOrReviving(player)) {
|
||||
return CompoundEventResult.interruptFalse(hand == Hand.MAIN_HAND ? player.getMainHandStack() : player.getOffHandStack());
|
||||
}
|
||||
return CompoundEventResult.pass();
|
||||
});
|
||||
InteractionEvent.RIGHT_CLICK_BLOCK.register((player, hand, pos, direction) -> {
|
||||
if (KnockdownsUtils.isKnockedOrReviving(player)) {
|
||||
return EventResult.interruptFalse();
|
||||
}
|
||||
return EventResult.pass();
|
||||
});
|
||||
}
|
||||
|
||||
private static void registerOnEntityUse() {
|
||||
InteractionEvent.INTERACT_ENTITY.register((player, entity, hand)
|
||||
-> player.getWorld().isClient() ? KnockdownsClient.onEntityUse(player, entity) : EventResult.pass());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package ru.octol1ttle.knockdowns.common.mixin;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import ru.octol1ttle.knockdowns.common.api.IKnockableDown;
|
||||
|
||||
@Mixin(LivingEntity.class)
|
||||
public abstract class LivingEntityMixin {
|
||||
@ModifyReturnValue(method = "canTarget(Lnet/minecraft/entity/LivingEntity;)Z", at = @At("RETURN"))
|
||||
private boolean dontTargetKnockedPlayers(boolean original, LivingEntity target) {
|
||||
return original && !(target instanceof IKnockableDown knockable && knockable.is_KnockedDown());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package ru.octol1ttle.knockdowns.common.mixin;
|
||||
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.mob.MobEntity;
|
||||
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 ru.octol1ttle.knockdowns.common.api.IKnockableDown;
|
||||
|
||||
@Mixin(MobEntity.class)
|
||||
public abstract class MobEntityMixin {
|
||||
@Inject(method = "setTarget", at = @At("HEAD"), cancellable = true)
|
||||
private void setTarget(LivingEntity target, CallbackInfo ci) {
|
||||
if (target instanceof IKnockableDown knockable && knockable.is_KnockedDown()) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
package ru.octol1ttle.knockdowns.common.mixin;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.data.DataTracker;
|
||||
import net.minecraft.entity.data.TrackedData;
|
||||
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.world.World;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import ru.octol1ttle.knockdowns.common.KnockdownsCommon;
|
||||
import ru.octol1ttle.knockdowns.common.api.IKnockableDown;
|
||||
|
||||
@SuppressWarnings("WrongEntityDataParameterClass")
|
||||
@Mixin(PlayerEntity.class)
|
||||
public abstract class PlayerEntityMixin extends Entity implements IKnockableDown {
|
||||
@Unique
|
||||
private static final TrackedData<Boolean> KNOCKED_DOWN = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
|
||||
@Unique
|
||||
private static final TrackedData<Boolean> IS_REVIVING = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
|
||||
@Unique
|
||||
private static final TrackedData<Integer> REVIVER_COUNT = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.INTEGER);
|
||||
@Unique
|
||||
private static final TrackedData<Integer> REVIVE_TIMER = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.INTEGER);
|
||||
@Unique
|
||||
public int knocked_age;
|
||||
|
||||
private PlayerEntityMixin(EntityType<?> type, World world) {
|
||||
super(type, world);
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@ModifyExpressionValue(method = "updatePose", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;isSwimming()Z"))
|
||||
private boolean enterSwimmingIfKnockedDown(boolean original) {
|
||||
return original || this.is_KnockedDown();
|
||||
}
|
||||
|
||||
@ModifyReturnValue(method = "canFoodHeal", at = @At("RETURN"))
|
||||
private boolean dontHealIfKnockedDown(boolean original) {
|
||||
return original && !this.is_KnockedDown();
|
||||
}
|
||||
|
||||
@Inject(method = "checkFallFlying", at = @At("HEAD"), cancellable = true)
|
||||
private void dontOpenElytraIfKnockedDown(CallbackInfoReturnable<Boolean> cir) {
|
||||
if (this.is_KnockedDown()) {
|
||||
cir.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "initDataTracker", at = @At("TAIL"))
|
||||
private void initCustomDataTracker(CallbackInfo ci) {
|
||||
this.dataTracker.startTracking(KNOCKED_DOWN, false);
|
||||
this.dataTracker.startTracking(IS_REVIVING, false);
|
||||
this.dataTracker.startTracking(REVIVER_COUNT, 0);
|
||||
this.dataTracker.startTracking(REVIVE_TIMER, KnockdownsCommon.REVIVE_WAIT_TIME);
|
||||
}
|
||||
|
||||
@Inject(method = "readCustomDataFromNbt", at = @At("TAIL"))
|
||||
private void readKnockedDownFromNbt(NbtCompound nbt, CallbackInfo ci) {
|
||||
this.set_KnockedDown(nbt.getBoolean("KnockedDown"));
|
||||
this.set_ReviveTimer(nbt.getInt("ReviveTimer"));
|
||||
this.set_KnockedAge(nbt.getInt("KnockedAge"));
|
||||
}
|
||||
|
||||
@Inject(method = "writeCustomDataToNbt", at = @At("TAIL"))
|
||||
private void writeKnockedDownToNbt(NbtCompound nbt, CallbackInfo ci) {
|
||||
nbt.putBoolean("KnockedDown", this.is_KnockedDown());
|
||||
nbt.putInt("ReviveTimer", this.get_ReviveTimer());
|
||||
nbt.putInt("KnockedAge", this.get_KnockedAge());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean is_KnockedDown() {
|
||||
return this.dataTracker.get(KNOCKED_DOWN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set_KnockedDown(boolean knockedDown) {
|
||||
this.dataTracker.set(KNOCKED_DOWN, knockedDown);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean is_Reviving() {
|
||||
return this.dataTracker.get(IS_REVIVING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set_Reviving(boolean reviving) {
|
||||
this.dataTracker.set(IS_REVIVING, reviving);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get_ReviverCount() {
|
||||
return this.dataTracker.get(REVIVER_COUNT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set_ReviverCount(int reviverCount) {
|
||||
this.dataTracker.set(REVIVER_COUNT, reviverCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get_ReviveTimer() {
|
||||
return this.dataTracker.get(REVIVE_TIMER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set_ReviveTimer(int reviveTimer) {
|
||||
this.dataTracker.set(REVIVE_TIMER, reviveTimer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get_KnockedAge() {
|
||||
return knocked_age;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set_KnockedAge(int knockedAge) {
|
||||
this.knocked_age = knockedAge;
|
||||
}
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
package ru.octol1ttle.knockdowns.mixin.client;
|
||||
package ru.octol1ttle.knockdowns.common.mixin.client;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import ru.octol1ttle.knockdowns.api.IKnockableDown;
|
||||
import ru.octol1ttle.knockdowns.common.api.IKnockableDown;
|
||||
|
||||
@Mixin(ClientPlayerEntity.class)
|
||||
public abstract class ClientPlayerEntityMixin {
|
||||
public abstract class ClientPlayerEntityMixin implements IKnockableDown {
|
||||
@ModifyReturnValue(method = "shouldSlowDown", at = @At("RETURN"))
|
||||
private boolean shouldSlowDown(boolean original) {
|
||||
return original || ((IKnockableDown) this).knockdowns$isKnockedDown();
|
||||
return original || this.is_KnockedDown();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package ru.octol1ttle.knockdowns.common.network;
|
||||
|
||||
import dev.architectury.networking.NetworkChannel;
|
||||
import dev.architectury.networking.NetworkManager;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.Identifier;
|
||||
import ru.octol1ttle.knockdowns.common.KnockdownsCommon;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.PlayKnockedDownSoundS2CPacket;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.RequestStartRevivingC2SPacket;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.StopRevivingC2SPacket;
|
||||
|
||||
public class KnockdownsNetwork {
|
||||
private static final NetworkChannel CHANNEL = NetworkChannel.create(new Identifier(KnockdownsCommon.MOD_ID, "main"));
|
||||
public static void registerPackets() {
|
||||
CHANNEL.register(PlayKnockedDownSoundS2CPacket.class, PlayKnockedDownSoundS2CPacket::encode, PlayKnockedDownSoundS2CPacket::new, PlayKnockedDownSoundS2CPacket::apply);
|
||||
CHANNEL.register(RequestStartRevivingC2SPacket.class, RequestStartRevivingC2SPacket::encode, RequestStartRevivingC2SPacket::new, RequestStartRevivingC2SPacket::apply);
|
||||
CHANNEL.register(StopRevivingC2SPacket.class, StopRevivingC2SPacket::encode, StopRevivingC2SPacket::new, StopRevivingC2SPacket::apply);
|
||||
}
|
||||
|
||||
public static <T> void sendToServer(T message) {
|
||||
if (CHANNEL.canServerReceive(message.getClass())) {
|
||||
CHANNEL.sendToServer(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> void sendToPlayer(PlayerEntity player, T message) {
|
||||
Packet<?> packet = CHANNEL.toPacket(NetworkManager.Side.S2C, message);
|
||||
Class<?> messageClass = message.getClass();
|
||||
|
||||
sendToPlayer(player, packet, messageClass);
|
||||
}
|
||||
|
||||
public static void sendToPlayer(PlayerEntity player, Packet<?> packet, Class<?> messageClass) {
|
||||
if (!(player instanceof ServerPlayerEntity serverPlayer)) {
|
||||
throw new IllegalArgumentException("Cannot send to client players");
|
||||
}
|
||||
if (CHANNEL.canPlayerReceive(serverPlayer, messageClass)) {
|
||||
serverPlayer.networkHandler.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> void sendToWorld(ServerWorld world, T message) {
|
||||
Packet<?> packet = CHANNEL.toPacket(NetworkManager.Side.S2C, message);
|
||||
Class<?> messageClass = message.getClass();
|
||||
|
||||
sendToWorld(world, packet, messageClass);
|
||||
}
|
||||
|
||||
private static void sendToWorld(ServerWorld world, Packet<?> packet, Class<?> messageClass) {
|
||||
for (ServerPlayerEntity player : world.getPlayers()) {
|
||||
sendToPlayer(player, packet, messageClass);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package ru.octol1ttle.knockdowns.common.network.packets;
|
||||
|
||||
import dev.architectury.networking.NetworkManager;
|
||||
import java.util.function.Supplier;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
|
||||
public abstract class KnockdownsPacket {
|
||||
public KnockdownsPacket(/* args here */) {
|
||||
// Message creation
|
||||
}
|
||||
|
||||
public abstract void encode(PacketByteBuf buf);
|
||||
|
||||
public abstract void apply(Supplier<NetworkManager.PacketContext> contextSupplier);
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package ru.octol1ttle.knockdowns.common.network.packets;
|
||||
|
||||
import dev.architectury.networking.NetworkManager;
|
||||
import java.util.function.Supplier;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import ru.octol1ttle.knockdowns.common.KnockdownsClient;
|
||||
|
||||
public class PlayKnockedDownSoundS2CPacket extends KnockdownsPacket {
|
||||
private final double x;
|
||||
private final double y;
|
||||
private final double z;
|
||||
|
||||
public PlayKnockedDownSoundS2CPacket(PacketByteBuf buf) {
|
||||
this(buf.readDouble(), buf.readDouble(), buf.readDouble());
|
||||
}
|
||||
|
||||
public PlayKnockedDownSoundS2CPacket(double x, double y, double z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(PacketByteBuf buf) {
|
||||
buf.writeDouble(this.x);
|
||||
buf.writeDouble(this.y);
|
||||
buf.writeDouble(this.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Supplier<NetworkManager.PacketContext> contextSupplier) {
|
||||
NetworkManager.PacketContext context = contextSupplier.get();
|
||||
context.queue(() -> KnockdownsClient.playKnockedDownSound(new Vec3d(this.x, this.y, this.z)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package ru.octol1ttle.knockdowns.common.network.packets;
|
||||
|
||||
import dev.architectury.networking.NetworkManager;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import ru.octol1ttle.knockdowns.common.api.IKnockableDown;
|
||||
|
||||
public class RequestStartRevivingC2SPacket extends KnockdownsPacket {
|
||||
private final UUID targetUuid;
|
||||
|
||||
public RequestStartRevivingC2SPacket(PacketByteBuf buf) {
|
||||
this(buf.readUuid());
|
||||
}
|
||||
|
||||
public RequestStartRevivingC2SPacket(UUID targetUuid) {
|
||||
this.targetUuid = targetUuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(PacketByteBuf buf) {
|
||||
buf.writeUuid(this.targetUuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Supplier<NetworkManager.PacketContext> contextSupplier) {
|
||||
NetworkManager.PacketContext context = contextSupplier.get();
|
||||
context.queue(() -> {
|
||||
PlayerEntity player = context.getPlayer();
|
||||
IKnockableDown playerKnockable = (IKnockableDown) player;
|
||||
IKnockableDown targetKnockable = (IKnockableDown) player.getWorld().getPlayerByUuid(this.targetUuid);
|
||||
if (!playerKnockable.is_Reviving() && targetKnockable != null && targetKnockable.is_KnockedDown()) {
|
||||
playerKnockable.set_Reviving(true);
|
||||
targetKnockable.set_ReviverCount(targetKnockable.get_ReviverCount() + 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package ru.octol1ttle.knockdowns.common.network.packets;
|
||||
|
||||
import dev.architectury.networking.NetworkManager;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import ru.octol1ttle.knockdowns.common.api.IKnockableDown;
|
||||
|
||||
public class StopRevivingC2SPacket extends KnockdownsPacket {
|
||||
private final UUID targetUuid;
|
||||
|
||||
public StopRevivingC2SPacket(PacketByteBuf buf) {
|
||||
this(buf.readUuid());
|
||||
}
|
||||
|
||||
public StopRevivingC2SPacket(UUID targetUuid) {
|
||||
this.targetUuid = targetUuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(PacketByteBuf buf) {
|
||||
buf.writeUuid(this.targetUuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Supplier<NetworkManager.PacketContext> contextSupplier) {
|
||||
NetworkManager.PacketContext context = contextSupplier.get();
|
||||
context.queue(() -> {
|
||||
PlayerEntity player = context.getPlayer();
|
||||
IKnockableDown playerKnockable = (IKnockableDown) player;
|
||||
IKnockableDown targetKnockable = (IKnockableDown) player.getWorld().getPlayerByUuid(this.targetUuid);
|
||||
if (playerKnockable.is_Reviving() && targetKnockable != null) {
|
||||
playerKnockable.set_Reviving(false);
|
||||
if (targetKnockable.is_KnockedDown()) {
|
||||
targetKnockable.set_ReviverCount(targetKnockable.get_ReviverCount() - 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package ru.octol1ttle.knockdowns.common.registries;
|
||||
|
||||
import dev.architectury.registry.registries.DeferredRegister;
|
||||
import dev.architectury.registry.registries.RegistrySupplier;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import net.minecraft.util.Identifier;
|
||||
import ru.octol1ttle.knockdowns.common.KnockdownsCommon;
|
||||
|
||||
public class KnockdownsSoundEvents {
|
||||
private static final DeferredRegister<SoundEvent> SOUND_EVENTS = DeferredRegister.create(KnockdownsCommon.MOD_ID, RegistryKeys.SOUND_EVENT);
|
||||
public static final RegistrySupplier<SoundEvent> KNOCKED_DOWN = SOUND_EVENTS.register(KnockdownsCommon.MOD_ID,
|
||||
() -> SoundEvent.of(new Identifier(KnockdownsCommon.MOD_ID, "knocked_down")));
|
||||
|
||||
public static void register() {
|
||||
SOUND_EVENTS.register();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package ru.octol1ttle.knockdowns.common.registries;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.client.sound.MovingSoundInstance;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
|
||||
public class KnockedDownSoundInstance extends MovingSoundInstance {
|
||||
private final Vec3d pos;
|
||||
|
||||
public KnockedDownSoundInstance(SoundEvent sound, Vec3d pos) {
|
||||
super(sound, SoundCategory.MASTER, Random.create(0L));
|
||||
this.pos = pos;
|
||||
this.relative = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
ClientPlayerEntity player = MinecraftClient.getInstance().player;
|
||||
if (player == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
Vec3d vec = pos.subtract(player.getPos()).normalize();
|
||||
this.x = vec.x;
|
||||
this.y = vec.y;
|
||||
this.z = vec.z;
|
||||
}
|
||||
}
|
3
common/src/main/resources/architectury.common.json
Normal file
3
common/src/main/resources/architectury.common.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"accessWidener": "knockdowns.accesswidener"
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
{
|
||||
"subtitles.knockdowns.knocked_down": "Player knocked down",
|
||||
|
||||
"knockdown.attack.anvil": "%1$s was knocked down by a falling anvil",
|
||||
"knockdown.attack.anvil.player": "%1$s was knocked down by a falling anvil while fighting %2$s",
|
||||
"knockdown.attack.arrow": "%1$s was knocked down due to an arrow fired by %2$s",
|
||||
|
@ -97,6 +99,5 @@
|
|||
"knockdown.fell.assist.item": "%1$s was doomed to get knocked down by %2$s using %3$s",
|
||||
"knockdown.fell.finish": "%1$s fell too far and was knocked down by %2$s",
|
||||
"knockdown.fell.finish.item": "%1$s fell too far and was knocked down by %2$s using %3$s",
|
||||
"knockdown.fell.killer": "%1$s was doomed to get knocked down by a fall",
|
||||
"subtitles.knockdowns.knocked_down": "Player knocked down"
|
||||
"knockdown.fell.killer": "%1$s was doomed to get knocked down by a fall"
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
{
|
||||
"subtitles.knockdowns.knocked_down": "Игрок тяжело ранен",
|
||||
|
||||
"knockdown.attack.anvil": "%1$s был тяжело ранен упавшей наковальней",
|
||||
"knockdown.attack.anvil.player": "%1$s был тяжело ранен упавшей наковальней, пока сражался с %2$s",
|
||||
"knockdown.attack.arrow": "%1$s тяжело ранен стрелой %2$s",
|
||||
|
@ -97,6 +99,5 @@
|
|||
"knockdown.fell.assist.item": "%1$s был тяжело ранен падением благодаря %2$s с помощью %3$s",
|
||||
"knockdown.fell.finish": "%1$s упал с высоты и был тяжело ранен %2$s",
|
||||
"knockdown.fell.finish.item": "%1$s упал с высоты и был тяжело ранен %2$s с помощью %3$s",
|
||||
"knockdown.fell.killer": "%1$s был тяжело ранен падением",
|
||||
"subtitles.knockdowns.knocked_down": "Игрок тяжело ранен"
|
||||
"knockdown.fell.killer": "%1$s был тяжело ранен падением"
|
||||
}
|
Binary file not shown.
17
common/src/main/resources/knockdowns-common.mixins.json
Normal file
17
common/src/main/resources/knockdowns-common.mixins.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"required": true,
|
||||
"package": "ru.octol1ttle.knockdowns.common.mixin",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"minVersion": "0.8",
|
||||
"client": [
|
||||
"client.ClientPlayerEntityMixin"
|
||||
],
|
||||
"mixins": [
|
||||
"LivingEntityMixin",
|
||||
"MobEntityMixin",
|
||||
"PlayerEntityMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
1
common/src/main/resources/knockdowns.accesswidener
Normal file
1
common/src/main/resources/knockdowns.accesswidener
Normal file
|
@ -0,0 +1 @@
|
|||
accessWidener v2 named
|
77
fabric/build.gradle
Normal file
77
fabric/build.gradle
Normal file
|
@ -0,0 +1,77 @@
|
|||
plugins {
|
||||
id "com.github.johnrengelman.shadow" version "7.1.2"
|
||||
}
|
||||
|
||||
architectury {
|
||||
platformSetupLoomIde()
|
||||
fabric()
|
||||
}
|
||||
|
||||
loom {
|
||||
accessWidenerPath = project(":common").loom.accessWidenerPath
|
||||
}
|
||||
|
||||
configurations {
|
||||
common
|
||||
shadowCommon // Don't use shadow from the shadow plugin since it *excludes* files.
|
||||
compileClasspath.extendsFrom common
|
||||
runtimeClasspath.extendsFrom common
|
||||
developmentFabric.extendsFrom common
|
||||
}
|
||||
|
||||
dependencies {
|
||||
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
||||
modApi "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}"
|
||||
// Remove the next line if you don't want to depend on the API
|
||||
modApi "dev.architectury:architectury-fabric:${rootProject.architectury_version}"
|
||||
|
||||
common(project(path: ":common", configuration: "namedElements")) { transitive false }
|
||||
shadowCommon(project(path: ":common", configuration: "transformProductionFabric")) { transitive false }
|
||||
}
|
||||
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
|
||||
filesMatching("fabric.mod.json") {
|
||||
expand "version": project.version
|
||||
}
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
exclude "architectury.common.json"
|
||||
|
||||
configurations = [project.configurations.shadowCommon]
|
||||
archiveClassifier = "dev-shadow"
|
||||
}
|
||||
|
||||
remapJar {
|
||||
injectAccessWidener = true
|
||||
input.set shadowJar.archiveFile
|
||||
dependsOn shadowJar
|
||||
}
|
||||
|
||||
sourcesJar {
|
||||
def commonSources = project(":common").sourcesJar
|
||||
dependsOn commonSources
|
||||
from commonSources.archiveFile.map { zipTree(it) }
|
||||
}
|
||||
|
||||
components.java {
|
||||
withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
|
||||
skip()
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
mavenFabric(MavenPublication) {
|
||||
artifactId = rootProject.archives_base_name + "-" + project.name
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
|
||||
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
|
||||
repositories {
|
||||
// Add repositories to publish to here.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package ru.octol1ttle.knockdowns.fabric;
|
||||
|
||||
import ru.octol1ttle.knockdowns.common.KnockdownsCommon;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
|
||||
public class KnockdownsFabric implements ModInitializer {
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
KnockdownsCommon.init();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package ru.octol1ttle.knockdowns.fabric;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import ru.octol1ttle.knockdowns.common.KnockdownsClient;
|
||||
|
||||
public class KnockdownsFabricClient implements ClientModInitializer {
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
KnockdownsClient.init();
|
||||
}
|
||||
}
|
34
fabric/src/main/resources/fabric.mod.json
Normal file
34
fabric/src/main/resources/fabric.mod.json
Normal file
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "knockdowns",
|
||||
"version": "${version}",
|
||||
"name": "Knockdowns",
|
||||
"description": "DBNO mechanic from Fortnite, ported to Minecraft",
|
||||
"authors": [
|
||||
"Octol1ttle"
|
||||
],
|
||||
"contact": {
|
||||
"homepage": "https://fabricmc.net/",
|
||||
"sources": "https://github.com/FabricMC/fabric-example-mod"
|
||||
},
|
||||
"license": "ARR",
|
||||
"icon": "assets/knockdowns/icon.png",
|
||||
"environment": "*",
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"ru.octol1ttle.knockdowns.fabric.KnockdownsFabric"
|
||||
],
|
||||
"client": [
|
||||
"ru.octol1ttle.knockdowns.fabric.KnockdownsFabricClient"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
"knockdowns.mixins.json",
|
||||
"knockdowns-common.mixins.json"
|
||||
],
|
||||
"depends": {
|
||||
"fabric": "*",
|
||||
"minecraft": ">=1.20.1",
|
||||
"architectury": ">=9.1.12"
|
||||
}
|
||||
}
|
13
fabric/src/main/resources/knockdowns.mixins.json
Normal file
13
fabric/src/main/resources/knockdowns.mixins.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"required": true,
|
||||
"package": "ru.octol1ttle.knockdowns.fabric.mixin",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"minVersion": "0.8",
|
||||
"client": [
|
||||
],
|
||||
"mixins": [
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
86
forge/build.gradle
Normal file
86
forge/build.gradle
Normal file
|
@ -0,0 +1,86 @@
|
|||
plugins {
|
||||
id "com.github.johnrengelman.shadow" version "7.1.2"
|
||||
}
|
||||
|
||||
architectury {
|
||||
platformSetupLoomIde()
|
||||
forge()
|
||||
}
|
||||
|
||||
loom {
|
||||
accessWidenerPath = project(":common").loom.accessWidenerPath
|
||||
|
||||
forge {
|
||||
convertAccessWideners = true
|
||||
extraAccessWideners.add loom.accessWidenerPath.get().asFile.name
|
||||
|
||||
mixinConfig "knockdowns-common.mixins.json"
|
||||
mixinConfig "knockdowns.mixins.json"
|
||||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
common
|
||||
shadowCommon // Don't use shadow from the shadow plugin since it *excludes* files.
|
||||
compileClasspath.extendsFrom common
|
||||
runtimeClasspath.extendsFrom common
|
||||
developmentForge.extendsFrom common
|
||||
}
|
||||
|
||||
dependencies {
|
||||
forge "net.minecraftforge:forge:${rootProject.forge_version}"
|
||||
// Remove the next line if you don't want to depend on the API
|
||||
modApi "dev.architectury:architectury-forge:${rootProject.architectury_version}"
|
||||
|
||||
common(project(path: ":common", configuration: "namedElements")) { transitive false }
|
||||
shadowCommon(project(path: ":common", configuration: "transformProductionForge")) { transitive = false }
|
||||
|
||||
implementation(include("io.github.llamalad7:mixinextras-forge:0.3.3"))
|
||||
}
|
||||
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
|
||||
filesMatching("META-INF/mods.toml") {
|
||||
expand "version": project.version
|
||||
}
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
exclude "fabric.mod.json"
|
||||
exclude "architectury.common.json"
|
||||
|
||||
configurations = [project.configurations.shadowCommon]
|
||||
archiveClassifier = "dev-shadow"
|
||||
}
|
||||
|
||||
remapJar {
|
||||
input.set shadowJar.archiveFile
|
||||
dependsOn shadowJar
|
||||
}
|
||||
|
||||
sourcesJar {
|
||||
def commonSources = project(":common").sourcesJar
|
||||
dependsOn commonSources
|
||||
from commonSources.archiveFile.map { zipTree(it) }
|
||||
}
|
||||
|
||||
components.java {
|
||||
withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
|
||||
skip()
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
mavenForge(MavenPublication) {
|
||||
artifactId = rootProject.archives_base_name + "-" + project.name
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
|
||||
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
|
||||
repositories {
|
||||
// Add repositories to publish to here.
|
||||
}
|
||||
}
|
1
forge/gradle.properties
Normal file
1
forge/gradle.properties
Normal file
|
@ -0,0 +1 @@
|
|||
loom.platform=forge
|
|
@ -0,0 +1,26 @@
|
|||
package ru.octol1ttle.knockdowns.forge;
|
||||
|
||||
import dev.architectury.platform.forge.EventBuses;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
import ru.octol1ttle.knockdowns.common.KnockdownsClient;
|
||||
import ru.octol1ttle.knockdowns.common.KnockdownsCommon;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Mod(KnockdownsCommon.MOD_ID)
|
||||
public class KnockdownsForge {
|
||||
public KnockdownsForge() {
|
||||
// Submit our event bus to let architectury register our content on the right time
|
||||
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
|
||||
EventBuses.registerModEventBus(KnockdownsCommon.MOD_ID, modEventBus);
|
||||
modEventBus.addListener(this::onInitializeClient);
|
||||
|
||||
KnockdownsCommon.init();
|
||||
}
|
||||
|
||||
public void onInitializeClient(FMLClientSetupEvent event) {
|
||||
KnockdownsClient.init();
|
||||
}
|
||||
}
|
35
forge/src/main/resources/META-INF/mods.toml
Normal file
35
forge/src/main/resources/META-INF/mods.toml
Normal file
|
@ -0,0 +1,35 @@
|
|||
modLoader = "javafml"
|
||||
loaderVersion = "[47,)"
|
||||
#issueTrackerURL = ""
|
||||
license = "ARR"
|
||||
|
||||
[[mods]]
|
||||
modId = "knockdowns"
|
||||
version = "${version}"
|
||||
displayName = "Knockdowns"
|
||||
authors = "Octol1ttle"
|
||||
description = '''
|
||||
DBNO mechanic from Fortnite, ported to Minecraft
|
||||
'''
|
||||
#logoFile = ""
|
||||
|
||||
[[dependencies.knockdowns]]
|
||||
modId = "forge"
|
||||
mandatory = true
|
||||
versionRange = "[47,)"
|
||||
ordering = "NONE"
|
||||
side = "BOTH"
|
||||
|
||||
[[dependencies.knockdowns]]
|
||||
modId = "minecraft"
|
||||
mandatory = true
|
||||
versionRange = "[1.20.1,)"
|
||||
ordering = "NONE"
|
||||
side = "BOTH"
|
||||
|
||||
[[dependencies.knockdowns]]
|
||||
modId = "architectury"
|
||||
mandatory = true
|
||||
versionRange = "[9.1.12,)"
|
||||
ordering = "AFTER"
|
||||
side = "BOTH"
|
|
@ -1,11 +1,13 @@
|
|||
{
|
||||
"required": true,
|
||||
"package": "ru.octol1ttle.knockdowns.mixin.client",
|
||||
"package": "ru.octol1ttle.knockdowns.forge.mixin",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"minVersion": "0.8",
|
||||
"client": [
|
||||
"ClientPlayerEntityMixin"
|
||||
],
|
||||
"mixins": [
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
||||
}
|
6
forge/src/main/resources/pack.mcmeta
Normal file
6
forge/src/main/resources/pack.mcmeta
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"pack": {
|
||||
"description": "Knockdowns",
|
||||
"pack_format": 15
|
||||
}
|
||||
}
|
|
@ -1,17 +1,17 @@
|
|||
# Done to increase the memory available to gradle.
|
||||
org.gradle.jvmargs=-Xmx1G
|
||||
org.gradle.parallel=true
|
||||
org.gradle.jvmargs=-Xmx2048M
|
||||
|
||||
# Fabric Properties
|
||||
# check these on https://fabricmc.net/develop
|
||||
minecraft_version=1.20.2
|
||||
yarn_mappings=1.20.2+build.4
|
||||
loader_version=0.14.24
|
||||
minecraft_version=1.20.1
|
||||
enabled_platforms=fabric,forge
|
||||
|
||||
# Mod Properties
|
||||
mod_version=1.1.1
|
||||
maven_group=ru.octol1ttle.knockdowns
|
||||
archives_base_name=knockdowns
|
||||
mod_version=2.1.0
|
||||
maven_group=ru.octol1ttle.knockdowns
|
||||
|
||||
architectury_version=9.1.12
|
||||
fabric_api_version=0.90.4+1.20.1
|
||||
|
||||
fabric_loader_version=0.15.5
|
||||
forge_version=1.20.1-47.2.0
|
||||
|
||||
|
||||
|
||||
# Dependencies
|
||||
fabric_version=0.90.4+1.20.2
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,7 +1,6 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
15
gradlew
vendored
15
gradlew
vendored
|
@ -83,8 +83,10 @@ done
|
|||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
@ -131,13 +133,10 @@ location of your Java installation."
|
|||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
|
@ -198,10 +197,6 @@ if "$cygwin" || "$msys" ; then
|
|||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
pluginManagement {
|
||||
repositories {
|
||||
maven {
|
||||
name = 'Fabric'
|
||||
url = 'https://maven.fabricmc.net/'
|
||||
}
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
maven { url "https://maven.fabricmc.net/" }
|
||||
maven { url "https://maven.architectury.dev/" }
|
||||
maven { url "https://maven.minecraftforge.net/" }
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
include("common")
|
||||
include("fabric")
|
||||
include("forge")
|
||||
|
||||
rootProject.name = "knockdowns-modern"
|
||||
|
|
|
@ -1,166 +0,0 @@
|
|||
package ru.octol1ttle.knockdowns;
|
||||
|
||||
import java.util.UUID;
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientEntityEvents;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
|
||||
import net.fabricmc.fabric.api.event.player.UseEntityCallback;
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.font.TextRenderer;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.hit.EntityHitResult;
|
||||
import net.minecraft.util.hit.HitResult;
|
||||
import ru.octol1ttle.knockdowns.api.IKnockableDown;
|
||||
import ru.octol1ttle.knockdowns.network.KnockdownsNetworkingConstants;
|
||||
|
||||
public class KnockdownsClient implements ClientModInitializer {
|
||||
private static final int REVIVAL_WAIT_TIME = 10 * SharedConstants.TICKS_PER_SECOND;
|
||||
private static IKnockableDown reviving = null;
|
||||
private static int revivalTimer = -1;
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
registerOnReceiveKnockedDown();
|
||||
registerOnReceiveReviving();
|
||||
registerOnEntityLoad();
|
||||
registerOnEntityUse();
|
||||
registerOnStartWorldTick();
|
||||
registerOnHudRender();
|
||||
}
|
||||
|
||||
private static void registerOnReceiveKnockedDown() {
|
||||
ClientPlayNetworking.registerGlobalReceiver(KnockdownsNetworkingConstants.S2C_SEND_PLAYER_KNOCKED_DOWN, (client, handler, buf, responseSender) -> {
|
||||
UUID uuid = buf.readUuid();
|
||||
boolean knockedDown = buf.readBoolean();
|
||||
|
||||
client.execute(() -> {
|
||||
IKnockableDown knockableDown = (IKnockableDown) handler.getWorld().getPlayerByUuid(uuid);
|
||||
if (knockableDown != null) {
|
||||
knockableDown.knockdowns$setKnockedDown(knockedDown);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static void registerOnReceiveReviving() {
|
||||
ClientPlayNetworking.registerGlobalReceiver(KnockdownsNetworkingConstants.S2C_SEND_PLAYER_REVIVING, (client, handler, buf, responseSender) -> {
|
||||
UUID uuid = buf.readUuid();
|
||||
boolean beingRevived = buf.readBoolean();
|
||||
|
||||
client.execute(() -> {
|
||||
IKnockableDown knockableDown = (IKnockableDown) handler.getWorld().getPlayerByUuid(uuid);
|
||||
if (knockableDown != null) {
|
||||
knockableDown.knockdowns$setBeingRevived(beingRevived);
|
||||
|
||||
if (client.player != null && uuid.equals(client.player.getUuid())) {
|
||||
if (knockableDown.knockdowns$isBeingRevived()) {
|
||||
revivalTimer = REVIVAL_WAIT_TIME;
|
||||
} else {
|
||||
revivalTimer = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (reviving != null && knockableDown.knockdowns$getUuid().equals(reviving.knockdowns$getUuid())
|
||||
&& !knockableDown.knockdowns$isBeingRevived()) {
|
||||
reviving = null;
|
||||
revivalTimer = -1;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static void registerOnEntityLoad() {
|
||||
ClientEntityEvents.ENTITY_LOAD.register((entity, world) -> {
|
||||
if (entity instanceof IKnockableDown) {
|
||||
PacketByteBuf buf = PacketByteBufs.create();
|
||||
buf.writeUuid(entity.getUuid());
|
||||
|
||||
ClientPlayNetworking.send(KnockdownsNetworkingConstants.C2S_REQUEST_PLAYER_KNOCKED_DOWN, PacketByteBufs.copy(buf));
|
||||
ClientPlayNetworking.send(KnockdownsNetworkingConstants.C2S_REQUEST_PLAYER_REVIVING, buf);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void registerOnEntityUse() {
|
||||
UseEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> {
|
||||
if (!(entity instanceof IKnockableDown knockableDown) || !knockableDown.knockdowns$isKnockedDown()
|
||||
|| knockableDown.knockdowns$isBeingRevived()) {
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
if (((IKnockableDown)player).knockdowns$isKnockedDown()) {
|
||||
return ActionResult.FAIL;
|
||||
}
|
||||
|
||||
knockableDown.knockdowns$setBeingRevived(true);
|
||||
|
||||
PacketByteBuf buf = PacketByteBufs.create();
|
||||
buf.writeUuid(entity.getUuid());
|
||||
buf.writeBoolean(true);
|
||||
|
||||
ClientPlayNetworking.send(KnockdownsNetworkingConstants.C2S_SEND_PLAYER_REVIVING, buf);
|
||||
|
||||
reviving = knockableDown;
|
||||
revivalTimer = REVIVAL_WAIT_TIME;
|
||||
|
||||
return ActionResult.SUCCESS;
|
||||
});
|
||||
}
|
||||
|
||||
private static void registerOnStartWorldTick() {
|
||||
ClientTickEvents.START_WORLD_TICK.register(world -> {
|
||||
boolean revived = false;
|
||||
revivalTimer--;
|
||||
if (revivalTimer <= 0) {
|
||||
revivalTimer = -1;
|
||||
revived = true;
|
||||
}
|
||||
|
||||
if (reviving == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
HitResult crosshairTarget = MinecraftClient.getInstance().crosshairTarget;
|
||||
if (revived || crosshairTarget == null || crosshairTarget.getType() != HitResult.Type.ENTITY
|
||||
|| !((EntityHitResult) crosshairTarget).getEntity().getUuid().equals(reviving.knockdowns$getUuid())) {
|
||||
reviving.knockdowns$setBeingRevived(false);
|
||||
|
||||
PacketByteBuf buf = PacketByteBufs.create();
|
||||
buf.writeUuid(reviving.knockdowns$getUuid());
|
||||
buf.writeBoolean(false);
|
||||
|
||||
ClientPlayNetworking.send(KnockdownsNetworkingConstants.C2S_SEND_PLAYER_REVIVING, buf);
|
||||
if (revived) {
|
||||
reviving.knockdowns$setKnockedDown(false);
|
||||
|
||||
PacketByteBuf revivedBuf = PacketByteBufs.create();
|
||||
revivedBuf.writeUuid(reviving.knockdowns$getUuid());
|
||||
|
||||
ClientPlayNetworking.send(KnockdownsNetworkingConstants.C2S_SEND_PLAYER_REVIVED, revivedBuf);
|
||||
}
|
||||
|
||||
reviving = null;
|
||||
revivalTimer = -1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void registerOnHudRender() {
|
||||
HudRenderCallback.EVENT.register((drawContext, tickDelta) -> {
|
||||
if (revivalTimer == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
TextRenderer renderer = MinecraftClient.getInstance().textRenderer;
|
||||
String text = String.format("%.1f", revivalTimer / (float) SharedConstants.TICKS_PER_SECOND);
|
||||
int x = (drawContext.getScaledWindowWidth() - renderer.getWidth(text)) / 2;
|
||||
|
||||
drawContext.drawTextWithShadow(renderer, text, x, drawContext.getScaledWindowHeight() / 2 + 15, 0xFFFFFF);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,219 +0,0 @@
|
|||
package ru.octol1ttle.knockdowns;
|
||||
|
||||
import java.util.UUID;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents;
|
||||
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
|
||||
import net.fabricmc.fabric.api.event.player.AttackEntityCallback;
|
||||
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
||||
import net.fabricmc.fabric.api.event.player.UseItemCallback;
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
||||
import net.fabricmc.fabric.api.networking.v1.PlayerLookup;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.packet.s2c.play.PlaySoundS2CPacket;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.TranslatableTextContent;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.TypedActionResult;
|
||||
import net.minecraft.world.GameRules;
|
||||
import ru.octol1ttle.knockdowns.api.IKnockableDown;
|
||||
import ru.octol1ttle.knockdowns.network.KnockdownsNetworkingConstants;
|
||||
|
||||
public class Knockdowns implements ModInitializer {
|
||||
public static final String MOD_ID = "knockdowns";
|
||||
private static final Identifier KNOCKED_DOWN_ID = new Identifier("knockdowns:knocked_down");
|
||||
private static final SoundEvent KNOCKED_DOWN = SoundEvent.of(KNOCKED_DOWN_ID);
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
registerSoundEvents();
|
||||
registerOnDeath();
|
||||
registerOnRequestKnockedDown();
|
||||
registerOnRequestReviving();
|
||||
registerOnReceiveReviving();
|
||||
registerOnReceiveRevived();
|
||||
registerOnPlayerInteractions();
|
||||
}
|
||||
|
||||
private static void registerSoundEvents() {
|
||||
Registry.register(Registries.SOUND_EVENT, KNOCKED_DOWN_ID, KNOCKED_DOWN);
|
||||
}
|
||||
|
||||
private static void registerOnDeath() {
|
||||
ServerLivingEntityEvents.ALLOW_DEATH.register((entity, damageSource, damageAmount) -> {
|
||||
if (!(entity instanceof IKnockableDown knockableDown) || knockableDown.knockdowns$isKnockedDown()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ServerPlayerEntity serverPlayer = (ServerPlayerEntity) entity;
|
||||
// TODO: timer
|
||||
if (!serverPlayer.getWorld().getGameRules().getBoolean(GameRules.KEEP_INVENTORY)) {
|
||||
serverPlayer.getInventory().dropAll();
|
||||
}
|
||||
entity.setHealth(1.0f);
|
||||
entity.setInvulnerable(true);
|
||||
entity.setGlowing(true);
|
||||
entity.setAir(entity.getMaxAir());
|
||||
entity.extinguish();
|
||||
entity.setFrozenTicks(0);
|
||||
entity.setOnFire(false);
|
||||
entity.clearStatusEffects();
|
||||
|
||||
knockableDown.knockdowns$setKnockedDown(true);
|
||||
|
||||
PacketByteBuf buf = PacketByteBufs.create();
|
||||
buf.writeUuid(entity.getUuid());
|
||||
buf.writeBoolean(true);
|
||||
|
||||
ServerPlayNetworking.send(serverPlayer, KnockdownsNetworkingConstants.S2C_SEND_PLAYER_KNOCKED_DOWN, buf);
|
||||
for (ServerPlayerEntity player : PlayerLookup.tracking(entity)) {
|
||||
ServerPlayNetworking.send(player, KnockdownsNetworkingConstants.S2C_SEND_PLAYER_KNOCKED_DOWN, buf);
|
||||
}
|
||||
|
||||
for (ServerPlayerEntity player : serverPlayer.getServerWorld().getPlayers()) {
|
||||
player.networkHandler.sendPacket(new PlaySoundS2CPacket(Registries.SOUND_EVENT.getEntry(KNOCKED_DOWN), SoundCategory.PLAYERS,
|
||||
player.getX(), player.getY(), player.getZ(), 1.0f, 1.0f, 0L));
|
||||
}
|
||||
|
||||
TranslatableTextContent content = (TranslatableTextContent) entity.getDamageTracker().getDeathMessage().getContent();
|
||||
Text replaced = Text.translatable(content.getKey().replace("death.", "knockdown."), content.getArgs());
|
||||
MinecraftServer server = serverPlayer.getServer();
|
||||
if (server != null) {
|
||||
server.getPlayerManager().broadcast(replaced, false);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
private static void registerOnRequestKnockedDown() {
|
||||
ServerPlayNetworking.registerGlobalReceiver(KnockdownsNetworkingConstants.C2S_REQUEST_PLAYER_KNOCKED_DOWN, (server, player, handler, buf, responseSender) -> {
|
||||
UUID uuid = buf.readUuid();
|
||||
|
||||
server.execute(() -> {
|
||||
IKnockableDown knockableDown = (IKnockableDown) player.getWorld().getPlayerByUuid(uuid);
|
||||
if (knockableDown == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
PacketByteBuf responseBuf = PacketByteBufs.create();
|
||||
responseBuf.writeUuid(uuid);
|
||||
responseBuf.writeBoolean(knockableDown.knockdowns$isKnockedDown());
|
||||
|
||||
responseSender.sendPacket(KnockdownsNetworkingConstants.S2C_SEND_PLAYER_KNOCKED_DOWN, responseBuf);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static void registerOnRequestReviving() {
|
||||
ServerPlayNetworking.registerGlobalReceiver(KnockdownsNetworkingConstants.C2S_REQUEST_PLAYER_REVIVING, (server, player, handler, buf, responseSender) -> {
|
||||
UUID uuid = buf.readUuid();
|
||||
|
||||
server.execute(() -> {
|
||||
IKnockableDown knockableDown = (IKnockableDown) player.getWorld().getPlayerByUuid(uuid);
|
||||
if (knockableDown == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
PacketByteBuf responseBuf = PacketByteBufs.create();
|
||||
responseBuf.writeUuid(uuid);
|
||||
responseBuf.writeBoolean(knockableDown.knockdowns$isBeingRevived());
|
||||
|
||||
responseSender.sendPacket(KnockdownsNetworkingConstants.S2C_SEND_PLAYER_REVIVING, responseBuf);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static void registerOnReceiveReviving() {
|
||||
ServerPlayNetworking.registerGlobalReceiver(KnockdownsNetworkingConstants.C2S_SEND_PLAYER_REVIVING, (server, player, handler, buf, responseSender) -> {
|
||||
UUID uuid = buf.readUuid();
|
||||
boolean beingRevived = buf.readBoolean();
|
||||
|
||||
// TODO: revival by multiple players
|
||||
server.execute(() -> {
|
||||
PlayerEntity reviving = player.getWorld().getPlayerByUuid(uuid);
|
||||
IKnockableDown knockableDown = (IKnockableDown) reviving;
|
||||
if (knockableDown == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
knockableDown.knockdowns$setBeingRevived(beingRevived);
|
||||
|
||||
PacketByteBuf broadcastBuf = PacketByteBufs.create();
|
||||
broadcastBuf.writeUuid(uuid);
|
||||
broadcastBuf.writeBoolean(beingRevived);
|
||||
|
||||
ServerPlayNetworking.send((ServerPlayerEntity) reviving, KnockdownsNetworkingConstants.S2C_SEND_PLAYER_REVIVING, broadcastBuf);
|
||||
for (ServerPlayerEntity entity : PlayerLookup.tracking(reviving)) {
|
||||
ServerPlayNetworking.send(entity, KnockdownsNetworkingConstants.S2C_SEND_PLAYER_REVIVING, broadcastBuf);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static void registerOnReceiveRevived() {
|
||||
ServerPlayNetworking.registerGlobalReceiver(KnockdownsNetworkingConstants.C2S_SEND_PLAYER_REVIVED, (server, player, handler, buf, responseSender) -> {
|
||||
UUID uuid = buf.readUuid();
|
||||
|
||||
server.execute(() -> {
|
||||
PlayerEntity reviving = player.getWorld().getPlayerByUuid(uuid);
|
||||
IKnockableDown knockableDown = (IKnockableDown) reviving;
|
||||
if (knockableDown == null || !knockableDown.knockdowns$isKnockedDown()) {
|
||||
return;
|
||||
}
|
||||
|
||||
reviving.setInvulnerable(false);
|
||||
reviving.setGlowing(false);
|
||||
reviving.setHealth(reviving.getHealth() + 5.0f);
|
||||
|
||||
knockableDown.knockdowns$setKnockedDown(false);
|
||||
|
||||
PacketByteBuf sendBuf = PacketByteBufs.create();
|
||||
sendBuf.writeUuid(reviving.getUuid());
|
||||
sendBuf.writeBoolean(false);
|
||||
|
||||
ServerPlayNetworking.send((ServerPlayerEntity) reviving, KnockdownsNetworkingConstants.S2C_SEND_PLAYER_KNOCKED_DOWN, sendBuf);
|
||||
for (ServerPlayerEntity entity : PlayerLookup.tracking(reviving)) {
|
||||
ServerPlayNetworking.send(entity, KnockdownsNetworkingConstants.S2C_SEND_PLAYER_KNOCKED_DOWN, sendBuf);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static void registerOnPlayerInteractions() {
|
||||
AttackBlockCallback.EVENT.register((player, world, hand, pos, direction) -> {
|
||||
if (player instanceof IKnockableDown && ((IKnockableDown) player).knockdowns$isKnockedDown()) {
|
||||
return ActionResult.FAIL;
|
||||
}
|
||||
return ActionResult.PASS;
|
||||
});
|
||||
AttackEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> {
|
||||
if (player instanceof IKnockableDown && ((IKnockableDown) player).knockdowns$isKnockedDown()) {
|
||||
return ActionResult.FAIL;
|
||||
}
|
||||
return ActionResult.PASS;
|
||||
});
|
||||
UseItemCallback.EVENT.register((player, world, hand) -> {
|
||||
if (player instanceof IKnockableDown && ((IKnockableDown) player).knockdowns$isKnockedDown()) {
|
||||
return TypedActionResult.fail(hand == Hand.MAIN_HAND ? player.getMainHandStack() : player.getOffHandStack());
|
||||
}
|
||||
return TypedActionResult.pass(hand == Hand.MAIN_HAND ? player.getMainHandStack() : player.getOffHandStack());
|
||||
});
|
||||
UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> {
|
||||
if (player instanceof IKnockableDown && ((IKnockableDown) player).knockdowns$isKnockedDown()) {
|
||||
return ActionResult.FAIL;
|
||||
}
|
||||
return ActionResult.PASS;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package ru.octol1ttle.knockdowns.api;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface IKnockableDown {
|
||||
boolean knockdowns$isKnockedDown();
|
||||
|
||||
void knockdowns$setKnockedDown(boolean knockedDown);
|
||||
|
||||
boolean knockdowns$isBeingRevived();
|
||||
|
||||
void knockdowns$setBeingRevived(boolean beingRevived);
|
||||
|
||||
UUID knockdowns$getUuid();
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
package ru.octol1ttle.knockdowns.mixin;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||
import java.util.UUID;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import ru.octol1ttle.knockdowns.api.IKnockableDown;
|
||||
|
||||
@Mixin(PlayerEntity.class)
|
||||
public abstract class PlayerEntityMixin implements IKnockableDown {
|
||||
@Unique
|
||||
private boolean knockedDown;
|
||||
@Unique
|
||||
private boolean beingRevived;
|
||||
|
||||
@ModifyExpressionValue(method = "updatePose", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;isSwimming()Z"))
|
||||
private boolean enterSwimmingIfKnockedDown(boolean original) {
|
||||
PlayerEntity player = (PlayerEntity)(Object)this;
|
||||
if (!(player instanceof IKnockableDown knockableDown)) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
return original || knockableDown.knockdowns$isKnockedDown();
|
||||
}
|
||||
|
||||
@ModifyReturnValue(method = "canFoodHeal", at = @At("RETURN"))
|
||||
private boolean dontHealIfKnockedDown(boolean original) {
|
||||
return original && !this.knockdowns$isKnockedDown();
|
||||
}
|
||||
|
||||
@Inject(method = "readCustomDataFromNbt", at = @At("TAIL"))
|
||||
public void readKnockedDownFromNbt(NbtCompound nbt, CallbackInfo ci) {
|
||||
this.knockedDown = nbt.getBoolean("KnockedDown");
|
||||
}
|
||||
|
||||
@Inject(method = "writeCustomDataToNbt", at = @At("TAIL"))
|
||||
public void writeKnockedDownToNbt(NbtCompound nbt, CallbackInfo ci) {
|
||||
nbt.putBoolean("KnockedDown", this.knockedDown);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean knockdowns$isKnockedDown() {
|
||||
return knockedDown;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void knockdowns$setKnockedDown(boolean knockedDown) {
|
||||
this.knockedDown = knockedDown;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean knockdowns$isBeingRevived() {
|
||||
return beingRevived;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void knockdowns$setBeingRevived(boolean beingRevived) {
|
||||
this.beingRevived = beingRevived;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID knockdowns$getUuid() {
|
||||
return ((PlayerEntity)(Object)this).getUuid();
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package ru.octol1ttle.knockdowns.network;
|
||||
|
||||
import net.minecraft.util.Identifier;
|
||||
import ru.octol1ttle.knockdowns.Knockdowns;
|
||||
|
||||
public class KnockdownsNetworkingConstants {
|
||||
public static final Identifier S2C_SEND_PLAYER_KNOCKED_DOWN = new Identifier(Knockdowns.MOD_ID, "s2c_send_player_knocked_down");
|
||||
public static final Identifier S2C_SEND_PLAYER_REVIVING = new Identifier(Knockdowns.MOD_ID, "s2c_send_player_reviving");
|
||||
public static final Identifier C2S_REQUEST_PLAYER_KNOCKED_DOWN = new Identifier(Knockdowns.MOD_ID, "c2s_request_player_knocked_down");
|
||||
public static final Identifier C2S_REQUEST_PLAYER_REVIVING = new Identifier(Knockdowns.MOD_ID, "c2s_request_player_reviving");
|
||||
public static final Identifier C2S_SEND_PLAYER_REVIVING = new Identifier(Knockdowns.MOD_ID, "c2s_send_player_reviving");
|
||||
public static final Identifier C2S_SEND_PLAYER_REVIVED = new Identifier(Knockdowns.MOD_ID, "c2s_send_player_revived");
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 453 B |
Binary file not shown.
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "knockdowns",
|
||||
"version": "${version}",
|
||||
"name": "Knockdowns",
|
||||
"description": "man hardcode is difficult",
|
||||
"authors": [
|
||||
"Octol1ttle"
|
||||
],
|
||||
"contact": {
|
||||
"homepage": "https://fabricmc.net/",
|
||||
"sources": "https://github.com/FabricMC/fabric-example-mod"
|
||||
},
|
||||
"license": "ARR",
|
||||
"icon": "assets/knockdowns/icon.png",
|
||||
"environment": "*",
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"ru.octol1ttle.knockdowns.Knockdowns"
|
||||
],
|
||||
"client": [
|
||||
"ru.octol1ttle.knockdowns.KnockdownsClient"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
"knockdowns.mixins.json",
|
||||
{
|
||||
"config": "knockdowns.client.mixins.json",
|
||||
"environment": "client"
|
||||
}
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.14.23",
|
||||
"minecraft": "~1.20.2",
|
||||
"java": ">=17",
|
||||
"fabric-api": "*"
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"required": true,
|
||||
"package": "ru.octol1ttle.knockdowns.mixin",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"mixins": [
|
||||
"PlayerEntityMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue