Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Staff Mod 0.10.0-beta #26

Merged
merged 3 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* AvM Staff Mod
* Copyright (c) 2024 opekope2
*
* This mod is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This mod is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this mod. If not, see <https://www.gnu.org/licenses/>.
*/

package opekope2.avm_staff.api.entity;

import net.minecraft.entity.TntEntity;
import net.minecraft.entity.data.DataTracker;
import net.minecraft.entity.data.TrackedData;
import net.minecraft.entity.data.TrackedDataHandlerRegistry;

/**
* A TNT, which can be configured to explode when collides (with blocks or other entities).
*/
public interface IImpactTnt {
/**
* Returns if the current TNT explodes, when it collides.
*/
boolean explodesOnImpact();

/**
* Configures the current TNT to explode or not, when it collides.
*
* @param explode Whether to explode on collision
*/
void explodeOnImpact(boolean explode);

/**
* NBT Key for TNT's explodes on impact property.
*/
String EXPLODES_ON_IMPACT_NBT_KEY = "ExplodesOnImpact";

/**
* Data tracker for TNT's explodes on impact property.
*/
TrackedData<Boolean> EXPLODES_ON_IMPACT = DataTracker.registerData(TntEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
}
111 changes: 111 additions & 0 deletions StaffMod/src/main/java/opekope2/avm_staff/mixin/TntEntityMixin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* AvM Staff Mod
* Copyright (c) 2024 opekope2
*
* This mod is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This mod is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this mod. If not, see <https://www.gnu.org/licenses/>.
*/

package opekope2.avm_staff.mixin;

import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.TntEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.world.World;
import opekope2.avm_staff.api.entity.IImpactTnt;
import org.jetbrains.annotations.Nullable;
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.CallbackInfo;

import java.util.List;

@Mixin(TntEntity.class)
public abstract class TntEntityMixin extends Entity implements IImpactTnt {
private TntEntityMixin(EntityType<?> type, World world) {
super(type, world);
}

@Shadow
protected abstract void explode();

@Shadow
@Nullable
public abstract LivingEntity getOwner();

@Inject(method = "initDataTracker", at = @At("TAIL"))
private void initDataTracker(CallbackInfo ci) {
dataTracker.startTracking(EXPLODES_ON_IMPACT, false);
}

@Inject(method = "writeCustomDataToNbt", at = @At("TAIL"))
private void writeCustomDataToNbt(NbtCompound nbt, CallbackInfo ci) {
nbt.putBoolean(EXPLODES_ON_IMPACT_NBT_KEY, explodesOnImpact());
}

@Inject(method = "readCustomDataFromNbt", at = @At("TAIL"))
private void readCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {
if (nbt.contains(EXPLODES_ON_IMPACT_NBT_KEY, NbtElement.BYTE_TYPE)) {
explodeOnImpact(nbt.getBoolean(EXPLODES_ON_IMPACT_NBT_KEY));
}
}

@Inject(
method = "tick",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/entity/TntEntity;move(Lnet/minecraft/entity/MovementType;Lnet/minecraft/util/math/Vec3d;)V",
shift = At.Shift.AFTER
)
)
private void explodeOnImpact(CallbackInfo ci) {
if (!explodesOnImpact()) return;

boolean explode = horizontalCollision || verticalCollision;
if (!explode) {
Entity owner = getOwner();
List<Entity> collisions = getWorld().getOtherEntities(this, getBoundingBox(), entity -> entity != owner);
explode = !collisions.isEmpty();

for (Entity collider : collisions) {
if (collider instanceof TntEntity tnt && ((IImpactTnt) tnt).explodesOnImpact()) {
// Force explode other TNT, because the current TNT gets discarded before the other TNT gets processed
tnt.setFuse(0);
}
}
}

if (!explode) return;

if (!getWorld().isClient) {
// Server sends EntitiesDestroyS2CPacket to client, because TntEntity.getOwner() isn't available on the client.
discard();
explode();
}
}

@Override
public boolean explodesOnImpact() {
return dataTracker.get(EXPLODES_ON_IMPACT);
}

@Override
public void explodeOnImpact(boolean explode) {
dataTracker.set(EXPLODES_ON_IMPACT, explode);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* AvM Staff Mod
* Copyright (c) 2024 opekope2
*
* This mod is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This mod is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this mod. If not, see <https://www.gnu.org/licenses/>.
*/

package opekope2.avm_staff.internal.staff_item_handler

import net.minecraft.entity.LivingEntity
import net.minecraft.entity.TntEntity
import net.minecraft.item.BlockItem
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
import net.minecraft.sound.SoundCategory
import net.minecraft.sound.SoundEvents
import net.minecraft.util.ActionResult
import net.minecraft.util.Hand
import net.minecraft.world.World
import net.minecraft.world.event.GameEvent
import opekope2.avm_staff.api.item.StaffItemHandler
import opekope2.avm_staff.api.item.renderer.InsideStaffBlockStateRenderer
import opekope2.avm_staff.api.entity.IImpactTnt

class TntHandler : StaffItemHandler() {
override val staffItemRenderer = InsideStaffBlockStateRenderer.forBlockItem(Items.TNT as BlockItem)

override fun attack(staffStack: ItemStack, world: World, attacker: LivingEntity, hand: Hand): ActionResult {
if (world.isClient) return ActionResult.SUCCESS

world.spawnEntity(
TntEntity(world, attacker.x, attacker.eyeY, attacker.z, attacker).apply {
velocity = attacker.rotationVector.normalize()
@Suppress("KotlinConstantConditions") // IImpactTnt is ducked into TntEntity
(this as IImpactTnt).explodeOnImpact(true)
world.playSound(null, x, y, z, SoundEvents.ENTITY_TNT_PRIMED, SoundCategory.BLOCKS, 1.0f, 1.0f)
world.emitGameEvent(attacker, GameEvent.PRIME_FUSE, pos)
}
)

return ActionResult.SUCCESS
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ fun register() {

SNOW_BLOCK.registerHandler(SnowBlockHandler())

TNT.registerHandler(TntHandler())

WHITE_WOOL.registerHandler(WoolHandler(WHITE_WOOL as BlockItem, WHITE_CARPET as BlockItem))
ORANGE_WOOL.registerHandler(WoolHandler(ORANGE_WOOL as BlockItem, ORANGE_CARPET as BlockItem))
MAGENTA_WOOL.registerHandler(WoolHandler(MAGENTA_WOOL as BlockItem, MAGENTA_CARPET as BlockItem))
Expand Down
3 changes: 2 additions & 1 deletion StaffMod/src/main/resources/avm_staff.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
],
"mixins": [
"IAbstractFurnaceBlockEntityMixin",
"LivingEntityMixin"
"LivingEntityMixin",
"TntEntityMixin"
]
}
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ loader_version=0.15.3
java_version=17
##########################################################################
# Mod Properties
mod_version=0.9.0-beta
mod_version=0.10.0-beta
maven_group=opekope2.avm_staff
##########################################################################
# Kotlin Dependencies
Expand Down
Loading