Skip to content
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
6 changes: 3 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: set up JDK 21
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
Expand All @@ -18,7 +18,7 @@ jobs:
- name: build with gradle
run: ./gradlew build
- name: capture build artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: artifacts
path: build/libs/
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//file:noinspection GroovyAssignabilityCheck
plugins {
id "fabric-loom" version "1.7.+"
id "com.github.johnrengelman.shadow" version "7.1.+"
Expand Down
14 changes: 7 additions & 7 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@ org.gradle.jvmargs = -Xmx1G

# minecraft, mappings and loader dependencies
# check these on https://modmuss50.me/fabric.html
minecraft_version = 1.21.3
quilt_mappings = 6
loader_version = 0.16.7
minecraft_version = 1.21.4
quilt_mappings = 3
loader_version = 0.16.10
kaleido_config_version = 0.3.1+1.3.2

# mod properties
mod_version = 1.3.5+mc1.21.3
mod_version = 1.3.5+mc1.21.4
maven_group = rainglow
archives_base_name = rainglow

# other dependencies
java_version = 21
mod_menu_version = 12.0.0-beta.1
fabric_api_version = 0.107.0+1.21.3
mod_menu_version = 13.0.0-beta.1
fabric_api_version = 0.118.5+1.21.4

pub.should_publish = true
pub.additional_versions = 1.21.2
pub.additional_versions = 1.21.4
14 changes: 13 additions & 1 deletion src/main/java/io/ix0rai/rainglow/Rainglow.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import io.ix0rai.rainglow.config.RainglowConfig;
import io.ix0rai.rainglow.data.*;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
Expand Down Expand Up @@ -71,8 +72,14 @@ public void onInitialize() {
});

ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> {
COLOURS.clear();
// Only clear colours on disconnect if server is NOT single-player to prevent NBT save failure (Unsure how this works with Lan-instances)
if (!server.isSingleplayer()) {
COLOURS.clear();
}
});

// Instead use SERVER_STOPPED for clearing colours from single-player worlds. (Doesn't affect others because mod would most likely be shutdown in non-single-player instances)
ServerLifecycleEvents.SERVER_STOPPED.register(server -> COLOURS.clear());
}

