diff --git a/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/TexRender.java b/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/TexRender.java index d1fd53d8..896e0671 100644 --- a/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/TexRender.java +++ b/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/TexRender.java @@ -14,6 +14,7 @@ import net.minecraft.client.resources.data.TextureMetadataSection; import net.minecraft.util.ResourceLocation; import org.apache.commons.io.IOUtils; import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; @@ -38,11 +39,54 @@ public class TexRender extends TextureRender { } } + /** + * 开始绘制:绑定材质、设置混合模式 + */ + private void beginDraw() { + GL11.glBindTexture(GL11.GL_TEXTURE_2D, sourceTexture.getGlTextureId()); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + GL11.glDepthMask(false); + } + + /** + * 结束绘制:还原混合模式 + */ + private void endDraw() { + GL11.glDisable(GL11.GL_BLEND); + GL11.glDepthMask(true); + } + + /** + * 绘制一个四边形 + * + * @param x0 X坐标 + * @param y0 Y坐标 + * @param x1 X坐标 + * @param y1 Y坐标 + * @param u0 材质U坐标 + * @param v0 材质V坐标 + * @param u1 材质U坐标 + * @param v1 材质V坐标 + * @param alpha 透明度 + */ + private static void drawQuad(float x0, float y0, float x1, float y1, + float u0, float v0, float u1, float v1, float alpha) { + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawingQuads(); + tessellator.setColorRGBA_F(1.0f, 1.0f, 1.0f, alpha); + tessellator.addVertexWithUV(x0, y1, 0, u0, v1); + tessellator.addVertexWithUV(x1, y1, 0, u1, v1); + tessellator.addVertexWithUV(x1, y0, 0, u1, v0); + tessellator.addVertexWithUV(x0, y0, 0, u0, v0); + tessellator.draw(); + } + @Override public void drawPic(float x, float y, float alpha) { - GL11.glBindTexture(GL11.GL_TEXTURE_2D, sourceTexture.getGlTextureId()); - GL11.glDepthMask(false); - GL11.glEnable(GL11.GL_BLEND); + beginDraw(); float w1 = (float) width / 2; float h1 = (float) height / 2; @@ -50,36 +94,16 @@ public class TexRender extends TextureRender { GL11.glPushMatrix(); GL11.glTranslatef(x + w1, y + h1, 0.0f); - float x0 = -w1; - float x1 = w1; - float y0 = -h1; - float y1 = h1; - float z = 0; - float u0 = 0; - float u1 = 1; - float v0 = 0; - float v1 = 1; + drawQuad(-w1, -h1, w1, h1, 0, 0, 1, 1, alpha); - Tessellator tessellator = Tessellator.instance; - tessellator.startDrawingQuads(); - tessellator.setColorRGBA_F(1.0f, 1.0f, 1.0f, alpha); - tessellator.addVertexWithUV(x0, y1, z, u0, v1); - tessellator.addVertexWithUV(x1, y1, z, u1, v1); - tessellator.addVertexWithUV(x1, y0, z, u1, v0); - tessellator.addVertexWithUV(x0, y0, z, u0, v0); - tessellator.draw(); - - GL11.glDisable(GL11.GL_BLEND); - GL11.glDepthMask(true); + endDraw(); GL11.glPopMatrix(); } @Override public void drawPic(float x, float y, float width, float alpha) { - GL11.glBindTexture(GL11.GL_TEXTURE_2D, sourceTexture.getGlTextureId()); - GL11.glDepthMask(false); - GL11.glEnable(GL11.GL_BLEND); + beginDraw(); float w1 = (float) (this.width / 2) * width; float h1 = (float) height / 2; @@ -87,27 +111,10 @@ public class TexRender extends TextureRender { GL11.glPushMatrix(); GL11.glTranslatef(x + w1, y + h1, 0.0f); - float x0 = -w1; - float x1 = w1; - float y0 = -h1; - float y1 = h1; - float z = 0; - float u0 = 0; - float u1 = width; - float v0 = 0; - float v1 = 1; + // 这里只画材质的 width 比例(进度条) + drawQuad(-w1, -h1, w1, h1, 0, 0, width, 1, alpha); - Tessellator tessellator = Tessellator.instance; - tessellator.startDrawingQuads(); - tessellator.setColorRGBA_F(1.0f, 1.0f, 1.0f, alpha); - tessellator.addVertexWithUV(x0, y1, z, u0, v1); - tessellator.addVertexWithUV(x1, y1, z, u1, v1); - tessellator.addVertexWithUV(x1, y0, z, u1, v0); - tessellator.addVertexWithUV(x0, y0, z, u0, v0); - tessellator.draw(); - - GL11.glDisable(GL11.GL_BLEND); - GL11.glDepthMask(true); + endDraw(); GL11.glPopMatrix(); } @@ -116,9 +123,7 @@ public class TexRender extends TextureRender { public void drawPic(float x, float y, float width, float height, HudPosType dir, float alpha) { Point2f point = AllMusicHud.getPos(width, height, x, y, dir); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, sourceTexture.getGlTextureId()); - GL11.glDepthMask(false); - GL11.glEnable(GL11.GL_BLEND); + beginDraw(); float w1 = width / 2; float h1 = height / 2; @@ -126,27 +131,10 @@ public class TexRender extends TextureRender { GL11.glPushMatrix(); GL11.glTranslatef(point.x + w1, point.y + h1, 0.0f); - float x0 = -w1; - float x1 = w1; - float y0 = -h1; - float y1 = h1; - float z = 0; - float u0 = 0; - float u1 = width; - float v0 = 0; - float v1 = 1; + // 整张贴图铺满整个四边形,U/V 都必须是 0~1,不能写成 width + drawQuad(-w1, -h1, w1, h1, 0, 0, 1, 1, alpha); - Tessellator tessellator = Tessellator.instance; - tessellator.startDrawingQuads(); - tessellator.setColorRGBA_F(1.0f, 1.0f, 1.0f, alpha); - tessellator.addVertexWithUV(x0, y1, z, u0, v1); - tessellator.addVertexWithUV(x1, y1, z, u1, v1); - tessellator.addVertexWithUV(x1, y0, z, u1, v0); - tessellator.addVertexWithUV(x0, y0, z, u0, v0); - tessellator.draw(); - - GL11.glDisable(GL11.GL_BLEND); - GL11.glDepthMask(true); + endDraw(); GL11.glPopMatrix(); } @@ -184,6 +172,12 @@ public class TexRender extends TextureRender { } TextureUtil.uploadTextureImageAllocate(this.getGlTextureId(), bufferedimage, flag, flag1); + + // HUD 贴图基本都不是 2 的幂(如 bg1.png 238x238),GL_REPEAT 采样会被拉伸/平铺, + // 这里统一改成 CLAMP_TO_EDGE,避免贴图边缘被重复 + GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.getGlTextureId()); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); } finally { IOUtils.closeQuietly(inputstream); } diff --git a/codec/src/main/java/com/coloryr/allmusic/codec/ByteArrayPacketWriter.java b/codec/src/main/java/com/coloryr/allmusic/codec/ByteArrayPacketWriter.java new file mode 100644 index 00000000..0f77a5d4 --- /dev/null +++ b/codec/src/main/java/com/coloryr/allmusic/codec/ByteArrayPacketWriter.java @@ -0,0 +1,46 @@ +package com.coloryr.allmusic.codec; + +import java.io.ByteArrayOutputStream; + +/** + * 纯 Java 的写入器,不依赖 Netty + */ +public class ByteArrayPacketWriter implements PacketWriter { + private final ByteArrayOutputStream stream; + + public ByteArrayPacketWriter() { + this(256); + } + + public ByteArrayPacketWriter(int size) { + stream = new ByteArrayOutputStream(size); + } + + @Override + public void writeByte(int value) { + stream.write(value); + } + + @Override + public void writeInt(int value) { + stream.write(value >>> 24); + stream.write(value >>> 16); + stream.write(value >>> 8); + stream.write(value); + } + + @Override + public void writeLong(long value) { + writeInt((int) (value >>> 32)); + writeInt((int) value); + } + + @Override + public void writeBytes(byte[] value) { + stream.write(value, 0, value.length); + } + + public byte[] toByteArray() { + return stream.toByteArray(); + } +} diff --git a/codec/src/main/java/com/coloryr/allmusic/codec/MusicPacketCodec.java b/codec/src/main/java/com/coloryr/allmusic/codec/MusicPacketCodec.java index 924663bb..33968076 100644 --- a/codec/src/main/java/com/coloryr/allmusic/codec/MusicPacketCodec.java +++ b/codec/src/main/java/com/coloryr/allmusic/codec/MusicPacketCodec.java @@ -9,9 +9,14 @@ import java.util.ArrayList; public class MusicPacketCodec { public static final CommandType[] types = CommandType.values(); + /** + * 打包成 ByteBuf + *
+ * 只有自带 Netty 4 的环境(客户端、Forge/Fabric 服务端)会用到 + */ public static ByteBuf pack(MusicPack pack) { ByteBuf buf = Unpooled.buffer(0); - pack(buf, pack); + write(new NettyPacketWriter(buf), pack); return buf; } @@ -23,22 +28,32 @@ public class MusicPacketCodec { * 1.7.x 客户端的自定义数据包长度是一个 VarShort,代理会按整个数组长度来写, * 数据被撑大后可能超过 32767 的上限,导致客户端收不到数据包。 * 因此这里只复制真正写入的字节。 + *
+ * 另外这里用纯 Java 的 {@link ByteArrayPacketWriter} 写入,不经过 Netty: + * 1.7.x 的 Spigot 服务端把 Netty 4 重打包成了 {@code net.minecraft.util.io.netty}, + * 插件的类加载器里没有 {@code io.netty},之前调用 {@code Unpooled} 会抛 + * NoClassDefFoundError,插件消息就发不出去。 * * @param pack 数据 * @return 精确长度的数据 */ public static byte[] packBytes(MusicPack pack) { - ByteBuf buf = pack(pack); - try { - byte[] data = new byte[buf.readableBytes()]; - buf.readBytes(data); - return data; - } finally { - buf.release(); - } + ByteArrayPacketWriter writer = new ByteArrayPacketWriter(); + write(writer, pack); + return writer.toByteArray(); } + /** + * 把数据写进已有的 ByteBuf(客户端编码器用) + * + * @param buf ByteBuf + * @param pack 数据 + */ public static void pack(ByteBuf buf, MusicPack pack) { + write(new NettyPacketWriter(buf), pack); + } + + private static void write(PacketWriter buf, MusicPack pack) { buf.writeByte(pack.type.ordinal()); switch (pack.type) { case HUD_DATA: @@ -59,14 +74,14 @@ public class MusicPacketCodec { if (pack3.data == null) { buf.writeLong(-1); } else { - buf.writeLong(pack3.time) - .writeLong(pack3.data.start) - .writeLong(pack3.data.time) - .writeInt(pack3.data.charCount) - .writeInt(pack3.data.items.size()); + buf.writeLong(pack3.time); + buf.writeLong(pack3.data.start); + buf.writeLong(pack3.data.time); + buf.writeInt(pack3.data.charCount); + buf.writeInt(pack3.data.items.size()); for (KtvLyricObj.KtvItem item : pack3.data.items) { - buf.writeLong(item.start) - .writeLong(item.time); + buf.writeLong(item.start); + buf.writeLong(item.time); writeString(buf, item.key); } } @@ -77,12 +92,13 @@ public class MusicPacketCodec { break; case TIME: MusicPack.TimeMusicPack pack5 = (MusicPack.TimeMusicPack) pack; - buf.writeLong(pack5.time).writeLong(pack5.now); + buf.writeLong(pack5.time); + buf.writeLong(pack5.now); break; } } - private static void writeString(ByteBuf buf, String text) { + private static void writeString(PacketWriter buf, String text) { byte[] temp = text.getBytes(StandardCharsets.UTF_8); buf.writeInt(temp.length); buf.writeBytes(temp); diff --git a/codec/src/main/java/com/coloryr/allmusic/codec/NettyPacketWriter.java b/codec/src/main/java/com/coloryr/allmusic/codec/NettyPacketWriter.java new file mode 100644 index 00000000..6767456e --- /dev/null +++ b/codec/src/main/java/com/coloryr/allmusic/codec/NettyPacketWriter.java @@ -0,0 +1,36 @@ +package com.coloryr.allmusic.codec; + +import io.netty.buffer.ByteBuf; + +/** + * Netty 的写入器 + *
+ * 只有自带 Netty 4 的环境(客户端、Forge/Fabric 服务端)才会加载这个类 + */ +public class NettyPacketWriter implements PacketWriter { + private final ByteBuf buf; + + public NettyPacketWriter(ByteBuf buf) { + this.buf = buf; + } + + @Override + public void writeByte(int value) { + buf.writeByte(value); + } + + @Override + public void writeInt(int value) { + buf.writeInt(value); + } + + @Override + public void writeLong(long value) { + buf.writeLong(value); + } + + @Override + public void writeBytes(byte[] value) { + buf.writeBytes(value); + } +} diff --git a/codec/src/main/java/com/coloryr/allmusic/codec/PacketWriter.java b/codec/src/main/java/com/coloryr/allmusic/codec/PacketWriter.java new file mode 100644 index 00000000..6f0e17bf --- /dev/null +++ b/codec/src/main/java/com/coloryr/allmusic/codec/PacketWriter.java @@ -0,0 +1,19 @@ +package com.coloryr.allmusic.codec; + +/** + * 打包写入器 + *
+ * 打包逻辑不能只依赖 Netty 的 ByteBuf:1.7.x 的 Spigot 服务端把 Netty 4 重打包成了 + * {@code net.minecraft.util.io.netty},插件的类加载器里没有 {@code io.netty}, + * 直接用 {@code Unpooled} 会抛 NoClassDefFoundError。 + * 这里把写入抽象出来,纯 Java 和 Netty 各自实现一份。 + */ +public interface PacketWriter { + void writeByte(int value); + + void writeInt(int value); + + void writeLong(long value); + + void writeBytes(byte[] value); +} diff --git a/server/forge_1_7_10/src/main/java/com/coloryr/allmusic/server/AllMusicServer.java b/server/forge_1_7_10/src/main/java/com/coloryr/allmusic/server/AllMusicServer.java index 5e3e5a8b..f81ba038 100644 --- a/server/forge_1_7_10/src/main/java/com/coloryr/allmusic/server/AllMusicServer.java +++ b/server/forge_1_7_10/src/main/java/com/coloryr/allmusic/server/AllMusicServer.java @@ -48,8 +48,6 @@ public class AllMusicServer { AllMusic.log = new LogForge(); AllMusic.side = new SideForge(); - - new AllMusic().init(new File(AllMusic.SERVER_DIR)); } @Mod.EventHandler @@ -61,6 +59,8 @@ public class AllMusicServer { public void onServerStarting(FMLServerStartingEvent event) { server = event.getServer(); + new AllMusic().init(new File(AllMusic.SERVER_DIR)); + ServerCommandManager commandManager = (ServerCommandManager) server.getCommandManager(); commandManager.registerCommand(new CommandForge()); }