diff --git a/README.md b/README.md index 848e0fd4..f3acff06 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # ClientAPI -ClientAPI is a modding API just like Forge, Sponge and Liteloader, it is designed to provide a shared base for large client-rewrite style mods. +ClientAPI is a modding API/Framework just like Forge, Sponge and Liteloader, it is designed to provide a shared base for large client-rewrite style mods. -Like other modding APIs it is a tweaker and has the potential to be stacked with other tweakers, so long as they do not both overwrite the same methods. +Like other modding APIs it is a tweaker and has the potential to be stacked with other tweakers, so long as they do not both entirely overwrite the same methods. Unlike most other modding APIs it is designed to be used by a single "client" mod. It is this "client" that is installed, not the ClientAPI, so the "client" mod has full control over all modifications to the vanilla code, unless of course the installation is stacked on top of other modding APIs. @@ -12,21 +12,18 @@ Unlike most other modding APIs it is designed to be used by a single "client" mo ## Credits | Name | Contribution | |---------------------|----------------------| -| Halalaboos | CFont | -| MatthewH & MarcoMC | CapesAPI Integration | | Nerxit | Tab GUI System | ## Development Kit -To use the Client API, you must download [Development Kit](https://github.com/ZeroMemes/ClientAPI-CDK). Instructions on how to set it up will be posted in the README. +To use the Client API, you must download [Development Kit](https://github.com/ZeroMemes/ClientAPI-CDK). Instructions on how to set it up are posted in the README. ## Concept - -* Clients will install into `.minecraft/versions` +* Clients will install into `.minecraft/versions` and `.minecraft/libraries` if they are published to a maven repo * An installer could be used to configure stacking on top of other tweakers (e.g. Forge) * If an installer is used, it could also add a profile to the launcher * The client will inherit from a vanilla minecraft version * This means the client doesn't need to include actual minecraft code -* The client will list ClientAPI as a maven dependancy +* The client will list ClientAPI as a maven dependency * The minecraft launcher will automatically download the ClientAPI lib to the `.minecraft/libraries` folder ## Usage diff --git a/build.gradle b/build.gradle index 32d2cadb..aa5b8fc3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,19 @@ +/* + * Copyright 2017 ZeroMemes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + buildscript { repositories { mavenCentral() @@ -13,7 +29,7 @@ buildscript { dependencies { classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT' - classpath 'org.spongepowered:mixingradle:0.4-SNAPSHOT' + classpath 'org.spongepowered:mixingradle:0.5-SNAPSHOT' } } @@ -21,19 +37,16 @@ apply plugin: 'java' apply plugin: 'net.minecraftforge.gradle.tweaker-client' apply plugin: 'org.spongepowered.mixin' -version '2.0' -group 'com.github.ZeroMemes' - sourceCompatibility = targetCompatibility = '1.8' // Needed so Eclipse task generates correctly compileJava { sourceCompatibility = targetCompatibility = '1.8' } minecraft { - version = '1.12' - runDir = 'run' + version = project.minecraftVersion + mappings = project.mappings tweakClass = 'me.zero.client.load.ClientTweaker' - mappings = 'snapshot_20170628' + runDir = 'run' makeObfSourceJar = false } @@ -55,8 +68,11 @@ repositories { dependencies { compile 'com.github.ZeroMemes:Alpine:1.4' compile 'net.jodah:typetools:0.5.0' - compile('org.spongepowered:mixin:0.6.10-SNAPSHOT') { + compile('org.spongepowered:mixin:0.7.1-SNAPSHOT') { exclude module: 'launchwrapper' + exclude module: 'guava' + exclude module: 'gson' + exclude module: 'commons-io' } } diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000..88d7f082 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,22 @@ +# +# Copyright 2017 ZeroMemes +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name = ClientAPI +group = com.github.ZeroMemes +description = An API to provids a shared base for writing modded clients. +version = 2.1 +minecraftVersion = 1.12.1 +mappings = snapshot_20170805 \ No newline at end of file diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 6419802e..00000000 --- a/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ -rootProject.name = 'client-api' - diff --git a/src/main/java/me/zero/client/api/ClientAPI.java b/src/main/java/me/zero/client/api/ClientAPI.java index c2b59e9b..ac01d166 100644 --- a/src/main/java/me/zero/client/api/ClientAPI.java +++ b/src/main/java/me/zero/client/api/ClientAPI.java @@ -32,6 +32,11 @@ public final class ClientAPI { */ private ClientAPI() {} + /** + * Current version of the API + */ + public static final double VERSION = 2.1; + /** * Instance of the API event bus. All default game event are * passed through this event bus. diff --git a/src/main/java/me/zero/client/api/command/Command.java b/src/main/java/me/zero/client/api/command/Command.java index 7c96d564..5f50969e 100644 --- a/src/main/java/me/zero/client/api/command/Command.java +++ b/src/main/java/me/zero/client/api/command/Command.java @@ -17,7 +17,7 @@ package me.zero.client.api.command; import me.zero.client.api.command.exception.CommandInitException; -import me.zero.client.api.util.ClientUtils; +import me.zero.client.api.util.ClientAPIUtils; /** * @author Brady @@ -46,7 +46,7 @@ private void setup(String[] headers, String description, String[] syntax) { this.description = description; this.syntax = syntax; - if (ClientUtils.containsNull(headers, description, syntax)) + if (ClientAPIUtils.containsNull(headers, description, syntax)) throw new NullPointerException("One or more Command members were null!"); } diff --git a/src/main/java/me/zero/client/api/command/handler/listener/ChatCommandListener.java b/src/main/java/me/zero/client/api/command/handler/listener/ChatCommandListener.java index f4f5e84e..59b37ed2 100644 --- a/src/main/java/me/zero/client/api/command/handler/listener/ChatCommandListener.java +++ b/src/main/java/me/zero/client/api/command/handler/listener/ChatCommandListener.java @@ -22,7 +22,7 @@ import me.zero.client.api.command.Command; import me.zero.client.api.command.handler.CommandHandler; import me.zero.client.api.command.executor.sender.CommandSender; -import me.zero.client.api.event.defaults.ChatEvent; +import me.zero.client.api.event.defaults.game.misc.ChatEvent; import me.zero.client.api.event.defaults.internal.CommandExecutionEvent; import me.zero.client.api.util.interfaces.Helper; import net.minecraft.util.text.TextComponentString; diff --git a/src/main/java/me/zero/client/api/event/CAPIEventManager.java b/src/main/java/me/zero/client/api/event/CAPIEventManager.java index bd052567..dbf93d37 100644 --- a/src/main/java/me/zero/client/api/event/CAPIEventManager.java +++ b/src/main/java/me/zero/client/api/event/CAPIEventManager.java @@ -1,3 +1,19 @@ +/* + * Copyright 2017 ZeroMemes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package me.zero.client.api.event; import me.zero.alpine.EventManager; diff --git a/src/main/java/me/zero/client/api/event/defaults/filters/PacketFilter.java b/src/main/java/me/zero/client/api/event/defaults/filters/PacketFilter.java index f059f99b..8719ae19 100644 --- a/src/main/java/me/zero/client/api/event/defaults/filters/PacketFilter.java +++ b/src/main/java/me/zero/client/api/event/defaults/filters/PacketFilter.java @@ -16,7 +16,7 @@ package me.zero.client.api.event.defaults.filters; -import me.zero.client.api.event.defaults.PacketEvent; +import me.zero.client.api.event.defaults.game.network.PacketEvent; import net.minecraft.network.Packet; import java.util.function.Predicate; diff --git a/src/main/java/me/zero/client/api/event/defaults/ClickEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/core/ClickEvent.java similarity index 97% rename from src/main/java/me/zero/client/api/event/defaults/ClickEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/core/ClickEvent.java index a772034c..52a604f6 100644 --- a/src/main/java/me/zero/client/api/event/defaults/ClickEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/core/ClickEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.core; import net.minecraft.client.Minecraft; diff --git a/src/main/java/me/zero/client/api/event/defaults/GameShutdownEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/core/GameShutdownEvent.java similarity index 95% rename from src/main/java/me/zero/client/api/event/defaults/GameShutdownEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/core/GameShutdownEvent.java index 4250b6ec..9a424355 100644 --- a/src/main/java/me/zero/client/api/event/defaults/GameShutdownEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/core/GameShutdownEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.core; import me.zero.alpine.type.Cancellable; diff --git a/src/main/java/me/zero/client/api/event/defaults/KeyEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/core/KeyEvent.java similarity index 92% rename from src/main/java/me/zero/client/api/event/defaults/KeyEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/core/KeyEvent.java index 6690f3ff..6a2453e2 100644 --- a/src/main/java/me/zero/client/api/event/defaults/KeyEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/core/KeyEvent.java @@ -14,12 +14,12 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.core; /** * Event called when a Key is pressed outside of a GUI while in-game * - * @see me.zero.client.api.event.defaults.ClickEvent + * @see ClickEvent * * @author Brady * @since 1/20/2017 12:00 PM diff --git a/src/main/java/me/zero/client/api/event/defaults/game/core/KeyUpEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/core/KeyUpEvent.java new file mode 100644 index 00000000..a81fa55f --- /dev/null +++ b/src/main/java/me/zero/client/api/event/defaults/game/core/KeyUpEvent.java @@ -0,0 +1,46 @@ +/* + * Copyright 2017 ZeroMemes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zero.client.api.event.defaults.game.core; + +/** + * Event called when a Key is released outside of a GUI while in-game + * + * @see ClickEvent + * + * @author Leaf + * @since 2.1 + */ +public final class KeyUpEvent { + + private final int key; + + /** + * Creates a new instance of KeyUpEvent. + * + * @param key - The key code for the key that was released + */ + public KeyUpEvent(int key) { + this.key = key; + } + + /** + * @return The key code that corresponds to the released key + */ + public final int getKey() { + return this.key; + } +} diff --git a/src/main/java/me/zero/client/api/event/defaults/LoopEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/core/LoopEvent.java similarity index 93% rename from src/main/java/me/zero/client/api/event/defaults/LoopEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/core/LoopEvent.java index eac6097a..0b4ea8de 100644 --- a/src/main/java/me/zero/client/api/event/defaults/LoopEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/core/LoopEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.core; import net.minecraft.client.Minecraft; diff --git a/src/main/java/me/zero/client/api/event/defaults/ProfilerEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/core/ProfilerEvent.java similarity index 62% rename from src/main/java/me/zero/client/api/event/defaults/ProfilerEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/core/ProfilerEvent.java index 5bfa7cf1..d9dcbf13 100644 --- a/src/main/java/me/zero/client/api/event/defaults/ProfilerEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/core/ProfilerEvent.java @@ -14,10 +14,10 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.core; /** - * Called when a section is started in the profiler + * Called when a section is started in the profiler. * * @author Brady * @since 4/8/2017 12:00 PM @@ -25,14 +25,31 @@ public final class ProfilerEvent { /** - * Current profiler section + * Complete current profiler section. + * + * ex) 'root.tick.render' + */ + private final String sectionPath; + + /** + * Current profiler section. + * + * ex) 'render' */ private final String section; - public ProfilerEvent(String section) { + public ProfilerEvent(String sectionPath, String section) { + this.sectionPath = sectionPath; this.section = section; } + /** + * @return The full profiler section + */ + public final String getSectionPath() { + return this.sectionPath; + } + /** * @return The current profiler section */ diff --git a/src/main/java/me/zero/client/api/event/defaults/TickEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/core/TickEvent.java similarity index 93% rename from src/main/java/me/zero/client/api/event/defaults/TickEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/core/TickEvent.java index 1833349c..dc4298f0 100644 --- a/src/main/java/me/zero/client/api/event/defaults/TickEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/core/TickEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.core; import net.minecraft.client.Minecraft; diff --git a/src/main/java/me/zero/client/api/event/defaults/UpdateEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/core/UpdateEvent.java similarity index 93% rename from src/main/java/me/zero/client/api/event/defaults/UpdateEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/core/UpdateEvent.java index b7f560b5..b942a724 100644 --- a/src/main/java/me/zero/client/api/event/defaults/UpdateEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/core/UpdateEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.core; /** * Called from EntityPlayerSP#onUpdate diff --git a/src/main/java/me/zero/client/api/event/defaults/EntityCollisionEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/entity/EntityCollisionEvent.java similarity index 96% rename from src/main/java/me/zero/client/api/event/defaults/EntityCollisionEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/entity/EntityCollisionEvent.java index 8f5f34c5..cea862eb 100644 --- a/src/main/java/me/zero/client/api/event/defaults/EntityCollisionEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/entity/EntityCollisionEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.entity; import me.zero.alpine.type.Cancellable; import net.minecraft.entity.Entity; diff --git a/src/main/java/me/zero/client/api/event/defaults/EntityDeathEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/entity/EntityDeathEvent.java similarity index 96% rename from src/main/java/me/zero/client/api/event/defaults/EntityDeathEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/entity/EntityDeathEvent.java index 9a0d371a..c5f73fdf 100644 --- a/src/main/java/me/zero/client/api/event/defaults/EntityDeathEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/entity/EntityDeathEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.DamageSource; diff --git a/src/main/java/me/zero/client/api/event/defaults/LivingUpdateEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/entity/LivingUpdateEvent.java similarity index 95% rename from src/main/java/me/zero/client/api/event/defaults/LivingUpdateEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/entity/LivingUpdateEvent.java index d2f9122a..20a862b0 100644 --- a/src/main/java/me/zero/client/api/event/defaults/LivingUpdateEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/entity/LivingUpdateEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.entity; import me.zero.alpine.type.EventState; diff --git a/src/main/java/me/zero/client/api/event/defaults/MotionUpdateEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/entity/MotionUpdateEvent.java similarity index 98% rename from src/main/java/me/zero/client/api/event/defaults/MotionUpdateEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/entity/MotionUpdateEvent.java index 22687d46..6ec3cdbe 100644 --- a/src/main/java/me/zero/client/api/event/defaults/MotionUpdateEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/entity/MotionUpdateEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.entity; import me.zero.alpine.type.EventState; import me.zero.client.api.util.interfaces.Helper; diff --git a/src/main/java/me/zero/client/api/event/defaults/MoveEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/entity/MoveEvent.java similarity index 97% rename from src/main/java/me/zero/client/api/event/defaults/MoveEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/entity/MoveEvent.java index 9ea7a4e9..9690014d 100644 --- a/src/main/java/me/zero/client/api/event/defaults/MoveEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/entity/MoveEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.entity; import me.zero.alpine.type.Cancellable; import net.minecraft.entity.MoverType; diff --git a/src/main/java/me/zero/client/api/event/defaults/ChatEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/misc/ChatEvent.java similarity index 97% rename from src/main/java/me/zero/client/api/event/defaults/ChatEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/misc/ChatEvent.java index 5549b209..af82eeeb 100644 --- a/src/main/java/me/zero/client/api/event/defaults/ChatEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/misc/ChatEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.misc; import me.zero.alpine.type.Cancellable; import net.minecraft.util.text.ITextComponent; diff --git a/src/main/java/me/zero/client/api/event/defaults/PacketEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/network/PacketEvent.java similarity index 66% rename from src/main/java/me/zero/client/api/event/defaults/PacketEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/network/PacketEvent.java index eca1bd0d..17fb67b0 100644 --- a/src/main/java/me/zero/client/api/event/defaults/PacketEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/network/PacketEvent.java @@ -14,9 +14,10 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.network; import me.zero.alpine.type.Cancellable; +import net.minecraft.network.EnumConnectionState; import net.minecraft.network.Packet; /** @@ -24,6 +25,8 @@ * * @see Send * @see Receive + * @see Encode + * @see Decode * * @author Brady * @since 2/7/2017 12:00 PM @@ -76,4 +79,38 @@ public Receive(Packet packet) { super(packet); } } + + /** + * Called when outgoing packets are encoded + */ + public static final class Encode extends PacketEvent { + + private final EnumConnectionState state; + + public Encode(Packet packet, EnumConnectionState state) { + super(packet); + this.state = state; + } + + public final EnumConnectionState getDirection() { + return this.state; + } + } + + /** + * Called when incoming packets are decoded + */ + public static final class Decode extends PacketEvent { + + private final EnumConnectionState state; + + public Decode(Packet packet, EnumConnectionState state) { + super(packet); + this.state = state; + } + + public final EnumConnectionState getDirection() { + return this.state; + } + } } diff --git a/src/main/java/me/zero/client/api/event/defaults/EntityRenderEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/render/EntityRenderEvent.java similarity index 98% rename from src/main/java/me/zero/client/api/event/defaults/EntityRenderEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/render/EntityRenderEvent.java index 12e48b99..bc137765 100644 --- a/src/main/java/me/zero/client/api/event/defaults/EntityRenderEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/render/EntityRenderEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.render; import me.zero.alpine.type.Cancellable; import me.zero.alpine.type.EventState; diff --git a/src/main/java/me/zero/client/api/event/defaults/GlintEffectEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/render/GlintEffectEvent.java similarity index 95% rename from src/main/java/me/zero/client/api/event/defaults/GlintEffectEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/render/GlintEffectEvent.java index 2992b5d1..ef737c16 100644 --- a/src/main/java/me/zero/client/api/event/defaults/GlintEffectEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/render/GlintEffectEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.render; import me.zero.alpine.type.Cancellable; diff --git a/src/main/java/me/zero/client/api/event/defaults/GuiEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/render/GuiEvent.java similarity index 96% rename from src/main/java/me/zero/client/api/event/defaults/GuiEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/render/GuiEvent.java index 6e75d931..39b4e94c 100644 --- a/src/main/java/me/zero/client/api/event/defaults/GuiEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/render/GuiEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.render; import net.minecraft.client.gui.GuiScreen; diff --git a/src/main/java/me/zero/client/api/event/defaults/ItemRenderEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/render/ItemRenderEvent.java similarity index 97% rename from src/main/java/me/zero/client/api/event/defaults/ItemRenderEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/render/ItemRenderEvent.java index 4ea98bdd..40930b5e 100644 --- a/src/main/java/me/zero/client/api/event/defaults/ItemRenderEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/render/ItemRenderEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.render; import me.zero.alpine.type.Cancellable; import me.zero.client.api.util.interfaces.Helper; @@ -25,8 +25,7 @@ /** * Called when ItemRenderer#renderItemInFirstPerson is called. - * If cancelled, the item isn't - * + * If cancelled, the item isn't rendered. * * @author Brady * @since 4/8/2017 12:00 PM diff --git a/src/main/java/me/zero/client/api/event/defaults/LayerRenderEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/render/LayerRenderEvent.java similarity index 96% rename from src/main/java/me/zero/client/api/event/defaults/LayerRenderEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/render/LayerRenderEvent.java index 1b053225..84502e04 100644 --- a/src/main/java/me/zero/client/api/event/defaults/LayerRenderEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/render/LayerRenderEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.render; import me.zero.alpine.type.Cancellable; import net.minecraft.client.renderer.entity.layers.LayerRenderer; diff --git a/src/main/java/me/zero/client/api/event/defaults/Render3DEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/render/Render3DEvent.java similarity index 95% rename from src/main/java/me/zero/client/api/event/defaults/Render3DEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/render/Render3DEvent.java index 72547be8..ae914979 100644 --- a/src/main/java/me/zero/client/api/event/defaults/Render3DEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/render/Render3DEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.render; import me.zero.client.api.util.interfaces.Helper; diff --git a/src/main/java/me/zero/client/api/event/defaults/RenderEntityLabelEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/render/RenderEntityLabelEvent.java similarity index 96% rename from src/main/java/me/zero/client/api/event/defaults/RenderEntityLabelEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/render/RenderEntityLabelEvent.java index d81b03fe..b38c5106 100644 --- a/src/main/java/me/zero/client/api/event/defaults/RenderEntityLabelEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/render/RenderEntityLabelEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.render; import me.zero.alpine.type.Cancellable; import net.minecraft.entity.Entity; diff --git a/src/main/java/me/zero/client/api/event/defaults/RenderHudEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/render/RenderHudEvent.java similarity index 95% rename from src/main/java/me/zero/client/api/event/defaults/RenderHudEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/render/RenderHudEvent.java index d759906d..af5a8b8f 100644 --- a/src/main/java/me/zero/client/api/event/defaults/RenderHudEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/render/RenderHudEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.render; import net.minecraft.client.gui.GuiIngame; diff --git a/src/main/java/me/zero/client/api/event/defaults/RenderScreenEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/render/RenderScreenEvent.java similarity index 95% rename from src/main/java/me/zero/client/api/event/defaults/RenderScreenEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/render/RenderScreenEvent.java index 4798dc68..6c42e329 100644 --- a/src/main/java/me/zero/client/api/event/defaults/RenderScreenEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/render/RenderScreenEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.render; import net.minecraft.client.renderer.EntityRenderer; diff --git a/src/main/java/me/zero/client/api/event/defaults/TeamColorEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/render/TeamColorEvent.java similarity index 96% rename from src/main/java/me/zero/client/api/event/defaults/TeamColorEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/render/TeamColorEvent.java index 1cfea0ab..d7cad99a 100644 --- a/src/main/java/me/zero/client/api/event/defaults/TeamColorEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/render/TeamColorEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.render; import me.zero.alpine.type.Cancellable; import net.minecraft.entity.Entity; diff --git a/src/main/java/me/zero/client/api/event/defaults/TextEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/render/TextEvent.java similarity index 95% rename from src/main/java/me/zero/client/api/event/defaults/TextEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/render/TextEvent.java index cccf1a43..d83bcd79 100644 --- a/src/main/java/me/zero/client/api/event/defaults/TextEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/render/TextEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.render; /** * Called in FontRenderer when text is rendered diff --git a/src/main/java/me/zero/client/api/event/defaults/BlockCollisionEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/world/BlockCollisionEvent.java similarity index 95% rename from src/main/java/me/zero/client/api/event/defaults/BlockCollisionEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/world/BlockCollisionEvent.java index dd4322d0..78cfcff2 100644 --- a/src/main/java/me/zero/client/api/event/defaults/BlockCollisionEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/world/BlockCollisionEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.world; import me.zero.alpine.type.Cancellable; import net.minecraft.block.Block; diff --git a/src/main/java/me/zero/client/api/event/defaults/BoundingBoxEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/world/BoundingBoxEvent.java similarity index 97% rename from src/main/java/me/zero/client/api/event/defaults/BoundingBoxEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/world/BoundingBoxEvent.java index f91924df..3ee46824 100644 --- a/src/main/java/me/zero/client/api/event/defaults/BoundingBoxEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/world/BoundingBoxEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.world; import me.zero.alpine.type.Cancellable; import net.minecraft.block.Block; diff --git a/src/main/java/me/zero/client/api/event/defaults/WorldEvent.java b/src/main/java/me/zero/client/api/event/defaults/game/world/WorldEvent.java similarity index 96% rename from src/main/java/me/zero/client/api/event/defaults/WorldEvent.java rename to src/main/java/me/zero/client/api/event/defaults/game/world/WorldEvent.java index 81f98846..a1f9bac1 100644 --- a/src/main/java/me/zero/client/api/event/defaults/WorldEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/game/world/WorldEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.game.world; import net.minecraft.client.multiplayer.WorldClient; diff --git a/src/main/java/me/zero/client/api/event/defaults/ModuleStateEvent.java b/src/main/java/me/zero/client/api/event/defaults/internal/ModuleStateEvent.java similarity index 96% rename from src/main/java/me/zero/client/api/event/defaults/ModuleStateEvent.java rename to src/main/java/me/zero/client/api/event/defaults/internal/ModuleStateEvent.java index 6cfd3466..73bd992e 100644 --- a/src/main/java/me/zero/client/api/event/defaults/ModuleStateEvent.java +++ b/src/main/java/me/zero/client/api/event/defaults/internal/ModuleStateEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.event.defaults; +package me.zero.client.api.event.defaults.internal; import me.zero.alpine.type.Cancellable; import me.zero.client.api.module.Module; diff --git a/src/main/java/me/zero/client/api/event/handle/ClientHandler.java b/src/main/java/me/zero/client/api/event/handle/ClientHandler.java index 5b3bd516..0614f061 100644 --- a/src/main/java/me/zero/client/api/event/handle/ClientHandler.java +++ b/src/main/java/me/zero/client/api/event/handle/ClientHandler.java @@ -19,21 +19,22 @@ import me.zero.client.api.ClientAPI; import me.zero.alpine.listener.EventHandler; import me.zero.alpine.listener.Listener; -import me.zero.client.api.event.defaults.*; import me.zero.client.api.event.defaults.filters.PacketFilter; import me.zero.alpine.type.EventPriority; +import me.zero.client.api.event.defaults.game.core.*; +import me.zero.client.api.event.defaults.game.misc.ChatEvent; +import me.zero.client.api.event.defaults.game.network.PacketEvent; +import me.zero.client.api.event.defaults.game.render.Render3DEvent; +import me.zero.client.api.event.defaults.game.render.RenderHudEvent; import me.zero.client.api.util.interfaces.Helper; import me.zero.client.api.util.keybind.Keybind; import me.zero.client.api.util.render.camera.Camera; import me.zero.client.api.util.render.camera.CameraManager; import net.minecraft.network.play.client.CPacketChatMessage; import net.minecraft.network.play.server.SPacketChat; -import org.lwjgl.input.Keyboard; import java.util.stream.Stream; -import static org.lwjgl.input.Keyboard.KEYBOARD_SIZE; - /** * Some basic events that the client uses * @@ -42,11 +43,6 @@ */ public final class ClientHandler implements Helper { - /** - * A map of all key states - */ - private final boolean[] keyMap = new boolean[KEYBOARD_SIZE]; - /** * Handles camera updates */ @@ -58,8 +54,24 @@ public final class ClientHandler implements Helper { * Handles keybinds */ @EventHandler - private final Listener keyListener = new Listener<>(event -> - Keybind.getKeybinds().stream().filter(keybind -> keybind.getType() == Keybind.Type.TOGGLE && keybind.getKey() == event.getKey()).forEach(Keybind::onClick)); + private final Listener keyListener = new Listener<>(event -> { + // Get all matching keybinds + Stream keybinds = Keybind.getKeybinds().stream() + .filter(bind -> bind.getKey() == event.getKey()); + + // Run onClick for the toggle keybinds + keybinds.filter(bind -> bind.getType() == Keybind.Type.TOGGLE) + .forEach(Keybind::onClick); + + // Run onPres for all matching keybinds + keybinds.forEach(Keybind::onPress); + }); + + @EventHandler + private final Listener keyUpListener = new Listener<>(event -> + Keybind.getKeybinds().stream() + .filter(bind -> bind.getKey() == event.getKey()) + .forEach(Keybind::onRelease)); /** * Handles profiling events @@ -72,29 +84,6 @@ public final class ClientHandler implements Helper { ClientAPI.EVENT_BUS.post(new Render3DEvent()); }); - /** - * Handles key states - */ - @EventHandler - private final Listener tickListener = new Listener<>(event -> { - if (mc.currentScreen != null) return; - - for (int i = 1; i < KEYBOARD_SIZE; i++) { - final int key = i; - boolean currentState = Keyboard.isKeyDown(i); - if (currentState != keyMap[i]) { - if (keyMap[i] = !keyMap[i]) - ClientAPI.EVENT_BUS.post(new KeyEvent(i)); - - Stream keybinds = Keybind.getKeybinds().stream().filter(keybind -> keybind.getKey() == key); - if (currentState) - keybinds.forEach(Keybind::onPress); - else - keybinds.forEach(Keybind::onRelease); - } - } - }); - /** * Handles packet out-flow */ diff --git a/src/main/java/me/zero/client/api/gui/widget/WidgetHandler.java b/src/main/java/me/zero/client/api/gui/widget/WidgetHandler.java index a03e8e58..90058aa4 100644 --- a/src/main/java/me/zero/client/api/gui/widget/WidgetHandler.java +++ b/src/main/java/me/zero/client/api/gui/widget/WidgetHandler.java @@ -19,6 +19,7 @@ import me.zero.client.api.gui.widget.data.WidgetPos; import me.zero.client.api.util.math.Vec2; import me.zero.client.api.util.render.RenderUtils; +import me.zero.client.api.util.render.gl.DisplayList; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.ScaledResolution; @@ -47,7 +48,7 @@ public final class WidgetHandler { /** * The Open GL instruction list used when rendering */ - private final int list; + private final DisplayList list = new DisplayList(1); private float padding, spacing, position; @@ -58,7 +59,7 @@ public final class WidgetHandler { private boolean outlines; public WidgetHandler() { - list = glGenLists(1); + list.gen(); } /** @@ -98,7 +99,7 @@ public final void draw(FontRenderer font, ScaledResolution sr) { // We write to a list so that the height can // be updated and the required vertical adjustment // can be made before we actually render the widgets - glNewList(list, GL_COMPILE); + list.start(GL_COMPILE); widgets.forEach(widget -> { float mP = (widget.getAlignment().getValue() + 0.5F != 0.0F) ? 1.0F : 0.0F; float xP = pos.getPadding().getX() * padding * mP; @@ -115,13 +116,13 @@ public final void draw(FontRenderer font, ScaledResolution sr) { glTranslatef(0.0F, widget.getHeight() + spacing, 0.0F); position += widget.getHeight(); }); - glEndList(); + list.stop(); position += spacing * (widgets.size() - 1); glTranslatef(0.0F, position * pos.getOffset(), 0.0F); // Render all of the widgets - glCallList(list); + list.call(); glPopMatrix(); }); diff --git a/src/main/java/me/zero/client/api/module/Module.java b/src/main/java/me/zero/client/api/module/Module.java index 63713b5e..1d10d01c 100644 --- a/src/main/java/me/zero/client/api/module/Module.java +++ b/src/main/java/me/zero/client/api/module/Module.java @@ -17,11 +17,11 @@ package me.zero.client.api.module; import me.zero.client.api.ClientAPI; -import me.zero.client.api.event.defaults.ModuleStateEvent; +import me.zero.client.api.event.defaults.internal.ModuleStateEvent; import me.zero.client.api.exception.ActionNotSupportedException; import me.zero.client.api.manage.Node; import me.zero.client.api.module.exception.ModuleInitException; -import me.zero.client.api.util.ClientUtils; +import me.zero.client.api.util.ClientAPIUtils; import me.zero.client.api.util.keybind.Keybind; import org.lwjgl.input.Keyboard; @@ -102,7 +102,7 @@ private void setup(String name, String description, int bind) { .filter(clazz -> clazz.isAnnotationPresent(Category.class)) .findFirst().orElse(Category.Default.class); - if (ClientUtils.containsNull(name, description, type)) + if (ClientAPIUtils.containsNull(name, description, type)) throw new NullPointerException("One or more Mod members were null!"); } diff --git a/src/main/java/me/zero/client/api/util/ClientUtils.java b/src/main/java/me/zero/client/api/util/ClientAPIUtils.java similarity index 81% rename from src/main/java/me/zero/client/api/util/ClientUtils.java rename to src/main/java/me/zero/client/api/util/ClientAPIUtils.java index 89032bbf..19bde107 100644 --- a/src/main/java/me/zero/client/api/util/ClientUtils.java +++ b/src/main/java/me/zero/client/api/util/ClientAPIUtils.java @@ -22,14 +22,14 @@ import java.util.Arrays; /** - * Utils that the Client API uses + * Contains methods that ClientAPI uses throughout its code. * * @author Brady * @since 1/20/2017 12:00 PM */ -public final class ClientUtils { +public final class ClientAPIUtils { - private ClientUtils() {} + private ClientAPIUtils() {} /** * Concatenates an array of generic arrays @@ -102,4 +102,25 @@ public static T objectFrom(T object, T[] array) { } } } + + /** + * Determines if the specified array of generics contains + * matching members. + * + * @param objects Objects being checked + * @return Whether or not all members match + */ + @SafeVarargs + public static boolean matchingMembers(T... objects) { + T baseline = null; + boolean set = false; + for (T object : objects) { + if (!set) + baseline = object; + if (object != baseline) + return false; + set = true; + } + return true; + } } diff --git a/src/main/java/me/zero/client/api/util/Messages.java b/src/main/java/me/zero/client/api/util/Messages.java index ea098b58..a8bf94d6 100644 --- a/src/main/java/me/zero/client/api/util/Messages.java +++ b/src/main/java/me/zero/client/api/util/Messages.java @@ -17,13 +17,15 @@ package me.zero.client.api.util; import me.zero.client.api.util.logger.Level; +import me.zero.client.api.util.logger.ILogger; /** * Storage for all Messages used by the Logger's logf method * as well as some generic messages sent to the client from * the api. * - * @see me.zero.client.api.util.logger.ILogger#logf(Level, String, Object...) + * @see ILogger#log(Level, String) + * @see ILogger#logf(Level, String, Object...) * * @author Brady * @since 1/21/2017 12:00 PM @@ -36,9 +38,4 @@ public interface Messages { String PLUGIN_CANT_CREATE_MODULE = "Unable to create Module, %s"; String PLUGIN_CANT_LOAD_CLASS = "Unable to load Class, %s"; String PLUGIN_CANT_CREATE_INPUTSTREAM = "Unable to create jar InputStream, %s"; - - String MODULE_INSTANTIATION = "Unable to instantiate Module, %s"; - - String COMMAND_MISSING_ARGS = "Missing required argument: %s, with type %s"; - String COMMAND_INVALID = "Invalid Command"; } diff --git a/src/main/java/me/zero/client/api/util/PluginFinder.java b/src/main/java/me/zero/client/api/util/PluginFinder.java index 55f91ce6..0a5511e5 100644 --- a/src/main/java/me/zero/client/api/util/PluginFinder.java +++ b/src/main/java/me/zero/client/api/util/PluginFinder.java @@ -20,8 +20,8 @@ import me.zero.client.api.ClientAPI; import me.zero.alpine.listener.EventHandler; import me.zero.alpine.listener.Listener; -import me.zero.client.api.event.defaults.PacketEvent; -import me.zero.client.api.event.defaults.TickEvent; +import me.zero.client.api.event.defaults.game.network.PacketEvent; +import me.zero.client.api.event.defaults.game.core.TickEvent; import me.zero.client.api.event.defaults.filters.PacketFilter; import me.zero.client.api.exception.InvalidActionException; import me.zero.client.api.util.interfaces.Helper; diff --git a/src/main/java/me/zero/client/api/util/Protocol.java b/src/main/java/me/zero/client/api/util/Protocol.java index 78d4e3e5..99c6e685 100644 --- a/src/main/java/me/zero/client/api/util/Protocol.java +++ b/src/main/java/me/zero/client/api/util/Protocol.java @@ -16,89 +16,53 @@ package me.zero.client.api.util; -import com.google.common.collect.ImmutableList; - -import java.util.List; - /** - * List of protocols + * List of official release version protocols + * after the netty rewrite in 1.7 * * @author Brady * @since 3/6/2017 12:00 PM */ -public final class Protocol { - - private static ImmutableList protocols = new ImmutableList.Builder() - .add(build(316, "1.11.x", "1.11", "1.11.2")) - .add(build(315, "1.11")) - .add(build(210, "1.10.x", "1.10", "1.10.1", "1.10.2")) - .add(build(110, "1.9.3", "1.9.3", "1.9.4")) - .add(build(109, "1.9.2", "1.9.2")) - .add(build(108, "1.9.1")) - .add(build(107, "1.9")) - .add(build(47, "1.8.x", "1.8", "1.8.1", "1.8.2", "1.8.3", "1.8.4", "1.8.5", "1.8.6", "1.8.7", "1.8.8", "1.8.9")) - .add(build(5, "1.7.10", "1.7.6", "1.7.7", "1.7.8", "1.7.9", "1.7.10")) - .add(build(4, "1.7.2", "1.7.2", "1.7.4", "1.7.5")) - .build(); +public enum Protocol { - /** - * Protocol ID - */ - private final int protocol; + ProtocolVersion4(4, "1.7.2", "1.7.4", "1.7.5"), + ProtocolVersion5(5, "1.7.6", "1.7.7", "1.7.8", "1.7.9", "1.7.10"), + ProtocolVersion47(47, "1.8", "1.8.1", "1.8.2", "1.8.3", "1.8.4", "1.8.5", "1.8.6", "1.8.7", "1.8.8", "1.8.9"), + ProtocolVersion107(107, "1.9"), + ProtocolVersion108(108, "1.9.1"), + ProtocolVersion109(109, "1.9.2"), + ProtocolVersion110(110, "1.9.3", "1.9.4"), + ProtocolVersion210(210, "1.10", "1.10.1", "1.10.2"), + ProtocolVersion315(315, "1.11"), + ProtocolVersion316(316, "1.11.1", "1.11.2"), + ProtocolVersion335(335, "1.12"); /** - * Protocol display name + * The Protocol ID */ - private final String name; + private final int id; /** - * Supported versions + * Array of supported game versions for this protocol version */ private final String[] versions; - private Protocol(int protocol, String name, String... versions) { - this.protocol = protocol; - this.name = name; + Protocol(int id, String... versions) { + this.id = id; this.versions = versions; } /** - * @return The protocol ID - */ - public final int getProtocol() { - return this.protocol; - } - - /** - * @return The protocol display name + * @return The Protocol ID */ - public final String getName() { - return this.name; + public final int getId() { + return this.id; } /** - * @return The supported version IDs + * @return Array of supported game versions for this protocol version */ public final String[] getVersions() { return this.versions; } - - /** - * Creates a Protocol object from its required parameters - * - * @param protocol The protocol id - * @param name The name of the protocol - * @param versions An array of supported versions - * @return The built object - */ - private static Protocol build(int protocol, String name, String... versions) { - return new Protocol(protocol, name, versions); - } - - /** - * @return All of the registered protocols - */ - public static List getProtocols() { - return protocols; - } } diff --git a/src/main/java/me/zero/client/api/util/math/Vec2.java b/src/main/java/me/zero/client/api/util/math/Vec2.java index 5e44bebc..8c278f23 100644 --- a/src/main/java/me/zero/client/api/util/math/Vec2.java +++ b/src/main/java/me/zero/client/api/util/math/Vec2.java @@ -16,7 +16,7 @@ package me.zero.client.api.util.math; -import me.zero.client.api.util.render.GlUtils; +import me.zero.client.api.util.render.gl.GlUtils; /** * A Vec with an X and Y position diff --git a/src/main/java/me/zero/client/api/util/math/Vec3.java b/src/main/java/me/zero/client/api/util/math/Vec3.java index 550be9a9..d19362ae 100644 --- a/src/main/java/me/zero/client/api/util/math/Vec3.java +++ b/src/main/java/me/zero/client/api/util/math/Vec3.java @@ -16,7 +16,7 @@ package me.zero.client.api.util.math; -import me.zero.client.api.util.render.GlUtils; +import me.zero.client.api.util.render.gl.GlUtils; /** * A Vec with a X, Y, and Z position diff --git a/src/main/java/me/zero/client/api/util/render/RenderUtils.java b/src/main/java/me/zero/client/api/util/render/RenderUtils.java index 4eb49f4c..20850439 100644 --- a/src/main/java/me/zero/client/api/util/render/RenderUtils.java +++ b/src/main/java/me/zero/client/api/util/render/RenderUtils.java @@ -18,10 +18,11 @@ import me.zero.client.api.util.math.Vec2; import me.zero.client.api.util.math.Vec3; +import me.zero.client.api.util.render.gl.glenum.GLClientState; +import me.zero.client.api.util.render.gl.GlUtils; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.OpenGlHelper; -import pw.knx.feather.tessellate.GrowingTess; -import pw.knx.feather.tessellate.OffsetTess; +import pw.knx.feather.tessellate.Tessellator; import java.util.ArrayList; import java.util.List; @@ -41,7 +42,7 @@ private RenderUtils() {} /** * Instance of the Tessellator */ - public static final OffsetTess tessellator = new OffsetTess(new GrowingTess(4)); + public static final Tessellator tessellator = Tessellator.createExpanding(4, 1, 2); /** * Stores ClientState Gl Caps when setting up @@ -78,7 +79,7 @@ public static void setupRender(boolean start) { * * @param enabled The new enabled state of {@code GL_VERTEX_ARRAY} */ - public static void setupClientState(GlClientState state, boolean enabled) { + public static void setupClientState(GLClientState state, boolean enabled) { csBuffer.clear(); if (state.ordinal() > 0) csBuffer.add(state.cap); @@ -139,9 +140,9 @@ public static void drawLine(float x, float y, float z, float x1, float y1, float glLineWidth(width); setupRender(true); - setupClientState(GlClientState.VERTEX, true); - tessellator.vertex(x, y, z).vertex(x1, y1, z1).draw(GL_LINE_STRIP); - setupClientState(GlClientState.VERTEX, false); + setupClientState(GLClientState.VERTEX, true); + tessellator.addVertex(x, y, z).addVertex(x1, y1, z1).draw(GL_LINE_STRIP); + setupClientState(GLClientState.VERTEX, false); setupRender(false); } @@ -154,16 +155,16 @@ public static void drawLine(float x, float y, float z, float x1, float y1, float * @param y2 Bottom corner Y of the rectangle */ public static void drawFlippedTexturedRect(float x1, float y1, float x2, float y2) { - setupClientState(GlClientState.TEXTURE, true); + setupClientState(GLClientState.TEXTURE, true); tessellator - .vertex(x1, y2, 0).texture(0, 0) - .vertex(x2, y2, 0).texture(1, 0) - .vertex(x2, y1, 0).texture(1, 1) - .vertex(x1, y1, 0).texture(0, 1) + .addVertex(x1, y2, 0).setTexture(0, 0) + .addVertex(x2, y2, 0).setTexture(1, 0) + .addVertex(x2, y1, 0).setTexture(1, 1) + .addVertex(x1, y1, 0).setTexture(0, 1) .draw(GL_QUADS); - setupClientState(GlClientState.TEXTURE, false); + setupClientState(GLClientState.TEXTURE, false); } /** @@ -175,16 +176,16 @@ public static void drawFlippedTexturedRect(float x1, float y1, float x2, float y * @param y2 Bottom corner Y of the rectangle */ public static void drawReflectedTexturedRect(float x1, float y1, float x2, float y2) { - setupClientState(GlClientState.TEXTURE, true); + setupClientState(GLClientState.TEXTURE, true); tessellator - .vertex(x1, y2, 0).texture(1, 0) - .vertex(x2, y2, 0).texture(1, 0) - .vertex(x2, y1, 0).texture(0, 1) - .vertex(x1, y1, 0).texture(1, 1) + .addVertex(x1, y2, 0).setTexture(1, 0) + .addVertex(x2, y2, 0).setTexture(1, 0) + .addVertex(x2, y1, 0).setTexture(0, 1) + .addVertex(x1, y1, 0).setTexture(1, 1) .draw(GL_QUADS); - setupClientState(GlClientState.TEXTURE, false); + setupClientState(GLClientState.TEXTURE, false); } /** @@ -199,10 +200,22 @@ public static void drawReflectedTexturedRect(float x1, float y1, float x2, float public static void rectangle(float x1, float y1, float x2, float y2, int color) { GlUtils.glColor(color); + if (x1 > x2) { + float temp = x1; + x1 = x2; + x2 = temp; + } + + if (y1 > y2) { + float temp = y1; + y1 = y2; + y2 = temp; + } + setupRender(true); - setupClientState(GlClientState.VERTEX, true); - tessellator.vertex(x1, y2, 0).vertex(x2, y2, 0).vertex(x2, y1, 0).vertex(x1, y1, 0).draw(GL_QUADS); - setupClientState(GlClientState.VERTEX, false); + setupClientState(GLClientState.VERTEX, true); + tessellator.addVertex(x1, y2, 0).addVertex(x2, y2, 0).addVertex(x2, y1, 0).addVertex(x1, y1, 0).draw(GL_QUADS); + setupClientState(GLClientState.VERTEX, false); setupRender(false); } @@ -230,46 +243,50 @@ private static void rectangleGradient(float x1, float y1, float x2, float y2, in if (color.length == 0) throw new RuntimeException("At least one set of colors should be supplied"); - float[] r = new float[color.length]; - float[] g = new float[color.length]; - float[] b = new float[color.length]; - float[] a = new float[color.length]; - for (int i = 0; i < color.length; i++) { - float[] c = Colors.getColor(color[i]); - r[i] = c[0]; g[i] = c[1]; b[i] = c[2]; a[i] = c[3]; - } + int c1, c2, c3, c4; if (color.length == 1) { - r = new float[] { r[0], r[0], r[0], r[0] }; - g = new float[] { g[0], g[0], g[0], g[0] }; - b = new float[] { b[0], b[0], b[0], b[0] }; - a = new float[] { a[0], a[0], a[0], a[0] }; - } else if (color.length > 1 && color.length < 4) { - r = new float[] { r[0], r[0], r[1], r[1] }; - g = new float[] { g[0], g[0], g[1], g[1] }; - b = new float[] { b[0], b[0], b[1], b[1] }; - a = new float[] { a[0], a[0], a[1], a[1] }; + c1 = color[0]; + c2 = color[0]; + c3 = color[0]; + c4 = color[0]; + } else if (color.length < 4) { + c1 = color[0]; + c2 = color[0]; + c3 = color[1]; + c4 = color[1]; } else { - r = new float[] { r[0], r[1], r[2], r[3] }; - g = new float[] { g[0], g[1], g[2], g[3] }; - b = new float[] { b[0], b[1], b[2], b[3] }; - a = new float[] { a[0], a[1], a[2], a[3] }; + c1 = color[0]; + c2 = color[1]; + c3 = color[2]; + c4 = color[3]; + } + + if (x1 > x2) { + float temp = x1; + x1 = x2; + x2 = temp; + } + + if (y1 > y2) { + float temp = y1; + y1 = y2; + y2 = temp; } setupRender(true); OpenGlHelper.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 1, 0); GlStateManager.shadeModel(GL_FLAT); - setupClientState(GlClientState.COLOR, true); + setupClientState(GLClientState.COLOR, true); tessellator - .color(r[0], g[0], b[0], a[0]).vertex(x1, y2, 0) - .color(r[1], g[1], b[1], a[1]).vertex(x2, y2, 0) - .color(r[2], g[2], b[2], a[2]).vertex(x2, y1, 0) - .color(r[3], g[3], b[3], a[3]).vertex(x1, y1, 0) + .setColor(c1).addVertex(x1, y2, 0) + .setColor(c2).addVertex(x2, y2, 0) + .setColor(c3).addVertex(x2, y1, 0) + .setColor(c4).addVertex(x1, y1, 0) .draw(GL_QUADS); - setupClientState(GlClientState.COLOR, false); - GlStateManager.shadeModel(GL_FLAT); + setupClientState(GLClientState.COLOR, false); setupRender(false); } diff --git a/src/main/java/me/zero/client/api/util/render/gl/DisplayList.java b/src/main/java/me/zero/client/api/util/render/gl/DisplayList.java new file mode 100644 index 00000000..3ad2ee41 --- /dev/null +++ b/src/main/java/me/zero/client/api/util/render/gl/DisplayList.java @@ -0,0 +1,80 @@ +/* + * Copyright 2017 ZeroMemes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zero.client.api.util.render.gl; + +import me.zero.client.api.util.render.gl.GLObject; + +import static org.lwjgl.opengl.GL11.*; + +/** + * Display lists are used to capture OpenGL instructions. + * These instructions can then later be called upon. This + * is generally more efficient then repeating the + * instructions multiple times in the code directly. + * + * @author Brady + * @since 7/22/2017 4:27 PM + */ +public final class DisplayList extends GLObject { + + /** + * The number of contiguous empty display lists to be generated. + * In most cases, '1' will suffice. + */ + private final int range; + + public DisplayList(int range) { + this.range = range; + } + + @Override + protected final int nativeGen() { + return glGenLists(range); + } + + @Override + protected final void nativeDelete() { + glDeleteLists(id(), range); + } + + /** + * Begins capturing all subsequent instructions + * + * @see #stop() + * + * @param mode Instruction capture mode + */ + public final void start(int mode) { + glNewList(id(), mode); + } + + /** + * Stops capturing all instructions since start + * + * @see #start(int) + */ + public final void stop() { + glEndList(); + } + + /** + * Calls all instructions that have been captured by this list + */ + public final void call() { + glCallList(id()); + } +} diff --git a/src/main/java/me/zero/client/api/util/render/gl/GLObject.java b/src/main/java/me/zero/client/api/util/render/gl/GLObject.java new file mode 100644 index 00000000..4f45258a --- /dev/null +++ b/src/main/java/me/zero/client/api/util/render/gl/GLObject.java @@ -0,0 +1,84 @@ +/* + * Copyright 2017 ZeroMemes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zero.client.api.util.render.gl; + +/** + * Representation of an Object in OpenGL + * + * @author Brady + * @since 7/22/2017 4:18 PM + */ +public abstract class GLObject { + + public static final int UNABLE_TO_GENERATE = 0; + public static final int NOT_GENERATED = -1; + + private int id = NOT_GENERATED; + + /** + * Generates this OpenGL Object. Return value reflects + * whether or not the operation was a success or not. + * + * @return Whether or not the operation was a success. + * May return 'false' if + */ + public final boolean gen() { + return !isGen() && (id = nativeGen()) != UNABLE_TO_GENERATE; + } + + /** + * Called by GlObject#gen() to generate this object. + * + * @return The ID of the (possibly) created object + */ + protected abstract int nativeGen(); + + /** + * Deletes this object from memory. This should be called + * when the application is shutting down to efficiently + * garbage collect memory. + * + * @return Whether or not the operation was a success + */ + public boolean delete() { + if (!isGen()) + return false; + + id = NOT_GENERATED; + nativeDelete(); + return true; + } + + /** + * Called by GlObject#delete() to delete this object from memory. + */ + protected abstract void nativeDelete(); + + /** + * @return The ID of this object + */ + public final int id() { + return this.id; + } + + /** + * @return Whether or not the object has been successfully generated + */ + public final boolean isGen() { + return id > 0; + } +} diff --git a/src/main/java/me/zero/client/api/util/render/GlUtils.java b/src/main/java/me/zero/client/api/util/render/gl/GlUtils.java similarity index 97% rename from src/main/java/me/zero/client/api/util/render/GlUtils.java rename to src/main/java/me/zero/client/api/util/render/gl/GlUtils.java index 1460830c..28f6b573 100644 --- a/src/main/java/me/zero/client/api/util/render/GlUtils.java +++ b/src/main/java/me/zero/client/api/util/render/gl/GlUtils.java @@ -14,13 +14,14 @@ * limitations under the License. */ -package me.zero.client.api.util.render; +package me.zero.client.api.util.render.gl; import me.zero.client.api.ClientAPI; import me.zero.alpine.listener.EventHandler; import me.zero.alpine.listener.Listener; -import me.zero.client.api.event.defaults.Render3DEvent; +import me.zero.client.api.event.defaults.game.render.Render3DEvent; import me.zero.client.api.util.math.Vec3; +import me.zero.client.api.util.render.Colors; import net.minecraft.client.renderer.GlStateManager; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.Display; diff --git a/src/main/java/me/zero/client/api/util/render/gl/Query.java b/src/main/java/me/zero/client/api/util/render/gl/Query.java new file mode 100644 index 00000000..d509e2e7 --- /dev/null +++ b/src/main/java/me/zero/client/api/util/render/gl/Query.java @@ -0,0 +1,74 @@ +/* + * Copyright 2017 ZeroMemes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zero.client.api.util.render.gl; + +import static org.lwjgl.opengl.GL11.*; +import static org.lwjgl.opengl.GL15.*; + +/** + * @author Brady + * @since 7/22/2017 10:16 PM + */ +public final class Query extends GLObject { + + private final int target; + + public Query(int target) { + this.target = target; + } + + @Override + protected int nativeGen() { + return glGenQueries(); + } + + @Override + protected void nativeDelete() { + glDeleteQueries(id()); + } + + /** + * Marks the starting bounds of the query scope + */ + public final void start() { + glBeginQuery(target, id()); + } + + /** + * Marks the stopping bounds of the query scope + */ + public final void stop() { + glEndQuery(target); + } + + /** + * Returns the result of the query, the result + * will vary based on the query target. + * + * @return The result of the query. + */ + public final int getResult() { + return glGetQueryObjecti(target, GL_QUERY_RESULT); + } + + /** + * @return Whether or not the result of the query is available yet + */ + public final boolean isResultAvailable() { + return glGetQueryObjecti(target, GL_QUERY_RESULT_AVAILABLE) == GL_TRUE; + } +} diff --git a/src/main/java/me/zero/client/api/util/render/gl/Shader.java b/src/main/java/me/zero/client/api/util/render/gl/Shader.java new file mode 100644 index 00000000..2dc8aa8e --- /dev/null +++ b/src/main/java/me/zero/client/api/util/render/gl/Shader.java @@ -0,0 +1,79 @@ +/* + * Copyright 2017 ZeroMemes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zero.client.api.util.render.gl; + +import me.zero.client.api.exception.ShaderException; +import me.zero.client.api.util.render.gl.glenum.GLShaderStatus; +import me.zero.client.api.util.render.gl.glenum.GLShaderType; +import me.zero.client.api.util.render.gl.shader.adapter.ShaderAdapter; +import me.zero.client.api.util.render.gl.shader.adapter.ShaderAdapters; + +/** + * @author Brady + * @since 7/23/2017 3:24 PM + */ +public final class Shader extends GLObject { + + /** + * Instance of the system supported shader adapter + */ + private static final ShaderAdapter adapter = ShaderAdapters.getSystemAdapter(); + + /** + * Source code of the shader + */ + private final String src; + + /** + * Type of shader + */ + private final GLShaderType type; + + public Shader(GLShaderType type, String src) { + this.type = type; + this.src = src; + } + + @Override + protected int nativeGen() { + int shaderID = adapter.createShader(type); + if (shaderID == 0) + return 0; + + try { + adapter.shaderSource(shaderID, src); + adapter.compileShader(shaderID); + adapter.checkStatus(shaderID, GLShaderStatus.COMPILE); + } catch (ShaderException e) { + return 0; + } + + return shaderID; + } + + @Override + protected void nativeDelete() { + adapter.deleteShader(id()); + } + + /** + * @return The type of shader this object represents + */ + public final GLShaderType getType() { + return this.type; + } +} diff --git a/src/main/java/me/zero/client/api/util/render/gl/ShaderProgram.java b/src/main/java/me/zero/client/api/util/render/gl/ShaderProgram.java new file mode 100644 index 00000000..8dca3f47 --- /dev/null +++ b/src/main/java/me/zero/client/api/util/render/gl/ShaderProgram.java @@ -0,0 +1,143 @@ +/* + * Copyright 2017 ZeroMemes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package me.zero.client.api.util.render.gl; + +import me.zero.client.api.exception.ShaderException; +import me.zero.client.api.util.render.gl.glenum.GLShaderStatus; +import me.zero.client.api.util.render.gl.glenum.GLShaderType; +import me.zero.client.api.util.render.gl.shader.Uniform; +import me.zero.client.api.util.render.gl.shader.adapter.ShaderAdapter; +import me.zero.client.api.util.render.gl.shader.adapter.ShaderAdapters; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Brady + * @since 7/23/2017 3:31 PM + */ +public class ShaderProgram extends GLObject { + + /** + * Instance of the system supported shader adapter + */ + private static final ShaderAdapter adapter = ShaderAdapters.getSystemAdapter(); + + /** + * The uniform variables for this shader program + */ + private final Map uniforms = new HashMap<>(); + + /** + * The shaders attached to this program + */ + private final List shaders = new ArrayList<>(); + + @Override + protected final int nativeGen() { + int id = adapter.createProgram(); + shaders.forEach(shader -> adapter.attachShader(id, shader.id())); + + try { + adapter.linkProgram(id); + adapter.checkStatus(id, GLShaderStatus.LINK); + adapter.validateProgram(id); + adapter.checkStatus(id, GLShaderStatus.VALIDATE); + } catch (ShaderException e) { + e.printStackTrace(); + return 0; + } + + return id; + } + + @Override + public boolean delete() { + shaders.forEach(shader -> { + adapter.detachShader(this.id(), shader.id()); + shader.delete(); + }); + return super.delete(); + } + + @Override + protected final void nativeDelete() { + adapter.deleteProgram(id()); + } + + /** + * Attaches the shader program. Multiple shader + * programs may not be attached simultaneously. + */ + public final void attach() { + adapter.useProgram(id()); + update(); + } + + /** + * Detaches the shader program + */ + public final void detach() { + adapter.useProgram(0); + } + + /** + * May be overriden by implementations of this class. Used to + * update uniform variable values when the shader is attached. + */ + protected void update() {} + + /** + * Attaches a shader to this shader program. This may only be + * done before the shader has been compiled via the gen() method + * and there isn't already a shader with the same type. + * + * @param shader The shader + * @return Whether or not the operation was a success + */ + public final boolean attachShader(Shader shader) { + if (isGen() || getShader(shader.getType()) != null) + return false; + + shaders.add(shader); + return true; + } + + /** + * Finds and returns a shader attached to this program + * with the specified type, if there is one. Returns 'null' + * if a shader isn't found. + * + * @param type The type of shader + * @return The shader with the specified type + */ + public final Shader getShader(GLShaderType type) { + return shaders.stream().filter(shader -> shader.getType() == type).findFirst().orElse(null); + } + + /** + * Gets a uniform variable from the specified name + * + * @param name The Uniform Name + * @return The Uniform Variable + */ + protected final Uniform getUniform(String name) { + return uniforms.computeIfAbsent(name, n -> Uniform.get(id(), n)); + } +} diff --git a/src/main/java/me/zero/client/api/util/render/GlClientState.java b/src/main/java/me/zero/client/api/util/render/gl/glenum/GLClientState.java similarity index 88% rename from src/main/java/me/zero/client/api/util/render/GlClientState.java rename to src/main/java/me/zero/client/api/util/render/gl/glenum/GLClientState.java index b00f6340..494ed7fb 100644 --- a/src/main/java/me/zero/client/api/util/render/GlClientState.java +++ b/src/main/java/me/zero/client/api/util/render/gl/glenum/GLClientState.java @@ -14,11 +14,11 @@ * limitations under the License. */ -package me.zero.client.api.util.render; +package me.zero.client.api.util.render.gl.glenum; import static org.lwjgl.opengl.GL11.*; -public enum GlClientState { +public enum GLClientState { VERTEX(GL_VERTEX_ARRAY), COLOR(GL_COLOR_ARRAY), @@ -26,7 +26,7 @@ public enum GlClientState { public final int cap; - GlClientState(int cap) { + GLClientState(int cap) { this.cap = cap; } } diff --git a/src/main/java/me/zero/client/api/util/render/shader/glenum/GlShaderStatus.java b/src/main/java/me/zero/client/api/util/render/gl/glenum/GLShaderStatus.java similarity index 89% rename from src/main/java/me/zero/client/api/util/render/shader/glenum/GlShaderStatus.java rename to src/main/java/me/zero/client/api/util/render/gl/glenum/GLShaderStatus.java index 925ebe67..a121d13d 100644 --- a/src/main/java/me/zero/client/api/util/render/shader/glenum/GlShaderStatus.java +++ b/src/main/java/me/zero/client/api/util/render/gl/glenum/GLShaderStatus.java @@ -14,13 +14,13 @@ * limitations under the License. */ -package me.zero.client.api.util.render.shader.glenum; +package me.zero.client.api.util.render.gl.glenum; /** * @author Brady * @since 5/21/2017 1:05 PM */ -public enum GlShaderStatus { +public enum GLShaderStatus { COMPILE, LINK, VALIDATE } diff --git a/src/main/java/me/zero/client/api/util/render/shader/glenum/GlShaderType.java b/src/main/java/me/zero/client/api/util/render/gl/glenum/GLShaderType.java similarity index 79% rename from src/main/java/me/zero/client/api/util/render/shader/glenum/GlShaderType.java rename to src/main/java/me/zero/client/api/util/render/gl/glenum/GLShaderType.java index ea020777..a751af69 100644 --- a/src/main/java/me/zero/client/api/util/render/shader/glenum/GlShaderType.java +++ b/src/main/java/me/zero/client/api/util/render/gl/glenum/GLShaderType.java @@ -14,17 +14,15 @@ * limitations under the License. */ -package me.zero.client.api.util.render.shader.glenum; +package me.zero.client.api.util.render.gl.glenum; /** * Enum to represent different shader types. - * Geometry shaders are excluded, because the - * usage of them is not needed. * * @author Brady * @since 5/21/2017 12:02 PM */ -public enum GlShaderType { +public enum GLShaderType { - VERTEX, FRAGMENT + VERTEX, FRAGMENT, GEOMETRY } diff --git a/src/main/java/me/zero/client/api/util/render/shader/Uniform.java b/src/main/java/me/zero/client/api/util/render/gl/shader/Uniform.java similarity index 93% rename from src/main/java/me/zero/client/api/util/render/shader/Uniform.java rename to src/main/java/me/zero/client/api/util/render/gl/shader/Uniform.java index c56cb5bc..3b385909 100644 --- a/src/main/java/me/zero/client/api/util/render/shader/Uniform.java +++ b/src/main/java/me/zero/client/api/util/render/gl/shader/Uniform.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.util.render.shader; +package me.zero.client.api.util.render.gl.shader; import me.zero.client.api.util.math.Vec2; import me.zero.client.api.util.math.Vec3; @@ -106,11 +106,11 @@ public final int getLocation() { /** * Creates a uniform variable from the shader object id and the uniform's name * - * @param shaderID Shader object ID + * @param programID Shader program ID * @param uniformName Uniform Name * @return The UniformVariable representation */ - public static Uniform get(int shaderID, String uniformName) { - return new Uniform(uniformName, glGetUniformLocationARB(shaderID, uniformName)); + public static Uniform get(int programID, String uniformName) { + return new Uniform(uniformName, glGetUniformLocationARB(programID, uniformName)); } } diff --git a/src/main/java/me/zero/client/api/util/render/shader/adapter/ARBShaderAdapter.java b/src/main/java/me/zero/client/api/util/render/gl/shader/adapter/ARBShaderAdapter.java similarity index 83% rename from src/main/java/me/zero/client/api/util/render/shader/adapter/ARBShaderAdapter.java rename to src/main/java/me/zero/client/api/util/render/gl/shader/adapter/ARBShaderAdapter.java index 73853885..17e566f7 100644 --- a/src/main/java/me/zero/client/api/util/render/shader/adapter/ARBShaderAdapter.java +++ b/src/main/java/me/zero/client/api/util/render/gl/shader/adapter/ARBShaderAdapter.java @@ -14,18 +14,19 @@ * limitations under the License. */ -package me.zero.client.api.util.render.shader.adapter; +package me.zero.client.api.util.render.gl.shader.adapter; import me.zero.client.api.exception.ShaderException; -import me.zero.client.api.util.render.shader.glenum.GlShaderStatus; -import me.zero.client.api.util.render.shader.glenum.GlShaderType; +import me.zero.client.api.util.render.gl.glenum.GLShaderStatus; +import me.zero.client.api.util.render.gl.glenum.GLShaderType; import java.util.Objects; import static org.lwjgl.opengl.ARBFragmentShader.*; +import static org.lwjgl.opengl.ARBGeometryShader4.*; import static org.lwjgl.opengl.ARBShaderObjects.*; import static org.lwjgl.opengl.ARBVertexShader.*; -import static org.lwjgl.opengl.GL11.GL_FALSE; +import static org.lwjgl.opengl.GL11.*; /** * @author Brady @@ -51,7 +52,7 @@ public void validateProgram(int programObj) { } @Override - public int createShader(GlShaderType type) { + public int createShader(GLShaderType type) { Objects.requireNonNull(type); switch (type) { @@ -59,6 +60,8 @@ public int createShader(GlShaderType type) { return glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); case FRAGMENT: return glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); + case GEOMETRY: + return glCreateShaderObjectARB(GL_GEOMETRY_SHADER_ARB); } return 0; @@ -75,12 +78,12 @@ public void compileShader(int shader) { } @Override - public void attachObject(int program, int shader) { + public void attachShader(int program, int shader) { glAttachObjectARB(program, shader); } @Override - public void detachObject(int program, int shader) { + public void detachShader(int program, int shader) { glDetachObjectARB(program, shader); } @@ -100,7 +103,7 @@ public void deleteShader(int shader) { } @Override - public void checkStatus(int program, GlShaderStatus status) { + public void checkStatus(int program, GLShaderStatus status) { Objects.requireNonNull(status); int pname = 0; diff --git a/src/main/java/me/zero/client/api/util/render/shader/adapter/GL20ShaderAdapter.java b/src/main/java/me/zero/client/api/util/render/gl/shader/adapter/GL20ShaderAdapter.java similarity index 82% rename from src/main/java/me/zero/client/api/util/render/shader/adapter/GL20ShaderAdapter.java rename to src/main/java/me/zero/client/api/util/render/gl/shader/adapter/GL20ShaderAdapter.java index d99db359..207dfd4d 100644 --- a/src/main/java/me/zero/client/api/util/render/shader/adapter/GL20ShaderAdapter.java +++ b/src/main/java/me/zero/client/api/util/render/gl/shader/adapter/GL20ShaderAdapter.java @@ -14,16 +14,17 @@ * limitations under the License. */ -package me.zero.client.api.util.render.shader.adapter; +package me.zero.client.api.util.render.gl.shader.adapter; import me.zero.client.api.exception.ShaderException; -import me.zero.client.api.util.render.shader.glenum.GlShaderStatus; -import me.zero.client.api.util.render.shader.glenum.GlShaderType; +import me.zero.client.api.util.render.gl.glenum.GLShaderStatus; +import me.zero.client.api.util.render.gl.glenum.GLShaderType; import java.util.Objects; -import static org.lwjgl.opengl.GL11.GL_FALSE; +import static org.lwjgl.opengl.GL11.*; import static org.lwjgl.opengl.GL20.*; +import static org.lwjgl.opengl.GL32.*; /** * @author Brady @@ -49,7 +50,7 @@ public void validateProgram(int programObj) { } @Override - public int createShader(GlShaderType type) { + public int createShader(GLShaderType type) { Objects.requireNonNull(type); switch (type) { @@ -57,6 +58,8 @@ public int createShader(GlShaderType type) { return glCreateShader(GL_VERTEX_SHADER); case FRAGMENT: return glCreateShader(GL_FRAGMENT_SHADER); + case GEOMETRY: + return glCreateShader(GL_GEOMETRY_SHADER); } return 0; @@ -73,12 +76,12 @@ public void compileShader(int shader) { } @Override - public void attachObject(int program, int shader) { + public void attachShader(int program, int shader) { glAttachShader(program, shader); } @Override - public void detachObject(int program, int shader) { + public void detachShader(int program, int shader) { glDetachShader(program, shader); } @@ -98,7 +101,7 @@ public void useProgram(int program) { } @Override - public void checkStatus(int program, GlShaderStatus status) { + public void checkStatus(int program, GLShaderStatus status) { Objects.requireNonNull(status); int pname = 0; diff --git a/src/main/java/me/zero/client/api/util/render/shader/adapter/ShaderAdapter.java b/src/main/java/me/zero/client/api/util/render/gl/shader/adapter/ShaderAdapter.java similarity index 89% rename from src/main/java/me/zero/client/api/util/render/shader/adapter/ShaderAdapter.java rename to src/main/java/me/zero/client/api/util/render/gl/shader/adapter/ShaderAdapter.java index 22d78a7e..0d9d6498 100644 --- a/src/main/java/me/zero/client/api/util/render/shader/adapter/ShaderAdapter.java +++ b/src/main/java/me/zero/client/api/util/render/gl/shader/adapter/ShaderAdapter.java @@ -14,10 +14,10 @@ * limitations under the License. */ -package me.zero.client.api.util.render.shader.adapter; +package me.zero.client.api.util.render.gl.shader.adapter; -import me.zero.client.api.util.render.shader.glenum.GlShaderStatus; -import me.zero.client.api.util.render.shader.glenum.GlShaderType; +import me.zero.client.api.util.render.gl.glenum.GLShaderStatus; +import me.zero.client.api.util.render.gl.glenum.GLShaderType; /** * The shell for a Shader Adapter. Used as @@ -58,7 +58,7 @@ public interface ShaderAdapter { * @param type The type of shader * @return The shader's object id */ - int createShader(GlShaderType type); + int createShader(GLShaderType type); /** * Attaches the shader's source with the shader object. @@ -82,7 +82,7 @@ public interface ShaderAdapter { * @param program The shader program id * @param shader The shader object id */ - void attachObject(int program, int shader); + void attachShader(int program, int shader); /** * Detaches a shader object from a shader program @@ -90,7 +90,7 @@ public interface ShaderAdapter { * @param program The shader program id * @param shader The shader object id */ - void detachObject(int program, int shader); + void detachShader(int program, int shader); /** * Prepares the specified shader program for usage @@ -121,7 +121,7 @@ public interface ShaderAdapter { * @param program The shader program id * @param status The status flag being checked */ - void checkStatus(int program, GlShaderStatus status); + void checkStatus(int program, GLShaderStatus status); /** * Gets a shader program's log info diff --git a/src/main/java/me/zero/client/api/util/render/shader/adapter/ShaderAdapters.java b/src/main/java/me/zero/client/api/util/render/gl/shader/adapter/ShaderAdapters.java similarity index 80% rename from src/main/java/me/zero/client/api/util/render/shader/adapter/ShaderAdapters.java rename to src/main/java/me/zero/client/api/util/render/gl/shader/adapter/ShaderAdapters.java index 70b87596..727f866a 100644 --- a/src/main/java/me/zero/client/api/util/render/shader/adapter/ShaderAdapters.java +++ b/src/main/java/me/zero/client/api/util/render/gl/shader/adapter/ShaderAdapters.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package me.zero.client.api.util.render.shader.adapter; +package me.zero.client.api.util.render.gl.shader.adapter; import org.lwjgl.opengl.GLContext; @@ -34,8 +34,10 @@ public final class ShaderAdapters { private ShaderAdapters() {} static { - // Check if OpenGL 2.0 is supported by the machine - if (GLContext.getCapabilities().OpenGL20) + // Check if OpenGL 2.0 and OpenGL 3.2 are supported by the machine + // If 3.2 is supported, 2.0 should be too, but we have 2 checks here + // just to be safe. + if (GLContext.getCapabilities().OpenGL20 && GLContext.getCapabilities().OpenGL32) systemDefault = new GL20ShaderAdapter(); else systemDefault = new ARBShaderAdapter(); diff --git a/src/main/java/me/zero/client/api/util/render/shader/Shader.java b/src/main/java/me/zero/client/api/util/render/shader/Shader.java deleted file mode 100644 index a981f6e8..00000000 --- a/src/main/java/me/zero/client/api/util/render/shader/Shader.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2017 ZeroMemes - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package me.zero.client.api.util.render.shader; - -import me.zero.client.api.util.interfaces.Helper; -import me.zero.client.api.util.render.shader.adapter.ShaderAdapter; -import me.zero.client.api.util.render.shader.adapter.ShaderAdapters; -import me.zero.client.api.util.render.shader.glenum.GlShaderStatus; -import me.zero.client.api.util.render.shader.glenum.GlShaderType; - -import java.util.HashMap; -import java.util.Map; - -import static me.zero.client.api.util.render.shader.ShaderHelper.*; - -/** - * Used to create ARB Shader Programs with OpenGL - * - * @author Brady - * @since 2/16/2017 12:00 PM - */ -public abstract class Shader implements Helper { - - /** - * Instance of the system supported shader adapter - */ - private final ShaderAdapter adapter = ShaderAdapters.getSystemAdapter(); - - /** - * The uniform variables for this shader - */ - private final Map uniforms = new HashMap<>(); - - /** - * Various Object IDs - */ - private final int programID, fragmentID, vertexID; - - public Shader(String vertex, String fragment) { - programID = adapter.createProgram(); - vertexID = loadShader(adapter, vertex, GlShaderType.VERTEX); - fragmentID = loadShader(adapter, fragment, GlShaderType.FRAGMENT); - - adapter.attachObject(programID, vertexID); - adapter.attachObject(programID, fragmentID); - - adapter.linkProgram(programID); - adapter.checkStatus(programID, GlShaderStatus.LINK); - - adapter.validateProgram(programID); - adapter.checkStatus(programID, GlShaderStatus.VALIDATE); - } - - /** - * Attaches the shader program - */ - public final void attach() { - adapter.useProgram(programID); - update(); - } - - /** - * Detaches the shader program - */ - public final void detach() { - adapter.useProgram(0); - } - - /** - * Called after the shader program is - * attached to update the uniform vars - */ - public abstract void update(); - - /** - * Deletes this ShaderProgram - */ - public final void delete() { - detach(); - adapter.detachObject(programID, vertexID); - adapter.detachObject(programID, fragmentID); - adapter.deleteShader(vertexID); - adapter.deleteShader(fragmentID); - adapter.deleteProgram(programID); - } - - /** - * Gets a uniform variable from the specified name - * - * @param name The Uniform Name - * @return The Uniform Variable - */ - protected final Uniform getUniform(String name) { - return uniforms.computeIfAbsent(name, n -> Uniform.get(programID, n)); - } -} diff --git a/src/main/java/me/zero/client/api/util/render/shader/ShaderHelper.java b/src/main/java/me/zero/client/api/util/render/shader/ShaderHelper.java deleted file mode 100644 index 8a0e6225..00000000 --- a/src/main/java/me/zero/client/api/util/render/shader/ShaderHelper.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2017 ZeroMemes - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package me.zero.client.api.util.render.shader; - -import me.zero.client.api.util.io.StreamReader; -import me.zero.client.api.util.render.shader.adapter.ShaderAdapter; -import me.zero.client.api.util.render.shader.glenum.GlShaderStatus; -import me.zero.client.api.util.render.shader.glenum.GlShaderType; - -/** - * Utils for Shader Programs - * - * @author Brady - * @since 2/16/2017 12:00 PM - */ -final class ShaderHelper { - - private ShaderHelper() {} - - /** - * Loads a shader of the specified type from the specified path - * - * @param path Shader path - * @param type Shader type - * @return The Shader's Object ID - */ - static int loadShader(ShaderAdapter adapter, String path, GlShaderType type) { - int shaderID = adapter.createShader(type); - if (shaderID == 0) - return 0; - - String src = new StreamReader(Shader.class.getResourceAsStream(path)).read(); - adapter.shaderSource(shaderID, src); - adapter.compileShader(shaderID); - adapter.checkStatus(shaderID, GlShaderStatus.COMPILE); - return shaderID; - } -} diff --git a/src/main/java/me/zero/client/api/value/Values.java b/src/main/java/me/zero/client/api/value/Values.java index 1e397858..c158e3b8 100644 --- a/src/main/java/me/zero/client/api/value/Values.java +++ b/src/main/java/me/zero/client/api/value/Values.java @@ -17,7 +17,7 @@ package me.zero.client.api.value; import me.zero.client.api.exception.ValueException; -import me.zero.client.api.util.ClientUtils; +import me.zero.client.api.util.ClientAPIUtils; import me.zero.client.api.util.annotation.Label; import me.zero.client.api.value.annotation.*; import me.zero.client.api.value.holder.IValueHolder; @@ -131,7 +131,7 @@ private static Value getValue(Object parent, Field field) { * @param data The resolver data for the annotation */ public static void define(Class type, ResolverData data) { - if (ClientUtils.containsNull(type, data)) + if (ClientAPIUtils.containsNull(type, data)) throw new NullPointerException("One or more parameters were null"); if (RESOLVERS.get(type) != null) diff --git a/src/main/java/me/zero/client/api/value/type/MultiType.java b/src/main/java/me/zero/client/api/value/type/MultiType.java index 28ec9195..dfc72cdf 100644 --- a/src/main/java/me/zero/client/api/value/type/MultiType.java +++ b/src/main/java/me/zero/client/api/value/type/MultiType.java @@ -16,7 +16,7 @@ package me.zero.client.api.value.type; -import me.zero.client.api.util.ClientUtils; +import me.zero.client.api.util.ClientAPIUtils; import me.zero.client.api.value.Value; import org.apache.commons.lang3.ArrayUtils; @@ -43,7 +43,7 @@ public MultiType(String name, String id, String description, Object object, Fiel @Override public final void setValue(String value) { - super.setValue(ClientUtils.objectFrom(value, values)); + super.setValue(ClientAPIUtils.objectFrom(value, values)); } /** diff --git a/src/main/java/me/zero/client/load/ClientTweaker.java b/src/main/java/me/zero/client/load/ClientTweaker.java index 7aae41c9..733254be 100644 --- a/src/main/java/me/zero/client/load/ClientTweaker.java +++ b/src/main/java/me/zero/client/load/ClientTweaker.java @@ -85,7 +85,7 @@ private void addArg(String label, File file) { } private void addArg(String label, String value) { - if (value != null) { + if (!args.contains("--" + label) && value != null) { this.args.add("--" + label); this.args.add(value); } diff --git a/src/main/java/me/zero/client/load/mixin/MixinBlock.java b/src/main/java/me/zero/client/load/mixin/MixinBlock.java index a4a52685..d0e07fde 100644 --- a/src/main/java/me/zero/client/load/mixin/MixinBlock.java +++ b/src/main/java/me/zero/client/load/mixin/MixinBlock.java @@ -17,8 +17,8 @@ package me.zero.client.load.mixin; import me.zero.client.api.ClientAPI; -import me.zero.client.api.event.defaults.BlockCollisionEvent; -import me.zero.client.api.event.defaults.BoundingBoxEvent; +import me.zero.client.api.event.defaults.game.world.BlockCollisionEvent; +import me.zero.client.api.event.defaults.game.world.BoundingBoxEvent; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; @@ -45,7 +45,7 @@ public abstract class MixinBlock { @Shadow protected static void addCollisionBoxToList(BlockPos pos, AxisAlignedBB entityBox, List collidingBoxes, @Nullable AxisAlignedBB blockBox) {} @Inject(method = "canCollideCheck", at = @At("HEAD"), cancellable = true) - public void canCollideCheck(IBlockState state, boolean hitIfLiquid, CallbackInfoReturnable ci) { + private void canCollideCheck(IBlockState state, boolean hitIfLiquid, CallbackInfoReturnable ci) { BlockCollisionEvent event = new BlockCollisionEvent((Block) (Object) this); ClientAPI.EVENT_BUS.post(event); if (event.isCancelled()) @@ -53,6 +53,7 @@ public void canCollideCheck(IBlockState state, boolean hitIfLiquid, CallbackInfo } /** + * @reason the overwritten method is only one line, we need to overwrite to mutate the AABB and pass params into the event constructor * @author Brady */ @Overwrite diff --git a/src/main/java/me/zero/client/load/mixin/MixinEntity.java b/src/main/java/me/zero/client/load/mixin/MixinEntity.java index 801ffeab..356a90ee 100644 --- a/src/main/java/me/zero/client/load/mixin/MixinEntity.java +++ b/src/main/java/me/zero/client/load/mixin/MixinEntity.java @@ -17,7 +17,7 @@ package me.zero.client.load.mixin; import me.zero.client.api.ClientAPI; -import me.zero.client.api.event.defaults.EntityCollisionEvent; +import me.zero.client.api.event.defaults.game.entity.EntityCollisionEvent; import me.zero.client.api.util.math.Vec2; import me.zero.client.api.util.math.Vec3; import me.zero.client.load.mixin.wrapper.IEntity; @@ -64,7 +64,7 @@ public abstract class MixinEntity implements IEntity { private Vec2 rotation, prevRotation; @Inject(method = "applyEntityCollision", at = @At("HEAD"), cancellable = true) - public void applyEntityCollision(Entity entityIn, CallbackInfo ci) { + private void applyEntityCollision(Entity entityIn, CallbackInfo ci) { EntityCollisionEvent event = new EntityCollisionEvent((Entity) (Object) this, entityIn); ClientAPI.EVENT_BUS.post(event); if (event.isCancelled()) diff --git a/src/main/java/me/zero/client/load/mixin/MixinEntityLivingBase.java b/src/main/java/me/zero/client/load/mixin/MixinEntityLivingBase.java index 978eec89..c7467439 100644 --- a/src/main/java/me/zero/client/load/mixin/MixinEntityLivingBase.java +++ b/src/main/java/me/zero/client/load/mixin/MixinEntityLivingBase.java @@ -17,7 +17,7 @@ package me.zero.client.load.mixin; import me.zero.client.api.ClientAPI; -import me.zero.client.api.event.defaults.EntityDeathEvent; +import me.zero.client.api.event.defaults.game.entity.EntityDeathEvent; import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.DamageSource; import org.spongepowered.asm.mixin.Mixin; @@ -33,7 +33,7 @@ public class MixinEntityLivingBase { @Inject(method = "onDeath", at = @At("HEAD")) - public void onDeath(DamageSource cause, CallbackInfo ci) { + private void onDeath(DamageSource cause, CallbackInfo ci) { ClientAPI.EVENT_BUS.post(new EntityDeathEvent((EntityLivingBase) (Object) this, cause)); } } diff --git a/src/main/java/me/zero/client/load/mixin/MixinEntityPlayerSP.java b/src/main/java/me/zero/client/load/mixin/MixinEntityPlayerSP.java index 28fde154..0552ce70 100644 --- a/src/main/java/me/zero/client/load/mixin/MixinEntityPlayerSP.java +++ b/src/main/java/me/zero/client/load/mixin/MixinEntityPlayerSP.java @@ -17,10 +17,10 @@ package me.zero.client.load.mixin; import me.zero.client.api.ClientAPI; -import me.zero.client.api.event.defaults.LivingUpdateEvent; -import me.zero.client.api.event.defaults.MotionUpdateEvent; -import me.zero.client.api.event.defaults.MoveEvent; -import me.zero.client.api.event.defaults.UpdateEvent; +import me.zero.client.api.event.defaults.game.entity.LivingUpdateEvent; +import me.zero.client.api.event.defaults.game.entity.MotionUpdateEvent; +import me.zero.client.api.event.defaults.game.entity.MoveEvent; +import me.zero.client.api.event.defaults.game.core.UpdateEvent; import me.zero.alpine.type.EventState; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.AbstractClientPlayer; @@ -62,22 +62,22 @@ public abstract class MixinEntityPlayerSP extends MixinEntity { @Shadow protected abstract boolean isCurrentViewEntity(); @Inject(method = "onUpdate", at = @At("HEAD")) - public void onUpdate(CallbackInfo ci) { + private void onUpdate(CallbackInfo ci) { ClientAPI.EVENT_BUS.post(new UpdateEvent()); } @Inject(method = "onLivingUpdate", at = @At("HEAD")) - public void onLivingUpdatePre(CallbackInfo ci) { + private void onLivingUpdatePre(CallbackInfo ci) { ClientAPI.EVENT_BUS.post(new LivingUpdateEvent(EventState.PRE)); } @Inject(method = "onLivingUpdate", at = @At("RETURN")) - public void onLivingUpdatePost(CallbackInfo ci) { + private void onLivingUpdatePost(CallbackInfo ci) { ClientAPI.EVENT_BUS.post(new LivingUpdateEvent(EventState.POST)); } @Redirect(method = "move", at = @At(value = "INVOKE", target = "net/minecraft/client/entity/AbstractClientPlayer.move(Lnet/minecraft/entity/MoverType;DDD)V")) - public void move(AbstractClientPlayer player, MoverType type, double x, double y, double z) { + private void move(AbstractClientPlayer player, MoverType type, double x, double y, double z) { MoveEvent event = new MoveEvent(type, x, y, z); ClientAPI.EVENT_BUS.post(event); if (event.isCancelled()) @@ -87,10 +87,11 @@ public void move(AbstractClientPlayer player, MoverType type, double x, double y } /** + * @reason In addition to firing pre and post events, we also want to override some position values (prefixed with p). * @author Brady */ @Overwrite - public void onUpdateWalkingPlayer() { + private void onUpdateWalkingPlayer() { EntityPlayerSP _this = (EntityPlayerSP) (Object) this; MotionUpdateEvent pre = new MotionUpdateEvent(EventState.PRE); @@ -110,6 +111,8 @@ public void onUpdateWalkingPlayer() { if (this.isCurrentViewEntity()) { + // Override vanilla defaults of _tis.posX, etc + // This is why we need to overwrite the method body. double pX = pre.getX(); double pY = pre.getY(); double pZ = pre.getZ(); diff --git a/src/main/java/me/zero/client/load/mixin/MixinEntityRenderer.java b/src/main/java/me/zero/client/load/mixin/MixinEntityRenderer.java index b1a11692..376af28e 100644 --- a/src/main/java/me/zero/client/load/mixin/MixinEntityRenderer.java +++ b/src/main/java/me/zero/client/load/mixin/MixinEntityRenderer.java @@ -17,7 +17,7 @@ package me.zero.client.load.mixin; import me.zero.client.api.ClientAPI; -import me.zero.client.api.event.defaults.RenderScreenEvent; +import me.zero.client.api.event.defaults.game.render.RenderScreenEvent; import me.zero.client.api.util.render.camera.Camera; import net.minecraft.client.renderer.EntityRenderer; import org.spongepowered.asm.mixin.Mixin; @@ -34,13 +34,13 @@ public class MixinEntityRenderer { @Inject(method = "getFOVModifier", at = @At("HEAD"), cancellable = true) - public void getFOVModifier(float partialTicks, boolean useFOVSetting, CallbackInfoReturnable ci) { + private void getFOVModifier(float partialTicks, boolean useFOVSetting, CallbackInfoReturnable ci) { if (Camera.isCapturing()) ci.setReturnValue(90.0F); } @Inject(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "net/minecraft/profiler/Profiler.endStartSection(Ljava/lang/String;)V")) - public void updateCameraAndRender(float partialTicks, long nanoTime, CallbackInfo ci) { + private void updateCameraAndRender(float partialTicks, long nanoTime, CallbackInfo ci) { ClientAPI.EVENT_BUS.post(new RenderScreenEvent(partialTicks)); } } diff --git a/src/main/java/me/zero/client/load/mixin/MixinFontRenderer.java b/src/main/java/me/zero/client/load/mixin/MixinFontRenderer.java index 0647550a..1f5edd33 100644 --- a/src/main/java/me/zero/client/load/mixin/MixinFontRenderer.java +++ b/src/main/java/me/zero/client/load/mixin/MixinFontRenderer.java @@ -17,7 +17,7 @@ package me.zero.client.load.mixin; import me.zero.client.api.ClientAPI; -import me.zero.client.api.event.defaults.TextEvent; +import me.zero.client.api.event.defaults.game.render.TextEvent; import net.minecraft.client.gui.FontRenderer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -31,14 +31,14 @@ public abstract class MixinFontRenderer { @ModifyVariable(method = "renderStringAtPos", at = @At("HEAD")) - public String renderStringAtPos(String text) { + private String renderStringAtPos(String text) { TextEvent event = new TextEvent(text); ClientAPI.EVENT_BUS.post(event); return event.getText(); } @ModifyVariable(method = "getStringWidth", at = @At("HEAD")) - public String getStringWidth(String text) { + private String getStringWidth(String text) { TextEvent event = new TextEvent(text); ClientAPI.EVENT_BUS.post(event); return event.getText(); diff --git a/src/main/java/me/zero/client/load/mixin/MixinGuiIngame.java b/src/main/java/me/zero/client/load/mixin/MixinGuiIngame.java index b7fdc648..954caaca 100644 --- a/src/main/java/me/zero/client/load/mixin/MixinGuiIngame.java +++ b/src/main/java/me/zero/client/load/mixin/MixinGuiIngame.java @@ -17,7 +17,7 @@ package me.zero.client.load.mixin; import me.zero.client.api.ClientAPI; -import me.zero.client.api.event.defaults.RenderHudEvent; +import me.zero.client.api.event.defaults.game.render.RenderHudEvent; import net.minecraft.client.gui.GuiIngame; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -32,7 +32,7 @@ public class MixinGuiIngame { @Inject(method = "renderGameOverlay", at = @At("RETURN")) - public void renderGameOverlay(float partialTicks, CallbackInfo ci) { + private void renderGameOverlay(float partialTicks, CallbackInfo ci) { ClientAPI.EVENT_BUS.post(new RenderHudEvent(partialTicks)); } } diff --git a/src/main/java/me/zero/client/load/mixin/MixinItemRenderer.java b/src/main/java/me/zero/client/load/mixin/MixinItemRenderer.java index a64b1bd8..402bfecf 100644 --- a/src/main/java/me/zero/client/load/mixin/MixinItemRenderer.java +++ b/src/main/java/me/zero/client/load/mixin/MixinItemRenderer.java @@ -17,7 +17,7 @@ package me.zero.client.load.mixin; import me.zero.client.api.ClientAPI; -import me.zero.client.api.event.defaults.ItemRenderEvent; +import me.zero.client.api.event.defaults.game.render.ItemRenderEvent; import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.client.renderer.ItemRenderer; import net.minecraft.item.ItemStack; @@ -35,7 +35,7 @@ public abstract class MixinItemRenderer { @Inject(method = "renderItemInFirstPerson(Lnet/minecraft/client/entity/AbstractClientPlayer;FFLnet/minecraft/util/EnumHand;FLnet/minecraft/item/ItemStack;F)V", at = @At("HEAD"), cancellable = true) - public void renderItemInFirstPerson(AbstractClientPlayer p_187457_1_, float p_187457_2_, float p_187457_3_, EnumHand p_187457_4_, float p_187457_5_, ItemStack p_187457_6_, float p_187457_7_, CallbackInfo ci) { + private void renderItemInFirstPerson(AbstractClientPlayer p_187457_1_, float p_187457_2_, float p_187457_3_, EnumHand p_187457_4_, float p_187457_5_, ItemStack p_187457_6_, float p_187457_7_, CallbackInfo ci) { ItemRenderEvent event = new ItemRenderEvent((ItemRenderer) (Object) this, p_187457_2_, p_187457_4_, p_187457_5_, p_187457_6_, p_187457_7_); ClientAPI.EVENT_BUS.post(event); if (event.isCancelled()) diff --git a/src/main/java/me/zero/client/load/mixin/MixinLayerArmorBase.java b/src/main/java/me/zero/client/load/mixin/MixinLayerArmorBase.java index 40350998..03fde9c1 100644 --- a/src/main/java/me/zero/client/load/mixin/MixinLayerArmorBase.java +++ b/src/main/java/me/zero/client/load/mixin/MixinLayerArmorBase.java @@ -17,7 +17,7 @@ package me.zero.client.load.mixin; import me.zero.client.api.ClientAPI; -import me.zero.client.api.event.defaults.GlintEffectEvent; +import me.zero.client.api.event.defaults.game.render.GlintEffectEvent; import net.minecraft.client.model.ModelBase; import net.minecraft.client.renderer.entity.RenderLivingBase; import net.minecraft.client.renderer.entity.layers.LayerArmorBase; diff --git a/src/main/java/me/zero/client/load/mixin/MixinMinecraft.java b/src/main/java/me/zero/client/load/mixin/MixinMinecraft.java index 1b187a76..52d4d799 100644 --- a/src/main/java/me/zero/client/load/mixin/MixinMinecraft.java +++ b/src/main/java/me/zero/client/load/mixin/MixinMinecraft.java @@ -20,9 +20,11 @@ import me.zero.client.api.Client; import me.zero.client.api.ClientInfo; import me.zero.client.api.ClientAPI; -import me.zero.client.api.event.defaults.*; +import me.zero.client.api.event.defaults.game.core.*; +import me.zero.client.api.event.defaults.game.render.GuiEvent; +import me.zero.client.api.event.defaults.game.world.WorldEvent; import me.zero.client.api.event.handle.ClientHandler; -import me.zero.client.api.util.render.GlUtils; +import me.zero.client.api.util.render.gl.GlUtils; import me.zero.client.load.ClientInitException; import me.zero.client.load.mixin.wrapper.IMinecraft; import net.minecraft.client.Minecraft; @@ -30,6 +32,7 @@ import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.util.Session; import net.minecraft.util.Timer; +import org.lwjgl.input.Keyboard; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.gen.Accessor; @@ -43,7 +46,7 @@ import java.io.InputStream; import java.io.InputStreamReader; -import static me.zero.client.api.event.defaults.ClickEvent.MouseButton.*; +import static me.zero.client.api.event.defaults.game.core.ClickEvent.MouseButton.*; /** * @author Brady @@ -52,6 +55,8 @@ @Mixin(Minecraft.class) public abstract class MixinMinecraft implements IMinecraft { + @Shadow public GuiScreen currentScreen; + @Accessor @Override public abstract Timer getTimer(); @Accessor @Override public abstract void setSession(Session session); @Accessor @Override public abstract void setRightClickDelayTimer(int delay); @@ -72,17 +77,28 @@ public void clickMouse(ClickEvent.MouseButton button) { } @Inject(method = "runTick", at = @At("HEAD")) - public void onTick(CallbackInfo ci) { + private void onTick(CallbackInfo ci) { ClientAPI.EVENT_BUS.post(new TickEvent()); } @Inject(method = "runGameLoop", at = @At("HEAD")) - public void onLoop(CallbackInfo ci) { + private void onLoop(CallbackInfo ci) { ClientAPI.EVENT_BUS.post(new LoopEvent()); } + @Inject(method = "runTickKeyboard", at = @At(value = "INVOKE_ASSIGN", target = "org/lwjgl/input/Keyboard.getEventKeyState()Z", remap = false)) + private void onKeyEvent(CallbackInfo ci) { + if (currentScreen != null) + return; + + boolean down = Keyboard.getEventKeyState(); + int key = Keyboard.getEventKey(); + + ClientAPI.EVENT_BUS.post(down ? new KeyEvent(key) : new KeyUpEvent(key)); + } + @Inject(method = "init", at = @At("RETURN")) - public void init(CallbackInfo ci) { + private void init(CallbackInfo ci) { // Try and find the "client.json" config InputStream stream = this.getClass().getResourceAsStream("/client.json"); @@ -125,29 +141,29 @@ public void init(CallbackInfo ci) { } @Inject(method = "clickMouse", at = @At("HEAD")) - public void clickMouse(CallbackInfo ci) { + private void clickMouse(CallbackInfo ci) { ClientAPI.EVENT_BUS.post(new ClickEvent(LEFT)); } @Inject(method = "rightClickMouse", at = @At("HEAD")) - public void rightClickMouse(CallbackInfo ci) { + private void rightClickMouse(CallbackInfo ci) { ClientAPI.EVENT_BUS.post(new ClickEvent(RIGHT)); } @Inject(method = "middleClickMouse", at = @At("HEAD")) - public void middleClickMouse(CallbackInfo ci) { + private void middleClickMouse(CallbackInfo ci) { ClientAPI.EVENT_BUS.post(new ClickEvent(MIDDLE)); } @ModifyVariable(method = "displayGuiScreen", at = @At("HEAD")) - public GuiScreen displayGuiScreen(GuiScreen screen) { + private GuiScreen displayGuiScreen(GuiScreen screen) { GuiEvent event = new GuiEvent(screen); ClientAPI.EVENT_BUS.post(event); return event.getScreen(); } @Inject(method = "loadWorld(Lnet/minecraft/client/multiplayer/WorldClient;Ljava/lang/String;)V", at = @At("HEAD")) - public void loadWorld(@Nullable WorldClient worldClientIn, String loadingMessage, CallbackInfo ci) { + private void loadWorld(@Nullable WorldClient worldClientIn, String loadingMessage, CallbackInfo ci) { // If the world is null, then it must be unloading if (worldClientIn != null) ClientAPI.EVENT_BUS.post(new WorldEvent.Load(worldClientIn)); @@ -156,7 +172,7 @@ public void loadWorld(@Nullable WorldClient worldClientIn, String loadingMessage } @Inject(method = "shutdown", at = @At("HEAD"), cancellable = true) - public void shutdown(CallbackInfo ci) { + private void shutdown(CallbackInfo ci) { GameShutdownEvent event = new GameShutdownEvent(); ClientAPI.EVENT_BUS.post(event); if (event.isCancelled()) diff --git a/src/main/java/me/zero/client/load/mixin/MixinNettyPacketDecoder.java b/src/main/java/me/zero/client/load/mixin/MixinNettyPacketDecoder.java new file mode 100644 index 00000000..d4e4622a --- /dev/null +++ b/src/main/java/me/zero/client/load/mixin/MixinNettyPacketDecoder.java @@ -0,0 +1,66 @@ +package me.zero.client.load.mixin; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import me.zero.client.api.ClientAPI; +import me.zero.client.api.event.defaults.game.network.PacketEvent; +import net.minecraft.network.*; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.Marker; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import java.io.IOException; +import java.util.List; + +/** + * @author Brady + * @since 7/17/2017 2:22 PM + */ +@Mixin(NettyPacketDecoder.class) +public class MixinNettyPacketDecoder { + + @Shadow @Final private static Logger LOGGER; + @Shadow @Final private static Marker RECEIVED_PACKET_MARKER; + @Shadow @Final private EnumPacketDirection direction; + + /** + * @reason we need to wait until the packet is built and then pass it (and the connection state) to the event constructor + * @author Brady + */ + @Overwrite + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws IOException, InstantiationException, IllegalAccessException { + if (in.readableBytes() == 0) + return; + + PacketBuffer packetbuffer = new PacketBuffer(in); + int packetId = packetbuffer.readVarInt(); + EnumConnectionState state = ctx.channel().attr(NetworkManager.PROTOCOL_ATTRIBUTE_KEY).get(); + Packet packet = state.getPacket(this.direction, packetId); + + // We need the packet to create our Event, so we have to overwrite the method body + PacketEvent event = new PacketEvent.Decode(packet, state); + ClientAPI.EVENT_BUS.post(event); + packet = event.getPacket(); + if (event.isCancelled()) + return; + + if (packet == null) { + throw new IOException(String.format("Bad packet id %s", packetId)); + } else { + packet.readPacketData(packetbuffer); + + if (packetbuffer.readableBytes() > 0) { + throw new IOException(String.format("Packet %s/%s (%s) was larger than I expected, found %s bytes extra whilst reading packet %s", state.getId(), packetId, packet.getClass().getSimpleName(), packetbuffer.readableBytes(), packetId)); + } else { + out.add(packet); + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug(RECEIVED_PACKET_MARKER, " IN: [{}:{}] {}", state, packetId, packet.getClass().getName()); + } + } + } + } +} diff --git a/src/main/java/me/zero/client/load/mixin/MixinNettyPacketEncoder.java b/src/main/java/me/zero/client/load/mixin/MixinNettyPacketEncoder.java new file mode 100644 index 00000000..06444213 --- /dev/null +++ b/src/main/java/me/zero/client/load/mixin/MixinNettyPacketEncoder.java @@ -0,0 +1,61 @@ +package me.zero.client.load.mixin; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import me.zero.client.api.ClientAPI; +import me.zero.client.api.event.defaults.game.network.PacketEvent; +import net.minecraft.network.*; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.Marker; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import java.io.IOException; + +/** + * @author Brady + * @since 7/16/2017 5:22 PM + */ +@Mixin(NettyPacketEncoder.class) +public class MixinNettyPacketEncoder { + + @Shadow @Final private static Logger LOGGER; + @Shadow @Final private static Marker RECEIVED_PACKET_MARKER; + @Shadow @Final private EnumPacketDirection direction; + + /** + * @reason mostly because we need to mutate msg, but also so that we can pass the connection state to the event constructor + * @author Brady + */ + @Overwrite + protected void encode(ChannelHandlerContext ctx, Packet msg, ByteBuf out) throws Exception { + EnumConnectionState state = ctx.channel().attr(NetworkManager.PROTOCOL_ATTRIBUTE_KEY).get(); + Integer packetId = state.getPacketId(this.direction, msg); + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug(RECEIVED_PACKET_MARKER, "OUT: [{}:{}] {}", state, packetId, msg.getClass().getName()); + } + + // We need the state and we plan to mutate the msg, hence the overwrite + PacketEvent event = new PacketEvent.Encode(msg, state); + ClientAPI.EVENT_BUS.post(event); + msg = event.getPacket(); + if (event.isCancelled() || msg == null) + return; + + if (packetId == null) { + throw new IOException("Can\'t serialize unregistered packet"); + } else { + PacketBuffer buffer = new PacketBuffer(out); + buffer.writeVarInt(packetId); + + try { + msg.writePacketData(buffer); + } catch (Throwable throwable) { + LOGGER.error(throwable); + } + } + } +} diff --git a/src/main/java/me/zero/client/load/mixin/MixinNetworkManager.java b/src/main/java/me/zero/client/load/mixin/MixinNetworkManager.java index 66e72220..ffee2b9b 100644 --- a/src/main/java/me/zero/client/load/mixin/MixinNetworkManager.java +++ b/src/main/java/me/zero/client/load/mixin/MixinNetworkManager.java @@ -19,7 +19,7 @@ import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; import me.zero.client.api.ClientAPI; -import me.zero.client.api.event.defaults.PacketEvent; +import me.zero.client.api.event.defaults.game.network.PacketEvent; import net.minecraft.network.INetHandler; import net.minecraft.network.NetworkManager; import net.minecraft.network.Packet; @@ -36,11 +36,11 @@ @Mixin(NetworkManager.class) public abstract class MixinNetworkManager { - @Shadow public abstract void dispatchPacket(final Packet inPacket, @Nullable final GenericFutureListener>[] futureListeners); + @Shadow protected abstract void dispatchPacket(final Packet inPacket, @Nullable final GenericFutureListener>[] futureListeners); @Redirect(method = "channelRead0", at = @At(value = "INVOKE", target = "net/minecraft/network/Packet.processPacket(Lnet/minecraft/network/INetHandler;)V")) @SuppressWarnings("unchecked") - public void processPacket(Packet packetIn, INetHandler handler) { + private void processPacket(Packet packetIn, INetHandler handler) { PacketEvent event = new PacketEvent.Receive(packetIn); ClientAPI.EVENT_BUS.post(event); if (event.isCancelled()) @@ -50,7 +50,7 @@ public void processPacket(Packet packetIn, INetHandler handler) { } @Redirect(method = "sendPacket", at = @At(value = "INVOKE", target = "net/minecraft/network/NetworkManager.dispatchPacket(Lnet/minecraft/network/Packet;[Lio/netty/util/concurrent/GenericFutureListener;)V")) - public void sendPacket(NetworkManager networkManager, Packet packetIn, @Nullable final GenericFutureListener>[] futureListeners) { + private void sendPacket(NetworkManager networkManager, Packet packetIn, @Nullable final GenericFutureListener>[] futureListeners) { PacketEvent event = new PacketEvent.Send(packetIn); ClientAPI.EVENT_BUS.post(event); if (event.isCancelled()) diff --git a/src/main/java/me/zero/client/load/mixin/MixinProfiler.java b/src/main/java/me/zero/client/load/mixin/MixinProfiler.java index 20dbf109..34b7968d 100644 --- a/src/main/java/me/zero/client/load/mixin/MixinProfiler.java +++ b/src/main/java/me/zero/client/load/mixin/MixinProfiler.java @@ -17,9 +17,10 @@ package me.zero.client.load.mixin; import me.zero.client.api.ClientAPI; -import me.zero.client.api.event.defaults.ProfilerEvent; +import me.zero.client.api.event.defaults.game.core.ProfilerEvent; import net.minecraft.profiler.Profiler; 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; @@ -31,8 +32,10 @@ @Mixin(Profiler.class) public class MixinProfiler { + @Shadow private String profilingSection; + @Inject(method = "startSection", at = @At("HEAD")) - public void startSection(String name, CallbackInfo ci) { - ClientAPI.EVENT_BUS.post(new ProfilerEvent(name)); + private void startSection(String name, CallbackInfo ci) { + ClientAPI.EVENT_BUS.post(new ProfilerEvent(profilingSection, name)); } } diff --git a/src/main/java/me/zero/client/load/mixin/MixinRender.java b/src/main/java/me/zero/client/load/mixin/MixinRender.java index ea245d15..78ec60ec 100644 --- a/src/main/java/me/zero/client/load/mixin/MixinRender.java +++ b/src/main/java/me/zero/client/load/mixin/MixinRender.java @@ -17,8 +17,8 @@ package me.zero.client.load.mixin; import me.zero.client.api.ClientAPI; -import me.zero.client.api.event.defaults.RenderEntityLabelEvent; -import me.zero.client.api.event.defaults.TeamColorEvent; +import me.zero.client.api.event.defaults.game.render.RenderEntityLabelEvent; +import me.zero.client.api.event.defaults.game.render.TeamColorEvent; import net.minecraft.client.renderer.entity.Render; import net.minecraft.entity.Entity; import org.spongepowered.asm.mixin.Mixin; @@ -35,7 +35,7 @@ public class MixinRender { @Inject(method = "getTeamColor", at = @At("HEAD"), cancellable = true) - public void getTeamColor(Entity entityIn, CallbackInfoReturnable ci) { + private void getTeamColor(Entity entityIn, CallbackInfoReturnable ci) { TeamColorEvent event = new TeamColorEvent(entityIn); ClientAPI.EVENT_BUS.post(event); if (event.isCancelled()) @@ -43,7 +43,7 @@ public void getTeamColor(Entity entityIn, CallbackInfoReturnable ci) { } @Inject(method = "renderLivingLabel", at = @At("HEAD"), cancellable = true) - public void renderLivingLabel(Entity entityIn, String str, double x, double y, double z, int maxDistance, CallbackInfo ci) { + private void renderLivingLabel(Entity entityIn, String str, double x, double y, double z, int maxDistance, CallbackInfo ci) { RenderEntityLabelEvent event = new RenderEntityLabelEvent(entityIn, str); ClientAPI.EVENT_BUS.post(event); if (event.isCancelled()) diff --git a/src/main/java/me/zero/client/load/mixin/MixinRenderItem.java b/src/main/java/me/zero/client/load/mixin/MixinRenderItem.java index c94f62da..ae353375 100644 --- a/src/main/java/me/zero/client/load/mixin/MixinRenderItem.java +++ b/src/main/java/me/zero/client/load/mixin/MixinRenderItem.java @@ -17,7 +17,7 @@ package me.zero.client.load.mixin; import me.zero.client.api.ClientAPI; -import me.zero.client.api.event.defaults.GlintEffectEvent; +import me.zero.client.api.event.defaults.game.render.GlintEffectEvent; import net.minecraft.client.renderer.RenderItem; import net.minecraft.client.renderer.block.model.IBakedModel; import org.spongepowered.asm.mixin.Mixin; @@ -33,7 +33,7 @@ public class MixinRenderItem { @Inject(method = "renderEffect", at = @At("HEAD"), cancellable = true) - public void renderEffect(IBakedModel model, CallbackInfo ci) { + private void renderEffect(IBakedModel model, CallbackInfo ci) { GlintEffectEvent event = new GlintEffectEvent(GlintEffectEvent.GlintTarget.ITEM); ClientAPI.EVENT_BUS.post(event); if (event.isCancelled()) diff --git a/src/main/java/me/zero/client/load/mixin/MixinRenderLivingBase.java b/src/main/java/me/zero/client/load/mixin/MixinRenderLivingBase.java index fb33b623..44613566 100644 --- a/src/main/java/me/zero/client/load/mixin/MixinRenderLivingBase.java +++ b/src/main/java/me/zero/client/load/mixin/MixinRenderLivingBase.java @@ -17,7 +17,7 @@ package me.zero.client.load.mixin; import me.zero.client.api.ClientAPI; -import me.zero.client.api.event.defaults.LayerRenderEvent; +import me.zero.client.api.event.defaults.game.render.LayerRenderEvent; import net.minecraft.client.renderer.entity.RenderLivingBase; import net.minecraft.client.renderer.entity.layers.LayerRenderer; import net.minecraft.entity.EntityLivingBase; @@ -34,7 +34,7 @@ public class MixinRenderLivingBase { @Redirect(method = "renderLayers", at = @At(value = "INVOKE", target = "net/minecraft/client/renderer/entity/layers/LayerRenderer.doRenderLayer(Lnet/minecraft/entity/EntityLivingBase;FFFFFFF)V")) @SuppressWarnings("unchecked") - public void doRenderLayer(LayerRenderer renderer, EntityLivingBase entitylivingbaseIn, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scaleIn) { + private void doRenderLayer(LayerRenderer renderer, EntityLivingBase entitylivingbaseIn, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scaleIn) { LayerRenderEvent event = new LayerRenderEvent(entitylivingbaseIn, renderer); ClientAPI.EVENT_BUS.post(event); if (!event.isCancelled()) diff --git a/src/main/java/me/zero/client/load/mixin/MixinRenderManager.java b/src/main/java/me/zero/client/load/mixin/MixinRenderManager.java index 4e6f1c0d..adc7b24a 100644 --- a/src/main/java/me/zero/client/load/mixin/MixinRenderManager.java +++ b/src/main/java/me/zero/client/load/mixin/MixinRenderManager.java @@ -17,7 +17,7 @@ package me.zero.client.load.mixin; import me.zero.client.api.ClientAPI; -import me.zero.client.api.event.defaults.EntityRenderEvent; +import me.zero.client.api.event.defaults.game.render.EntityRenderEvent; import me.zero.alpine.type.EventState; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderManager; @@ -35,7 +35,7 @@ public class MixinRenderManager { @Redirect(method = "doRenderEntity(Lnet/minecraft/entity/Entity;DDDFFZ)V", at = @At(value = "INVOKE", target = "net/minecraft/client/renderer/entity/Render.doRender(Lnet/minecraft/entity/Entity;DDDFF)V")) @SuppressWarnings("unchecked") - public void doRender(Render render, Entity entity, double x, double y, double z, float entityYaw, float partialTicks) { + private void doRender(Render render, Entity entity, double x, double y, double z, float entityYaw, float partialTicks) { EntityRenderEvent event = new EntityRenderEvent(EventState.PRE, render, entity, x, y, z, entityYaw, partialTicks); ClientAPI.EVENT_BUS.post(event); if (!event.isCancelled()) diff --git a/src/main/java/me/zero/client/load/mixin/wrapper/IMinecraft.java b/src/main/java/me/zero/client/load/mixin/wrapper/IMinecraft.java index bfc7b5b2..3ae386dc 100644 --- a/src/main/java/me/zero/client/load/mixin/wrapper/IMinecraft.java +++ b/src/main/java/me/zero/client/load/mixin/wrapper/IMinecraft.java @@ -16,7 +16,7 @@ package me.zero.client.load.mixin.wrapper; -import me.zero.client.api.event.defaults.ClickEvent; +import me.zero.client.api.event.defaults.game.core.ClickEvent; import net.minecraft.util.Session; import net.minecraft.util.Timer; diff --git a/src/main/java/pw/knx/feather/Feather.java b/src/main/java/pw/knx/feather/Feather.java new file mode 100644 index 00000000..f8f184d7 --- /dev/null +++ b/src/main/java/pw/knx/feather/Feather.java @@ -0,0 +1,138 @@ +package pw.knx.feather; + +import pw.knx.feather.font.FontCache; +import pw.knx.feather.font.FontGlyph; +import pw.knx.feather.font.GlyphLayout; +import pw.knx.feather.tessellate.Tessellator; +import pw.knx.feather.texture.Texture; + +import java.awt.*; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.HashMap; +import java.util.Map; + +import static org.lwjgl.opengl.GL11.*; +import static org.lwjgl.opengl.GL15.*; + +/** + * The central class of the Feather library. + * + * Basically functions as a convenient state manager for OpenGL, + * wrapping the most commonly used functions in intuitive, intelligent, + * chainable methods. In this way, Feather reduces your required knowledge of + * obscure OpenGL constants and compacts otherwise painfully verbose state management code. + * + * Probably going to use the enum singleton pattern for simplicity, thread safety and global access. + * This should not pose an inconvenience since LWJGL only allows once thread to interact + * with OpenGL anyways. + * + * WIP + * + * @author KNOXDEV + * @since 6/7/2017 6:54 PM + */ +public enum Feather { + feather; + + /** + * The simple Feather Tessellator we've designated to render our glyphs. + */ + private final Tessellator tess = Tessellator.createExpanding(4 * 4, 1, 2); + + private final Map fonts = new HashMap<>(); + private FontCache currentFont; + + + /* + * State Management - Most of these return Feather so they can be chained. + */ + + /** + * Binds an existing texture object to the working texture2D buffer + * + * @param id The OpenGL ID of the texture object to be bound + * @return the Feather manager, for additional chaining + */ + public Feather bindTexture(int id) { + glBindTexture(GL_TEXTURE_2D, id); + return this; + } + + /** + * Binds an existing buffer object to the working array buffer + * + * @param id The OpenGL ID of the buffer object to be bound + * @return the Feather manager, for additional chaining + */ + public Feather bindBuffer(int id) { + glBindBuffer(GL_ARRAY_BUFFER, id); + return this; + } + + + /* + * Allocators - Methods that wrap Java's unfortunate Buffer API + */ + + /** + * Allocates a ByteBuffer in the platform's native byte order + * + * @param capacity the size of the Buffer to be allocated in bytes + * @return the allocated ByteBuffer + */ + public synchronized ByteBuffer allocateBuffer(int capacity) { + return ByteBuffer.allocateDirect(capacity).order(ByteOrder.nativeOrder()); + } + + + /* + * Basic Rendering Routines + */ + + public Feather setFont(Font font) { + // holy shit streams + currentFont = fonts.computeIfAbsent(font, FontCache::from); + return this; + } + + public Feather drawString(String str, float x, float y) { + if(currentFont == null) + throw new RuntimeException("You must first set the Font to draw"); + + /* Make sure the entire string is cached before rendering and return its glyph representation */ + final GlyphLayout entry = currentFont.cacheString(str); + + /* Track which texture is currently bound to minimize the number of glBindTexture() and Tessellator.draw() calls needed */ + int boundTex = 0; + + /* Cycle through the Glyphs to be rendered */ + for (FontGlyph glyph : entry.glyphs) { + final Texture texture = glyph.texture; + + /* + * Make sure the OpenGL texture storing this glyph's image is bound (if not already bound). All pending glyphs in the + * Tessellator's vertex array must be drawn before switching textures, otherwise they would erroneously use the new + * texture as well. + */ + if (boundTex != texture.id()) { + if (boundTex != 0) + tess.draw(GL_QUADS); + boundTex = texture.bind().id(); + } + final float x1 = x + glyph.x; + final float x2 = x1 + texture.width(); + final float y1 = y + glyph.y; + final float y2 = y1 + texture.height(); + tess.setTexture(texture.u(), texture.v()).addVertex(x1, y1, 0); + tess.setTexture(texture.u(), texture.v1()).addVertex(x1, y2, 0); + tess.setTexture(texture.u1(), texture.v1()).addVertex(x2, y2, 0); + tess.setTexture(texture.u1(), texture.v()).addVertex(x2, y1, 0); + } + + /* Draw any remaining glyphs in the Tessellator's vertex array (there should be at least one glyph pending) */ + tess.draw(GL_QUADS); + + return this; + } +} diff --git a/src/main/java/pw/knx/feather/render/FontRend.java b/src/main/java/pw/knx/feather/font/FontCache.java similarity index 77% rename from src/main/java/pw/knx/feather/render/FontRend.java rename to src/main/java/pw/knx/feather/font/FontCache.java index 0c9eb4e6..fdae8ea7 100644 --- a/src/main/java/pw/knx/feather/render/FontRend.java +++ b/src/main/java/pw/knx/feather/font/FontCache.java @@ -1,9 +1,8 @@ -package pw.knx.feather.render; +package pw.knx.feather.font; import org.lwjgl.opengl.GL11; -import pw.knx.feather.tessellate.GrowingTess; -import pw.knx.feather.tessellate.base.Tessellator; -import pw.knx.feather.texture.base.Texture; +import pw.knx.feather.tessellate.Tessellator; +import pw.knx.feather.texture.Texture; import java.awt.*; import java.awt.font.FontRenderContext; @@ -18,7 +17,7 @@ import java.util.List; /** - * FontRend is a simple, one-class library for the rendering of all Unicode Strings using OpenType fonts. + * FontCache is a simple, one-class library for the rendering of all Unicode Strings using OpenType fonts. * It is adapted from thvortex's BetterFonts, found here: https://github.com/user/thvortex/BetterFonts *