public static Identifier id(String id) {
Expand Down Expand Up @@ -116,6 +123,11 @@ public static RainglowColour getColour(Entity entity) {
return colour;
}

// Simplified method without any colour checks (Entity information isn't being passed through Rendering anymore, can be adjusted to apply in the RenderStateInteract if needed)
public static RainglowColour getColour(UUID entity) {
return COLOURS.get(entity);
}

public static void setColour(Entity entity, RainglowColour colour) {
setColour(entity.getUuid(), colour);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.ix0rai.rainglow.data;

import net.minecraft.entity.Entity;

import java.util.UUID;

/**
* @author A5ho9999
* Interface to track entity data in render states
*/
public interface EntityRenderStateTracker {
/**
* Set the associated entity
* @param entity The entity to associate with this render state
*/
void rainglow$setEntity(Entity entity);

/**
* Get the associated entity UUID
* @return The UUID of the associated entity, or null if not set
*/
UUID rainglow$getEntityUuid();
}
15 changes: 13 additions & 2 deletions src/main/java/io/ix0rai/rainglow/data/GlowSquidEntityData.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
package io.ix0rai.rainglow.data;

import net.minecraft.entity.EntityData;
import net.minecraft.entity.passive.PassiveEntity;

public record GlowSquidEntityData(RainglowColour colour) implements EntityData {
public class GlowSquidEntityData extends PassiveEntity.PassiveData {
private final RainglowColour colour;

public GlowSquidEntityData(RainglowColour colour) {
// copied from SquidEntity#initialize. as far as i can tell we have to duplicate this constant
super(0.05F);
this.colour = colour;
}

public RainglowColour getColour() {
return colour;
}
}
22 changes: 22 additions & 0 deletions src/main/java/io/ix0rai/rainglow/data/ParticleHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.ix0rai.rainglow.data;

import net.minecraft.client.particle.ItemBreakParticle;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.unmapped.C_hvackyip;

/**
* @author A5ho9999
* Helper for creating particles because Mojang likes to torture everyone
*/
public class ParticleHelper {
public static class CustomItemBreakParticle extends ItemBreakParticle {
public CustomItemBreakParticle(ClientWorld world, double d, double e, double f, C_hvackyip c_hvackyip) {
super(world, d, e, f, c_hvackyip);
}
}

public static Particle createItemBreakParticle(ClientWorld world, double d, double e, double f, C_hvackyip c_hvackyip) {
return new CustomItemBreakParticle(world, d, e, f, c_hvackyip);
}
}
27 changes: 23 additions & 4 deletions src/main/java/io/ix0rai/rainglow/data/RainglowEntity.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.ix0rai.rainglow.data;

import io.ix0rai.rainglow.Rainglow;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityData;
import net.minecraft.entity.mob.SlimeEntity;
Expand All @@ -13,10 +14,11 @@
import net.minecraft.util.random.RandomGenerator;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.Arrays;
import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;

public enum RainglowEntity {
Expand Down Expand Up @@ -99,14 +101,31 @@ public static RainglowEntity get(Entity entity) {
return null;
}

public void overrideTexture(Entity entity, CallbackInfoReturnable<Identifier> cir) {
@Nullable
public Identifier overrideTexture(ClientWorld world, UUID uuid) {
AtomicReference<Identifier> texture = new AtomicReference<>();

world.getEntities().forEach(entity -> {
if (entity.getUuid().equals(uuid)) {
texture.set(this.overrideTexture(entity));
}
});

return texture.get();
}

// Return the override texture instead of applying through callback
public Identifier overrideTexture(Entity entity) {
RainglowColour colour = Rainglow.getColour(entity);

// Returning null will just use default texture, no need for extra checks

// if the colour is default we don't need to override the method
// this optimises a tiny bit
if (Rainglow.CONFIG.isEntityEnabled(this) && colour != this.getDefaultColour()) {
Identifier texture = colour.getTexture(this);
cir.setReturnValue(texture != null ? texture : this.getDefaultTexture());
return colour.getTexture(this);
}

return null;
}
}
6 changes: 3 additions & 3 deletions src/main/java/io/ix0rai/rainglow/data/RainglowNetworking.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public static void syncConfig(ServerPlayerEntity player) {

public record ConfigSyncPayload(String currentMode, List<RainglowColour> customMode, Map<RainglowEntity, Boolean> enabledMobs, Map<RainglowEntity, Integer> rarities) implements CustomPayload {
public static final CustomPayload.Id<ConfigSyncPayload> PACKET_ID = new CustomPayload.Id<>(Rainglow.id("config_sync"));
public static final PacketCodec<RegistryByteBuf, ConfigSyncPayload> PACKET_CODEC = PacketCodec.create(ConfigSyncPayload::write, ConfigSyncPayload::read);
public static final PacketCodec<RegistryByteBuf, ConfigSyncPayload> PACKET_CODEC = PacketCodec.of(ConfigSyncPayload::write, ConfigSyncPayload::read);

public void write(RegistryByteBuf buf) {
buf.writeString(this.currentMode);
Expand Down Expand Up @@ -55,7 +55,7 @@ public static void syncModes(ServerPlayerEntity player) {

public record ModeSyncPayload(Collection<RainglowMode> modes) implements CustomPayload {
public static final CustomPayload.Id<ModeSyncPayload> PACKET_ID = new CustomPayload.Id<>(Rainglow.id("mode_sync"));
public static final PacketCodec<RegistryByteBuf, ModeSyncPayload> PACKET_CODEC = PacketCodec.create(ModeSyncPayload::write, ModeSyncPayload::read);
public static final PacketCodec<RegistryByteBuf, ModeSyncPayload> PACKET_CODEC = PacketCodec.of(ModeSyncPayload::write, ModeSyncPayload::read);

public void write(RegistryByteBuf buf) {
buf.writeCollection(this.modes, RainglowMode::write);
Expand Down Expand Up @@ -91,7 +91,7 @@ public static void sendColourChangeToClients(Entity entity, RainglowColour colou

public record ColourPayload(Map<UUID, RainglowColour> colours) implements CustomPayload {
public static final CustomPayload.Id<ColourPayload> PACKET_ID = new CustomPayload.Id<>(Rainglow.id("colour_change"));
public static final PacketCodec<RegistryByteBuf, ColourPayload> PACKET_CODEC = PacketCodec.create(ColourPayload::write, ColourPayload::read);
public static final PacketCodec<RegistryByteBuf, ColourPayload> PACKET_CODEC = PacketCodec.of(ColourPayload::write, ColourPayload::read);

public void write(RegistryByteBuf buf) {
buf.writeMap(this.colours, (b, uuid) -> b.writeUuid(uuid), RainglowColour::write);
Expand Down
44 changes: 36 additions & 8 deletions src/main/java/io/ix0rai/rainglow/mixin/SlimeEntityMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@
import io.ix0rai.rainglow.data.RainglowColour;
import io.ix0rai.rainglow.data.RainglowEntity;
import io.ix0rai.rainglow.data.SlimeVariantProvider;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.*;
import net.minecraft.entity.mob.SlimeEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.particle.ParticleEffect;
import net.minecraft.scoreboard.Team;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.Slice;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

Expand Down Expand Up @@ -43,11 +42,40 @@ public void readCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {
/**
* @reason make smaller slimes spawn with the same colour as the parent in a split
*/
@Redirect(method = "remove", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;spawnEntity(Lnet/minecraft/entity/Entity;)Z"))
public boolean spawnWithParentColour(World instance, Entity entity) {
RainglowColour colour = Rainglow.getColour(this);
((SlimeVariantProvider) entity).setVariant(colour);
return this.getWorld().spawnEntity(entity);
@Inject(method = "remove", at = @At("HEAD"), cancellable = true)
private void preserveColorOnSplit(Entity.RemovalReason reason, CallbackInfo ci) {
SlimeEntity thisSlime = (SlimeEntity) (Object) this;
int size = thisSlime.getSize();

if (!thisSlime.getWorld().isClient && size > 1 && thisSlime.isDead()) {
RainglowColour parentColor = Rainglow.getColour(thisSlime.getUuid());

float width = thisSlime.getDimensions(thisSlime.getPose()).width();
float halfWidth = width / 2.0F;
int newSize = size / 2;
Team team = thisSlime.getScoreboardTeam();

int count = 2 + thisSlime.getRandom().nextInt(3);

// Create multiple slimes individually while making sure it matches vanilla
for (int i = 0; i < count; i++) {
float offsetX = ((float) (i % 2) - 0.5F) * halfWidth;
float offsetZ = ((float) (i / 2) - 0.5F) * halfWidth;

//noinspection unchecked
thisSlime.convert((EntityType<SlimeEntity>) thisSlime.getType(), new EntityConversionParameters(EntityConversionType.SPLIT_ON_DEATH, false, false, team), SpawnReason.TRIGGERED, (newSlime) -> {
newSlime.setSize(newSize, true);
newSlime.refreshPositionAndAngles(thisSlime.getX() + offsetX, thisSlime.getY() + 0.5, thisSlime.getZ() + offsetZ, thisSlime.getRandom().nextFloat() * 360.0F, 0.0F);

// Now that headache is done, finally set the child slime color to match the parent
((SlimeVariantProvider) newSlime).setVariant(parentColor);
});
}

// Don't forget this, boy was that a mistake
super.remove(reason);
ci.cancel();
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
package io.ix0rai.rainglow.mixin.client;

import io.ix0rai.rainglow.data.EntityRenderStateTracker;
import io.ix0rai.rainglow.data.RainglowEntity;
import net.minecraft.class_9996;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.entity.AllayEntityRenderer;
import net.minecraft.entity.passive.AllayEntity;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.UUID;

@Mixin(AllayEntityRenderer.class)
public class AllayEntityRendererMixin {
@Inject(method = "getTexture*", at = @At("HEAD"), cancellable = true)
public void getTexture(AllayEntity allayEntity, CallbackInfoReturnable<Identifier> cir) {
RainglowEntity.ALLAY.overrideTexture(allayEntity, cir);
@Inject(method = "m_vhdjjpxx", at = @At("HEAD"), cancellable = true)
public void getTexture(class_9996 state, CallbackInfoReturnable<Identifier> cir) {
if (state instanceof EntityRenderStateTracker) {
UUID entityUuid = ((EntityRenderStateTracker) state).rainglow$getEntityUuid();
if (entityUuid != null) {
ClientWorld world = MinecraftClient.getInstance().world;
if (world != null) {
RainglowEntity type = RainglowEntity.ALLAY;
Identifier texture = type.overrideTexture(world, entityUuid);
cir.setReturnValue(texture != null ? texture : type.getDefaultTexture());
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.ix0rai.rainglow.mixin.client;

import io.ix0rai.rainglow.data.EntityRenderStateTracker;
import net.minecraft.class_10017;
import net.minecraft.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;

import java.util.UUID;

@Mixin(class_10017.class)
public class EntityRenderStateMixin implements EntityRenderStateTracker {
@Unique
private UUID entityUuid;

@Override
public void rainglow$setEntity(Entity entity) {
if (entity != null) {
this.entityUuid = entity.getUuid();
}
}

// TODO: This could be used to just get the Entity as well as the UUID but just saving the UUID is better for long term memory usage

@Override
public UUID rainglow$getEntityUuid() {
return this.entityUuid;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.ix0rai.rainglow.mixin.client;

import io.ix0rai.rainglow.data.EntityRenderStateTracker;
import net.minecraft.class_10017;
import net.minecraft.client.render.entity.EntityRenderer;
import net.minecraft.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(EntityRenderer.class)
public class EntityRendererMixin<T extends Entity, S extends class_10017> {
@Inject(method = "method_62354", at = @At("HEAD"))
private void updateRenderState(T entity, S state, float f, CallbackInfo ci) {
if (state instanceof EntityRenderStateTracker) {
((EntityRenderStateTracker) state).rainglow$setEntity(entity);
}
}
}
Loading