Compare commits

...

4 commits

Author SHA1 Message Date
petrak@ 994aec97a4 syncing code sucks 2023-05-01 13:13:43 -05:00
petrak@ 6a4c254ed0 patternado 2023-05-01 12:42:01 -05:00
petrak@ 19f35e1205 Merge branch 'main' into famos-amos
because i'm too clever, who the hell knows what SYN/ACK means
2023-04-27 21:37:06 -05:00
petrak@ 79cbfabb48 start work on amo's pattern rendering stuff 2023-04-27 21:34:49 -05:00
9 changed files with 361 additions and 2 deletions

View file

@ -4,6 +4,7 @@ import at.petrak.hexcasting.api.client.ScryingLensOverlayRegistry;
import at.petrak.hexcasting.api.misc.DiscoveryHandlers;
import at.petrak.hexcasting.api.player.Sentinel;
import at.petrak.hexcasting.client.ClientTickCounter;
import at.petrak.hexcasting.client.render.patternado.PatternadosTracker;
import at.petrak.hexcasting.xplat.IXplatAbstractions;
import com.google.common.collect.Lists;
import com.mojang.blaze3d.platform.GlStateManager;
@ -26,12 +27,15 @@ import net.minecraft.util.Mth;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
import java.util.List;
import java.util.function.BiConsumer;
public class HexAdditionalRenderers {
private static final float PATTERNADO_SPEEN_SPEED = 0.01f;
public static void overlayLevel(PoseStack ps, float partialTick) {
var player = Minecraft.getInstance().player;
if (player != null) {
@ -46,6 +50,74 @@ public class HexAdditionalRenderers {
tryRenderScryingLensOverlay(ps, partialTicks);
}
public static void renderPatternado(LocalPlayer player, PoseStack ps, float partialTicks) {
var me = Minecraft.getInstance().player;
if (me == player && !Minecraft.getInstance().options.getCameraType().isFirstPerson()) {
return;
}
var pats = PatternadosTracker.getPatterns(player.getUUID());
if (pats == null) {
return;
}
var oldShader = RenderSystem.getShader();
RenderSystem.setShader(GameRenderer::getPositionColorShader);
RenderSystem.enableDepthTest();
RenderSystem.disableCull();
ps.pushPose();
float time = player.level.getGameTime() + partialTicks;
var col = IXplatAbstractions.INSTANCE.getColorizer(player).getColorProvider();
for (var spinner : pats) {
// So it stops moving near the end?
float lifetimeOffset = spinner.getLifetime() <= 5 ? (5f - spinner.getLifetime()) / 5f : 0f;
{
ps.mulPose(Vector3f.YP.rotationDegrees(time * spinner.getLifetime() * PATTERNADO_SPEEN_SPEED));
// X: sideways, don't move it
// Y: up/down, each pattern stays on its own ring
// Z: in/out, it's mostly determined by the idx but also slowly drifts in/out
ps.translate(
0,
Mth.sin(spinner.getIdx() * 0.75f),
0.75f + (Mth.cos(spinner.getIdx() / 8f) * 0.25f) + Mth.cos(time) / (7f + (spinner.getIdx() / 4f)) * 0.065f
);
var scale = 1f / 24f * (1 - lifetimeOffset);
ps.scale(scale, scale, scale);
// Don't know why amo did this in two translate calls
ps.translate(
0,
Mth.floor(spinner.getIdx() / 8f) + Mth.sin(time) / (7f + (spinner.getIdx() / 8f)),
0
);
}
var pat = spinner.getPattern();
var lines = RenderLib.getCenteredPattern(pat, 1, 1, 3.8f).getSecond();
float variance = 0.65f;
float speed = 0.1f;
List<Vec2> zappy = RenderLib.makeZappy(lines, RenderLib.findDupIndices(pat.positions()),
5, variance, speed, 0.2f, 0f,
1f, spinner.getUuid().hashCode());
int outer = col.getColor(ClientTickCounter.getTotal() / 2f, Vec3.ZERO);
int rgbOnly = outer & 0x00FFFFFF;
int newAlpha = outer >>> 24;
if (spinner.getLifetime() <= 60) {
newAlpha = (int) Math.floor(spinner.getLifetime() / 60f * 255);
}
int newARGB = (newAlpha << 24) | rgbOnly;
int inner = RenderLib.screen(newARGB);
RenderLib.drawLineSeq(ps.last().pose(), zappy, 0.35f, 0f, newARGB, newARGB);
RenderLib.drawLineSeq(ps.last().pose(), zappy, 0.14f, 0.01f, inner, inner);
}
ps.popPose();
RenderSystem.setShader(() -> oldShader);
RenderSystem.enableCull();
}
private static void renderSentinel(Sentinel sentinel, LocalPlayer owner,
PoseStack ps, float partialTicks) {
ps.pushPose();

View file

@ -0,0 +1,84 @@
package at.petrak.hexcasting.client.render.patternado;
import at.petrak.hexcasting.common.casting.patternado.PatternadoPatInstance;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* Keeps track of the patterns swirling around each player
*/
public class PatternadosTracker {
// god i'm really calling this a patternado what is wrong with me
private static final Map<UUID, PlayerPats> PATTERNADOS = new HashMap<>();
/**
* Get notified of a new pattern around a player.
*/
public static void getNewPat(UUID owner, PatternadoPatInstance newPat) {
var nado = PATTERNADOS.get(owner);
if (nado == null) {
nado = PATTERNADOS.put(owner, PlayerPats.empty());
}
nado.pats.put(newPat.getUuid(), newPat);
}
/**
* Remove a pattern by its uuid. (More accurately, enqueue it for being removed after ticking)
*/
public static void removePat(UUID owner, UUID pattern) {
var nado = PATTERNADOS.get(owner);
if (nado == null) {
return;
}
nado.pats.remove(pattern);
}
/**
* Load a player fresh.
*/
public static void clobberPatterns(UUID owner, List<PatternadoPatInstance> pats) {
PATTERNADOS.put(owner, PlayerPats.newFromList(pats));
}
public static @Nullable Collection<PatternadoPatInstance> getPatterns(UUID owner) {
var pats = PATTERNADOS.get(owner);
if (pats == null) {
return null;
}
return pats.pats.values();
}
// TODO: this might cause a memory leak if you view tons and tons of players.
// Perhaps find some way to remove entries from this map if they're not in view?
public static void tick() {
for (var nados : PATTERNADOS.values()) {
var toRemove = new ArrayList<UUID>();
for (var pat : nados.pats.values()) {
pat.tick();
if (pat.getLifetime() == 0) {
toRemove.add(pat.getUuid());
}
}
for (var uuid : toRemove) {
nados.pats.remove(uuid);
}
}
}
private record PlayerPats(Map<UUID, PatternadoPatInstance> pats) {
static PlayerPats newFromList(List<PatternadoPatInstance> pats) {
var map = new HashMap<UUID, PatternadoPatInstance>();
for (var pat : pats) {
map.put(pat.getUuid(), pat);
}
return new PlayerPats(map);
}
static PlayerPats empty() {
return new PlayerPats(new HashMap<>());
}
}
}

View file

@ -0,0 +1,36 @@
package at.petrak.hexcasting.common.casting.patternado;
import at.petrak.hexcasting.api.casting.math.HexPattern;
import net.minecraft.world.entity.player.Player;
import java.util.ArrayDeque;
import java.util.Deque;
/**
* The patterns swirling around a particular player.
* <p>
* The canonical version of each player's patternado is stored on the server. When a new pattern is added on the server,
* the client hears about the addition. Clients remove patterns once they've run out of time themselves.
* <p>
* Also there's something about loading a brand new patternado when meeting a player for the first time
*/
public class Patternado {
private static final int MAX_IDX = 300;
private static final String TAG_PATS = "patterns",
TAG_IDX_COUNTER = "idx_counter";
private Player owner;
private Deque<PatternadoPatInstance> pats;
private int idxCounter;
public Patternado(Player owner) {
this.owner = owner;
this.pats = new ArrayDeque<>();
this.idxCounter = 0;
}
public void addPattern(HexPattern pattern, int lifetime) {
}
}

View file

@ -0,0 +1,71 @@
package at.petrak.hexcasting.common.casting.patternado;
import at.petrak.hexcasting.api.casting.math.HexPattern;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.util.RandomSource;
import java.util.UUID;
public final class PatternadoPatInstance {
private static final RandomSource RANDOM = RandomSource.create();
private final HexPattern pattern;
// Idx is used to determine where to draw it
private final int idx;
// -1 == infinite
private int lifetime;
// Use this so we can remove particular pats once a player finishes staffcasting
private UUID uuid;
public PatternadoPatInstance(HexPattern pattern, int lifetime, int idx) {
this.pattern = pattern;
this.lifetime = lifetime;
this.idx = idx;
this.uuid = UUID.randomUUID();
}
private PatternadoPatInstance(HexPattern pattern, int lifetime, int idx, UUID uuid) {
this.pattern = pattern;
this.lifetime = lifetime;
this.idx = idx;
this.uuid = uuid;
}
public HexPattern getPattern() {
return pattern;
}
public int getLifetime() {
return lifetime;
}
public int getIdx() {
return this.idx;
}
public UUID getUuid() {
return this.uuid;
}
public void tick() {
if (this.lifetime > 0) {
this.lifetime--;
}
}
// we need to go through and make the ser/de names consistent
public static PatternadoPatInstance loadFromWire(FriendlyByteBuf buf) {
var pattern = HexPattern.fromNBT(buf.readNbt());
var lifetime = buf.readVarInt();
var idx = buf.readVarInt();
var uuid = buf.readUUID();
return new PatternadoPatInstance(pattern, lifetime, idx, uuid);
}
public void saveToWire(FriendlyByteBuf buf) {
buf.writeNbt(this.pattern.serializeToNBT());
buf.writeVarInt(this.lifetime);
buf.writeInt(this.idx);
buf.writeUUID(this.uuid);
}
}

View file

@ -0,0 +1,3 @@
Thanks to Amo for writing the original code for this.
https://github.com/amoooooo/Jinx/tree/main

View file

@ -0,0 +1,44 @@
package at.petrak.hexcasting.common.msgs;
import at.petrak.hexcasting.client.render.patternado.PatternadosTracker;
import at.petrak.hexcasting.common.casting.patternado.PatternadoPatInstance;
import io.netty.buffer.ByteBuf;
import net.minecraft.client.Minecraft;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import java.util.UUID;
import static at.petrak.hexcasting.api.HexAPI.modLoc;
public record MsgNewPatternadoPatS2C(UUID owner, PatternadoPatInstance newPat) implements IMessage {
public static final ResourceLocation ID = modLoc("nado1");
@Override
public ResourceLocation getFabricId() {
return ID;
}
public static MsgNewPatternadoPatS2C deserialize(ByteBuf buffer) {
var buf = new FriendlyByteBuf(buffer);
var owner = buf.readUUID();
var pat = PatternadoPatInstance.loadFromWire(buf);
return new MsgNewPatternadoPatS2C(owner, pat);
}
@Override
public void serialize(FriendlyByteBuf buf) {
buf.writeUUID(this.owner);
this.newPat.saveToWire(buf);
}
public static void handle(MsgNewPatternadoPatS2C msg) {
Minecraft.getInstance().execute(new Runnable() {
@Override
public void run() {
PatternadosTracker.getNewPat(msg.owner, msg.newPat);
}
});
}
}

View file

@ -0,0 +1,48 @@
package at.petrak.hexcasting.common.msgs;
import at.petrak.hexcasting.client.render.patternado.PatternadosTracker;
import at.petrak.hexcasting.common.casting.patternado.PatternadoPatInstance;
import io.netty.buffer.ByteBuf;
import net.minecraft.client.Minecraft;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import static at.petrak.hexcasting.api.HexAPI.modLoc;
/**
* Set the patternado of a given player to this, overwrite the previous
*/
public record MsgOverridePatternadoS2C(UUID owner, List<PatternadoPatInstance> pats) implements IMessage {
public static final ResourceLocation ID = modLoc("nados");
@Override
public ResourceLocation getFabricId() {
return ID;
}
public static MsgOverridePatternadoS2C deserialize(ByteBuf buffer) {
var buf = new FriendlyByteBuf(buffer);
var owner = buf.readUUID();
var pats = buf.readCollection(ArrayList::new, PatternadoPatInstance::loadFromWire);
return new MsgOverridePatternadoS2C(owner, pats);
}
@Override
public void serialize(FriendlyByteBuf buf) {
buf.writeUUID(this.owner);
buf.writeCollection(this.pats, (bf, it) -> it.saveToWire(bf));
}
public static void handle(MsgOverridePatternadoS2C msg) {
Minecraft.getInstance().execute(new Runnable() {
@Override
public void run() {
PatternadosTracker.clobberPatterns(msg.owner, msg.pats);
}
});
}
}

View file

@ -42,11 +42,11 @@ public class HexCardinalComponents implements EntityComponentInitializer, ItemCo
CCSentinel.class);
public static final ComponentKey<CCFlight> FLIGHT = ComponentRegistry.getOrCreate(modLoc("flight"),
CCFlight.class);
public static final ComponentKey<CCAltiora> ALTIORA = ComponentRegistry.getOrCreate(modLoc("altiora"),
CCAltiora.class);
public static final ComponentKey<CCStaffcastImage> STAFFCAST_IMAGE = ComponentRegistry.getOrCreate(modLoc(
"harness"),
"harness"),
CCStaffcastImage.class);
public static final ComponentKey<CCPatterns> PATTERNS = ComponentRegistry.getOrCreate(modLoc("patterns"),
CCPatterns.class);

View file

@ -29,6 +29,7 @@ public class CapSyncers {
x.setAltiora(player, x.getAltiora(proto));
x.setSentinel(player, x.getSentinel(proto));
x.setColorizer(player, x.getColorizer(proto));
// TODO: do we want staff stuff to remain on death?
x.setStaffcastImage(player, x.getStaffcastVM(proto, InteractionHand.MAIN_HAND).getImage());
x.setPatterns(player, x.getPatternsSavedInUi(proto));
}