* There are is one key way in which this implementation differs from thvortex's: @@ -28,7 +27,7 @@ * Regardless of these changes, as much of the model remains the same, plenty of documentation will * be copied directly from thvortex's original repository. *

- * This aforementioned processing model is as follows: FontRend caches the glyph layout of individual strings, + * This aforementioned processing model is as follows: FontCache caches the glyph layout of individual strings, * and it also caches the pre-rendered images for individual glyphs. Once a string and its glyph images are cached, * the critical path in renderString() will draw the glyphs as fast as if using a bitmap font. Strings are cached * using weak references through a two layer string cache. Strings that are no longer in use by LWJGL will be @@ -41,7 +40,7 @@ * @author KNOXDEV, thvortex * @since 1/23/2017 14:40 */ -public class FontRend { +public class FontCache { /* * Constants @@ -72,7 +71,7 @@ public class FontRend { * All font glyphs are packed inside this image and are then loaded from here into an OpenGL texture. */ private final BufferedImage glyphImage = new BufferedImage(TEXTURE_WIDTH, TEXTURE_HEIGHT, - BufferedImage.TYPE_INT_ARGB); + BufferedImage.TYPE_INT_ARGB); /** * The Graphics2D associated with stringImage and used for string drawing to extract the individual glyph shapes. @@ -88,10 +87,14 @@ public class FontRend { * String Graphics */ - /** Temporary image for rendering a string to and then extracting the glyph images from. */ + /** + * Temporary image for rendering a string to and then extracting the glyph images from. + */ private BufferedImage stringImage; - /** The Graphics2D associated with stringImage and used for string drawing to extract the individual glyph shapes. */ + /** + * The Graphics2D associated with stringImage and used for string drawing to extract the individual glyph shapes. + */ private Graphics2D stringGraphics; /** @@ -108,7 +111,9 @@ public class FontRend { */ private int cacheLineHeight = 0; - /** ID of current OpenGL cache texture being used by cacheGlyphs() to store pre-rendered glyph images. */ + /** + * ID of current OpenGL cache texture being used by cacheGlyphs() to store pre-rendered glyph images. + */ private int texture; /* @@ -118,7 +123,7 @@ public class FontRend { /** * List of all available physical fonts on the system. Used by lookupFont() to find alternate fonts. */ - private Font[] allFonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); + private final Font[] allFonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); /** * A list of all fonts that have been returned so far by lookupFont(), and that will always be searched first for a usable font before @@ -126,7 +131,7 @@ public class FontRend { * have multiple entries for the various styles (i.e. bold, italic, etc.) of a font. This list starts with Java's "SansSerif" logical * font. */ - private List usedFonts = new ArrayList<>(); + private final List usedFonts = new ArrayList<>(); /* * Internal Caches @@ -137,7 +142,7 @@ public class FontRend { * continues to hold a strong reference to the String object (i.e. from TileEntitySign and ChatLine) passed here, the * weakRefCache map will continue to hold a strong reference to the Entry object that said strings all map to. */ - private final Map stringCache = new WeakHashMap<>(); + private final Map stringCache = new WeakHashMap<>(); /** * A cache of all fonts that have at least one glyph pre-rendered in a texture. Each font maps to an integer (monotonically @@ -157,7 +162,9 @@ public class FontRend { * Working Data */ - /** Intermediate data array for use with textureImage.getRgb(). */ + /** + * Intermediate data array for use with textureImage.getRgb(). + */ private final int[] imageData = new int[TEXTURE_WIDTH * TEXTURE_HEIGHT]; /** @@ -166,15 +173,14 @@ public class FontRend { * that the integers holding packed RGBA colors are stored into memory in a predictable order. */ private final IntBuffer imageBuffer = ByteBuffer.allocateDirect(4 * TEXTURE_WIDTH * TEXTURE_HEIGHT) - .order(ByteOrder.BIG_ENDIAN).asIntBuffer(); + .order(ByteOrder.BIG_ENDIAN).asIntBuffer(); - /** The simple Feather Tessellator we've designated to render our glyphs. */ - private final Tessellator tess = new GrowingTess(4 * 4); - - /** A simple list of glyphs we're currently working with */ - private final List glyphs = new ArrayList<>(); + /** + * A simple list of glyphs we're currently working with + */ + private final List glyphs = new ArrayList<>(); - public FontRend(Font font) { + FontCache() { /* Set background color for use with clearRect() */ glyphGraphics.setBackground(CLEAR); @@ -187,88 +193,15 @@ public FontRend(Font font) { /* Use Java's logical font as the default initial font if user does not override it in some configuration file */ GraphicsEnvironment.getLocalGraphicsEnvironment().preferLocaleFonts(); - setFont(font); - } - - /** - * Change the preferred font used to pre-render glyph images. If this method is called at runtime, the existing glyph images will remain cached - * in their respective textures and will remain accessible. - * - * @param font the new font - */ - public void setFont(Font font) { - stringCache.clear(); - usedFonts.clear(); - usedFonts.add(font); } public Font getFont() { return usedFonts.get(0); } - /* - * String Methods - */ - - /** - * Render a single-line string to the screen using the current OpenGL color. The (x,y) coordinates are of the uppet-left - * corner of the string's bounding box, rather than the baseline position as is typical with fonts. This function will also - * add the string to the cache so the next renderString() call with the same string is faster. - * - * @param str the string being rendered - * @param x the x coordinate to draw at - * @param y the y coordinate to draw at - */ - public void renderString(String str, float x, float y) { - /* Make sure the entire string is cached before rendering and return its glyph representation */ - final Entry entry = this.cacheString(str); - - /* Track which texture is currently bound to minimize the number of glBindTexture() and Tessellator.draw() calls needed */ - int boundTex = 0; - - /* Cycle through the Glyphs to be rendered */ - for (Glyph glyph : entry.glyphs) { - final Texture texture = glyph.texture; - - /* - * Make sure the OpenGL texture storing this glyph's image is bound (if not already bound). All pending glyphs in the - * Tessellator's vertex array must be drawn before switching textures, otherwise they would erroneously use the new - * texture as well. - */ - if (boundTex != texture.getID()) { - if (boundTex != 0) { - tess.draw(GL11.GL_QUADS); - } - GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture.getID()); - boundTex = texture.getID(); - } - final float x1 = x + glyph.x; - final float x2 = x1 + texture.getWidth(); - final float y1 = y + glyph.y; - final float y2 = y1 + texture.getHeight(); - tess.texture(texture.getU(), texture.getV()).vertex(x1, y1, 0); - tess.texture(texture.getU(), texture.getV1()).vertex(x1, y2, 0); - tess.texture(texture.getU1(), texture.getV1()).vertex(x2, y2, 0); - tess.texture(texture.getU1(), texture.getV()).vertex(x2, y1, 0); - } - - /* Draw any remaining glyphs in the Tessellator's vertex array (there should be at least one glyph pending) */ - tess.draw(GL11.GL_QUADS); - } - - /** - * Return the width of a string in pixels. - * - * @param str compute the width of this string - * - * @return the width in pixels - */ - public int getStringWidth(String str) { - return this.cacheString(str).width; - } /* - * Caching Methods + * Caching Routines */ /** @@ -277,19 +210,18 @@ public int getStringWidth(String str) { * existing Entry from the cache. * * @param str this String will be laid out and added to the cache (or looked up, if already cached) - * * @return the string's cache entry containing all the glyph positions */ - private Entry cacheString(String str) { + public GlyphLayout cacheString(String str) { /* If this string is already in the cache, simply return the cached Entry object */ - Entry entry = stringCache.get(str); + GlyphLayout entry = stringCache.get(str); /* If string is not cached then layout the string */ if (entry == null) { final int width = layoutBidi(str); - entry = new Entry(glyphs.toArray(new Glyph[glyphs.size()]), width); + entry = new GlyphLayout(glyphs.toArray(new FontGlyph[glyphs.size()]), width); glyphs.clear(); /* Sorts these glyphs by associated TextureID to minimize OpenGL bind calls */ @@ -307,16 +239,14 @@ private Entry cacheString(String str) { * in the fontCache (based on the request style). Failing that, it searches the usedFonts list followed by the allFonts[] array. * * @param ch the character to check against the font - * * @return an OpenType font capable of displaying this character */ private Font cacheFont(char ch) { /* Try using an already known base font; the first font in usedFonts list is the one set with setFont() */ for (Font font : usedFonts) { /* Only use the font if it can layout the character */ - if (font.canDisplay(ch)) { + if (font.canDisplay(ch)) return font; - } } for (Font font : allFonts) { @@ -344,7 +274,6 @@ private Font cacheFont(char ch) { * @param limit the limit (offset + length) which to stop performing the layout * @param directionFlag either Font.LAYOUT_RIGHT_TO_LEFT or Font.LAYOUT_LEFT_TO_RIGHT * @param font the font to use to layout a GlyphVector - * * @return width of the glyphs cached */ private int cacheGlyphs(char[] text, int start, int limit, int directionFlag, Font font) { @@ -388,12 +317,11 @@ private int cacheGlyphs(char[] text, int start, int limit, int directionFlag, Fo * array of glyphcodes (and therefore render only a few glyphs at a time), this produces corrupted * Davengari glyphs under Windows 7. This will draw the string at most one time. */ - if (vectorBounds == null) { + if (vectorBounds == null) vectorBounds = cacheVector(vector); - } /* - * Get the glyph's pixel-aligned bounding box. The JavaDoc claims that the "The outline returned + * Get the glyph's pixel-aligned bounding box. The JavaDoc claims that the "The outline returned * by this method is positioned around the origin of each individual glyph." However, the actual * bounds are all relative to the start of the entire GlyphVector, which is actually more useful * for extracting the glyph's image from the rendered string. @@ -431,7 +359,7 @@ private int cacheGlyphs(char[] text, int start, int limit, int directionFlag, Fo * first because the composite method in the Graphics object is always set to AlphaComposite.Src. */ glyphGraphics.drawImage(stringImage, cacheX, cacheY, cacheX + rect.width, cacheY + rect.height, rect.x, - rect.y, rect.x + rect.width, rect.y + rect.height, null); + rect.y, rect.x + rect.width, rect.y + rect.height, null); /* * Store this glyph's position in texture and its origin offset. Note that "rect" will not be modified after @@ -443,7 +371,7 @@ private int cacheGlyphs(char[] text, int start, int limit, int directionFlag, Fo * Create new cache entry to record both the texture used by the glyph and its position within that texture. * Texture coordinates are normalized to 0.0-1.0 by dividing with TEXTURE_WIDTH and TEXTURE_HEIGHT. */ - tex = Texture.tex.createTexture(texture, rect.x, rect.y, rect.width, rect.height, TEXTURE_WIDTH); + tex = Texture.from(rect.x, rect.y, rect.width, rect.height, TEXTURE_WIDTH).setID(texture); /* * The lower 32 bits of the glyphCache key are the glyph codepoint. The upper 64 bits are the font number @@ -457,18 +385,17 @@ private int cacheGlyphs(char[] text, int start, int limit, int directionFlag, Fo * region than using the add(x, y) method to extend by a single point. Also note that creating the first * dirty rectangle here avoids having to deal with the special rules for empty/non-existent rectangles. */ - if (dirty == null) { + if (dirty == null) dirty = new Rectangle(cacheX, cacheY, rect.width, rect.height); - } else { + else dirty.add(rect); - } /* Advance cachePosX so the next glyph can be stored immediately to the right of this one */ cacheX += rect.width + 1; } final Point point = vector.getGlyphPixelBounds(index, null, 0, 0).getLocation(); - glyphs.add(new Glyph(tex, point.x - 2 * index, point.y)); + glyphs.add(new FontGlyph(tex, point.x - 2 * index, point.y)); } /* Update OpenGL texture if any part of the glyphCacheImage has changed */ @@ -488,10 +415,9 @@ private Rectangle cacheVector(GlyphVector vector) { final Rectangle vectorBounds = vector.getPixelBounds(fontContext, 0, 0); /* Enlage the stringImage if it is too small to store the entire rendered string */ - if (vectorBounds.width > stringImage.getWidth() || vectorBounds.height > stringImage.getHeight()) { + if (vectorBounds.width > stringImage.getWidth() || vectorBounds.height > stringImage.getHeight()) allocateStringImage(Math.max(vectorBounds.width, stringImage.getWidth()), - Math.max(vectorBounds.height, stringImage.getHeight())); - } + Math.max(vectorBounds.height, stringImage.getHeight())); /* Erase the upper-left corner where the string will get drawn*/ stringGraphics.clearRect(0, 0, vectorBounds.width, vectorBounds.height); @@ -502,24 +428,23 @@ private Rectangle cacheVector(GlyphVector vector) { return vectorBounds; } + /* - * Layout Methods + * Layout Routines */ private int layoutBidi(String str) { final char[] text = str.toCharArray(); /* Avoid performing full bidirectional analysis if text has no "strong" right-to-left characters */ - if (!Bidi.requiresBidi(text, 0, text.length)) { + if (!Bidi.requiresBidi(text, 0, text.length)) return layoutFont(text, 0, text.length, Font.LAYOUT_LEFT_TO_RIGHT); - } final Bidi bidi = new Bidi(text, 0, null, 0, text.length, Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT); /* If text is entirely right-to-left, then just lay it out */ - if (bidi.isRightToLeft()) { + if (bidi.isRightToLeft()) return layoutFont(text, 0, text.length, Font.LAYOUT_RIGHT_TO_LEFT); - } /* Otherwise text has a mixture of LTR and RLT, and it requires full bidirectional analysis */ final int runCount = bidi.getRunCount(); @@ -554,11 +479,10 @@ private int layoutFont(char[] text, int start, int limit, int directionFlag) { * one unsupported character (which will use the font's "missing glyph code"), then retry the lookup again at the * next character after that. */ - if (next == start) { + if (next == start) next++; - } else if (next == -1) /* canDisplayUpTo returns -1 if the entire string range is supported by this font */ { + else if (next == -1) /* canDisplayUpTo returns -1 if the entire string range is supported by this font */ next = limit; - } width += cacheGlyphs(text, start, next, directionFlag, font); start = next; @@ -574,19 +498,18 @@ private int layoutFont(char[] text, int start, int limit, int directionFlag) { * @param start the offset into text at which to start the layout * @param limit the (offset + length) at which to stop performing the layout * @param layoutFlags either Font.LAYOUT_RIGHT_TO_LEFT or Font.LAYOUT_LEFT_TO_RIGHT - * * @return the newly created GlyphVector */ private GlyphVector layoutVector(Font font, char text[], int start, int limit, int layoutFlags) { /* Ensure this font is already in fontCache so it can be referenced by cacheGlyphs() later on */ - if (!fontCache.containsKey(font)) { + if (!fontCache.containsKey(font)) fontCache.put(font, fontCache.size()); - } return font.layoutGlyphVector(fontContext, text, start, limit, layoutFlags); } + /* - * OpenGL Methods + * OpenGL Routines */ /** @@ -599,7 +522,7 @@ private void updateTexture(Rectangle dirty) { updateBuffer(dirty.x, dirty.y, dirty.width, dirty.height); GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture); GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0, dirty.x, dirty.y, dirty.width, dirty.height, GL11.GL_RGBA, - GL11.GL_UNSIGNED_BYTE, imageBuffer); + GL11.GL_UNSIGNED_BYTE, imageBuffer); } } @@ -624,7 +547,7 @@ private void allocateTexture() { */ GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture); GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_ALPHA8, TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, GL11.GL_RGBA, - GL11.GL_UNSIGNED_BYTE, imageBuffer); + GL11.GL_UNSIGNED_BYTE, imageBuffer); /* Explicitly disable mipmap support because updateTexture() will only update the base level 0 */ GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); @@ -685,71 +608,19 @@ private void setRenderingHints() { .setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF); } - /* - * Inner Classes - */ - /** - * This entry holds the laid-out glyph positions for the cached string along with some relevant metadata. + /* + * Static Construction Methods */ - private class Entry { - - /** - * Array of fully laid-out glyphs for the string. Sorted by logical order of characters (i.e. glyph.stringIndex) - */ - final Glyph[] glyphs; - - /** - * The total horizontal advance (i.e. width) for this string in pixels. - */ - final int width; - - Entry(Glyph[] glyphs, int width) { - this.glyphs = glyphs; - this.width = width; - } - } /** - * Identifies a single glyph in the laid-out string. Includes a reference to a Texture Object with the OpenGL texture ID - * and position of the pre-rendered glyph image, and includes the x/y pixel coordinates of where this glyph occurs within - * the string to which this Glyph object belongs. - */ - private class Glyph implements Comparable { - - /** - * Glyph's horizontal/vertical position (in pixels) relative to the entire string's baseline - */ - final int x, y; - - /** - * Texture ID and position/size of the glyph's pre-rendered image within the cache texture. - */ - final Texture texture; - - /** - * Your standard constructor. See class documentation for details. - * - * @param texture Texture ID and position/size of the glyph's pre-rendered image within the cache texture - * @param x Glyph's horizontal position (in pixels) relative to the entire string's baseline - * @param y Glyph's vertical position (in pixels) relative to the entire string's baseline - */ - Glyph(Texture texture, int x, int y) { - this.texture = texture; - this.x = x; - this.y = y; - } - - /** - * Allows arrays of Glyph objects to be sorted. Performs numeric comparison on texture ID. - * - * @param o the other Glyph object being compared with this one - * - * @return either -1, 0, or 1 if this < other, this == other, or this > other - */ - @Override - public int compareTo(Glyph o) { - return (this.texture.getID() == o.texture.getID()) ? 0 : 1; - } + * Creates a FontCache of the requested Font object + * @param font The Font to cache + * @return the Cache of the font passed + */ + public static FontCache from(Font font) { + FontCache cache = new FontCache(); + cache.usedFonts.add(font); + return cache; } } diff --git a/src/main/java/pw/knx/feather/font/FontGlyph.java b/src/main/java/pw/knx/feather/font/FontGlyph.java new file mode 100644 index 00000000..1fa822c6 --- /dev/null +++ b/src/main/java/pw/knx/feather/font/FontGlyph.java @@ -0,0 +1,48 @@ +package pw.knx.feather.font; + +import pw.knx.feather.texture.Texture; + +/** + * Identifies a single glyph in the laid-out string. Includes a reference to a Texture Object with the OpenGL texture ID + * and position of the pre-rendered glyph image, and includes the x/y pixel coordinates of where this glyph occurs within + * the string to which this Glyph object belongs. + * + * @author KNOXDEV + * @since 6/8/2017 5:35 PM + */ +public class FontGlyph implements Comparable { + + /** + * Glyph's horizontal/vertical position (in pixels) relative to the entire string's baseline + */ + public final int x, y; + + /** + * Texture ID and position/size of the glyph's pre-rendered image within the cache texture. + */ + public final Texture texture; + + /** + * Your standard constructor. See class documentation for details. + * + * @param texture Texture ID and position/size of the glyph's pre-rendered image within the cache texture + * @param x Glyph's horizontal position (in pixels) relative to the entire string's baseline + * @param y Glyph's vertical position (in pixels) relative to the entire string's baseline + */ + FontGlyph(Texture texture, int x, int y) { + this.texture = texture; + this.x = x; + this.y = y; + } + + /** + * Allows arrays of Glyph objects to be sorted. Performs numeric comparison on texture ID. + * + * @param o the other Glyph object being compared with this one + * @return either -1, 0, or 1 if this < other, this == other, or this > other + */ + @Override + public int compareTo(FontGlyph o) { + return (this.texture.id() == o.texture.id()) ? 0 : 1; + } +} diff --git a/src/main/java/pw/knx/feather/font/GlyphLayout.java b/src/main/java/pw/knx/feather/font/GlyphLayout.java new file mode 100644 index 00000000..fc7fd8b7 --- /dev/null +++ b/src/main/java/pw/knx/feather/font/GlyphLayout.java @@ -0,0 +1,26 @@ +package pw.knx.feather.font; + +/** + * + * This entry holds the laid-out glyph positions for the cached string along with some relevant metadata. + * + * @author KNOXDEV + * @since 6/8/2017 5:34 PM + */ +public class GlyphLayout { + + /** + * Array of fully laid-out glyphs for the string. Sorted by logical order of characters (i.e. glyph.stringIndex) + */ + public final FontGlyph[] glyphs; + + /** + * The total horizontal advance (i.e. width) for this string in pixels. + */ + public final int width; + + GlyphLayout(FontGlyph[] glyphs, int width) { + this.glyphs = glyphs; + this.width = width; + } +} diff --git a/src/main/java/pw/knx/feather/shapes/Dimensions.java b/src/main/java/pw/knx/feather/shapes/Dimensions.java new file mode 100644 index 00000000..8308f28e --- /dev/null +++ b/src/main/java/pw/knx/feather/shapes/Dimensions.java @@ -0,0 +1,101 @@ +package pw.knx.feather.shapes; + +/** + * The simplest 2-Dimensional shape, basically a paired width-height vector. + *

+ * We decided to create our own shape structures because LWJGL's and the JDK's + * did not suit the conventions of the Feather library. + *

+ * In standard Feather convention, the setters in this class return itself + * to allow for efficient and readable method chaining. + * + * @author KNOXDEV + * @since 5/25/2017 4:58 AM + */ +public class Dimensions { + // we can keep these private because the methods we have totally expose them + private int width, height; + + + /* + * Getters - For retrieving internal values + */ + + /** + * @return this shape's width + */ + public int width() { + return width; + } + + /** + * @return this shape's height + */ + public int height() { + return height; + } + + + /* + * Setters - For setting internal values + */ + + /** + * Set this shape's width + * + * @param w the width to set + * @return this shape, freshly set + */ + public Dimensions setWidth(int w) { + width = w; + return this; + } + + /** + * Set this shape's height + * + * @param h the height to set + * @return this shape, freshly set + */ + public Dimensions setHeight(int h) { + height = h; + return this; + } + + /** + * Set the width and height of this shape + * + * @param width the width value to use + * @param height the height value to use + * @return this shape, freshly set + */ + public Dimensions setTo(int width, int height) { + return setWidth(width).setHeight(height); + } + + /** + * Set the width and height of this shape to match the Dimension provided + * + * @param size the Dimensions to be set to + * @return this shape, freshly set + */ + public Dimensions setTo(Dimensions size) { + return setTo(size.width, size.height); + } + + + /* + * Modifiers - For now, just an offset shorthand method + */ + + /** + * Offset this shape by the width and height provided + * + * @param dWidth the change in width + * @param dHeight the change in height + * @return this shape, freshly offset + */ + public Dimensions offset(int dWidth, int dHeight) { + return setTo(width + dWidth, height + dHeight); + } +} diff --git a/src/main/java/pw/knx/feather/shapes/Rectangle.java b/src/main/java/pw/knx/feather/shapes/Rectangle.java new file mode 100644 index 00000000..372ebb8b --- /dev/null +++ b/src/main/java/pw/knx/feather/shapes/Rectangle.java @@ -0,0 +1,232 @@ +package pw.knx.feather.shapes; + +/** + * Representation of a geometric Rectangle. + * Four vectors, x position, y position, width, and height. + *

+ * We decided to create our own shape structures because LWJGL's and the JDK's + * did not suit the conventions of the Feather library. + *

+ * In standard Feather convention, the setters in this class return itself + * to allow for efficient and readable method chaining. + * + * @author KNOXDEV + * @since 5/25/2017 5:01 AM + */ +public class Rectangle { + // we can keep these private because the methods we have totally expose them + private int x, y, width, height; + + + /* + * Getters - For retrieving internal values, some literal, some logical (such as x1, etc.) + */ + + /** + * @return this shape's x-position + */ + public int x() { + return x; + } + + /** + * @return this shape's y-position + */ + public int y() { + return y; + } + + /** + * @return this shape's width + */ + public int width() { + return width; + } + + /** + * @return this shape's height + */ + public int height() { + return height; + } + + /** + * @return the calculated x-position of this shape's opposite vertex + */ + public int x1() { + return x + width; + } + + /** + * @return the calculated y-position of this shape's opposite vertex + */ + public int y1() { + return y + height; + } + + + /* + * Setters - For setting internal values, some literal, some logical (such as x1, etc.) + */ + + /** + * Set this shape's x-position + * + * @param x the x-position to set + * @return this shape, freshly set + */ + public Rectangle setX(int x) { + this.x = x; + return this; + } + + /** + * Set this shape's y-position + * + * @param y the y-position to set + * @return this shape, freshly set + */ + public Rectangle setY(int y) { + this.y = y; + return this; + } + + /** + * Set the x-position of this shape's opposite vertex + * + * @param x1 the x-position to set + * @return this shape, freshly set + */ + public Rectangle setX1(int x1) { + return setWidth(x1 - x); + } + + /** + * Set the y-position of this shape's opposite vertex + * + * @param y1 the y-position to set + * @return this shape, freshly set + */ + public Rectangle setY1(int y1) { + return setHeight(y1 - y); + } + + /** + * Set this shape's width + * + * @param w the width to set + * @return this shape, freshly set + */ + public Rectangle setWidth(int w) { + width = w; + return this; + } + + /** + * Set this shape's height + * + * @param h the height to set + * @return this shape, freshly set + */ + public Rectangle setHeight(int h) { + height = h; + return this; + } + + /** + * Set the x-position, y-position, width, and height of this shape + * + * @param x the x-position value to use + * @param y the xy-position value to use + * @param w the width value to use + * @param h the height value to use + * @return this shape, freshly set + */ + public Rectangle setTo(int x, int y, int w, int h) { + return setX(x).setY(y).setWidth(w).setHeight(h); + } + + /** + * Set the x-position, y-position, width, and height of this shape to match the Rectangle provided + * + * @param rect the Rectangle area to be set to + * @return this shape, freshly set + */ + public Rectangle setTo(Rectangle rect) { + return setTo(rect.x, rect.y, rect.width, rect.height); + } + + + /* + * Modifiers - Mostly just short hands for common adjustment operations + */ + + /** + * Offset this shape by the x and y provided + * + * @param dx the change in x-position + * @param dy the change in y-position + * @return this shape, freshly offset + */ + public Rectangle offset(int dx, int dy) { + return offset(dx, dy, 0, 0); + } + + /** + * Offset this shape's x-position, y-position, width, and height by the deltas provided + * + * @param dx the change in x-position + * @param dy the change in y-position + * @param dWidth the change in width + * @param dHeight the change in height + * @return this shape, freshly offset + */ + public Rectangle offset(int dx, int dy, int dWidth, int dHeight) { + return setTo(x + dx, y + dy, width + dWidth, height + dHeight); + } + + /** + * Expand this shape by the x and y provided + * + * @param dx the horizontal change + * @param dy the vertical change + * @return this shape, freshly expanded + */ + public Rectangle expand(int dx, int dy) { + return offset(-dx, -dy, 2*dx, 2*dy); + } + + /** + * Contract this shape by the x and y provided + * + * @param dx the horizontal change + * @param dy the vertical change + * @return this shape, freshly contracted + */ + public Rectangle contract(int dx, int dy) { + return offset(dx, dy, -2*dx, -2*dy); + } + + + /* + * Misc. Functions: + */ + + /** + * Checks if the provided point is inside the bounds of this shape, inclusive + * + * @param i the point's horizontal position + * @param j the point's vertical position + * @return true, if the point lies on the plane described by this shape + */ + public boolean contains(int i, int j) { + return i >= x && j >= y && i <= x1() && j <= y1(); + } + + /** + * @return an exact, dereferenced copy of this Rectangle with the same values + */ + public Rectangle copy() { + return new Rectangle().setTo(this); + } +} diff --git a/src/main/java/pw/knx/feather/util/Color.java b/src/main/java/pw/knx/feather/structures/Color.java similarity index 99% rename from src/main/java/pw/knx/feather/util/Color.java rename to src/main/java/pw/knx/feather/structures/Color.java index a8f841bc..0aee7bac 100644 --- a/src/main/java/pw/knx/feather/util/Color.java +++ b/src/main/java/pw/knx/feather/structures/Color.java @@ -1,4 +1,4 @@ -package pw.knx.feather.util; +package pw.knx.feather.structures; /** * A simple objectual representation of a Color. @@ -22,7 +22,7 @@ * @author KNOXDEV * @since 9/8/2016 21:41 */ -public class Color implements BufferUtils { +public class Color { /** * In this class, we store alpha separately and persistently, @@ -412,9 +412,8 @@ public Color hex(int hex) { */ public Color hex(int hex, HexFormat format) { int alpha = format.getAlphaInt(hex); - if (alpha != 0) { + if (alpha != 0) alpha(alpha); - } return red(format.getRedInt(hex)).green(format.getGreenInt(hex)).blue(format.getBlueInt(hex)); } diff --git a/src/main/java/pw/knx/feather/util/VBO.java b/src/main/java/pw/knx/feather/structures/VBO.java similarity index 88% rename from src/main/java/pw/knx/feather/util/VBO.java rename to src/main/java/pw/knx/feather/structures/VBO.java index 986926dc..e734a59c 100644 --- a/src/main/java/pw/knx/feather/util/VBO.java +++ b/src/main/java/pw/knx/feather/structures/VBO.java @@ -1,4 +1,4 @@ -package pw.knx.feather.util; +package pw.knx.feather.structures; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL15; @@ -6,6 +6,8 @@ import java.nio.ByteBuffer; import java.nio.FloatBuffer; +import static pw.knx.feather.Feather.feather; + /** * A simple OpenGL VertexBufferObject implementation for rendering shapes that will stay * consistent throughout Runtime and be used often. A key feature of this particular @@ -13,15 +15,15 @@ * with older builds of OpenGL. Please also note that this class is only compatible with * vertices and not factors like textures or colors. *

- * I seem to recall Halalalaboos creating something like this, + * I seem to recall Halalaboos creating something like this, * so credit is given accordingly. *

* The voids in this interface return the VBO object for easy method chaining. * - * @author KNOXDEV, Halalalaboos + * @author KNOXDEV, Halalaboos * @since 8/9/2016 05:58 */ -public class VBO implements BufferUtils { +public class VBO { /** * The VBO's buffer ID, for binding this object to. @@ -30,7 +32,7 @@ public class VBO implements BufferUtils { /** * Quite literally, this object's dimensions. - * No seriously, if you want to render 1-dimensional objects feel free. + * No seriously, if you want to render 1-dimensional objects feel free. That's weird though. */ protected final int dimensions; @@ -75,7 +77,7 @@ public VBO(int dimensions, int id) { */ public VBO compile(float... points) { if (points != null && points.length > 0) { - final FloatBuffer buffer = buff.createDirectBuffer(points.length * 4).asFloatBuffer(); + final FloatBuffer buffer = feather.allocateBuffer(points.length * 4).asFloatBuffer(); buffer.put(points).flip(); return this.compile(buffer); } @@ -90,9 +92,9 @@ public VBO compile(float... points) { */ public VBO compile(FloatBuffer buffer) { this.size = buffer.capacity(); - buff.bindBuffer(this.id); + feather.bindBuffer(this.id); GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW); - buff.bindBuffer(0); + feather.bindBuffer(0); return this; } @@ -102,7 +104,7 @@ public VBO compile(FloatBuffer buffer) { * @return The original VBO */ public VBO bind() { - buff.bindBuffer(this.id); + feather.bindBuffer(this.id); GL11.glVertexPointer(this.dimensions, GL11.GL_FLOAT, 0, 0L); GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY); return this; diff --git a/src/main/java/pw/knx/feather/tessellate/BasicTess.java b/src/main/java/pw/knx/feather/tessellate/BasicTess.java index 90cd457e..0fb4f478 100644 --- a/src/main/java/pw/knx/feather/tessellate/BasicTess.java +++ b/src/main/java/pw/knx/feather/tessellate/BasicTess.java @@ -1,52 +1,52 @@ package pw.knx.feather.tessellate; import org.lwjgl.opengl.GL11; -import pw.knx.feather.tessellate.base.Tessellator; -import pw.knx.feather.util.BufferUtils; import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; +import static pw.knx.feather.Feather.feather; + /** * A standard implementation of the Tessellator interface. *

* The most noteworthy point to make about this Tessellator is that it *will not grow*. * Its size is final from the moment it's instantiated. If you attempt to add more data * than it can hold, it will throw an error. To create an automatically resizing - * Tessellator, use the GrowingTess implementation, also found in this package. + * Tessellator, use the ExpandingTess implementation, also found in this package. *

* The voids in this interface return the Tessellator object for easy method chaining. * * @author KNOXDEV * @since 8/9/2016 03:00 */ -public class BasicTess implements Tessellator, BufferUtils { +public class BasicTess implements Tessellator { /** * Tracks the current index in the total data buffer that we're on */ - protected int index; + int index; /** * The raw array of integers that stores vertex information */ - protected int[] raw; + int[] raw; /** * A byte buffer mainly utilized as a vehicle for transferring the raw data to OpenGL upon binding */ - protected ByteBuffer buffer; + ByteBuffer buffer; /** * A float buffer view of the main byte buffer */ - protected FloatBuffer fBuffer; + FloatBuffer fBuffer; /** * A integer buffer view of the main byte buffer */ - protected IntBuffer iBuffer; + IntBuffer iBuffer; /** * An integer storing our main color data for this vertex @@ -68,12 +68,12 @@ public class BasicTess implements Tessellator, BufferUtils { * * @param capacity The total capacity, in whole verticies, that this Tessellator will be able to render at once. */ - public BasicTess(int capacity) { + BasicTess(int capacity) { /** Why times 6? Because 6 is how much space (in integers) that each vertex * takes up in the buffer, since each vertex stores color and texture as well. */ capacity *= 6; this.raw = new int[capacity]; - this.buffer = buff.createDirectBuffer(capacity * 4); // 4 bytes in an integer! + this.buffer = feather.allocateBuffer(capacity * 4); // 4 bytes in an integer! this.fBuffer = this.buffer.asFloatBuffer(); this.iBuffer = this.buffer.asIntBuffer(); } @@ -83,7 +83,7 @@ public BasicTess(int capacity) { * @return The original Tessellator Object */ @Override - public Tessellator color(int color) { + public Tessellator setColor(int color) { this.color = true; this.colors = color; return this; @@ -97,7 +97,7 @@ public Tessellator color(int color) { * @return The original Tessellator Object */ @Override - public Tessellator texture(float u, float v) { + public Tessellator setTexture(float u, float v) { this.texture = true; this.texU = u; this.texV = v; @@ -115,7 +115,7 @@ public Tessellator texture(float u, float v) { * @return The original Tessellator Object */ @Override - public Tessellator vertex(float x, float y, float z) { + public Tessellator addVertex(float x, float y, float z) { final int dex = this.index * 6; this.raw[dex] = Float.floatToRawIntBits(x); this.raw[dex + 1] = Float.floatToRawIntBits(y); diff --git a/src/main/java/pw/knx/feather/tessellate/GrowingTess.java b/src/main/java/pw/knx/feather/tessellate/ExpandingTess.java similarity index 70% rename from src/main/java/pw/knx/feather/tessellate/GrowingTess.java rename to src/main/java/pw/knx/feather/tessellate/ExpandingTess.java index 659b69dc..22004e80 100644 --- a/src/main/java/pw/knx/feather/tessellate/GrowingTess.java +++ b/src/main/java/pw/knx/feather/tessellate/ExpandingTess.java @@ -1,6 +1,6 @@ package pw.knx.feather.tessellate; -import pw.knx.feather.tessellate.base.Tessellator; +import static pw.knx.feather.Feather.feather; /** * An automatically resizing implementation of the Tessellator interface. @@ -12,37 +12,26 @@ * @author KNOXDEV * @since 8/9/2016 03:00 */ -public class GrowingTess extends BasicTess { +public class ExpandingTess extends BasicTess { /** * The target ratio, between 0 and 1.0, that this Tessellator must hit before it grows. */ - final float ratio; + private final float ratio; /** * The factor of which this Tessellator will grow when it hits the ratio. */ - final float factor; + private final float factor; /** - * Constructs a Growing Tessellator. See Class Documentation for more information. - * By default, a GrowingTess's capacity will double every time it hits its maximum capacity. - * Use the alternate constructor if you wish to change this behavior. - * - * @param initial The total initial capacity, in whole vertices. - */ - public GrowingTess(int initial) { - this(initial, 1, 2); - } - - /** - * Constructs a Growing Tessellator. See Class Documentation for more information. + * Constructs an Expanding Tessellator. See Class Documentation for more information. * * @param initial The total initial capacity, in whole vertices. * @param ratio The target ratio, between 0 and 1.0, that this Tessellator must hit before it grows. * @param factor The factor of which this Tessellator will grow when it hits the ratio. */ - public GrowingTess(int initial, float ratio, float factor) { + ExpandingTess(int initial, float ratio, float factor) { super(initial); this.ratio = ratio; this.factor = factor; @@ -62,17 +51,17 @@ public GrowingTess(int initial, float ratio, float factor) { * @return The original Tessellator Object */ @Override - public Tessellator vertex(float x, float y, float z) { + public Tessellator addVertex(float x, float y, float z) { int capacity = raw.length; if (index * 6 >= capacity * ratio) { // if we've hit our capacity limit capacity *= factor; // raise our limit by the amount specified final int[] newBuffer = new int[capacity]; // allocate the new data System.arraycopy(raw, 0, newBuffer, 0, raw.length); // transfer the data from the old array to the new array raw = newBuffer; // replace the array - buffer = buff.createDirectBuffer(capacity * 4); // allocate a new corresponding ByteBuffer + buffer = feather.allocateBuffer(capacity * 4); // allocate a new corresponding ByteBuffer iBuffer = buffer.asIntBuffer(); fBuffer = buffer.asFloatBuffer(); } - return super.vertex(x, y, z); + return super.addVertex(x, y, z); } } \ No newline at end of file diff --git a/src/main/java/pw/knx/feather/tessellate/OffsetTess.java b/src/main/java/pw/knx/feather/tessellate/OffsetTess.java deleted file mode 100644 index 72431501..00000000 --- a/src/main/java/pw/knx/feather/tessellate/OffsetTess.java +++ /dev/null @@ -1,168 +0,0 @@ -package pw.knx.feather.tessellate; - -import org.lwjgl.opengl.GL11; -import pw.knx.feather.tessellate.base.Tessellator; - -/** - * An easily translatable implementation of the Tessellator interface. - *

- * This class is an unusual implementation as it does not strictly handle tessellating itself, - * rather, this class is designed to wrap around an existing Tessellator, so developers can be - * flexible about what kind of Tessellator they want to translate. Most methods in this class - * will simply be passed through to the original Tessellator and leaves most of its - * behavior intact. The only difference is a series of methods that allow for simple - * offsetting of the current shape, which is handy for rendering the same shape in multiple - * places without binding completely new data. If the shape is totally consistent throughout - * Runtime, consider using the VBO class instead. - * - * @author KNOXDEV - * @since 8/9/2016 03:55 - */ -public class OffsetTess implements Tessellator { - - /** - * The original Tessellator object that most methods will pass to. - */ - private final Tessellator tess; - - /** - * Floats representing the X, Y, and Z distance that this Tessellator is currently offset by. - */ - public float offsetX, offsetY, offsetZ; - - /** - * Constructs an Offset Tessellator. See Class Documentation for more information. - * Please note that by default, this Tessellator will offset a Basic Tessellator. - * Use the alternate constructor if you wish to change this behavior. - * - * @param capacity The total initial capacity, in whole vertices. - */ - public OffsetTess(int capacity) { - this(new BasicTess(capacity)); - } - - /** - * Constructs an Offset Tessellator. See Class Documentation for more information. - * - * @param tess The Tessellator object you wish to wrap and offset - */ - public OffsetTess(Tessellator tess) { - this.tess = tess; - } - - /** - * Please see implemented Tessellator documentation for specific information. - * - * @param color The color to associate the upcoming vertex data with - * @return The original Tessellator Object - */ - @Override - public Tessellator color(int color) { - tess.color(color); - return this; - } - - /** - * Set the texture coordinates to associate the upcoming vertex data with. - *

- * Please see implemented Tessellator documentation for specific information. - * - * @param u The x starting coordinate - * @param v The y starting coordinate - * @return The original Tessellator Object - */ - @Override - public Tessellator texture(float u, float v) { - tess.texture(u, v); - return this; - } - - /** - * Enters a vertex of the shape to be rendered. - * All data fed to the Tessellator revolves around the vertex data, - * as it is the only information absolutely necessary to render a shape. - *

- * Please see implemented Tessellator documentation for specific information. - * - * @param x The x coordinate of this vertex - * @param y The y coordinate of this vertex - * @param z The z coordinate of this vertex - * @return The original Tessellator Object - */ - @Override - public Tessellator vertex(float x, float y, float z) { - tess.vertex(x, y, z); - return this; - } - - /** - * The first stage of rendering. - * Binds (finalizes) the current rendering data stored in the buffer for drawing. - * This must be executed before you perform a rendering pass. - *

- * Please see implemented Tessellator documentation for specific information. - * - * @return The original Tessellator Object - */ - @Override - public Tessellator bind() { - tess.bind(); - return this; - } - - /** - * The second stage of rendering. - * Performs a rendering pass with the data bound to the buffer. - * If the data is not bound first, this method will fail. - * Otherwise, you can render the data for as many passes as you please. - *

- * Please see implemented Tessellator documentation for specific information. - * - * @param mode The OpenGL mode to render the data with - * @return The original Tessellator Object - */ - @Override - public Tessellator pass(int mode) { - GL11.glTranslatef(offsetX, offsetY, offsetZ); - final Tessellator sup = tess.pass(mode); - GL11.glTranslatef(-offsetX, -offsetY, offsetZ); - return sup; - } - - /** - * The third and final stage of rendering. - * Clears up the buffer and resets the Tessellator so it can - * be used again with new data. Passes can no longer be made - * after this method is executed. - *

- * Please see implemented Tessellator documentation for specific information. - * - * @return The original Tessellator Object - */ - @Override - public Tessellator reset() { - tess.reset(); - return this; - } - - @Override - public Tessellator unbind() { - tess.unbind(); - return this; - } - - /** - * Performs all three rendering stages in one method. - * This method cannot be run more than once without entering new data. - *

- * Please see implemented Tessellator documentation for specific information. - * - * @param mode The OpenGL mode to render the data with - * @return The original Tessellator Object - */ - @Override - public Tessellator draw(int mode) { - tess.draw(mode); - return this; - } -} \ No newline at end of file diff --git a/src/main/java/pw/knx/feather/tessellate/base/Tessellator.java b/src/main/java/pw/knx/feather/tessellate/Tessellator.java similarity index 65% rename from src/main/java/pw/knx/feather/tessellate/base/Tessellator.java rename to src/main/java/pw/knx/feather/tessellate/Tessellator.java index 09389371..561e4d8b 100644 --- a/src/main/java/pw/knx/feather/tessellate/base/Tessellator.java +++ b/src/main/java/pw/knx/feather/tessellate/Tessellator.java @@ -1,6 +1,6 @@ -package pw.knx.feather.tessellate.base; +package pw.knx.feather.tessellate; -import pw.knx.feather.util.Color; +import pw.knx.feather.structures.Color; /** * A standard abstract interface for an OpenGL Tessellator. @@ -12,41 +12,24 @@ */ public interface Tessellator { - /** - * @param color The color to associate the upcoming vertex data with - * NOTE: Must be in ABGR format - * @return The original Tessellator Object - */ - Tessellator color(int color); - /** - * @param color The color to associate the upcoming vertex data with - * @return The original Tessellator Object + /* + * Setters - Setting and adding values to this tessellator */ - default Tessellator color(Color color) { - return color(color.getHex(Color.HexFormat.ABGR)); - } /** - * @param red The red component of the color to bind - * @param green The green component of the color to bind - * @param blue The blue component of the color to bind - * @param alpha The alpha component of the color to bind + * @param color The color to associate the upcoming vertex data with + * NOTE: Must be in ABGR format * @return The original Tessellator Object */ - default Tessellator color(int red, int green, int blue, int alpha) { - return color(Color.HexFormat.ABGR.getHex(red, green, blue, alpha)); - } + Tessellator setColor(int color); /** - * @param red The red component of the color to bind - * @param green The green component of the color to bind - * @param blue The blue component of the color to bind - * @param alpha The alpha component of the color to bind + * @param color The color to associate the upcoming vertex data with * @return The original Tessellator Object */ - default Tessellator color(float red, float green, float blue, float alpha) { - return color((int) (red * 255), (int) (green * 255), (int) (blue * 255), (int) (alpha * 255)); + default Tessellator setColor(Color color) { + return setColor(color.getHex(Color.HexFormat.ABGR)); } /** @@ -56,11 +39,11 @@ default Tessellator color(float red, float green, float blue, float alpha) { * @param v The y starting coordinate * @return The original Tessellator Object */ - Tessellator texture(float u, float v); + Tessellator setTexture(float u, float v); /** * Enters a vertex of the shape to be rendered. - * All data fed to the Tessellator revolves around the vertex data, + * All data fed to the Tessellator relies on the vertex data, * as it is the only information absolutely necessary to render a shape. * * @param x The x coordinate of this vertex @@ -68,7 +51,13 @@ default Tessellator color(float red, float green, float blue, float alpha) { * @param z The z coordinate of this vertex * @return The original Tessellator Object */ - Tessellator vertex(float x, float y, float z); + Tessellator addVertex(float x, float y, float z); + + + /* + * Render Commands - These provide fine-tuned control over the + * three-stage render process, if needed + */ /** * The first stage of rendering. @@ -116,7 +105,8 @@ default Tessellator color(float red, float green, float blue, float alpha) { /** * Performs all three rendering stages in one method. - * This method cannot be run more than once without entering new data. + * This method cannot be run more than once without entering new data, + * due to the fact it resets the buffer. * * @param mode The OpenGL mode to render the data with * @return The original Tessellator Object @@ -124,4 +114,31 @@ default Tessellator color(float red, float green, float blue, float alpha) { default Tessellator draw(int mode) { return this.bind().pass(mode).reset(); } + + + /* + * Static Constructors - allows intuitive initialization of a Tessellator to fit any purpose + */ + + /** + * Creates an immutable Tessellator that will not grow past its initial capacity + * + * @param size the initial (and final) capacity of this Tessellator + * @return the requested Basic Tessellator + */ + static Tessellator createBasic(int size) { + return new BasicTess(size); + } + + /** + * Creates a growing Tessellator that will increase in capacity as its limit is reached + * + * @param size the initial capacity of this Tessellator + * @param ratio The target ratio, between 0 and 1.0, that this Tessellator must hit before it grows. + * @param factor The factor of which this Tessellator will grow when it hits the ratio. + * @return the requested Basic Tessellator + */ + static Tessellator createExpanding(int size, float ratio, float factor) { + return new ExpandingTess(size, ratio, factor); + } } \ No newline at end of file diff --git a/src/main/java/pw/knx/feather/texture/BasicTexture.java b/src/main/java/pw/knx/feather/texture/BasicTexture.java index 77c47bf3..f72d965f 100644 --- a/src/main/java/pw/knx/feather/texture/BasicTexture.java +++ b/src/main/java/pw/knx/feather/texture/BasicTexture.java @@ -1,8 +1,9 @@ package pw.knx.feather.texture; import org.lwjgl.opengl.GL11; -import pw.knx.feather.tessellate.base.Tessellator; -import pw.knx.feather.texture.base.Texture; +import pw.knx.feather.tessellate.Tessellator; + +import static pw.knx.feather.Feather.feather; /** * A simple implementation of our OpenGL Texture interface @@ -30,7 +31,7 @@ public class BasicTexture implements Texture { */ @Override public Texture bind() { - GL11.glBindTexture(GL11.GL_TEXTURE_2D, texID); + feather.bindTexture(texID); return this; } @@ -45,8 +46,8 @@ public Texture bind() { */ @Override public Texture draw(Tessellator tess, int mode, float x, float y) { - tess.texture(u1, v).vertex(x + width, y, 0).texture(u, v).vertex(x, y, 0); - tess.texture(u, v1).vertex(x, y + height, 0).texture(u1, v1).vertex(x + width, y + height, 0); + tess.setTexture(u1, v).addVertex(x + width, y, 0).setTexture(u, v).addVertex(x, y, 0); + tess.setTexture(u, v1).addVertex(x, y + height, 0).setTexture(u1, v1).addVertex(x + width, y + height, 0); tess.draw(mode); return this; } @@ -55,7 +56,7 @@ public Texture draw(Tessellator tess, int mode, float x, float y) { * @return the OpenGL Texture ID */ @Override - public int getID() { + public int id() { return this.texID; } @@ -63,7 +64,7 @@ public int getID() { * @return the x coordinate of the top-left texture point, on a float scale from 0 to 1.0 */ @Override - public float getU() { + public float u() { return this.u; } @@ -71,7 +72,7 @@ public float getU() { * @return the y coordinate of the top-left texture point, on a float scale from 0 to 1.0 */ @Override - public float getV() { + public float v() { return this.v; } @@ -79,7 +80,7 @@ public float getV() { * @return the x coordinate of the bottom-right texture point, on a float scale from 0 to 1.0 */ @Override - public float getU1() { + public float u1() { return this.u1; } @@ -87,7 +88,7 @@ public float getU1() { * @return the y coordinate of the bottom-right texture point, on a float scale from 0 to 1.0 */ @Override - public float getV1() { + public float v1() { return this.v1; } @@ -95,7 +96,7 @@ public float getV1() { * @return the width of the texture rendering in pixels */ @Override - public float getWidth() { + public float width() { return this.width; } @@ -103,7 +104,7 @@ public float getWidth() { * @return the height of the texture rendering in pixels */ @Override - public float getHeight() { + public float height() { return this.height; } diff --git a/src/main/java/pw/knx/feather/texture/base/Texture.java b/src/main/java/pw/knx/feather/texture/Texture.java similarity index 50% rename from src/main/java/pw/knx/feather/texture/base/Texture.java rename to src/main/java/pw/knx/feather/texture/Texture.java index c6b9b44a..720f7234 100644 --- a/src/main/java/pw/knx/feather/texture/base/Texture.java +++ b/src/main/java/pw/knx/feather/texture/Texture.java @@ -1,51 +1,54 @@ -package pw.knx.feather.texture.base; +package pw.knx.feather.texture; -import pw.knx.feather.tessellate.base.Tessellator; -import pw.knx.feather.util.TextureUtils; +import pw.knx.feather.tessellate.Tessellator; /** * A simple OpenGL Texture interface * The voids in this interface return the Texture object for easy method chaining + *

+ * In addition, this interface contains construction methods that can be called intuitively: + * Texture.from(); + * ...rather than needing to know to use 'new ***Texture()' * * @author KNOXDEV * @since 8/8/2016 23:53 */ -public interface Texture extends TextureUtils { +public interface Texture { /** * @return the OpenGL Texture ID */ - int getID(); + int id(); /** * @return the x coordinate of the top-left texture point, on a float scale from 0 to 1.0 */ - float getU(); + float u(); /** * @return the y coordinate of the top-left texture point, on a float scale from 0 to 1.0 */ - float getV(); + float v(); /** * @return the x coordinate of the bottom-right texture point, on a float scale from 0 to 1.0 */ - float getU1(); + float u1(); /** * @return the y coordinate of the bottom-right texture point, on a float scale from 0 to 1.0 */ - float getV1(); + float v1(); /** * @return the width of the texture rendering in pixels */ - float getWidth(); + float width(); /** * @return the height of the texture rendering in pixels */ - float getHeight(); + float height(); /** * @param id The OpenGL Texture object ID @@ -104,4 +107,39 @@ public interface Texture extends TextureUtils { * @return The original Texture object */ Texture draw(Tessellator tess, int mode, float x, float y); + + + /* ##################### + * Static Constructors + * ##################### */ + + /** + * @param u The x coordinate of the top-left texture point, on a float scale from 0 to 1.0 + * @param v The y coordinate of the top-left texture point, on a float scale from 0 to 1.0 + * @param u1 The x coordinate of the bottom-right texture point, on a float scale from 0 to 1.0 + * @param v1 The y coordinate of the bottom-right texture point, on a float scale from 0 to 1.0 + * @param width The width of the texture rendering in pixels + * @param height The height of the texture rendering in pixels + * @return a freshly instantiated BasicTexture object with the parameters provided + */ + static Texture from(float u, float v, float u1, float v1, float width, float height) { + return new BasicTexture().setU(u).setV(v).setU1(u1).setV1(v1).setWidth(width).setHeight(height); + } + + /** + * Like above, creates a new BasicTexture object with the parameters provided. + * The difference is that it allows you to pass pixel-based U&V rather than 0-1 floats. + * In exchange for automatically calculating U, V, U1, and V1, the method requires the texture + * resource's original dimensions. (64, 256, etc.) + * + * @param u Starting x coordinate of section of the origin resource to be rendered in pixels. + * @param v Starting y coordinate of section of the origin resource to be rendered in pixels. + * @param width The width of section of the origin resource to be rendered in pixels. + * @param height The height of section of the origin resource to be rendered in pixels. + * @param dimensions The origin texture resource's original dimensions. (64, 256, etc.) + * @return a freshly instantiated BasicTexture object with the parameters provided + */ + static Texture from(float u, float v, float width, float height, int dimensions) { + return from(u / dimensions, v / dimensions, (u + width) / dimensions, (v + height) / dimensions, width, height); + } } \ No newline at end of file diff --git a/src/main/java/pw/knx/feather/util/BufferUtils.java b/src/main/java/pw/knx/feather/util/BufferUtils.java deleted file mode 100644 index 644a7654..00000000 --- a/src/main/java/pw/knx/feather/util/BufferUtils.java +++ /dev/null @@ -1,67 +0,0 @@ -package pw.knx.feather.util; - -import org.lwjgl.opengl.GL15; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * A utility class currently used to generate, bind, and manage buffers. - *

- * This particular interface-with-inner-class structure is - * implemented as a new form of Singleton model well-suited - * for classes holding utility methods, as it allows a - * developer to simply implement the interface to access the - * methods within via the Singleton object, while also making - * it easily apparent which classes require a given range of - * utilities by it's *implements* clause. - * - * @author KNOXDEV - * @since 8/9/2016 01:34 - */ -public interface BufferUtils { - - /** - * The static Singleton Object containing Buffer Utilities - */ - BufferUtil buff = new BufferUtil(); - - /** - * The Singleton inner-class which contains the utility methods - */ - class BufferUtil { - - /** - * This line exists solely to prevent additional instantiation - */ - private BufferUtil() { - } - - /** - * A ByteOrder object containing the native order of the platform - */ - private final ByteOrder nativeOrder = ByteOrder.nativeOrder(); - - /** - * @param capacity The size of the Buffer to be allocated in Bytes - * @return The ByteBuffer object allocated to the specified capacity - */ - public synchronized ByteBuffer createDirectBuffer(int capacity) { - return ByteBuffer.allocateDirect(capacity).order(nativeOrder); - } - - /** - * @param id The OpenGL ID of the buffer object to be bound - */ - public void bindBuffer(int id) { - GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, id); - } - - /** - * @return true if the native order of the platform is Big Endian (Most significant first) - */ - public boolean isBigEndian() { - return nativeOrder == ByteOrder.BIG_ENDIAN; - } - } -} \ No newline at end of file diff --git a/src/main/java/pw/knx/feather/util/TextureUtils.java b/src/main/java/pw/knx/feather/util/TextureUtils.java deleted file mode 100644 index 269e778c..00000000 --- a/src/main/java/pw/knx/feather/util/TextureUtils.java +++ /dev/null @@ -1,101 +0,0 @@ -package pw.knx.feather.util; - -import pw.knx.feather.texture.BasicTexture; -import pw.knx.feather.texture.base.Texture; - -/** - * A utility class currently only used to generate Basic textures. - *

- * This particular interface-with-inner-class structure is - * implemented as a new form of Singleton model well-suited - * for classes holding utility methods, as it allows a - * developer to simply implement the interface to access the - * methods within via the Singleton object, while also making - * it easily apparent which classes require a given range of - * utilities by it's *implements* clause. - * - * @author KNOXDEV - * @since 8/9/2016 00:53 - */ -public interface TextureUtils { - /** - * The static Singleton Object containing TextureUtils - */ - TextureUtil tex = new TextureUtil(); - - /** - * The Singleton inner-class which contains the utility methods - */ - class TextureUtil { - - /** - * This line exists solely to prevent additional instantiation - */ - private TextureUtil() { - } - - /** - * @return a freshly instantiated BasicTexture object - */ - public Texture createTexture() { - return new BasicTexture(); - } - - /** - * @param u The x coordinate of the top-left texture point, on a float scale from 0 to 1.0 - * @param v The y coordinate of the top-left texture point, on a float scale from 0 to 1.0 - * @param u1 The x coordinate of the bottom-right texture point, on a float scale from 0 to 1.0 - * @param v1 The y coordinate of the bottom-right texture point, on a float scale from 0 to 1.0 - * @param width The width of the texture rendering in pixels - * @param height The height of the texture rendering in pixels - * @return a freshly instantiated BasicTexture object with the parameters provided - */ - public Texture createTexture(float u, float v, float u1, float v1, float width, float height) { - final Texture texture = this.createTexture(); - texture.setU(u); - texture.setV(v); - texture.setU1(u1); - texture.setV1(v1); - texture.setWidth(width); - texture.setHeight(height); - return texture; - } - - /** - * Like above, creates a new BasicTexture object with the parameters provided. - * The difference is that it allows you to pass pixel-based U&V rather than 0-1 floats. - * In exchange for automatically calculating U, V, U1, and V1, the method requires the texture - * resource's original dimensions. (64, 256, etc.) - * - * @param u Starting x coordinate of section of the origin resource to be rendered in pixels. - * @param v Starting y coordinate of section of the origin resource to be rendered in pixels. - * @param width The width of section of the origin resource to be rendered in pixels. - * @param height The height of section of the origin resource to be rendered in pixels. - * @param dimensions The origin texture resource's original dimensions. (64, 256, etc.) - * @return a freshly instantiated BasicTexture object with the parameters provided - */ - public Texture createTexture(float u, float v, float width, float height, float dimensions) { - return this.createTexture(u / dimensions, v / dimensions, (u + width) / dimensions, (v + height) / dimensions, width, height); - } - - /** - * Like above, creates a new BasicTexture object with the parameters provided. - * The difference is that it allows you to pass pixel-based U&V rather than 0-1 floats. - * In exchange for automatically calculating U, V, U1, and V1, the method requires the texture - * resource's original dimensions. (64, 256, etc.) - * - * @param id The OpenGL Texture ID you wish to create a Texture for. - * @param u Starting x coordinate of section of the origin resource to be rendered in pixels. - * @param v Starting y coordinate of section of the origin resource to be rendered in pixels. - * @param width The width of section of the origin resource to be rendered in pixels. - * @param height The height of section of the origin resource to be rendered in pixels. - * @param dimensions The origin texture resource's original dimensions. (64, 256, etc.) - * @return a freshly instantiated BasicTexture object with the parameters provided - */ - public Texture createTexture(int id, float u, float v, float width, float height, float dimensions) { - final Texture texture = this.createTexture(u, v, width, height, dimensions); - texture.setID(id); - return texture; - } - } -} \ No newline at end of file diff --git a/src/main/resources/mixins.capi.json b/src/main/resources/mixins.capi.json index 11dfd964..1a395c4c 100644 --- a/src/main/resources/mixins.capi.json +++ b/src/main/resources/mixins.capi.json @@ -14,12 +14,15 @@ "MixinItemRenderer", "MixinLayerArmorBase", "MixinMinecraft", + "MixinNettyPacketDecoder", + "MixinNettyPacketEncoder", "MixinNetworkManager", "MixinProfiler", "MixinRender", "MixinRenderItem", "MixinRenderLivingBase", "MixinRenderManager", + "wrapper.ICPacketPlayer", "wrapper.IEntityPlayer", "wrapper.IGameType", diff --git a/src/test b/src/test index 80eff033..fadefd65 160000 --- a/src/test +++ b/src/test @@ -1 +1 @@ -Subproject commit 80eff03351e4891a0e73c942b10ef8421436f1ec +Subproject commit fadefd65ec58fc412514b7ab841186219fd64bb9